aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS30
-rw-r--r--Makefile.common6
-rw-r--r--NEWS21
-rw-r--r--README159
-rw-r--r--backends/audiocd/audiocd.h2
-rw-r--r--backends/audiocd/sdl/sdl-audiocd.cpp3
-rw-r--r--backends/base-backend.cpp17
-rw-r--r--backends/base-backend.h7
-rw-r--r--backends/events/dinguxsdl/dinguxsdl-events.h47
-rw-r--r--backends/events/gp2xsdl/gp2xsdl-events.h60
-rw-r--r--backends/events/linuxmotosdl/linuxmotosdl-events.h43
-rw-r--r--backends/events/sdl/sdl-events.h138
-rw-r--r--backends/events/symbiansdl/symbiansdl-events.cpp201
-rw-r--r--backends/fs/ps2/ps2-fs-factory.cpp4
-rw-r--r--backends/fs/stdiostream.cpp3
-rw-r--r--backends/fs/windows/windows-fs-factory.cpp4
-rw-r--r--backends/graphics/dinguxsdl/dinguxsdl-graphics.h69
-rw-r--r--backends/graphics/gp2xsdl/gp2xsdl-graphics.cpp183
-rw-r--r--backends/graphics/gp2xwizsdl/gp2xwizsdl-graphics.cpp445
-rw-r--r--backends/graphics/graphics.h91
-rw-r--r--backends/graphics/linuxmotosdl/linuxmotosdl-graphics.h50
-rw-r--r--backends/graphics/null/null-graphics.h88
-rw-r--r--backends/graphics/opengl/glerrorcheck.cpp69
-rw-r--r--backends/graphics/opengl/glerrorcheck.h38
-rw-r--r--backends/graphics/opengl/gltexture.cpp189
-rw-r--r--backends/graphics/opengl/gltexture.h115
-rw-r--r--backends/graphics/opengl/opengl-graphics.cpp1304
-rw-r--r--backends/graphics/opengl/opengl-graphics.h293
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.cpp671
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.h120
-rw-r--r--backends/graphics/sdl/sdl-graphics.h329
-rw-r--r--backends/graphics/symbiansdl/symbiansdl-graphics.cpp77
-rw-r--r--backends/graphics/symbiansdl/symbiansdl-graphics.h42
-rw-r--r--backends/midi/alsa.cpp3
-rw-r--r--backends/midi/camd.cpp3
-rw-r--r--backends/midi/coreaudio.cpp3
-rw-r--r--backends/midi/coremidi.cpp3
-rw-r--r--backends/midi/dmedia.cpp3
-rw-r--r--backends/midi/seq.cpp3
-rw-r--r--backends/midi/stmidi.cpp3
-rw-r--r--backends/midi/timidity.cpp3
-rw-r--r--backends/midi/windows.cpp3
-rw-r--r--backends/mixer/doublebuffersdl/doublebuffersdl-mixer.cpp129
-rw-r--r--backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h69
-rw-r--r--backends/mixer/sdl/sdl-mixer.cpp143
-rw-r--r--backends/mixer/sdl/sdl-mixer.h105
-rw-r--r--backends/mixer/symbiansdl/symbiansdl-mixer.cpp102
-rw-r--r--backends/modular-backend.cpp273
-rw-r--r--backends/modular-backend.h178
-rw-r--r--backends/module.mk38
-rw-r--r--backends/mutex/mutex.h46
-rw-r--r--backends/mutex/null/null-mutex.h42
-rw-r--r--backends/mutex/sdl/sdl-mutex.cpp52
-rw-r--r--backends/platform/android/README.build3
-rw-r--r--backends/platform/android/android.cpp10
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/ScummVM.java123
-rw-r--r--backends/platform/android/video.cpp40
-rw-r--r--backends/platform/dingux/dingux-events.cpp (renamed from backends/events/dinguxsdl/dinguxsdl-events.cpp)43
-rw-r--r--backends/platform/dingux/dingux-graphics.cpp (renamed from backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp)86
-rw-r--r--backends/platform/dingux/dingux.cpp40
-rw-r--r--backends/platform/dingux/dingux.h41
-rw-r--r--backends/platform/dingux/main.cpp12
-rw-r--r--backends/platform/dingux/module.mk4
-rw-r--r--backends/platform/ds/arm9/source/dsmain.cpp4
-rwxr-xr-xbackends/platform/ds/build-ds.sh26
-rw-r--r--backends/platform/gp2x/build/README-GP2X144
-rwxr-xr-xbackends/platform/gp2x/build/config.sh3
-rwxr-xr-xbackends/platform/gp2x/build/scummvm.gpe2
-rw-r--r--backends/platform/gp2x/events.cpp (renamed from backends/events/gp2xsdl/gp2xsdl-events.cpp)420
-rw-r--r--backends/platform/gp2x/gp2x-common.h381
-rw-r--r--backends/platform/gp2x/gp2x-hw.cpp7
-rw-r--r--backends/platform/gp2x/gp2x-main.cpp50
-rw-r--r--backends/platform/gp2x/gp2x-mem.cpp23
-rw-r--r--backends/platform/gp2x/gp2x-mem.h3
-rw-r--r--backends/platform/gp2x/gp2x.cpp510
-rw-r--r--backends/platform/gp2x/graphics.cpp1701
-rw-r--r--backends/platform/gp2x/module.mk5
-rw-r--r--backends/platform/gph/build/README-GP2XWIZ140
-rw-r--r--backends/platform/gph/build/README-GPH60
-rwxr-xr-xbackends/platform/gph/build/config-alleng.sh9
-rwxr-xr-xbackends/platform/gph/build/config.sh9
-rwxr-xr-xbackends/platform/gph/build/scummvm-gdb.gpe2
-rwxr-xr-xbackends/platform/gph/build/scummvm.gpe2
-rwxr-xr-xbackends/platform/gph/caanoo-bundle.mk4
-rwxr-xr-xbackends/platform/gph/caanoo/config-alleng.sh17
-rwxr-xr-xbackends/platform/gph/caanoo/config.sh13
-rwxr-xr-xbackends/platform/gph/caanoo/scummvm-gdb.gpe2
-rwxr-xr-xbackends/platform/gph/caanoo/scummvm.gpe2
-rwxr-xr-xbackends/platform/gph/gp2xwiz-bundle.mk4
-rw-r--r--backends/platform/gph/gph-events.cpp1
-rw-r--r--backends/platform/gph/gph-hw.cpp3
-rw-r--r--backends/platform/gph/gph-main.cpp11
-rw-r--r--backends/platform/iphone/osys_events.cpp3
-rw-r--r--backends/platform/iphone/osys_main.cpp3
-rw-r--r--backends/platform/iphone/osys_sound.cpp3
-rw-r--r--backends/platform/iphone/osys_video.cpp3
-rw-r--r--backends/platform/linuxmoto/linuxmoto-events.cpp (renamed from backends/events/linuxmotosdl/linuxmotosdl-events.cpp)71
-rw-r--r--backends/platform/linuxmoto/linuxmoto-graphics.cpp (renamed from backends/graphics/linuxmotosdl/linuxmotosdl-graphics.cpp)65
-rw-r--r--backends/platform/linuxmoto/linuxmoto-main.cpp19
-rw-r--r--backends/platform/linuxmoto/linuxmoto-sdl.cpp47
-rw-r--r--backends/platform/linuxmoto/linuxmoto-sdl.h38
-rw-r--r--backends/platform/linuxmoto/module.mk2
-rw-r--r--backends/platform/null/null.cpp265
-rwxr-xr-xbackends/platform/openpandora/build/README-OPENPANDORA2
-rwxr-xr-xbackends/platform/openpandora/build/config-alleng.sh9
-rwxr-xr-xbackends/platform/openpandora/build/config.sh9
-rwxr-xr-xbackends/platform/openpandora/op-main.cpp3
-rw-r--r--backends/platform/ps2/fileio.cpp3
-rw-r--r--backends/platform/ps2/systemps2.cpp14
-rw-r--r--backends/platform/psp/Makefile17
-rw-r--r--backends/platform/psp/README.PSP35
-rw-r--r--backends/platform/psp/display_client.cpp176
-rw-r--r--backends/platform/psp/display_client.h22
-rw-r--r--backends/platform/psp/display_manager.cpp26
-rw-r--r--backends/platform/psp/display_manager.h9
-rw-r--r--backends/platform/psp/dummy.cpp59
-rw-r--r--backends/platform/psp/elf32.h209
-rw-r--r--backends/platform/psp/image_viewer.cpp327
-rw-r--r--backends/platform/psp/image_viewer.h105
-rw-r--r--backends/platform/psp/input.cpp66
-rw-r--r--backends/platform/psp/input.h49
-rw-r--r--backends/platform/psp/module.mk5
-rw-r--r--backends/platform/psp/osys_psp.cpp12
-rw-r--r--backends/platform/psp/osys_psp.h4
-rw-r--r--backends/platform/psp/png_loader.cpp65
-rw-r--r--backends/platform/psp/png_loader.h8
-rw-r--r--backends/platform/psp/psp.spec2
-rw-r--r--backends/platform/psp/pspkeyboard.cpp7
-rw-r--r--backends/platform/psp/psploader.cpp732
-rw-r--r--backends/platform/psp/psploader.h137
-rw-r--r--backends/platform/samsungtv/events.cpp (renamed from backends/events/samsungtvsdl/samsungtvsdl-events.cpp)17
-rw-r--r--backends/platform/samsungtv/main.cpp9
-rw-r--r--backends/platform/samsungtv/module.mk1
-rw-r--r--backends/platform/samsungtv/samsungtv.cpp33
-rw-r--r--backends/platform/samsungtv/samsungtv.h25
-rw-r--r--backends/platform/sdl/amigaos/amigaos-main.cpp54
-rw-r--r--backends/platform/sdl/events.cpp (renamed from backends/events/sdl/sdl-events.cpp)157
-rw-r--r--backends/platform/sdl/graphics.cpp (renamed from backends/graphics/sdl/sdl-graphics.cpp)441
-rw-r--r--backends/platform/sdl/macosx/macosx-main.cpp54
-rw-r--r--backends/platform/sdl/macosx/macosx.cpp76
-rw-r--r--backends/platform/sdl/main.cpp33
-rw-r--r--backends/platform/sdl/module.mk26
-rw-r--r--backends/platform/sdl/posix/posix-main.cpp54
-rw-r--r--backends/platform/sdl/posix/posix.cpp68
-rw-r--r--backends/platform/sdl/sdl.cpp834
-rw-r--r--backends/platform/sdl/sdl.h486
-rw-r--r--backends/platform/sdl/win32/win32-main.cpp66
-rw-r--r--backends/platform/sdl/win32/win32.cpp93
-rw-r--r--backends/platform/symbian/AdaptAllMMPs.pl7
-rw-r--r--backends/platform/symbian/BuildPackageUpload_LocalSettings.pl8
-rw-r--r--backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in3
-rw-r--r--backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in3
-rw-r--r--backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in5
-rw-r--r--backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in4
-rw-r--r--backends/platform/symbian/mmp/scummvm_base.mmp.in12
-rw-r--r--backends/platform/symbian/mmp/scummvm_toon.mmp.in64
-rw-r--r--backends/platform/symbian/src/SymbianOS.cpp465
-rw-r--r--backends/platform/symbian/src/SymbianOS.h118
-rw-r--r--backends/platform/symbian/src/Symbianmain.cpp99
-rw-r--r--backends/platform/symbian/src/portdefs.h7
-rw-r--r--backends/platform/wii/main.cpp5
-rw-r--r--backends/platform/wii/options.cpp2
-rw-r--r--backends/platform/wii/wii.mk4
-rw-r--r--backends/platform/wince/CEActionsPocket.cpp17
-rw-r--r--backends/platform/wince/CEActionsPocket.h50
-rw-r--r--backends/platform/wince/CEActionsSmartphone.cpp6
-rw-r--r--backends/platform/wince/CEActionsSmartphone.h36
-rw-r--r--backends/platform/wince/CEDevice.cpp5
-rw-r--r--backends/platform/wince/CEDevice.h26
-rw-r--r--backends/platform/wince/CELauncherDialog.cpp4
-rw-r--r--backends/platform/wince/CEScaler.cpp1
-rw-r--r--backends/platform/wince/CEgui/GUIElement.cpp152
-rw-r--r--backends/platform/wince/CEgui/GUIElement.h63
-rw-r--r--backends/platform/wince/CEgui/ItemAction.cpp42
-rw-r--r--backends/platform/wince/CEgui/ItemAction.h20
-rw-r--r--backends/platform/wince/CEgui/ItemSwitch.cpp110
-rw-r--r--backends/platform/wince/CEgui/ItemSwitch.h33
-rw-r--r--backends/platform/wince/CEgui/Panel.cpp85
-rw-r--r--backends/platform/wince/CEgui/Panel.h37
-rw-r--r--backends/platform/wince/CEgui/PanelItem.cpp24
-rw-r--r--backends/platform/wince/CEgui/PanelItem.h27
-rw-r--r--backends/platform/wince/CEgui/PanelKeyboard.cpp122
-rw-r--r--backends/platform/wince/CEgui/PanelKeyboard.h21
-rw-r--r--backends/platform/wince/CEgui/SDL_ImageResource.cpp98
-rw-r--r--backends/platform/wince/CEgui/SDL_ImageResource.h28
-rw-r--r--backends/platform/wince/CEgui/Toolbar.cpp12
-rw-r--r--backends/platform/wince/CEgui/Toolbar.h23
-rw-r--r--backends/platform/wince/CEgui/ToolbarHandler.cpp161
-rw-r--r--backends/platform/wince/CEgui/ToolbarHandler.h47
-rw-r--r--backends/platform/wince/CEkeys/EventsBuffer.cpp5
-rw-r--r--backends/platform/wince/CEkeys/EventsBuffer.h2
-rw-r--r--backends/platform/wince/missing/assert.h2
-rw-r--r--backends/platform/wince/missing/conio.h2
-rw-r--r--backends/platform/wince/missing/dir.h1
-rw-r--r--backends/platform/wince/missing/direct.h1
-rw-r--r--backends/platform/wince/missing/dirent.h52
-rw-r--r--backends/platform/wince/missing/fcntl.h1
-rw-r--r--backends/platform/wince/missing/gcc/assert.h9
-rw-r--r--backends/platform/wince/missing/gcc/direct.h1
-rw-r--r--backends/platform/wince/missing/gcc/errno.h1
-rw-r--r--backends/platform/wince/missing/gcc/sys/stat.h23
-rw-r--r--backends/platform/wince/missing/missing.cpp153
-rw-r--r--backends/platform/wince/missing/signal.h3
-rw-r--r--backends/platform/wince/missing/sys/stat.h25
-rw-r--r--backends/platform/wince/missing/sys/time.h10
-rw-r--r--backends/platform/wince/missing/sys/types.h5
-rw-r--r--backends/platform/wince/missing/unistd.h1
-rw-r--r--backends/platform/wince/portdefs.h4
-rw-r--r--backends/platform/wince/wince-sdl.cpp24
-rw-r--r--backends/plugins/ds/ds-provider.cpp (renamed from backends/mixer/symbiansdl/symbiansdl-mixer.h)32
-rw-r--r--backends/plugins/ds/ds-provider.h41
-rw-r--r--backends/plugins/ds/plugin.ld217
-rw-r--r--backends/plugins/elf/arm-loader.cpp133
-rw-r--r--backends/plugins/elf/arm-loader.h (renamed from backends/events/samsungtvsdl/samsungtvsdl-events.h)24
-rw-r--r--backends/plugins/elf/elf-loader.cpp440
-rw-r--r--backends/plugins/elf/elf-loader.h102
-rw-r--r--backends/plugins/elf/elf-provider.cpp177
-rw-r--r--backends/plugins/elf/elf-provider.h97
-rw-r--r--backends/plugins/elf/elf32.h252
-rw-r--r--backends/plugins/elf/mips-loader.cpp342
-rw-r--r--backends/plugins/elf/mips-loader.h (renamed from engines/sword25/kernel/bs_stdint.h)56
-rw-r--r--backends/plugins/elf/plugin.syms (renamed from backends/platform/psp/plugin.syms)1
-rw-r--r--backends/plugins/elf/ppc-loader.cpp129
-rw-r--r--backends/plugins/elf/ppc-loader.h44
-rw-r--r--backends/plugins/elf/shorts-segment-manager.cpp90
-rw-r--r--backends/plugins/elf/shorts-segment-manager.h117
-rw-r--r--backends/plugins/elf/version.cpp (renamed from backends/platform/sdl/win32/win32.h)17
-rw-r--r--backends/plugins/elf/version.h35
-rw-r--r--backends/plugins/ps2/main_prog.ld99
-rw-r--r--backends/plugins/ps2/plugin.ld94
-rw-r--r--backends/plugins/ps2/ps2-provider.cpp (renamed from backends/timer/sdl/sdl-timer.h)34
-rw-r--r--backends/plugins/ps2/ps2-provider.h41
-rw-r--r--backends/plugins/psp/main_prog.ld (renamed from backends/platform/psp/main_prog.ld)0
-rw-r--r--backends/plugins/psp/plugin.ld (renamed from backends/platform/psp/plugin.ld)9
-rw-r--r--backends/plugins/psp/psp-provider.cpp85
-rw-r--r--backends/plugins/psp/psp-provider.h22
-rw-r--r--backends/plugins/sdl/sdl-provider.cpp3
-rw-r--r--backends/plugins/wii/plugin.ld263
-rw-r--r--backends/plugins/wii/wii-provider.cpp (renamed from backends/graphics/gp2xsdl/gp2xsdl-graphics.h)33
-rw-r--r--backends/plugins/wii/wii-provider.h41
-rw-r--r--backends/saves/default/default-saves.cpp3
-rw-r--r--backends/timer/default/default-timer.h3
-rw-r--r--backends/timer/sdl/sdl-timer.cpp51
-rw-r--r--backends/vkeybd/virtual-keyboard-parser.cpp6
-rw-r--r--base/commandLine.cpp20
-rw-r--r--base/internal_version.h2
-rw-r--r--base/internal_version.h.in2
-rw-r--r--base/main.cpp33
-rw-r--r--base/plugins.cpp155
-rw-r--r--base/plugins.h44
-rw-r--r--base/version.cpp4
-rw-r--r--common/algorithm.h8
-rw-r--r--common/config-manager.cpp14
-rw-r--r--common/debug.cpp30
-rw-r--r--common/debug.h19
-rw-r--r--common/forbidden.h161
-rw-r--r--common/hashmap.cpp4
-rw-r--r--common/hashmap.h38
-rw-r--r--common/macresman.cpp56
-rw-r--r--common/macresman.h42
-rw-r--r--common/md5.cpp28
-rw-r--r--common/md5.h31
-rw-r--r--common/memorypool.cpp2
-rw-r--r--common/memorypool.h2
-rw-r--r--common/mutex.h4
-rw-r--r--common/ptr.h3
-rw-r--r--common/scummsys.h8
-rw-r--r--common/str.cpp2
-rw-r--r--common/str.h2
-rw-r--r--common/textconsole.cpp9
-rw-r--r--common/timer.h1
-rw-r--r--common/unzip.cpp2
-rw-r--r--common/util.cpp28
-rw-r--r--common/util.h14
-rw-r--r--common/xmlparser.cpp97
-rw-r--r--common/xmlparser.h100
-rwxr-xr-xconfigure207
-rw-r--r--dists/engine-data/README7
-rw-r--r--dists/engine-data/hugo.datbin174491 -> 174483 bytes
-rw-r--r--dists/engine-data/kyra.datbin355807 -> 355898 bytes
-rw-r--r--engines/advancedDetector.cpp59
-rw-r--r--engines/advancedDetector.h1
-rw-r--r--engines/agi/agi.cpp47
-rw-r--r--engines/agi/agi.h14
-rw-r--r--engines/agi/console.cpp2
-rw-r--r--engines/agi/cycle.cpp4
-rw-r--r--engines/agi/id.cpp4
-rw-r--r--engines/agi/keyboard.cpp1
-rw-r--r--engines/agi/loader_v2.cpp5
-rw-r--r--engines/agi/loader_v3.cpp2
-rw-r--r--engines/agi/objects.cpp18
-rw-r--r--engines/agi/op_cmd.cpp14
-rw-r--r--engines/agi/op_dbg.cpp20
-rw-r--r--engines/agi/preagi_mickey.cpp6
-rw-r--r--engines/agi/predictive.cpp2
-rw-r--r--engines/agi/sound_2gs.cpp14
-rw-r--r--engines/agi/sound_coco3.cpp4
-rw-r--r--engines/agi/sound_midi.cpp2
-rw-r--r--engines/agi/sound_sarien.cpp7
-rw-r--r--engines/agi/words.cpp4
-rw-r--r--engines/agos/agos.cpp2
-rw-r--r--engines/agos/agos.h11
-rw-r--r--engines/agos/animation.cpp4
-rw-r--r--engines/agos/debug.cpp72
-rw-r--r--engines/agos/event.cpp1
-rw-r--r--engines/agos/menus.cpp2
-rw-r--r--engines/agos/midi.cpp8
-rw-r--r--engines/agos/res.cpp10
-rw-r--r--engines/agos/res_snd.cpp16
-rw-r--r--engines/agos/rooms.cpp42
-rw-r--r--engines/agos/saveload.cpp6
-rw-r--r--engines/agos/script_pn.cpp2
-rw-r--r--engines/agos/script_pp.cpp7
-rw-r--r--engines/agos/sound.cpp44
-rw-r--r--engines/agos/string.cpp163
-rw-r--r--engines/agos/subroutine.cpp20
-rw-r--r--engines/agos/verb_pn.cpp2
-rw-r--r--engines/agos/vga.cpp4
-rw-r--r--engines/agos/vga_ff.cpp4
-rw-r--r--engines/cine/cine.cpp3
-rw-r--r--engines/cine/cine.h8
-rw-r--r--engines/cine/console.cpp (renamed from engines/gob/helper.h)23
-rw-r--r--engines/cine/console.h (renamed from backends/platform/sdl/macosx/macosx.h)27
-rw-r--r--engines/cine/main_loop.cpp6
-rw-r--r--engines/cine/module.mk1
-rw-r--r--engines/cine/script_fw.cpp2
-rw-r--r--engines/cruise/background.cpp3
-rw-r--r--engines/cruise/cruise.h2
-rw-r--r--engines/cruise/cruise_main.cpp4
-rw-r--r--engines/cruise/dataLoader.cpp2
-rw-r--r--engines/cruise/decompiler.cpp20
-rw-r--r--engines/cruise/function.cpp7
-rw-r--r--engines/cruise/overlay.cpp1
-rw-r--r--engines/cruise/saveload.cpp3
-rw-r--r--engines/cruise/script.cpp7
-rw-r--r--engines/cruise/vars.cpp4
-rw-r--r--engines/cruise/vars.h4
-rw-r--r--engines/dialogs.cpp30
-rw-r--r--engines/draci/console.cpp43
-rw-r--r--engines/draci/console.h50
-rw-r--r--engines/draci/detection.cpp9
-rw-r--r--engines/draci/draci.cpp15
-rw-r--r--engines/draci/draci.h12
-rw-r--r--engines/draci/game.cpp14
-rw-r--r--engines/draci/module.mk1
-rw-r--r--engines/draci/mouse.cpp8
-rw-r--r--engines/draci/saveload.cpp4
-rw-r--r--engines/draci/sound.cpp14
-rw-r--r--engines/drascula/detection.cpp13
-rw-r--r--engines/drascula/drascula.h4
-rw-r--r--engines/drascula/resource.cpp10
-rw-r--r--engines/drascula/rooms.cpp4
-rw-r--r--engines/drascula/saveload.cpp4
-rw-r--r--engines/engine.cpp29
-rw-r--r--engines/engine.h29
-rw-r--r--engines/engines.mk5
-rw-r--r--engines/game.h1
-rw-r--r--engines/gob/console.cpp163
-rw-r--r--engines/gob/console.h (renamed from backends/platform/sdl/posix/posix.h)38
-rw-r--r--engines/gob/dataio.cpp676
-rw-r--r--engines/gob/dataio.h127
-rw-r--r--engines/gob/demos/demoplayer.cpp1
-rw-r--r--engines/gob/detection_tables.h10
-rw-r--r--engines/gob/draw.cpp14
-rw-r--r--engines/gob/draw_playtoons.cpp2
-rw-r--r--engines/gob/draw_v1.cpp4
-rw-r--r--engines/gob/draw_v2.cpp4
-rw-r--r--engines/gob/game.cpp23
-rw-r--r--engines/gob/gob.cpp6
-rw-r--r--engines/gob/gob.h16
-rw-r--r--engines/gob/goblin.cpp142
-rw-r--r--engines/gob/goblin_v1.cpp52
-rw-r--r--engines/gob/goblin_v2.cpp302
-rw-r--r--engines/gob/goblin_v4.cpp126
-rw-r--r--engines/gob/hotspots.cpp13
-rw-r--r--engines/gob/init.cpp87
-rw-r--r--engines/gob/inter.cpp35
-rw-r--r--engines/gob/inter_bargon.cpp4
-rw-r--r--engines/gob/inter_playtoons.cpp26
-rw-r--r--engines/gob/inter_v1.cpp74
-rw-r--r--engines/gob/inter_v2.cpp63
-rw-r--r--engines/gob/inter_v4.cpp4
-rw-r--r--engines/gob/inter_v6.cpp16
-rw-r--r--engines/gob/map.cpp451
-rw-r--r--engines/gob/map.h193
-rw-r--r--engines/gob/map_v1.cpp30
-rw-r--r--engines/gob/map_v2.cpp31
-rw-r--r--engines/gob/module.mk1
-rw-r--r--engines/gob/resources.cpp21
-rw-r--r--engines/gob/save/savefile.h37
-rw-r--r--engines/gob/script.cpp25
-rw-r--r--engines/gob/script.h2
-rw-r--r--engines/gob/sound/adlib.cpp2
-rw-r--r--engines/gob/sound/cdrom.cpp6
-rw-r--r--engines/gob/sound/cdrom.h4
-rw-r--r--engines/gob/sound/sound.cpp29
-rw-r--r--engines/gob/totfile.cpp4
-rw-r--r--engines/gob/util.cpp6
-rw-r--r--engines/gob/variables.cpp4
-rw-r--r--engines/gob/video.cpp4
-rw-r--r--engines/gob/videoplayer.cpp5
-rw-r--r--engines/groovie/font.cpp4
-rw-r--r--engines/groovie/groovie.h2
-rw-r--r--engines/groovie/saveload.h1
-rw-r--r--engines/groovie/script.cpp4
-rw-r--r--engines/hugo/console.cpp (renamed from engines/hugo/engine.h)27
-rw-r--r--engines/hugo/console.h50
-rw-r--r--engines/hugo/detection.cpp4
-rw-r--r--engines/hugo/display.cpp179
-rw-r--r--engines/hugo/display.h33
-rw-r--r--engines/hugo/display_v1d.cpp33
-rw-r--r--engines/hugo/display_v1w.cpp21
-rw-r--r--engines/hugo/engine.cpp968
-rw-r--r--engines/hugo/file.cpp237
-rw-r--r--engines/hugo/file.h28
-rw-r--r--engines/hugo/file_v1d.cpp18
-rw-r--r--engines/hugo/file_v1w.cpp6
-rw-r--r--engines/hugo/file_v2d.cpp26
-rw-r--r--engines/hugo/file_v3d.cpp34
-rw-r--r--engines/hugo/game.h139
-rw-r--r--engines/hugo/hugo.cpp1377
-rw-r--r--engines/hugo/hugo.h162
-rw-r--r--engines/hugo/intro.cpp2
-rw-r--r--engines/hugo/intro.h16
-rw-r--r--engines/hugo/intro_v1d.cpp74
-rw-r--r--engines/hugo/intro_v1w.cpp10
-rw-r--r--engines/hugo/intro_v2d.cpp12
-rw-r--r--engines/hugo/intro_v2w.cpp2
-rw-r--r--engines/hugo/intro_v3d.cpp36
-rw-r--r--engines/hugo/intro_v3w.cpp30
-rw-r--r--engines/hugo/inventory.cpp87
-rw-r--r--engines/hugo/inventory.h4
-rw-r--r--engines/hugo/module.mk9
-rw-r--r--engines/hugo/mouse.cpp144
-rw-r--r--engines/hugo/mouse.h4
-rw-r--r--engines/hugo/object.cpp454
-rw-r--r--engines/hugo/object.h131
-rw-r--r--engines/hugo/object_v1d.cpp372
-rw-r--r--engines/hugo/object_v1w.cpp385
-rw-r--r--engines/hugo/object_v2d.cpp364
-rw-r--r--engines/hugo/object_v3d.cpp266
-rw-r--r--engines/hugo/parser.cpp117
-rw-r--r--engines/hugo/parser.h18
-rw-r--r--engines/hugo/parser_v1d.cpp187
-rw-r--r--engines/hugo/parser_v1w.cpp231
-rw-r--r--engines/hugo/parser_v2d.cpp43
-rw-r--r--engines/hugo/parser_v3d.cpp71
-rw-r--r--engines/hugo/route.cpp146
-rw-r--r--engines/hugo/route.h4
-rw-r--r--engines/hugo/schedule.cpp1247
-rw-r--r--engines/hugo/schedule.h91
-rw-r--r--engines/hugo/schedule_v1d.cpp369
-rw-r--r--engines/hugo/schedule_v1w.cpp493
-rw-r--r--engines/hugo/schedule_v2d.cpp395
-rw-r--r--engines/hugo/schedule_v3d.cpp281
-rw-r--r--engines/hugo/sound.cpp18
-rw-r--r--engines/hugo/sound.h6
-rw-r--r--engines/hugo/util.cpp40
-rw-r--r--engines/hugo/util.h1
-rw-r--r--engines/kyra/animator_v2.cpp2
-rw-r--r--engines/kyra/debugger.cpp20
-rw-r--r--engines/kyra/debugger.h6
-rw-r--r--engines/kyra/detection.cpp2
-rw-r--r--engines/kyra/detection_tables.h17
-rw-r--r--engines/kyra/gui_hof.cpp58
-rw-r--r--engines/kyra/gui_lok.cpp17
-rw-r--r--engines/kyra/gui_lol.cpp2
-rw-r--r--engines/kyra/gui_mr.cpp24
-rw-r--r--engines/kyra/gui_v2.cpp2
-rw-r--r--engines/kyra/item.h (renamed from backends/platform/sdl/amigaos/amigaos.h)22
-rw-r--r--engines/kyra/items_hof.cpp34
-rw-r--r--engines/kyra/items_lok.cpp57
-rw-r--r--engines/kyra/items_lol.cpp28
-rw-r--r--engines/kyra/items_mr.cpp46
-rw-r--r--engines/kyra/items_v2.cpp22
-rw-r--r--engines/kyra/kyra_hof.cpp32
-rw-r--r--engines/kyra/kyra_hof.h26
-rw-r--r--engines/kyra/kyra_lok.cpp17
-rw-r--r--engines/kyra/kyra_lok.h24
-rw-r--r--engines/kyra/kyra_mr.cpp30
-rw-r--r--engines/kyra/kyra_mr.h20
-rw-r--r--engines/kyra/kyra_v1.cpp15
-rw-r--r--engines/kyra/kyra_v1.h9
-rw-r--r--engines/kyra/kyra_v2.h26
-rw-r--r--engines/kyra/lol.cpp4
-rw-r--r--engines/kyra/lol.h38
-rw-r--r--engines/kyra/resource_intern.cpp2
-rw-r--r--engines/kyra/saveload.cpp4
-rw-r--r--engines/kyra/saveload_hof.cpp10
-rw-r--r--engines/kyra/saveload_lok.cpp6
-rw-r--r--engines/kyra/saveload_lol.cpp10
-rw-r--r--engines/kyra/saveload_mr.cpp10
-rw-r--r--engines/kyra/scene_hof.cpp12
-rw-r--r--engines/kyra/scene_lok.cpp5
-rw-r--r--engines/kyra/scene_lol.cpp2
-rw-r--r--engines/kyra/scene_mr.cpp22
-rw-r--r--engines/kyra/screen.cpp6
-rw-r--r--engines/kyra/screen.h1
-rw-r--r--engines/kyra/screen_hof.h1
-rw-r--r--engines/kyra/screen_lok.h1
-rw-r--r--engines/kyra/screen_lol.h3
-rw-r--r--engines/kyra/screen_mr.h1
-rw-r--r--engines/kyra/screen_v2.cpp6
-rw-r--r--engines/kyra/script_hof.cpp8
-rw-r--r--engines/kyra/script_lok.cpp5
-rw-r--r--engines/kyra/script_lol.cpp7
-rw-r--r--engines/kyra/script_mr.cpp10
-rw-r--r--engines/kyra/script_tim.cpp2
-rw-r--r--engines/kyra/script_v2.cpp2
-rw-r--r--engines/kyra/sequences_hof.cpp4
-rw-r--r--engines/kyra/sequences_lol.cpp2
-rw-r--r--engines/kyra/sound.h2
-rw-r--r--engines/kyra/sound_adlib.cpp2
-rw-r--r--engines/kyra/sound_adlib.h2
-rw-r--r--engines/kyra/sound_intern.h2
-rw-r--r--engines/kyra/sound_midi.cpp2
-rw-r--r--engines/kyra/sound_towns.cpp4
-rw-r--r--engines/kyra/sprites_lol.cpp9
-rw-r--r--engines/kyra/staticres.cpp27
-rw-r--r--engines/kyra/text_lol.cpp13
-rw-r--r--engines/kyra/text_lol.h2
-rw-r--r--engines/kyra/timer_mr.cpp2
-rw-r--r--engines/lastexpress/data/animation.cpp300
-rw-r--r--engines/lastexpress/data/animation.h114
-rw-r--r--engines/lastexpress/data/archive.cpp115
-rw-r--r--engines/lastexpress/data/archive.h75
-rw-r--r--engines/lastexpress/data/background.cpp141
-rw-r--r--engines/lastexpress/data/background.h81
-rw-r--r--engines/lastexpress/data/cursor.cpp144
-rw-r--r--engines/lastexpress/data/cursor.h93
-rw-r--r--engines/lastexpress/data/font.cpp205
-rw-r--r--engines/lastexpress/data/font.h82
-rw-r--r--engines/lastexpress/data/scene.cpp292
-rw-r--r--engines/lastexpress/data/scene.h245
-rw-r--r--engines/lastexpress/data/sequence.cpp482
-rw-r--r--engines/lastexpress/data/sequence.h205
-rw-r--r--engines/lastexpress/data/snd.cpp141
-rw-r--r--engines/lastexpress/data/snd.h97
-rw-r--r--engines/lastexpress/data/subtitle.cpp244
-rw-r--r--engines/lastexpress/data/subtitle.h79
-rw-r--r--engines/lastexpress/debug.cpp1177
-rw-r--r--engines/lastexpress/debug.h106
-rw-r--r--engines/lastexpress/detection.cpp211
-rw-r--r--engines/lastexpress/drawable.h42
-rw-r--r--engines/lastexpress/entities/abbot.cpp1910
-rw-r--r--engines/lastexpress/entities/abbot.h225
-rw-r--r--engines/lastexpress/entities/alexei.cpp2002
-rw-r--r--engines/lastexpress/entities/alexei.h213
-rw-r--r--engines/lastexpress/entities/alouan.cpp504
-rw-r--r--engines/lastexpress/entities/alouan.h139
-rw-r--r--engines/lastexpress/entities/anna.cpp4032
-rw-r--r--engines/lastexpress/entities/anna.h252
-rw-r--r--engines/lastexpress/entities/august.cpp3536
-rw-r--r--engines/lastexpress/entities/august.h275
-rw-r--r--engines/lastexpress/entities/boutarel.cpp1260
-rw-r--r--engines/lastexpress/entities/boutarel.h188
-rw-r--r--engines/lastexpress/entities/chapters.cpp1820
-rw-r--r--engines/lastexpress/entities/chapters.h166
-rw-r--r--engines/lastexpress/entities/cooks.cpp571
-rw-r--r--engines/lastexpress/entities/cooks.h109
-rw-r--r--engines/lastexpress/entities/coudert.cpp4179
-rw-r--r--engines/lastexpress/entities/coudert.h229
-rw-r--r--engines/lastexpress/entities/entity.cpp486
-rw-r--r--engines/lastexpress/entities/entity.h800
-rw-r--r--engines/lastexpress/entities/entity39.cpp103
-rw-r--r--engines/lastexpress/entities/entity39.h78
-rw-r--r--engines/lastexpress/entities/entity_intern.h528
-rw-r--r--engines/lastexpress/entities/francois.cpp1295
-rw-r--r--engines/lastexpress/entities/francois.h170
-rw-r--r--engines/lastexpress/entities/gendarmes.cpp620
-rw-r--r--engines/lastexpress/entities/gendarmes.h99
-rw-r--r--engines/lastexpress/entities/hadija.cpp532
-rw-r--r--engines/lastexpress/entities/hadija.h144
-rw-r--r--engines/lastexpress/entities/ivo.cpp829
-rw-r--r--engines/lastexpress/entities/ivo.h177
-rw-r--r--engines/lastexpress/entities/kahina.cpp1528
-rw-r--r--engines/lastexpress/entities/kahina.h166
-rw-r--r--engines/lastexpress/entities/kronos.cpp892
-rw-r--r--engines/lastexpress/entities/kronos.h138
-rw-r--r--engines/lastexpress/entities/mahmud.cpp839
-rw-r--r--engines/lastexpress/entities/mahmud.h153
-rw-r--r--engines/lastexpress/entities/max.cpp628
-rw-r--r--engines/lastexpress/entities/max.h129
-rw-r--r--engines/lastexpress/entities/mertens.cpp4113
-rw-r--r--engines/lastexpress/entities/mertens.h220
-rw-r--r--engines/lastexpress/entities/milos.cpp1805
-rw-r--r--engines/lastexpress/entities/milos.h175
-rw-r--r--engines/lastexpress/entities/mmeboutarel.cpp1301
-rw-r--r--engines/lastexpress/entities/mmeboutarel.h164
-rw-r--r--engines/lastexpress/entities/pascale.cpp1232
-rw-r--r--engines/lastexpress/entities/pascale.h165
-rw-r--r--engines/lastexpress/entities/rebecca.cpp1838
-rw-r--r--engines/lastexpress/entities/rebecca.h230
-rw-r--r--engines/lastexpress/entities/salko.cpp642
-rw-r--r--engines/lastexpress/entities/salko.h149
-rw-r--r--engines/lastexpress/entities/servers0.cpp1039
-rw-r--r--engines/lastexpress/entities/servers0.h172
-rw-r--r--engines/lastexpress/entities/servers1.cpp787
-rw-r--r--engines/lastexpress/entities/servers1.h167
-rw-r--r--engines/lastexpress/entities/sophie.cpp279
-rw-r--r--engines/lastexpress/entities/sophie.h98
-rw-r--r--engines/lastexpress/entities/tables.cpp221
-rw-r--r--engines/lastexpress/entities/tables.h (renamed from backends/events/symbiansdl/symbiansdl-events.h)64
-rw-r--r--engines/lastexpress/entities/tatiana.cpp2272
-rw-r--r--engines/lastexpress/entities/tatiana.h235
-rw-r--r--engines/lastexpress/entities/train.cpp575
-rw-r--r--engines/lastexpress/entities/train.h95
-rw-r--r--engines/lastexpress/entities/vassili.cpp589
-rw-r--r--engines/lastexpress/entities/vassili.h110
-rw-r--r--engines/lastexpress/entities/verges.cpp1898
-rw-r--r--engines/lastexpress/entities/verges.h182
-rw-r--r--engines/lastexpress/entities/vesna.cpp1161
-rw-r--r--engines/lastexpress/entities/vesna.h176
-rw-r--r--engines/lastexpress/entities/yasmin.cpp490
-rw-r--r--engines/lastexpress/entities/yasmin.h142
-rw-r--r--engines/lastexpress/eventhandler.h (renamed from backends/graphics/gp2xwizsdl/gp2xwizsdl-graphics.h)43
-rw-r--r--engines/lastexpress/game/action.cpp1966
-rw-r--r--engines/lastexpress/game/action.h135
-rw-r--r--engines/lastexpress/game/beetle.cpp517
-rw-r--r--engines/lastexpress/game/beetle.h118
-rw-r--r--engines/lastexpress/game/entities.cpp2744
-rw-r--r--engines/lastexpress/game/entities.h380
-rw-r--r--engines/lastexpress/game/fight.cpp1587
-rw-r--r--engines/lastexpress/game/fight.h269
-rw-r--r--engines/lastexpress/game/inventory.cpp599
-rw-r--r--engines/lastexpress/game/inventory.h180
-rw-r--r--engines/lastexpress/game/logic.cpp593
-rw-r--r--engines/lastexpress/game/logic.h92
-rw-r--r--engines/lastexpress/game/menu.cpp1538
-rw-r--r--engines/lastexpress/game/menu.h210
-rw-r--r--engines/lastexpress/game/object.cpp109
-rw-r--r--engines/lastexpress/game/object.h92
-rw-r--r--engines/lastexpress/game/savegame.cpp564
-rw-r--r--engines/lastexpress/game/savegame.h288
-rw-r--r--engines/lastexpress/game/savepoint.cpp296
-rw-r--r--engines/lastexpress/game/savepoint.h151
-rw-r--r--engines/lastexpress/game/scenes.cpp1195
-rw-r--r--engines/lastexpress/game/scenes.h120
-rw-r--r--engines/lastexpress/game/sound.cpp1734
-rw-r--r--engines/lastexpress/game/sound.h343
-rw-r--r--engines/lastexpress/game/state.cpp82
-rw-r--r--engines/lastexpress/game/state.h657
-rw-r--r--engines/lastexpress/graphics.cpp166
-rw-r--r--engines/lastexpress/graphics.h76
-rw-r--r--engines/lastexpress/helpers.h102
-rw-r--r--engines/lastexpress/lastexpress.cpp310
-rw-r--r--engines/lastexpress/lastexpress.h153
-rw-r--r--engines/lastexpress/module.mk73
-rw-r--r--engines/lastexpress/resource.cpp248
-rw-r--r--engines/lastexpress/resource.h72
-rw-r--r--engines/lastexpress/shared.h1716
-rw-r--r--engines/lure/debugger.cpp9
-rw-r--r--engines/lure/hotspots.cpp44
-rw-r--r--engines/lure/hotspots.h3
-rw-r--r--engines/lure/lure.h6
-rw-r--r--engines/lure/res.cpp2
-rw-r--r--engines/lure/res_struct.cpp67
-rw-r--r--engines/lure/res_struct.h7
-rw-r--r--engines/m4/assets.cpp30
-rw-r--r--engines/m4/console.cpp16
-rw-r--r--engines/m4/converse.cpp311
-rw-r--r--engines/m4/dialogs.cpp2
-rw-r--r--engines/m4/events.cpp2
-rw-r--r--engines/m4/font.cpp10
-rw-r--r--engines/m4/globals.cpp33
-rw-r--r--engines/m4/globals.h11
-rw-r--r--engines/m4/graphics.cpp12
-rw-r--r--engines/m4/hotspot.cpp2
-rw-r--r--engines/m4/m4.cpp31
-rw-r--r--engines/m4/m4.h7
-rw-r--r--engines/m4/m4_scene.cpp8
-rw-r--r--engines/m4/mads_anim.cpp8
-rw-r--r--engines/m4/mads_logic.cpp8
-rw-r--r--engines/m4/mads_menus.cpp2
-rw-r--r--engines/m4/mads_scene.cpp17
-rw-r--r--engines/m4/mads_scene.h4
-rw-r--r--engines/m4/rails.cpp4
-rw-r--r--engines/m4/resource.cpp26
-rw-r--r--engines/m4/script.cpp199
-rw-r--r--engines/m4/script.h2
-rw-r--r--engines/m4/sound.cpp16
-rw-r--r--engines/m4/woodscript.cpp10
-rw-r--r--engines/m4/ws_machine.cpp62
-rw-r--r--engines/m4/ws_sequence.cpp101
-rw-r--r--engines/made/console.cpp43
-rw-r--r--engines/made/console.h (renamed from backends/platform/sdl/amigaos/amigaos.cpp)29
-rw-r--r--engines/made/made.cpp9
-rw-r--r--engines/made/made.h11
-rw-r--r--engines/made/module.mk1
-rw-r--r--engines/made/resource.cpp1
-rw-r--r--engines/made/screen.cpp2
-rw-r--r--engines/metaengine.h1
-rw-r--r--engines/mohawk/console.cpp20
-rw-r--r--engines/mohawk/mohawk.h9
-rw-r--r--engines/mohawk/myst.cpp22
-rw-r--r--engines/mohawk/myst_scripts.cpp27
-rw-r--r--engines/mohawk/riven_scripts.cpp44
-rw-r--r--engines/parallaction/detection.cpp2
-rw-r--r--engines/parallaction/font.cpp4
-rw-r--r--engines/parallaction/gfxbase.cpp2
-rw-r--r--engines/parallaction/gui_ns.cpp2
-rw-r--r--engines/parallaction/parallaction.h5
-rw-r--r--engines/parallaction/parallaction_br.cpp3
-rw-r--r--engines/parallaction/parser_ns.cpp3
-rw-r--r--engines/parallaction/staticres.cpp399
-rw-r--r--engines/queen/debug.cpp8
-rw-r--r--engines/queen/logic.cpp6
-rw-r--r--engines/queen/queen.h4
-rw-r--r--engines/queen/talk.cpp2
-rw-r--r--engines/saga/actor.cpp388
-rw-r--r--engines/saga/actor.h70
-rw-r--r--engines/saga/actor_walk.cpp42
-rw-r--r--engines/saga/animation.cpp128
-rw-r--r--engines/saga/animation.h33
-rw-r--r--engines/saga/detection.cpp6
-rw-r--r--engines/saga/events.cpp127
-rw-r--r--engines/saga/events.h26
-rw-r--r--engines/saga/font.cpp74
-rw-r--r--engines/saga/font.h11
-rw-r--r--engines/saga/gfx.cpp33
-rw-r--r--engines/saga/gfx.h7
-rw-r--r--engines/saga/image.cpp112
-rw-r--r--engines/saga/interface.cpp152
-rw-r--r--engines/saga/interface.h11
-rw-r--r--engines/saga/introproc_ihnm.cpp20
-rw-r--r--engines/saga/introproc_ite.cpp146
-rw-r--r--engines/saga/isomap.cpp154
-rw-r--r--engines/saga/isomap.h21
-rw-r--r--engines/saga/itedata.cpp2
-rw-r--r--engines/saga/itedata.h8
-rw-r--r--engines/saga/music.cpp39
-rw-r--r--engines/saga/music.h8
-rw-r--r--engines/saga/objectmap.cpp173
-rw-r--r--engines/saga/objectmap.h38
-rw-r--r--engines/saga/palanim.cpp147
-rw-r--r--engines/saga/palanim.h19
-rw-r--r--engines/saga/puzzle.cpp4
-rw-r--r--engines/saga/resource.cpp33
-rw-r--r--engines/saga/resource.h2
-rw-r--r--engines/saga/resource_res.cpp131
-rw-r--r--engines/saga/saga.cpp64
-rw-r--r--engines/saga/saga.h163
-rw-r--r--engines/saga/saveload.cpp11
-rw-r--r--engines/saga/scene.cpp383
-rw-r--r--engines/saga/scene.h81
-rw-r--r--engines/saga/script.cpp154
-rw-r--r--engines/saga/script.h92
-rw-r--r--engines/saga/sfuncs.cpp40
-rw-r--r--engines/saga/sfuncs_ihnm.cpp10
-rw-r--r--engines/saga/shorten.cpp23
-rw-r--r--engines/saga/sndres.cpp51
-rw-r--r--engines/saga/sndres.h11
-rw-r--r--engines/saga/sound.cpp3
-rw-r--r--engines/saga/sound.h1
-rw-r--r--engines/saga/sprite.cpp244
-rw-r--r--engines/saga/sprite.h38
-rw-r--r--engines/saga/sthread.cpp26
-rw-r--r--engines/savestate.cpp6
-rw-r--r--engines/savestate.h5
-rw-r--r--engines/sci/console.cpp229
-rw-r--r--engines/sci/console.h5
-rw-r--r--engines/sci/detection.cpp27
-rw-r--r--engines/sci/detection_tables.h62
-rw-r--r--engines/sci/engine/kernel.cpp40
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel_tables.h845
-rw-r--r--engines/sci/engine/kfile.cpp16
-rw-r--r--engines/sci/engine/kgraphics.cpp23
-rw-r--r--engines/sci/engine/kmath.cpp4
-rw-r--r--engines/sci/engine/kmisc.cpp31
-rw-r--r--engines/sci/engine/kparse.cpp4
-rw-r--r--engines/sci/engine/kpathing.cpp2
-rw-r--r--engines/sci/engine/kvideo.cpp4
-rw-r--r--engines/sci/engine/message.cpp2
-rw-r--r--engines/sci/engine/savegame.cpp264
-rw-r--r--engines/sci/engine/savegame.h17
-rw-r--r--engines/sci/engine/script.cpp28
-rw-r--r--engines/sci/engine/script.h10
-rw-r--r--engines/sci/engine/script_patches.cpp191
-rw-r--r--engines/sci/engine/scriptdebug.cpp132
-rw-r--r--engines/sci/engine/seg_manager.cpp4
-rw-r--r--engines/sci/engine/seg_manager.h5
-rw-r--r--engines/sci/engine/segment.cpp2
-rw-r--r--engines/sci/engine/segment.h9
-rw-r--r--engines/sci/engine/selector.cpp4
-rw-r--r--engines/sci/engine/state.h1
-rw-r--r--engines/sci/engine/vm.cpp70
-rw-r--r--engines/sci/engine/workarounds.cpp16
-rw-r--r--engines/sci/engine/workarounds.h1
-rw-r--r--engines/sci/graphics/animate.cpp34
-rw-r--r--engines/sci/graphics/animate.h8
-rw-r--r--engines/sci/graphics/cursor.cpp8
-rw-r--r--engines/sci/graphics/font.cpp30
-rw-r--r--engines/sci/graphics/font.h4
-rw-r--r--engines/sci/graphics/frameout.cpp106
-rw-r--r--engines/sci/graphics/frameout.h2
-rw-r--r--engines/sci/graphics/helpers.h36
-rw-r--r--engines/sci/graphics/menu.cpp2
-rw-r--r--engines/sci/graphics/palette.cpp17
-rw-r--r--engines/sci/graphics/picture.cpp13
-rw-r--r--engines/sci/graphics/ports.cpp9
-rw-r--r--engines/sci/graphics/ports.h14
-rw-r--r--engines/sci/graphics/screen.cpp11
-rw-r--r--engines/sci/graphics/screen.h1
-rw-r--r--engines/sci/graphics/view.cpp33
-rw-r--r--engines/sci/graphics/view.h1
-rw-r--r--engines/sci/parser/grammar.cpp40
-rw-r--r--engines/sci/parser/said.cpp2
-rw-r--r--engines/sci/parser/vocabulary.cpp68
-rw-r--r--engines/sci/parser/vocabulary.h2
-rw-r--r--engines/sci/resource.cpp12
-rw-r--r--engines/sci/sci.cpp121
-rw-r--r--engines/sci/sci.h10
-rw-r--r--engines/sci/sound/drivers/amigamac.cpp18
-rw-r--r--engines/sci/sound/drivers/gm_names.h220
-rw-r--r--engines/sci/sound/drivers/map-mt32-to-gm.h447
-rw-r--r--engines/sci/sound/drivers/midi.cpp32
-rw-r--r--engines/sci/sound/music.cpp6
-rw-r--r--engines/sci/sound/soundcmd.h2
-rw-r--r--engines/scumm/actor.cpp74
-rw-r--r--engines/scumm/actor.h15
-rw-r--r--engines/scumm/akos.cpp8
-rw-r--r--engines/scumm/boxes.cpp28
-rw-r--r--engines/scumm/charset-fontdata.cpp10
-rw-r--r--engines/scumm/charset.cpp462
-rw-r--r--engines/scumm/charset.h29
-rw-r--r--engines/scumm/costume.cpp2
-rw-r--r--engines/scumm/debugger.cpp5
-rw-r--r--engines/scumm/detection.cpp17
-rw-r--r--engines/scumm/detection_tables.h2
-rw-r--r--engines/scumm/dialogs.cpp17
-rw-r--r--engines/scumm/file.cpp2
-rw-r--r--engines/scumm/file_nes.cpp26
-rw-r--r--engines/scumm/gfx.cpp22
-rw-r--r--engines/scumm/he/logic_he.cpp32
-rw-r--r--engines/scumm/he/logic_he.h8
-rw-r--r--engines/scumm/he/palette_he.cpp4
-rw-r--r--engines/scumm/he/resource_he.cpp293
-rw-r--r--engines/scumm/he/resource_he.h2
-rw-r--r--engines/scumm/he/script_v100he.cpp7
-rw-r--r--engines/scumm/he/script_v60he.cpp7
-rw-r--r--engines/scumm/he/script_v70he.cpp1
-rw-r--r--engines/scumm/he/script_v72he.cpp9
-rw-r--r--engines/scumm/he/script_v80he.cpp1
-rw-r--r--engines/scumm/he/script_v90he.cpp55
-rw-r--r--engines/scumm/he/sound_he.cpp6
-rw-r--r--engines/scumm/he/wiz_he.cpp3
-rw-r--r--engines/scumm/he/wiz_he.h3
-rw-r--r--engines/scumm/imuse/imuse.cpp4
-rw-r--r--engines/scumm/insane/insane.cpp6
-rw-r--r--engines/scumm/insane/insane_ben.cpp2
-rw-r--r--engines/scumm/insane/insane_enemy.cpp4
-rw-r--r--engines/scumm/module.mk1
-rw-r--r--engines/scumm/object.cpp10
-rw-r--r--engines/scumm/palette.cpp6
-rw-r--r--engines/scumm/player_nes.h2
-rw-r--r--engines/scumm/player_pce.cpp324
-rw-r--r--engines/scumm/player_v2.cpp660
-rw-r--r--engines/scumm/player_v2.h264
-rw-r--r--engines/scumm/player_v2base.cpp657
-rw-r--r--engines/scumm/player_v2base.h148
-rw-r--r--engines/scumm/player_v2cms.cpp761
-rw-r--r--engines/scumm/player_v2cms.h166
-rw-r--r--engines/scumm/resource.cpp13
-rw-r--r--engines/scumm/resource_v2.cpp12
-rw-r--r--engines/scumm/saveload.cpp6
-rw-r--r--engines/scumm/saveload.h2
-rw-r--r--engines/scumm/script.cpp76
-rw-r--r--engines/scumm/script_v0.cpp7
-rw-r--r--engines/scumm/script_v2.cpp3
-rw-r--r--engines/scumm/script_v5.cpp18
-rw-r--r--engines/scumm/script_v6.cpp15
-rw-r--r--engines/scumm/script_v8.cpp2
-rw-r--r--engines/scumm/scumm-md5.h6
-rw-r--r--engines/scumm/scumm.cpp26
-rw-r--r--engines/scumm/scumm.h25
-rw-r--r--engines/scumm/smush/codec47.cpp4
-rw-r--r--engines/scumm/string.cpp22
-rw-r--r--engines/scumm/verbs.cpp34
-rw-r--r--engines/sky/disk.cpp2
-rw-r--r--engines/sky/logic.cpp2
-rw-r--r--engines/sky/sky.h4
-rw-r--r--engines/sword1/console.cpp43
-rw-r--r--engines/sword1/console.h50
-rw-r--r--engines/sword1/control.cpp8
-rw-r--r--engines/sword1/detection.cpp7
-rw-r--r--engines/sword1/module.mk1
-rw-r--r--engines/sword1/resman.cpp11
-rw-r--r--engines/sword1/screen.cpp4
-rw-r--r--engines/sword1/sword1.cpp12
-rw-r--r--engines/sword1/sword1.h10
-rw-r--r--engines/sword2/animation.cpp6
-rw-r--r--engines/sword2/animation.h1
-rw-r--r--engines/sword2/console.cpp6
-rw-r--r--engines/sword2/controls.cpp6
-rw-r--r--engines/sword2/debug.cpp9
-rw-r--r--engines/sword2/logic.cpp10
-rw-r--r--engines/sword2/logic.h2
-rw-r--r--engines/sword2/music.cpp13
-rw-r--r--engines/sword2/palette.cpp3
-rw-r--r--engines/sword2/protocol.cpp4
-rw-r--r--engines/sword2/render.cpp4
-rw-r--r--engines/sword2/resman.cpp9
-rw-r--r--engines/sword2/sound.cpp12
-rw-r--r--engines/sword2/sound.h3
-rw-r--r--engines/sword2/sword2.cpp80
-rw-r--r--engines/sword2/sword2.h13
-rw-r--r--engines/sword25/detection.cpp34
-rw-r--r--engines/sword25/fmv/movieplayer.cpp112
-rw-r--r--engines/sword25/fmv/movieplayer.h13
-rw-r--r--engines/sword25/fmv/movieplayer_script.cpp26
-rw-r--r--engines/sword25/fmv/theora_decoder.cpp29
-rw-r--r--engines/sword25/fmv/theora_decoder.h6
-rw-r--r--engines/sword25/fmv/yuvtorgba.cpp4
-rw-r--r--engines/sword25/fmv/yuvtorgba.h5
-rw-r--r--engines/sword25/gfx/animation.cpp185
-rw-r--r--engines/sword25/gfx/animation.h16
-rw-r--r--engines/sword25/gfx/animationdescription.h2
-rw-r--r--engines/sword25/gfx/animationresource.cpp10
-rw-r--r--engines/sword25/gfx/animationtemplate.cpp30
-rw-r--r--engines/sword25/gfx/animationtemplateregistry.cpp4
-rw-r--r--engines/sword25/gfx/animationtemplateregistry.h14
-rw-r--r--engines/sword25/gfx/bitmap.cpp40
-rw-r--r--engines/sword25/gfx/bitmap.h8
-rw-r--r--engines/sword25/gfx/bitmapresource.cpp6
-rw-r--r--engines/sword25/gfx/bitmapresource.h5
-rw-r--r--engines/sword25/gfx/dynamicbitmap.cpp40
-rw-r--r--engines/sword25/gfx/dynamicbitmap.h25
-rw-r--r--engines/sword25/gfx/fontresource.cpp65
-rw-r--r--engines/sword25/gfx/fontresource.h54
-rw-r--r--engines/sword25/gfx/framecounter.cpp28
-rw-r--r--engines/sword25/gfx/framecounter.h29
-rw-r--r--engines/sword25/gfx/graphicengine.cpp395
-rw-r--r--engines/sword25/gfx/graphicengine.h180
-rw-r--r--engines/sword25/gfx/graphicengine_script.cpp1454
-rw-r--r--engines/sword25/gfx/image/art.cpp71
-rw-r--r--engines/sword25/gfx/image/b25sloader.cpp119
-rw-r--r--engines/sword25/gfx/image/b25sloader.h67
-rw-r--r--engines/sword25/gfx/image/image.h2
-rw-r--r--engines/sword25/gfx/image/imageloader.cpp129
-rw-r--r--engines/sword25/gfx/image/imageloader.h209
-rw-r--r--engines/sword25/gfx/image/imageloader_ids.h62
-rw-r--r--engines/sword25/gfx/image/pngloader.cpp232
-rw-r--r--engines/sword25/gfx/image/pngloader.h76
-rw-r--r--engines/sword25/gfx/image/renderedimage.cpp18
-rw-r--r--engines/sword25/gfx/image/swimage.cpp30
-rw-r--r--engines/sword25/gfx/image/swimage.h8
-rw-r--r--engines/sword25/gfx/image/vectorimage.cpp1
-rw-r--r--engines/sword25/gfx/image/vectorimagerenderer.cpp18
-rw-r--r--engines/sword25/gfx/panel.cpp26
-rw-r--r--engines/sword25/gfx/panel.h12
-rw-r--r--engines/sword25/gfx/renderobject.cpp53
-rw-r--r--engines/sword25/gfx/renderobject.h17
-rw-r--r--engines/sword25/gfx/renderobjectmanager.cpp6
-rw-r--r--engines/sword25/gfx/renderobjectmanager.h2
-rw-r--r--engines/sword25/gfx/renderobjectptr.h6
-rw-r--r--engines/sword25/gfx/renderobjectregistry.cpp4
-rw-r--r--engines/sword25/gfx/renderobjectregistry.h29
-rw-r--r--engines/sword25/gfx/screenshot.cpp60
-rw-r--r--engines/sword25/gfx/screenshot.h12
-rw-r--r--engines/sword25/gfx/staticbitmap.cpp66
-rw-r--r--engines/sword25/gfx/staticbitmap.h24
-rw-r--r--engines/sword25/gfx/text.cpp328
-rw-r--r--engines/sword25/gfx/text.h74
-rw-r--r--engines/sword25/gfx/timedrenderobject.h8
-rw-r--r--engines/sword25/input/inputengine.cpp372
-rw-r--r--engines/sword25/input/inputengine.h291
-rw-r--r--engines/sword25/input/inputengine_script.cpp266
-rw-r--r--engines/sword25/kernel/callbackregistry.cpp131
-rw-r--r--engines/sword25/kernel/callbackregistry.h93
-rw-r--r--engines/sword25/kernel/filesystemutil.cpp119
-rw-r--r--engines/sword25/kernel/filesystemutil.h33
-rw-r--r--engines/sword25/kernel/inputpersistenceblock.cpp144
-rw-r--r--engines/sword25/kernel/inputpersistenceblock.h42
-rw-r--r--engines/sword25/kernel/kernel.cpp403
-rw-r--r--engines/sword25/kernel/kernel.h242
-rw-r--r--engines/sword25/kernel/kernel_script.cpp645
-rw-r--r--engines/sword25/kernel/log.cpp178
-rw-r--r--engines/sword25/kernel/log.h93
-rw-r--r--engines/sword25/kernel/objectregistry.h4
-rw-r--r--engines/sword25/kernel/outputpersistenceblock.cpp96
-rw-r--r--engines/sword25/kernel/outputpersistenceblock.h34
-rw-r--r--engines/sword25/kernel/persistable.h2
-rw-r--r--engines/sword25/kernel/persistenceblock.h62
-rw-r--r--engines/sword25/kernel/persistenceservice.cpp421
-rw-r--r--engines/sword25/kernel/persistenceservice.h32
-rw-r--r--engines/sword25/kernel/resmanager.cpp199
-rw-r--r--engines/sword25/kernel/resmanager.h80
-rw-r--r--engines/sword25/kernel/resource.cpp7
-rw-r--r--engines/sword25/kernel/resource.h22
-rw-r--r--engines/sword25/kernel/resservice.h5
-rw-r--r--engines/sword25/kernel/scummvmwindow.cpp297
-rw-r--r--engines/sword25/kernel/scummvmwindow.h85
-rw-r--r--engines/sword25/kernel/service.h4
-rw-r--r--engines/sword25/kernel/service_ids.h80
-rw-r--r--engines/sword25/kernel/string.h111
-rw-r--r--engines/sword25/kernel/window.cpp69
-rw-r--r--engines/sword25/kernel/window.h177
-rw-r--r--engines/sword25/math/geometry.cpp4
-rw-r--r--engines/sword25/math/geometry_script.cpp28
-rw-r--r--engines/sword25/math/polygon.cpp2
-rw-r--r--engines/sword25/math/polygon.h5
-rw-r--r--engines/sword25/math/region.cpp10
-rw-r--r--engines/sword25/math/regionregistry.cpp4
-rw-r--r--engines/sword25/math/regionregistry.h15
-rw-r--r--engines/sword25/math/vertex.cpp7
-rw-r--r--engines/sword25/math/vertex.h29
-rw-r--r--engines/sword25/math/walkregion.cpp15
-rw-r--r--engines/sword25/module.mk15
-rw-r--r--engines/sword25/package/packagemanager.cpp37
-rw-r--r--engines/sword25/package/packagemanager.h17
-rw-r--r--engines/sword25/package/packagemanager_script.cpp20
-rw-r--r--engines/sword25/script/lua_extensions.cpp2
-rw-r--r--engines/sword25/script/luabindhelper.h9
-rw-r--r--engines/sword25/script/luacallback.cpp7
-rw-r--r--engines/sword25/script/luacallback.h6
-rw-r--r--engines/sword25/script/luascript.cpp18
-rw-r--r--engines/sword25/script/luascript.h9
-rw-r--r--engines/sword25/script/script.h4
-rw-r--r--engines/sword25/sfx/soundengine.cpp6
-rw-r--r--engines/sword25/sfx/soundengine.h2
-rw-r--r--engines/sword25/sfx/soundengine_script.cpp80
-rw-r--r--engines/sword25/sword25.cpp63
-rw-r--r--engines/sword25/sword25.h16
-rw-r--r--engines/sword25/util/lua/lapi.cpp (renamed from engines/sword25/util/lua/lapi.c)14
-rw-r--r--engines/sword25/util/lua/lapi.h2
-rw-r--r--engines/sword25/util/lua/lauxlib.cpp (renamed from engines/sword25/util/lua/lauxlib.c)2
-rw-r--r--engines/sword25/util/lua/lauxlib.h2
-rw-r--r--engines/sword25/util/lua/lbaselib.cpp (renamed from engines/sword25/util/lua/lbaselib.c)2
-rw-r--r--engines/sword25/util/lua/lcode.cpp (renamed from engines/sword25/util/lua/lcode.c)2
-rw-r--r--engines/sword25/util/lua/lcode.h2
-rw-r--r--engines/sword25/util/lua/ldblib.cpp (renamed from engines/sword25/util/lua/ldblib.c)2
-rw-r--r--engines/sword25/util/lua/ldebug.cpp (renamed from engines/sword25/util/lua/ldebug.c)2
-rw-r--r--engines/sword25/util/lua/ldebug.h2
-rw-r--r--engines/sword25/util/lua/ldo.cpp (renamed from engines/sword25/util/lua/ldo.c)2
-rw-r--r--engines/sword25/util/lua/ldo.h2
-rw-r--r--engines/sword25/util/lua/ldump.cpp (renamed from engines/sword25/util/lua/ldump.c)2
-rw-r--r--engines/sword25/util/lua/lfunc.cpp (renamed from engines/sword25/util/lua/lfunc.c)2
-rw-r--r--engines/sword25/util/lua/lfunc.h2
-rw-r--r--engines/sword25/util/lua/lgc.cpp (renamed from engines/sword25/util/lua/lgc.c)2
-rw-r--r--engines/sword25/util/lua/lgc.h2
-rw-r--r--engines/sword25/util/lua/linit.cpp (renamed from engines/sword25/util/lua/linit.c)2
-rw-r--r--engines/sword25/util/lua/liolib.cpp (renamed from engines/sword25/util/lua/liolib.c)2
-rw-r--r--engines/sword25/util/lua/llex.cpp (renamed from engines/sword25/util/lua/llex.c)2
-rw-r--r--engines/sword25/util/lua/llex.h2
-rw-r--r--engines/sword25/util/lua/llimits.h2
-rw-r--r--engines/sword25/util/lua/lmathlib.cpp (renamed from engines/sword25/util/lua/lmathlib.c)12
-rw-r--r--engines/sword25/util/lua/lmem.cpp (renamed from engines/sword25/util/lua/lmem.c)2
-rw-r--r--engines/sword25/util/lua/lmem.h2
-rw-r--r--engines/sword25/util/lua/loadlib.cpp (renamed from engines/sword25/util/lua/loadlib.c)2
-rw-r--r--engines/sword25/util/lua/lobject.cpp (renamed from engines/sword25/util/lua/lobject.c)2
-rw-r--r--engines/sword25/util/lua/lobject.h2
-rw-r--r--engines/sword25/util/lua/lopcodes.cpp (renamed from engines/sword25/util/lua/lopcodes.c)2
-rw-r--r--engines/sword25/util/lua/lopcodes.h2
-rw-r--r--engines/sword25/util/lua/loslib.cpp (renamed from engines/sword25/util/lua/loslib.c)2
-rw-r--r--engines/sword25/util/lua/lparser.cpp (renamed from engines/sword25/util/lua/lparser.c)2
-rw-r--r--engines/sword25/util/lua/lparser.h2
-rw-r--r--engines/sword25/util/lua/lstate.cpp (renamed from engines/sword25/util/lua/lstate.c)2
-rw-r--r--engines/sword25/util/lua/lstate.h2
-rw-r--r--engines/sword25/util/lua/lstring.cpp (renamed from engines/sword25/util/lua/lstring.c)2
-rw-r--r--engines/sword25/util/lua/lstring.h2
-rw-r--r--engines/sword25/util/lua/lstrlib.cpp (renamed from engines/sword25/util/lua/lstrlib.c)2
-rw-r--r--engines/sword25/util/lua/ltable.cpp (renamed from engines/sword25/util/lua/ltable.c)17
-rw-r--r--engines/sword25/util/lua/ltable.h2
-rw-r--r--engines/sword25/util/lua/ltablib.cpp (renamed from engines/sword25/util/lua/ltablib.c)2
-rw-r--r--engines/sword25/util/lua/ltm.cpp (renamed from engines/sword25/util/lua/ltm.c)2
-rw-r--r--engines/sword25/util/lua/ltm.h2
-rw-r--r--engines/sword25/util/lua/lua.c392
-rw-r--r--engines/sword25/util/lua/lua.h2
-rw-r--r--engines/sword25/util/lua/luac.c200
-rw-r--r--engines/sword25/util/lua/luaconf.h4
-rw-r--r--engines/sword25/util/lua/lualib.h2
-rw-r--r--engines/sword25/util/lua/lundump.cpp (renamed from engines/sword25/util/lua/lundump.c)2
-rw-r--r--engines/sword25/util/lua/lundump.h2
-rw-r--r--engines/sword25/util/lua/lvm.cpp (renamed from engines/sword25/util/lua/lvm.c)2
-rw-r--r--engines/sword25/util/lua/lvm.h2
-rw-r--r--engines/sword25/util/lua/lzio.cpp (renamed from engines/sword25/util/lua/lzio.c)2
-rw-r--r--engines/sword25/util/lua/lzio.h2
-rw-r--r--engines/sword25/util/lua/print.cpp (renamed from engines/sword25/util/lua/print.c)2
-rw-r--r--engines/sword25/util/pluto/pdep.cpp (renamed from engines/sword25/util/pluto/pdep.c)0
-rw-r--r--engines/sword25/util/pluto/pdep/lauxlib.h2
-rw-r--r--engines/sword25/util/pluto/pdep/ldo.h2
-rw-r--r--engines/sword25/util/pluto/pdep/lfunc.h2
-rw-r--r--engines/sword25/util/pluto/pdep/lgc.h2
-rw-r--r--engines/sword25/util/pluto/pdep/llimits.h2
-rw-r--r--engines/sword25/util/pluto/pdep/lobject.h2
-rw-r--r--engines/sword25/util/pluto/pdep/lopcodes.h2
-rw-r--r--engines/sword25/util/pluto/pdep/lstate.h2
-rw-r--r--engines/sword25/util/pluto/pdep/lstring.h2
-rw-r--r--engines/sword25/util/pluto/pdep/ltm.h2
-rw-r--r--engines/sword25/util/pluto/pdep/lua.h2
-rw-r--r--engines/sword25/util/pluto/pdep/lzio.h2
-rw-r--r--engines/sword25/util/pluto/pluto.cpp (renamed from engines/sword25/util/pluto/pluto.c)9
-rw-r--r--engines/sword25/util/pluto/plzio.cpp (renamed from engines/sword25/util/pluto/plzio.c)2
-rw-r--r--engines/sword25/util/pluto/pptest.cpp (renamed from engines/sword25/util/pluto/pptest.c)0
-rw-r--r--engines/sword25/util/pluto/puptest.cpp (renamed from engines/sword25/util/pluto/puptest.c)0
-rw-r--r--engines/teenagent/animation.cpp2
-rw-r--r--engines/teenagent/detection.cpp13
-rw-r--r--engines/teenagent/teenagent.cpp6
-rw-r--r--engines/teenagent/teenagent.h2
-rw-r--r--engines/testbed/config.cpp8
-rw-r--r--engines/testbed/detection.cpp11
-rw-r--r--engines/testbed/graphics.cpp4
-rw-r--r--engines/testbed/misc.cpp2
-rw-r--r--engines/testbed/sound.cpp15
-rw-r--r--engines/testbed/testbed.cpp4
-rw-r--r--engines/testbed/testsuite.cpp2
-rw-r--r--engines/tinsel/actors.cpp9
-rw-r--r--engines/tinsel/bmv.cpp2
-rw-r--r--engines/tinsel/coroutine.cpp86
-rw-r--r--engines/tinsel/coroutine.h47
-rw-r--r--engines/tinsel/debugger.cpp5
-rw-r--r--engines/tinsel/detection.cpp31
-rw-r--r--engines/tinsel/detection_tables.h89
-rw-r--r--engines/tinsel/dialogs.cpp33
-rw-r--r--engines/tinsel/graphics.cpp6
-rw-r--r--engines/tinsel/heapmem.cpp2
-rw-r--r--engines/tinsel/module.mk1
-rw-r--r--engines/tinsel/music.cpp2
-rw-r--r--engines/tinsel/object.cpp2
-rw-r--r--engines/tinsel/palette.cpp4
-rw-r--r--engines/tinsel/pdisplay.cpp18
-rw-r--r--engines/tinsel/rince.cpp4
-rw-r--r--engines/tinsel/saveload.cpp16
-rw-r--r--engines/tinsel/savescn.h12
-rw-r--r--engines/tinsel/scene.h6
-rw-r--r--engines/tinsel/sched.cpp15
-rw-r--r--engines/tinsel/sound.cpp4
-rw-r--r--engines/tinsel/text.cpp2
-rw-r--r--engines/tinsel/text.h2
-rw-r--r--engines/tinsel/tinlib.cpp55
-rw-r--r--engines/tinsel/tinsel.cpp4
-rw-r--r--engines/tinsel/tinsel.h4
-rw-r--r--engines/toon/anim.cpp54
-rw-r--r--engines/toon/anim.h4
-rw-r--r--engines/toon/audio.cpp166
-rw-r--r--engines/toon/audio.h38
-rw-r--r--engines/toon/character.cpp67
-rw-r--r--engines/toon/character.h4
-rw-r--r--engines/toon/console.cpp43
-rw-r--r--engines/toon/console.h50
-rw-r--r--engines/toon/detection.cpp23
-rw-r--r--engines/toon/font.cpp45
-rw-r--r--engines/toon/font.h3
-rw-r--r--engines/toon/hotspot.cpp2
-rw-r--r--engines/toon/hotspot.h2
-rw-r--r--engines/toon/module.mk1
-rw-r--r--engines/toon/movie.cpp5
-rw-r--r--engines/toon/movie.h3
-rw-r--r--engines/toon/path.cpp50
-rw-r--r--engines/toon/path.h13
-rw-r--r--engines/toon/picture.cpp6
-rw-r--r--engines/toon/picture.h1
-rw-r--r--engines/toon/resource.cpp11
-rw-r--r--engines/toon/script.cpp5
-rw-r--r--engines/toon/script.h9
-rw-r--r--engines/toon/script_func.cpp51
-rw-r--r--engines/toon/script_func.h5
-rw-r--r--engines/toon/toon.cpp341
-rw-r--r--engines/toon/toon.h44
-rw-r--r--engines/touche/console.cpp43
-rw-r--r--engines/touche/console.h (renamed from backends/mutex/sdl/sdl-mutex.h)29
-rw-r--r--engines/touche/detection.cpp14
-rw-r--r--engines/touche/module.mk1
-rw-r--r--engines/touche/touche.cpp7
-rw-r--r--engines/touche/touche.h9
-rw-r--r--engines/tucker/console.cpp43
-rw-r--r--engines/tucker/console.h50
-rw-r--r--engines/tucker/detection.cpp13
-rw-r--r--engines/tucker/module.mk1
-rw-r--r--engines/tucker/tucker.cpp8
-rw-r--r--engines/tucker/tucker.h7
-rw-r--r--graphics/scaler/scale2x.cpp110
-rw-r--r--graphics/scaler/scale3x.cpp71
-rw-r--r--graphics/scaler/scalebit.cpp136
-rw-r--r--graphics/sjis.cpp88
-rw-r--r--graphics/sjis.h59
-rw-r--r--graphics/video/codecs/qdm2.cpp12
-rw-r--r--graphics/video/coktel_decoder.cpp14
-rw-r--r--graphics/video/flic_decoder.cpp4
-rw-r--r--graphics/video/smk_decoder.cpp36
-rw-r--r--gui/Actions.cpp19
-rw-r--r--gui/ThemeEngine.h4
-rw-r--r--gui/ThemeParser.cpp40
-rw-r--r--gui/about.cpp2
-rw-r--r--gui/browser.h6
-rw-r--r--gui/browser_osx.mm3
-rw-r--r--gui/console.cpp27
-rw-r--r--gui/console.h10
-rw-r--r--gui/credits.h30
-rw-r--r--gui/debugger.cpp5
-rw-r--r--gui/debugger.h2
-rw-r--r--gui/launcher.cpp8
-rw-r--r--gui/options.cpp59
-rw-r--r--gui/options.h1
-rw-r--r--gui/themes/default.inc6
-rw-r--r--gui/themes/scummclassic.zipbin73968 -> 13474 bytes
-rw-r--r--gui/themes/scummclassic/THEMERC2
-rw-r--r--gui/themes/scummclassic/classic_layout.stx3
-rw-r--r--gui/themes/scummclassic/classic_layout_lowres.stx3
-rw-r--r--gui/themes/scummmodern.zipbin181827 -> 56615 bytes
-rw-r--r--gui/themes/scummmodern/THEMERC2
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx3
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx3
-rw-r--r--icons/scummvm.infobin17326 -> 17326 bytes
-rw-r--r--ports.mk11
-rw-r--r--sound/audiostream.h5
-rw-r--r--sound/decoders/adpcm.cpp13
-rw-r--r--sound/decoders/adpcm.h17
-rw-r--r--sound/decoders/flac.cpp5
-rw-r--r--sound/decoders/vorbis.cpp5
-rw-r--r--sound/decoders/wave.cpp20
-rw-r--r--sound/mididrv.cpp45
-rw-r--r--sound/mixer.cpp1
-rw-r--r--sound/mods/tfmx.cpp4
-rw-r--r--sound/rate_arm.cpp14
-rw-r--r--sound/softsynth/cms.cpp242
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_audio.cpp1
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_euphony.cpp4
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp1
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp1
-rw-r--r--sound/softsynth/mt32/mt32_file.cpp18
-rw-r--r--sound/softsynth/mt32/mt32_file.h2
-rw-r--r--sound/softsynth/mt32/tables.cpp2
-rw-r--r--test/common/md5.h4
-rw-r--r--test/common/str.h10
-rw-r--r--test/module.mk3
-rw-r--r--tools/README53
-rw-r--r--tools/create_hugo/create_hugo.cpp43
-rw-r--r--tools/create_hugo/create_hugo.h2
-rw-r--r--tools/create_hugo/enums.h2
-rw-r--r--tools/create_hugo/staticdata.h6037
-rw-r--r--tools/create_hugo/staticdisplay.h60
-rw-r--r--tools/create_kyradat/create_kyradat.cpp7
-rw-r--r--tools/create_kyradat/extract.cpp55
-rw-r--r--tools/create_kyradat/extract.h1
-rw-r--r--tools/create_kyradat/games.cpp3
-rw-r--r--tools/create_kyradat/md5.cpp3
-rw-r--r--tools/create_kyradat/pak.cpp3
-rw-r--r--tools/create_kyradat/search.cpp3
-rw-r--r--tools/create_kyradat/tables.cpp3
-rw-r--r--tools/create_kyradat/util.cpp3
-rw-r--r--tools/create_lure/create_lure_dat.cpp3
-rw-r--r--tools/create_lure/process_actions.cpp3
-rw-r--r--tools/create_msvc/create_msvc.cpp25
-rw-r--r--tools/create_teenagent/create_teenagent.cpp3
-rw-r--r--tools/create_teenagent/md5.cpp3
-rw-r--r--tools/create_toon/create_toon.cpp3
-rwxr-xr-xtools/credits.pl37
-rw-r--r--tools/sci/classes.cpp76
-rw-r--r--tools/sci/graphics_png.h112
-rw-r--r--tools/sci/listwords.cpp85
-rw-r--r--tools/sci/old_objects.cpp679
-rw-r--r--tools/sci/old_objects.h72
-rw-r--r--tools/sci/sciunpack.cpp473
-rw-r--r--tools/sci/sciunpack.h68
-rw-r--r--tools/sci/scriptdump.cpp45
-rw-r--r--tools/sci/vocabdump.cpp70
-rw-r--r--tools/scumm-md5.txt4
-rwxr-xr-xtools/update-version.pl3
1260 files changed, 114105 insertions, 36127 deletions
diff --git a/AUTHORS b/AUTHORS
index 4a413d6294..30470de5e7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -64,6 +64,13 @@ ScummVM Team
Fabio Battaglia - PSX version support
Jonathan Gray - (retired)
+ Broken Sword 2.5:
+ Eugene Sandulenko
+ Filippos Karapetis
+ Max Horn
+ Paul Gilbert
+ Torbjorn Andersson
+
Cinematique evo 1:
Vincent Hamm - (retired)
Pawel Kolodziejski
@@ -99,6 +106,11 @@ ScummVM Team
Scott Thomas
Jordi Vilalta Prat
+ Hugo:
+ Arnaud Boutonne
+ Oystein Eftevaag
+ Eugene Sandulenko
+
Kyra:
Torbjorn Andersson - VQA Player
Oystein Eftevaag
@@ -106,6 +118,11 @@ ScummVM Team
Gregory Montoir
Johannes Schickel
+ Last Express:
+ Matthew Hoops
+ Jordi Vilalta Prat
+ Julien Templier
+
Lure:
Paul Gilbert
@@ -158,6 +175,9 @@ ScummVM Team
Filippos Karapetis
Joost Peters
+ Toon:
+ Sylvain Dupont
+
Touche:
Gregory Montoir
@@ -172,7 +192,7 @@ ScummVM Team
Dreamcast:
Marcus Comstedt
- GP2X:
+ GPH Devices (GP2X, GP2XWiz & Caanoo):
John Willis
iPhone:
@@ -190,6 +210,9 @@ ScummVM Team
Nintendo DS:
Neil Millstone
+ OpenPandora:
+ John Willis
+
PocketPC / WinCE:
Nicolas Bacca - (retired)
Kostas Nakos
@@ -219,6 +242,7 @@ ScummVM Team
Max Horn - Backend & Engine APIs, file API, sound mixer,
audiostreams, data structures, etc.
Eugene Sandulenko
+ Johannes Schickel
GUI:
Vicent Marti
@@ -249,6 +273,7 @@ ScummVM Team
-------------
Thierry Crozat - Numerous contributions to documentation
Joachim Eberhard - Numerous contributions to documentation
+ (retired)
Matthew Hoops - Wiki editor
Retired Team Members
@@ -492,3 +517,6 @@ Special thanks to
David P. Gray from Gray Design Associate for sharing the source code of
the Hugo trilogy.
+ Broken Sword 2.5 team for providing sources of their engine and their
+ great support.
+
diff --git a/Makefile.common b/Makefile.common
index 91f4309599..5abfc2e784 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -23,8 +23,8 @@ MODULES := test tools base $(MODULES)
# After the game specific modules follow the shared modules
MODULES += \
gui \
- backends \
sound \
+ backends \
engines \
graphics \
common \
@@ -54,6 +54,10 @@ DEPFILES =
# the build date in gScummVMBuildDate is correct.
base/version.o: $(filter-out base/libbase.a,$(OBJS))
+ifdef USE_ELF_LOADER
+backends/plugins/elf/version.o: $(filter-out base/libbase.a,$(filter-out backends/libbackends.a,$(OBJS)))
+endif
+
# Replace regular output with quiet messages
ifneq ($(findstring $(MAKEFLAGS),s),s)
ifneq ($(VERBOSE_BUILD),1)
diff --git a/NEWS b/NEWS
index 2f2c496d78..d988f9b17a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,10 @@
For a more comprehensive changelog for the latest experimental SVN code, see:
http://scummvm.svn.sourceforge.net/viewvc/scummvm/?view=log
1.3.0 (????-??-??)
+ New Games:
+ - Added support for Backyard Baseball.
+ - Added support for Backyard Baseball 2001.
+
Drascula:
- Added German and French subtitles in the Von Braun cutscene (#3069981:
no subtitles in scene with "von Braun").
@@ -12,6 +16,9 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
SCUMM:
- Improved support for FM-TOWNS versions of games.
+1.2.1 (2010-??-??)
+ Groovie:
+ - Fixed a regression that made the Russian version of T7G crash.
1.2.0 (2010-10-15)
New Games:
@@ -80,7 +87,7 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
- Added support of MIDI devices.
- Added support for accurate Tandy sound emulation. Switched to it as default.
- Broken Sword 2
+ Broken Sword 2:
- Fixed missing speech in some cutscenes.
- Fixed a memory leak that would eventually cause the game to hang.
(#2976008 - BS2: Game lockup in British Museum)
@@ -100,10 +107,10 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
- Added support for playing Kyrandia 3 with the original CD file layout.
LURE:
- - Fixed bug where Goewin could get stuck in the Weregate
- - Fixed issue with Ratpouch repeatedly moving between two rooms
- - Fix for Goewin losing her schedule after Were-cave
- - Fix for player getting stuck in sewer exit room
+ - Fixed bug where Goewin could get stuck in the Weregate.
+ - Fixed issue with Ratpouch repeatedly moving between two rooms.
+ - Fix for Goewin losing her schedule after Were-cave.
+ - Fix for player getting stuck in sewer exit room.
Parallaction:
- Made part one of The Big Red Adventure completable.
@@ -156,7 +163,7 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
- Fixed several memory leaks.
- Corrected problems in the handling of followers when blocked from performing
actions by closed doors between rooms.
- - Solved issues with Goewin not always correctly following the player out of the caves
+ - Solved issues with Goewin not always correctly following the player out of the caves.
Tinsel:
- Fix video playback regression in Discworld 2.
@@ -210,7 +217,7 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
The Secret of Monkey Island. (GSoC Task)
- Fixed some other bugs related to game versions for the Amiga.
- Added support for original save/load dialog in MM NES.
- - Added support for savepoint passcodes for Sega CD MI1 via debugger command 'passcode'
+ - Added support for savepoint passcodes for Sega CD MI1 via debugger command 'passcode'.
- Added support for Kanji rendering in Japanese version of Monkey Island Sega CD.
1.0.0 (2009-11-15)
diff --git a/README b/README
index e49277010f..6b4539ac0f 100644
--- a/README
+++ b/README
@@ -268,6 +268,8 @@ Other Games:
Musketeer [touche]
SCUMM Games by Humongous Entertainment:
+ Backyard Baseball [baseball]
+ Backyard Baseball 2001 [baseball2001]
Backyard Football [football]
Big Thinkers First Grade [thinker1]
Big Thinkers Kindergarten [thinkerk]
@@ -321,8 +323,6 @@ these at your own risk, and please do not file bug reports about them.
If you want the latest updates on game compatibility, visit our web site
and view the compatibility chart.
- Backyard Baseball [baseball]
- Backyard Baseball 2001 [baseball2001]
Backyard Baseball 2003 [baseball2003]
Backyard Football 2002 [football2002]
Backyard Soccer [soccer]
@@ -394,9 +394,9 @@ in the previous paragraph.
3.3) Maniac Mansion NES notes:
---- -------------------------
-Supported versions are English GB (E), French (F), German (G), Swedish
-(SW) and English US (U). ScummVM requires just the PRG section to run
-and not the whole ROM.
+Supported versions are English GB (E), French (F), German (G), Italian (I),
+Swedish (SW) and English US (U). ScummVM requires just the PRG section
+to run and not the whole ROM.
In order to get the game working, you will have to strip out the first
16 bytes from the ROM you are trying to work with. Any hex editor will
@@ -404,7 +404,7 @@ work as long as you are able to copy/paste. After you open the ROM with
the hex editor, copy everything from the second row (17th byte) to the
end. After you do this, paste it to a new hex file. Name the new file
"Maniac Mansion (XX).prg" while XX stands for the version you are
-working with (E, F, G, SW, or U). The final size should be exactly
+working with (E, F, G, I, SW, or U). The final size should be exactly
262144 bytes.
If you add the game manually make sure that the platform is set to NES.
@@ -1926,91 +1926,92 @@ An example config file looks as follows:
The following keywords are recognized:
- path string The path to where a game's data files are
- autosave_period number The seconds between autosaving (default: 300)
- save_slot number The savegame number to load on startup.
- savepath string The path to where a game will store its
- savegames.
- versioninfo string The version of the ScummVM that created the
- configuration file.
-
- gameid string The real id of a game. Useful if you have
- several versions of the same game, and want
- different aliases for them. See the example.
- description string The description of the game as it will appear
- in the launcher.
-
- language string Specify language (en, us, de, fr, it, pt, es,
- jp, zh, kr, se, gb, hb, cz, ru)
- speech_mute bool If true, speech is muted
- subtitles bool Set to true to enable subtitles.
- talkspeed number Text delay in SCUMM games, or text speed in
- other games.
-
- fullscreen bool Fullscreen mode
- aspect_ratio bool Enable aspect ratio correction
- gfx_mode string Graphics mode (normal, 2x, 3x, 2xsai,
- super2xsai, supereagle, advmame2x, advmame3x,
- hq2x, hq3x, tv2x, dotmatrix)
-
- confirm_exit bool Ask for confirmation by the user before quitting
- (SDL backend only).
- cdrom number Number of CD-ROM unit to use for audio. If
- negative, don't even try to access the CD-ROM.
- joystick_num number Number of joystick device to use for input
- music_driver string The music engine to use.
- opl_driver string The AdLib (OPL) emulator to use.
- output_rate number The output sample rate to use, in Hz. Sensible
- values are 11025, 22050 and 44100.
- alsa_port string Port to use for output when using the
- ALSA music driver.
- music_volume number The music volume setting (0-255)
- multi_midi bool If true, enable combination AdLib and native
- MIDI.
- soundfont string The SoundFont to use for MIDI playback. (Only
- supported by some MIDI drivers.)
- native_mt32 bool If true, disable GM emulation and assume that
- there is a true Roland MT-32 available.
- enable_gs bool If true, enable Roland GS-specific features to
- enhance GM emulation. If native_mt32 is also
- true, the GS device will select an MT-32 map
- to play the correct instruments.
- sfx_volume number The sfx volume setting (0-255)
- tempo number The music tempo (50-200) (default: 100)
- speech_volume number The speech volume setting (0-255)
- midi_gain number The MIDI gain (0-1000) (default: 100) (Only
- supported by some MIDI drivers.)
-
- copy_protection bool Enable copy protection in certain games, in those
- cases where ScummVM disables it by default.
- demo_mode bool Start demo in Maniac Mansion
- alt_intro bool Use alternative intro for CD versions of
- Beneath a Steel Sky and Flight of the Amazon
- Queen
-
- boot_param number Pass this number to the boot script
+ path string The path to where a game's data files are
+ autosave_period number The seconds between autosaving (default: 300)
+ save_slot number The savegame number to load on startup.
+ savepath string The path to where a game will store its
+ savegames.
+ versioninfo string The version of the ScummVM that created the
+ configuration file.
+
+ gameid string The real id of a game. Useful if you have
+ several versions of the same game, and want
+ different aliases for them. See the example.
+ description string The description of the game as it will appear
+ in the launcher.
+
+ language string Specify language (en, us, de, fr, it, pt, es,
+ jp, zh, kr, se, gb, hb, cz, ru)
+ speech_mute bool If true, speech is muted
+ subtitles bool Set to true to enable subtitles.
+ talkspeed number Text delay in SCUMM games, or text speed in
+ other games.
+
+ fullscreen bool Fullscreen mode
+ aspect_ratio bool Enable aspect ratio correction
+ disable_dithering bool Remove dithering artifacts from EGA games
+ gfx_mode string Graphics mode (normal, 2x, 3x, 2xsai,
+ super2xsai, supereagle, advmame2x, advmame3x,
+ hq2x, hq3x, tv2x, dotmatrix)
+
+ confirm_exit bool Ask for confirmation by the user before quitting
+ (SDL backend only).
+ cdrom number Number of CD-ROM unit to use for audio. If
+ negative, don't even try to access the CD-ROM.
+ joystick_num number Number of joystick device to use for input
+ music_driver string The music engine to use.
+ opl_driver string The AdLib (OPL) emulator to use.
+ output_rate number The output sample rate to use, in Hz. Sensible
+ values are 11025, 22050 and 44100.
+ alsa_port string Port to use for output when using the
+ ALSA music driver.
+ music_volume number The music volume setting (0-255)
+ multi_midi bool If true, enable combination AdLib and native
+ MIDI.
+ soundfont string The SoundFont to use for MIDI playback. (Only
+ supported by some MIDI drivers.)
+ native_mt32 bool If true, disable GM emulation and assume that
+ there is a true Roland MT-32 available.
+ enable_gs bool If true, enable Roland GS-specific features to
+ enhance GM emulation. If native_mt32 is also
+ true, the GS device will select an MT-32 map
+ to play the correct instruments.
+ sfx_volume number The sfx volume setting (0-255)
+ tempo number The music tempo (50-200) (default: 100)
+ speech_volume number The speech volume setting (0-255)
+ midi_gain number The MIDI gain (0-1000) (default: 100) (Only
+ supported by some MIDI drivers.)
+
+ copy_protection bool Enable copy protection in certain games, in
+ those cases where ScummVM disables it by default.
+ demo_mode bool Start demo in Maniac Mansion
+ alt_intro bool Use alternative intro for CD versions of
+ Beneath a Steel Sky and Flight of the Amazon
+ Queen
+
+ boot_param number Pass this number to the boot script
Broken Sword II adds the following non-standard keywords:
- gfx_details number Graphics details setting (0-3)
- music_mute bool If true, music is muted
- object_labels bool If true, object labels are enabled
- reverse_stereo bool If true, stereo channels are reversed
- sfx_mute bool If true, sound effects are muted
+ gfx_details number Graphics details setting (0-3)
+ music_mute bool If true, music is muted
+ object_labels bool If true, object labels are enabled
+ reverse_stereo bool If true, stereo channels are reversed
+ sfx_mute bool If true, sound effects are muted
Flight of the Amazon Queen adds the following non-standard keywords:
- music_mute bool If true, music is muted
- sfx_mute bool If true, sound effects are muted
+ music_mute bool If true, music is muted
+ sfx_mute bool If true, sound effects are muted
Simon the Sorcerer 1 and 2 add the following non-standard keywords:
- music_mute bool If true, music is muted
- sfx_mute bool If true, sound effects are muted
+ music_mute bool If true, music is muted
+ sfx_mute bool If true, sound effects are muted
The Legend of Kyrandia adds the following non-standard keyword:
- walkspeed int The walk speed (0-4)
+ walkspeed int The walk speed (0-4)
9.0) Compiling:
diff --git a/backends/audiocd/audiocd.h b/backends/audiocd/audiocd.h
index 5ea5bfcfd4..f218db7f72 100644
--- a/backends/audiocd/audiocd.h
+++ b/backends/audiocd/audiocd.h
@@ -26,8 +26,8 @@
#ifndef BACKENDS_AUDIOCD_ABSTRACT_H
#define BACKENDS_AUDIOCD_ABSTRACT_H
-#include "common/noncopyable.h"
#include "common/scummsys.h"
+#include "common/noncopyable.h"
/**
* Abstract Audio CD manager class. Subclasses implement the actual
diff --git a/backends/audiocd/sdl/sdl-audiocd.cpp b/backends/audiocd/sdl/sdl-audiocd.cpp
index b906a3786f..62ab333f54 100644
--- a/backends/audiocd/sdl/sdl-audiocd.cpp
+++ b/backends/audiocd/sdl/sdl-audiocd.cpp
@@ -25,6 +25,9 @@
#if defined(SDL_BACKEND)
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/audiocd/sdl/sdl-audiocd.h"
SdlAudioCDManager::SdlAudioCDManager()
diff --git a/backends/base-backend.cpp b/backends/base-backend.cpp
index aa08e94c32..42ab7b887a 100644
--- a/backends/base-backend.cpp
+++ b/backends/base-backend.cpp
@@ -25,6 +25,7 @@
#include "backends/base-backend.h"
#include "backends/events/default/default-events.h"
+#include "backends/audiocd/default/default-audiocd.h"
#include "gui/message.h"
void BaseBackend::displayMessageOnOSD(const char *msg) {
@@ -71,6 +72,14 @@ void BaseBackend::fillScreen(uint32 col) {
#define DEFAULT_CONFIG_FILE "scummvm.ini"
#endif
+BaseBackend::BaseBackend() {
+ _audiocdManager = 0;
+}
+
+BaseBackend::~BaseBackend() {
+ delete _audiocdManager;
+}
+
Common::SeekableReadStream *BaseBackend::createConfigReadStream() {
Common::FSNode file(DEFAULT_CONFIG_FILE);
return file.createReadStream();
@@ -85,12 +94,10 @@ Common::WriteStream *BaseBackend::createConfigWriteStream() {
#endif
}
-static DefaultAudioCDManager *s_audiocdManager = 0;
-
AudioCDManager *BaseBackend::getAudioCDManager() {
- if (!s_audiocdManager)
- s_audiocdManager = new DefaultAudioCDManager();
- return (AudioCDManager *)s_audiocdManager;
+ if (!_audiocdManager)
+ _audiocdManager = new DefaultAudioCDManager();
+ return _audiocdManager;
}
void BaseBackend::resetGraphicsScale() {
diff --git a/backends/base-backend.h b/backends/base-backend.h
index bcacde9aad..de94d85523 100644
--- a/backends/base-backend.h
+++ b/backends/base-backend.h
@@ -28,10 +28,12 @@
#include "common/system.h"
#include "backends/events/default/default-events.h"
-#include "backends/audiocd/default/default-audiocd.h"
class BaseBackend : public OSystem, Common::EventSource {
public:
+ BaseBackend();
+ ~BaseBackend();
+
virtual Common::EventManager *getEventManager();
virtual void displayMessageOnOSD(const char *msg);
virtual void fillScreen(uint32 col);
@@ -42,6 +44,9 @@ public:
virtual AudioCDManager *getAudioCDManager();
virtual void resetGraphicsScale();
+
+protected:
+ AudioCDManager *_audiocdManager;
};
diff --git a/backends/events/dinguxsdl/dinguxsdl-events.h b/backends/events/dinguxsdl/dinguxsdl-events.h
deleted file mode 100644
index f269fcf358..0000000000
--- a/backends/events/dinguxsdl/dinguxsdl-events.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_EVENTS_SDL_DINGUX_H
-#define BACKENDS_EVENTS_SDL_DINGUX_H
-#if defined(DINGUX)
-
-#include "backends/platform/dingux/dingux.h"
-#include "backends/events/dinguxsdl/dinguxsdl-events.h"
-
-class DINGUXSdlEventSource : public SdlEventSource {
-public:
- DINGUXSdlEventSource();
- void setCurrentGraphMan(DINGUXSdlGraphicsManager *_graphicManager);
-
-protected:
- DINGUXSdlGraphicsManager *_grpMan;
-
- bool remapKey(SDL_Event &ev, Common::Event &event);
- void fillMouseEvent(Common::Event &event, int x, int y);
- void warpMouse(int x, int y);
-};
-
-#endif /* DINGUX */
-#endif /* BACKENDS_EVENTS_SDL_DINGUX_H */
diff --git a/backends/events/gp2xsdl/gp2xsdl-events.h b/backends/events/gp2xsdl/gp2xsdl-events.h
deleted file mode 100644
index dbbdb2993b..0000000000
--- a/backends/events/gp2xsdl/gp2xsdl-events.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if !defined(BACKEND_EVENTS_SDL_GP2X_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
-#define BACKEND_EVENTS_SDL_GP2X_H
-
-#include "backends/events/sdl/sdl-events.h"
-
-/**
- * SDL events manager for GP2X and GP2XWIZ
- */
-class GP2XSdlEventManager : public SdlEventManager {
-public:
- GP2XSdlEventManager(Common::EventSource *boss);
-
-protected:
- bool _stickBtn[32];
-
- /** Button state for L button modifier */
- bool _buttonStateL;
-
- /**
- * Handles the stick movement
- */
- void moveStick();
-
- virtual bool handleKeyDown(SDL_Event &ev, Common::Event &event);
- virtual bool handleKeyUp(SDL_Event &ev, Common::Event &event);
- virtual bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event);
- virtual bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event);
- virtual bool GP2XSdlEventManager::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event);
-
- virtual void SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event);
-
- virtual bool GP2XSdlEventManager::remapKey(SDL_Event &ev, Common::Event &event);
-};
-
-#endif
diff --git a/backends/events/linuxmotosdl/linuxmotosdl-events.h b/backends/events/linuxmotosdl/linuxmotosdl-events.h
deleted file mode 100644
index 414db080ed..0000000000
--- a/backends/events/linuxmotosdl/linuxmotosdl-events.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if !defined(BACKEND_EVENTS_SDL_LINUXMOTO_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
-#define BACKEND_EVENTS_SDL_LINUXMOTO_H
-
-#include "backends/events/sdl/sdl-events.h"
-
-/**
- * SDL events manager for LINUXMOTO
- */
-class LinuxmotoSdlEventManager : public SdlEventManager {
-public:
- LinuxmotoSdlEventManager(Common::EventSource *boss);
-
-protected:
- virtual void preprocessEvents(SDL_Event *event);
- virtual bool remapKey(SDL_Event &ev, Common::Event &event);
-};
-
-#endif
diff --git a/backends/events/sdl/sdl-events.h b/backends/events/sdl/sdl-events.h
deleted file mode 100644
index b060d021fc..0000000000
--- a/backends/events/sdl/sdl-events.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if !defined(BACKEND_EVENTS_SDL_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
-#define BACKEND_EVENTS_SDL_H
-
-#include "backends/events/default/default-events.h"
-
-#if defined(__SYMBIAN32__)
-#include <esdl\SDL.h>
-#else
-#include <SDL.h>
-#endif
-
-/**
- * The SDL event source.
- */
-class SdlEventSource : public Common::EventSource {
-public:
- SdlEventSource();
- virtual ~SdlEventSource();
-
- /**
- * Gets and processes SDL events.
- */
- virtual bool pollEvent(Common::Event &event);
-
- /**
- * Resets keyboard emulation after a video screen change
- */
- virtual void resetKeyboadEmulation(int16 x_max, int16 y_max);
-
- /**
- * Toggles mouse input grab
- */
- virtual void toggleMouseGrab();
-
-protected:
- /** @name Keyboard mouse emulation
- * Disabled by fingolfin 2004-12-18.
- * I am keeping the rest of the code in for now, since the joystick
- * code (or rather, "hack") uses it, too.
- */
- //@{
-
- struct KbdMouse {
- int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count;
- uint32 last_time, delay_time, x_down_time, y_down_time;
- };
- KbdMouse _km;
-
- //@}
-
- /** Scroll lock state - since SDL doesn't track it */
- bool _scrollLock;
-
- /** Joystick */
- SDL_Joystick *_joystick;
-
- /** Last screen id for checking if it was modified */
- int _lastScreenID;
-
- /**
- * Pre process an event before it is dispatched.
- */
- virtual void preprocessEvents(SDL_Event *event) {}
-
- /**
- * Dispatchs SDL events for each handler.
- */
- virtual bool dispatchSDLEvent(SDL_Event &ev, Common::Event &event);
-
-
- /** @name Event Handlers
- * Handlers for specific SDL events, called by SdlEventManager::dispatchSDLEvent().
- * This way, if a managers inherits fromt this SDL events manager, it can
- * change the behavior of only a single event, without having to override all
- * of SdlEventManager::dispatchSDLEvent().
- */
- //@{
-
- virtual bool handleKeyDown(SDL_Event &ev, Common::Event &event);
- virtual bool handleKeyUp(SDL_Event &ev, Common::Event &event);
- virtual bool handleMouseMotion(SDL_Event &ev, Common::Event &event);
- virtual bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event);
- virtual bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event);
- virtual bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event);
- virtual bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event);
- virtual bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event);
- virtual void handleKbdMouse();
-
- //@}
-
- /**
- * Assigns the mouse coords to the mouse event
- */
- virtual void fillMouseEvent(Common::Event &event, int x, int y);
-
- /**
- * Remaps key events. This allows platforms to configure
- * their custom keys.
- */
- virtual bool remapKey(SDL_Event &ev, Common::Event &event);
-
- /**
- * Maps the ASCII value of key
- */
- virtual int mapKey(SDLKey key, SDLMod mod, Uint16 unicode);
-
- /**
- * Configures the key modifiers flags status
- */
- virtual void SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event);
-};
-
-#endif
diff --git a/backends/events/symbiansdl/symbiansdl-events.cpp b/backends/events/symbiansdl/symbiansdl-events.cpp
deleted file mode 100644
index 2d144f9ad9..0000000000
--- a/backends/events/symbiansdl/symbiansdl-events.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef __SYMBIAN32__
-
-#include "backends/events/symbiansdl/symbiansdl-events.h"
-#include "backends/platform/symbian/src/SymbianActions.h"
-#include "gui/message.h"
-#include "common/translation.h"
-
-#include <bautils.h>
-
-SymbianSdlEventManager::zoneDesc SymbianSdlEventManager::_zones[TOTAL_ZONES] = {
- { 0, 0, 320, 145 },
- { 0, 145, 150, 55 },
- { 150, 145, 170, 55 }
-};
-
-SymbianSdlEventManager::SymbianSdlEventManager(Common::EventSource *boss)
- :
- _currentZone(0),
- SdlEventManager(boss) {
- for (int i = 0; i < TOTAL_ZONES; i++) {
- _mouseXZone[i] = (_zones[i].x + (_zones[i].width / 2));
- _mouseYZone[i] = (_zones[i].y + (_zones[i].height / 2));
- }
-}
-
-bool SymbianSdlEventManager::remapKey(SDL_Event &ev, Common::Event &event) {
- if (GUI::Actions::Instance()->mappingActive() || ev.key.keysym.sym <= SDLK_UNKNOWN)
- return false;
-
- for (TInt loop = 0; loop < GUI::ACTION_LAST; loop++) {
- if (GUI::Actions::Instance()->getMapping(loop) == (uint)ev.key.keysym.sym &&
- GUI::Actions::Instance()->isEnabled(loop)) {
- // Create proper event instead
- switch (loop) {
- case GUI::ACTION_UP:
- if (ev.type == SDL_KEYDOWN) {
- _km.y_vel = -1;
- _km.y_down_count = 1;
- } else {
- _km.y_vel = 0;
- _km.y_down_count = 0;
- }
- event.type = Common::EVENT_MOUSEMOVE;
- fillMouseEvent(event, _km.x, _km.y);
-
- return true;
-
- case GUI::ACTION_DOWN:
- if (ev.type == SDL_KEYDOWN) {
- _km.y_vel = 1;
- _km.y_down_count = 1;
- } else {
- _km.y_vel = 0;
- _km.y_down_count = 0;
- }
- event.type = Common::EVENT_MOUSEMOVE;
- fillMouseEvent(event, _km.x, _km.y);
-
- return true;
-
- case GUI::ACTION_LEFT:
- if (ev.type == SDL_KEYDOWN) {
- _km.x_vel = -1;
- _km.x_down_count = 1;
- } else {
- _km.x_vel = 0;
- _km.x_down_count = 0;
- }
- event.type = Common::EVENT_MOUSEMOVE;
- fillMouseEvent(event, _km.x, _km.y);
-
- return true;
-
- case GUI::ACTION_RIGHT:
- if (ev.type == SDL_KEYDOWN) {
- _km.x_vel = 1;
- _km.x_down_count = 1;
- } else {
- _km.x_vel = 0;
- _km.x_down_count = 0;
- }
- event.type = Common::EVENT_MOUSEMOVE;
- fillMouseEvent(event, _km.x, _km.y);
-
- return true;
-
- case GUI::ACTION_LEFTCLICK:
- event.type = (ev.type == SDL_KEYDOWN ? Common::EVENT_LBUTTONDOWN : Common::EVENT_LBUTTONUP);
- fillMouseEvent(event, _km.x, _km.y);
-
- return true;
-
- case GUI::ACTION_RIGHTCLICK:
- event.type = (ev.type == SDL_KEYDOWN ? Common::EVENT_RBUTTONDOWN : Common::EVENT_RBUTTONUP);
- fillMouseEvent(event, _km.x, _km.y);
-
- return true;
-
- case GUI::ACTION_ZONE:
- if (ev.type == SDL_KEYDOWN) {
- for (int i = 0; i < TOTAL_ZONES; i++)
- if (_km.x >= _zones[i].x && _km.y >= _zones[i].y &&
- _km.x <= _zones[i].x + _zones[i].width && _km.y <= _zones[i].y + _zones[i].height
- ) {
- _mouseXZone[i] = _km.x;
- _mouseYZone[i] = _km.y;
- break;
- }
- _currentZone++;
- if (_currentZone >= TOTAL_ZONES)
- _currentZone = 0;
- event.type = Common::EVENT_MOUSEMOVE;
- fillMouseEvent(event, _mouseXZone[_currentZone], _mouseYZone[_currentZone]);
- SDL_WarpMouse(event.mouse.x, event.mouse.y);
- }
-
- return true;
- case GUI::ACTION_MULTI: {
- GUI::Key &key = GUI::Actions::Instance()->getKeyAction(loop);
- // if key code is pause, then change event to interactive or just fall through
- if (key.keycode() == SDLK_PAUSE) {
- event.type = Common::EVENT_PREDICTIVE_DIALOG;
- return true;
- }
- }
- case GUI::ACTION_SAVE:
- case GUI::ACTION_SKIP:
- case GUI::ACTION_SKIP_TEXT:
- case GUI::ACTION_PAUSE:
- case GUI::ACTION_SWAPCHAR:
- case GUI::ACTION_FASTMODE:
- case GUI::ACTION_DEBUGGER:
- case GUI::ACTION_MAINMENU:
- case GUI::ACTION_VKB:
- case GUI::ACTION_KEYMAPPER:{
- GUI::Key &key = GUI::Actions::Instance()->getKeyAction(loop);
- ev.key.keysym.sym = (SDLKey) key.keycode();
- ev.key.keysym.scancode = 0;
- ev.key.keysym.mod = (SDLMod) key.flags();
-
- // Translate from SDL keymod event to Scummvm Key Mod Common::Event.
- // This codes is also present in GP32 backend and in SDL backend as a static function
- // Perhaps it should be shared.
- if (key.flags() != 0) {
- event.kbd.flags = 0;
-
- if (ev.key.keysym.mod & KMOD_SHIFT)
- event.kbd.flags |= Common::KBD_SHIFT;
-
- if (ev.key.keysym.mod & KMOD_ALT)
- event.kbd.flags |= Common::KBD_ALT;
-
- if (ev.key.keysym.mod & KMOD_CTRL)
- event.kbd.flags |= Common::KBD_CTRL;
- }
-
- return false;
- }
-
- case GUI::ACTION_QUIT:
- {
- GUI::MessageDialog alert(_("Do you want to quit ?"), _("Yes"), _("No"));
- if (alert.runModal() == GUI::kMessageOK)
- g_system->quit();
-
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-#endif
-
diff --git a/backends/fs/ps2/ps2-fs-factory.cpp b/backends/fs/ps2/ps2-fs-factory.cpp
index 8d3c22d2d0..05c18c8a7f 100644
--- a/backends/fs/ps2/ps2-fs-factory.cpp
+++ b/backends/fs/ps2/ps2-fs-factory.cpp
@@ -23,6 +23,10 @@
*/
#if defined(__PLAYSTATION2__)
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/fs/ps2/ps2-fs-factory.h"
#include "backends/fs/ps2/ps2-fs.cpp"
diff --git a/backends/fs/stdiostream.cpp b/backends/fs/stdiostream.cpp
index 8845d796c6..d0600f41a6 100644
--- a/backends/fs/stdiostream.cpp
+++ b/backends/fs/stdiostream.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use FILE, fopen etc.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/fs/stdiostream.h"
StdioStream::StdioStream(void *handle) : _handle(handle) {
diff --git a/backends/fs/windows/windows-fs-factory.cpp b/backends/fs/windows/windows-fs-factory.cpp
index c74868b40d..f7b9c837f2 100644
--- a/backends/fs/windows/windows-fs-factory.cpp
+++ b/backends/fs/windows/windows-fs-factory.cpp
@@ -23,6 +23,10 @@
*/
#if defined(WIN32)
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/fs/windows/windows-fs-factory.h"
#include "backends/fs/windows/windows-fs.cpp"
diff --git a/backends/graphics/dinguxsdl/dinguxsdl-graphics.h b/backends/graphics/dinguxsdl/dinguxsdl-graphics.h
deleted file mode 100644
index b2edd73f6d..0000000000
--- a/backends/graphics/dinguxsdl/dinguxsdl-graphics.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_SDL_DINGUX_H
-#define BACKENDS_GRAPHICS_SDL_DINGUX_H
-#if defined (DINGUX)
-
-#include "backends/graphics/sdl/sdl-graphics.h"
-
-#include "graphics/scaler/aspect.h" // for aspect2Real
-#include "graphics/scaler/downscaler.h"
-
-enum {
- GFX_HALF = 12
-};
-
-class DINGUXSdlGraphicsManager : public SdlGraphicsManager {
-public:
- DINGUXSdlGraphicsManager(SdlEventSource *boss);
-
- bool hasFeature(OSystem::Feature f);
- void setFeatureState(OSystem::Feature f, bool enable);
- bool getFeatureState(OSystem::Feature f);
- int getDefaultGraphicsMode() const;
-
- void initSize(uint w, uint h);
- const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
- bool setGraphicsMode(const char *name);
- bool setGraphicsMode(int mode);
- void setGraphicsModeIntern();
- void internUpdateScreen();
- void showOverlay();
- void hideOverlay();
- bool loadGFXMode();
- void drawMouse();
- void undrawMouse();
-
- SdlGraphicsManager::MousePos *getMouseCurState();
- SdlGraphicsManager::VideoState *getVideoMode();
- bool isOverlayVisible();
-
-protected:
- SdlEventSource *_evSrc;
-};
-
-#endif /* DINGUX */
-#endif /* BACKENDS_GRAPHICS_SDL_DINGUX_H */
diff --git a/backends/graphics/gp2xsdl/gp2xsdl-graphics.cpp b/backends/graphics/gp2xsdl/gp2xsdl-graphics.cpp
deleted file mode 100644
index a1e351251a..0000000000
--- a/backends/graphics/gp2xsdl/gp2xsdl-graphics.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef GP2X
-
-#include "backends/graphics/gp2xsdl/gp2xsdl-graphics.h"
-#include "graphics/scaler/aspect.h"
-#include <SDL_gp2x.h>
-
-static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
- {"Fullscreen", "1x", GFX_NORMAL},
- {0, 0, 0}
-};
-
-GP2XSdlGraphicsManager::GP2XSdlGraphicsManager()
- :
- _adjustZoomOnMouse(false) {
-
-}
-
-const OSystem::GraphicsMode *GP2XSdlGraphicsManager::getSupportedGraphicsModes() const {
- return s_supportedGraphicsModes;
-}
-
-int GP2XSdlGraphicsManager::getDefaultGraphicsMode() const {
- return GFX_NORMAL;
-}
-
-
-bool GP2XSdlGraphicsManager::hasFeature(OSystem::Feature f) {
- if (f == OSystem::kFeatureIconifyWindow)
- return false;
-
- return SdlGraphicsManager::hasFeature(f);
-}
-
-void GP2XSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
- if (f != OSystem::kFeatureIconifyWindow)
- SdlGraphicsManager::setFeatureState(f, enable);
-}
-
-void GP2XSdlGraphicsManager::drawMouse() {
- if (!_mouseVisible || !_mouseSurface) {
- _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
- return;
- }
-
- SDL_Rect zoomdst;
- SDL_Rect dst;
- int scale;
- int hotX, hotY;
- int tmpScreenWidth, tmpScreenHeight;
-
- // Temp vars to ensure we zoom to the LCD resolution or greater.
- tmpScreenWidth = _videoMode.screenWidth;
- tmpScreenHeight = _videoMode.screenHeight;
-
- if (_videoMode.screenHeight <= 240) {
- tmpScreenHeight = 240;
- }
-
- if (_videoMode.screenWidth <= 320) {
- tmpScreenWidth = 320;
- }
-
- dst.x = _mouseCurState.x;
- dst.y = _mouseCurState.y;
-
- if (!_overlayVisible) {
- scale = _videoMode.scaleFactor;
- dst.w = _mouseCurState.vW;
- dst.h = _mouseCurState.vH;
- hotX = _mouseCurState.vHotX;
- hotY = _mouseCurState.vHotY;
- } else {
- scale = 1;
- dst.w = _mouseCurState.rW;
- dst.h = _mouseCurState.rH;
- hotX = _mouseCurState.rHotX;
- hotY = _mouseCurState.rHotY;
- }
-
- // The mouse is undrawn using virtual coordinates, i.e. they may be
- // scaled and aspect-ratio corrected.
-
- _mouseBackup.x = dst.x - hotX;
- _mouseBackup.y = dst.y - hotY;
- _mouseBackup.w = dst.w;
- _mouseBackup.h = dst.h;
-
- // We draw the pre-scaled cursor image, so now we need to adjust for
- // scaling, shake position and aspect ratio correction manually.
-
- if (!_overlayVisible) {
- dst.y += _currentShakePos;
- }
-
- if (_videoMode.aspectRatioCorrection && !_overlayVisible)
- dst.y = real2Aspect(dst.y);
-
- dst.x = scale * dst.x - _mouseCurState.rHotX;
- dst.y = scale * dst.y - _mouseCurState.rHotY;
- dst.w = _mouseCurState.rW;
- dst.h = _mouseCurState.rH;
-
- // Hacking about with the zoom around mouse pointer stuff.
- if (_adjustZoomOnMouse){
-
- zoomdst.w = (tmpScreenWidth / 2);
- zoomdst.h = (tmpScreenHeight / 2);
-
- // Create a zoomed rect centered on the mouse pointer.
- // Will pan 1/4 of the screen.
-
- if (dst.x > ((tmpScreenWidth / 4) * 3)) {
- zoomdst.x = (tmpScreenWidth / 2);
- } else {
- zoomdst.x = (dst.x - (tmpScreenWidth / 4));
- if (zoomdst.x < 0) {
- zoomdst.x = 0;
- }
- }
-
- if (dst.y > ((tmpScreenHeight / 4) * 3)) {
- zoomdst.y = (tmpScreenHeight / 2);
- } else {
- zoomdst.y = (dst.y - (tmpScreenHeight / 4));
- if (zoomdst.y < 0) {
- zoomdst.y = 0;
- }
- }
- SDL_GP2X_Display(&zoomdst);
- } else {
-
- // Make sure we are looking at the whole screen otherwise.
-
- zoomdst.x = 0;
- zoomdst.y = 0;
- zoomdst.w = (tmpScreenWidth);
- zoomdst.h = (tmpScreenHeight);
-
- SDL_GP2X_Display(&zoomdst);
- };
-
- // Note that SDL_BlitSurface() and addDirtyRect() will both perform any
- // clipping necessary
-
- if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0)
- error("SDL_BlitSurface failed: %s", SDL_GetError());
-
- // The screen will be updated using real surface coordinates, i.e.
- // they will not be scaled or aspect-ratio corrected.
-
- addDirtyRect(dst.x, dst.y, dst.w, dst.h, true);
-}
-
-void GP2XSdlGraphicsManager::toggleZoomOnMouse() {
- _adjustZoomOnMouse = !_adjustZoomOnMouse;
-}
-
-#endif
diff --git a/backends/graphics/gp2xwizsdl/gp2xwizsdl-graphics.cpp b/backends/graphics/gp2xwizsdl/gp2xwizsdl-graphics.cpp
deleted file mode 100644
index 8cb3eed083..0000000000
--- a/backends/graphics/gp2xwizsdl/gp2xwizsdl-graphics.cpp
+++ /dev/null
@@ -1,445 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef GP2XWIZ
-
-#include "backends/graphics/gp2xwizsdl/gp2xwizsdl-graphics.h"
-#include "backends/events/gp2xsdl/gp2xsdl-events.h"
-
-#include "common/mutex.h"
-#include "graphics/scaler/aspect.h"
-#include "graphics/scaler/downscaler.h"
-
-static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
- {"1x", "Fullscreen", GFX_NORMAL},
-// {"½x", "Downscale", GFX_HALF},
- {0, 0, 0}
-};
-
-const OSystem::GraphicsMode *GP2XWIZSdlGraphicsManager::getSupportedGraphicsModes() const {
- return s_supportedGraphicsModes;
-}
-
-int GP2XWIZSdlGraphicsManager::getDefaultGraphicsMode() const {
- return GFX_NORMAL;
-}
-
-bool GP2XWIZSdlGraphicsManager::setGraphicsMode(int mode) {
- Common::StackLock lock(_graphicsMutex);
-
- assert(_transactionMode == kTransactionActive);
-
- if (_oldVideoMode.setup && _oldVideoMode.mode == mode)
- return true;
-
- int newScaleFactor = 1;
-
- switch (mode) {
- case GFX_NORMAL:
- newScaleFactor = 1;
- break;
- case GFX_HALF:
- newScaleFactor = 1;
- break;
- default:
- warning("unknown gfx mode %d", mode);
- return false;
- }
-
- _transactionDetails.normal1xScaler = (mode == GFX_NORMAL);
- if (_oldVideoMode.setup && _oldVideoMode.scaleFactor != newScaleFactor)
- _transactionDetails.needHotswap = true;
-
- _transactionDetails.needUpdatescreen = true;
-
- _videoMode.mode = mode;
- _videoMode.scaleFactor = newScaleFactor;
-
- return true;
-}
-
-void GP2XWIZSdlGraphicsManager::setGraphicsModeIntern() {
- Common::StackLock lock(_graphicsMutex);
- ScalerProc *newScalerProc = 0;
-
- switch (_videoMode.mode) {
- case GFX_NORMAL:
- newScalerProc = Normal1x;
- break;
- case GFX_HALF:
- newScalerProc = DownscaleAllByHalf;
- break;
-
- default:
- error("Unknown gfx mode %d", _videoMode.mode);
- }
-
- _scalerProc = newScalerProc;
-
- if (!_screen || !_hwscreen)
- return;
-
- // Blit everything to the screen
- _forceFull = true;
-
- // Even if the old and new scale factors are the same, we may have a
- // different scaler for the cursor now.
- blitCursor();
-}
-
-void GP2XWIZSdlGraphicsManager::initSize(uint w, uint h) {
- assert(_transactionMode == kTransactionActive);
-
- // Avoid redundant res changes
- if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight)
- return;
-
- _videoMode.screenWidth = w;
- _videoMode.screenHeight = h;
- if (w > 320 || h > 240){
- setGraphicsMode(GFX_HALF);
- setGraphicsModeIntern();
- ((GP2XSdlEventManager *)g_system->getEventManager())->toggleMouseGrab();
- }
-
- _transactionDetails.sizeChanged = true;
-}
-
-bool GP2XWIZSdlGraphicsManager::loadGFXMode() {
- _videoMode.overlayWidth = 320;
- _videoMode.overlayHeight = 240;
- _videoMode.fullscreen = true;
-
- if (_videoMode.screenHeight != 200 && _videoMode.screenHeight != 400)
- _videoMode.aspectRatioCorrection = false;
-
- return SdlGraphicsManager::loadGFXMode();
-}
-
-void GP2XWIZSdlGraphicsManager::drawMouse() {
- if (!_mouseVisible || !_mouseSurface) {
- _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
- return;
- }
-
- SDL_Rect dst;
- int scale;
- int hotX, hotY;
-
- if (_videoMode.mode == GFX_HALF && !_overlayVisible){
- dst.x = _mouseCurState.x/2;
- dst.y = _mouseCurState.y/2;
- } else {
- dst.x = _mouseCurState.x;
- dst.y = _mouseCurState.y;
- }
-
- if (!_overlayVisible) {
- scale = _videoMode.scaleFactor;
- dst.w = _mouseCurState.vW;
- dst.h = _mouseCurState.vH;
- hotX = _mouseCurState.vHotX;
- hotY = _mouseCurState.vHotY;
- } else {
- scale = 1;
- dst.w = _mouseCurState.rW;
- dst.h = _mouseCurState.rH;
- hotX = _mouseCurState.rHotX;
- hotY = _mouseCurState.rHotY;
- }
-
- // The mouse is undrawn using virtual coordinates, i.e. they may be
- // scaled and aspect-ratio corrected.
-
- _mouseBackup.x = dst.x - hotX;
- _mouseBackup.y = dst.y - hotY;
- _mouseBackup.w = dst.w;
- _mouseBackup.h = dst.h;
-
- // We draw the pre-scaled cursor image, so now we need to adjust for
- // scaling, shake position and aspect ratio correction manually.
-
- if (!_overlayVisible) {
- dst.y += _currentShakePos;
- }
-
- if (_videoMode.aspectRatioCorrection && !_overlayVisible)
- dst.y = real2Aspect(dst.y);
-
- dst.x = scale * dst.x - _mouseCurState.rHotX;
- dst.y = scale * dst.y - _mouseCurState.rHotY;
- dst.w = _mouseCurState.rW;
- dst.h = _mouseCurState.rH;
-
- // Note that SDL_BlitSurface() and addDirtyRect() will both perform any
- // clipping necessary
-
- if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0)
- error("SDL_BlitSurface failed: %s", SDL_GetError());
-
- // The screen will be updated using real surface coordinates, i.e.
- // they will not be scaled or aspect-ratio corrected.
- addDirtyRect(dst.x, dst.y, dst.w, dst.h, true);
-}
-
-void GP2XWIZSdlGraphicsManager::undrawMouse() {
- const int x = _mouseBackup.x;
- const int y = _mouseBackup.y;
-
- // When we switch bigger overlay off mouse jumps. Argh!
- // This is intended to prevent undrawing offscreen mouse
- if (!_overlayVisible && (x >= _videoMode.screenWidth || y >= _videoMode.screenHeight))
- return;
-
- if (_mouseBackup.w != 0 && _mouseBackup.h != 0){
- if (_videoMode.mode == GFX_HALF && !_overlayVisible){
- addDirtyRect(x*2, y*2, _mouseBackup.w*2, _mouseBackup.h*2);
- } else {
- addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h);
- }
- }
-}
-
-void GP2XWIZSdlGraphicsManager::internUpdateScreen() {
- SDL_Surface *srcSurf, *origSurf;
- int height, width;
- ScalerProc *scalerProc;
- int scale1;
-
-#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
- assert(_hwscreen != NULL);
- assert(_hwscreen->map->sw_data != NULL);
-#endif
-
- // If the shake position changed, fill the dirty area with blackness
- if (_currentShakePos != _newShakePos) {
- SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _videoMode.scaleFactor, _newShakePos * _videoMode.scaleFactor};
-
- if (_videoMode.aspectRatioCorrection && !_overlayVisible)
- blackrect.h = real2Aspect(blackrect.h - 1) + 1;
-
- SDL_FillRect(_hwscreen, &blackrect, 0);
-
- _currentShakePos = _newShakePos;
-
- _forceFull = true;
- }
-
- // Check whether the palette was changed in the meantime and update the
- // screen surface accordingly.
- if (_screen && _paletteDirtyEnd != 0) {
- SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart,
- _paletteDirtyStart,
- _paletteDirtyEnd - _paletteDirtyStart);
-
- _paletteDirtyEnd = 0;
-
- _forceFull = true;
- }
-
-#ifdef USE_OSD
- // OSD visible (i.e. non-transparent)?
- if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
- // Updated alpha value
- const int diff = SDL_GetTicks() - _osdFadeStartTime;
- if (diff > 0) {
- if (diff >= kOSDFadeOutDuration) {
- // Back to full transparency
- _osdAlpha = SDL_ALPHA_TRANSPARENT;
- } else {
- // Do a linear fade out...
- const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
- _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration;
- }
- SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha);
- _forceFull = true;
- }
- }
-#endif
-
- if (!_overlayVisible) {
- origSurf = _screen;
- srcSurf = _tmpscreen;
- width = _videoMode.screenWidth;
- height = _videoMode.screenHeight;
- scalerProc = _scalerProc;
- scale1 = _videoMode.scaleFactor;
- } else {
- origSurf = _overlayscreen;
- srcSurf = _tmpscreen2;
- width = _videoMode.overlayWidth;
- height = _videoMode.overlayHeight;
- scalerProc = Normal1x;
-
- scale1 = 1;
- }
-
- // Add the area covered by the mouse cursor to the list of dirty rects if
- // we have to redraw the mouse.
- if (_mouseNeedsRedraw)
- undrawMouse();
-
- // Force a full redraw if requested
- if (_forceFull) {
- _numDirtyRects = 1;
- _dirtyRectList[0].x = 0;
- _dirtyRectList[0].y = 0;
- _dirtyRectList[0].w = width;
- _dirtyRectList[0].h = height;
- }
-
- // Only draw anything if necessary
- if (_numDirtyRects > 0 || _mouseNeedsRedraw) {
- SDL_Rect *r;
- SDL_Rect dst;
- uint32 srcPitch, dstPitch;
- SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects;
-
- for (r = _dirtyRectList; r != lastRect; ++r) {
- dst = *r;
- dst.x++; // Shift rect by one since 2xSai needs to access the data around
- dst.y++; // any pixel to scale it, and we want to avoid mem access crashes.
-
- if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
- error("SDL_BlitSurface failed: %s", SDL_GetError());
- }
-
- SDL_LockSurface(srcSurf);
- SDL_LockSurface(_hwscreen);
-
- srcPitch = srcSurf->pitch;
- dstPitch = _hwscreen->pitch;
-
- for (r = _dirtyRectList; r != lastRect; ++r) {
- register int dst_y = r->y + _currentShakePos;
- register int dst_h = 0;
- register int dst_w = r->w;
- register int orig_dst_y = 0;
- register int dst_x = r->x;
- register int src_y;
- register int src_x;
-
- if (dst_y < height) {
- dst_h = r->h;
- if (dst_h > height - dst_y)
- dst_h = height - dst_y;
-
- orig_dst_y = dst_y;
- src_x = dst_x;
- src_y = dst_y;
-
- if (_videoMode.aspectRatioCorrection && !_overlayVisible)
- dst_y = real2Aspect(dst_y);
-
- assert(scalerProc != NULL);
-
- if (_videoMode.mode == GFX_HALF && scalerProc == DownscaleAllByHalf){
- if (dst_x%2==1){
- dst_x--;
- dst_w++;
- }
- if (dst_y%2==1){
- dst_y--;
- dst_h++;
- }
- src_x = dst_x;
- src_y = dst_y;
- dst_x = dst_x / 2;
- dst_y = dst_y / 2;
- }
- scalerProc((byte *)srcSurf->pixels + (src_x * 2 + 2) + (src_y + 1) * srcPitch, srcPitch,
- (byte *)_hwscreen->pixels + dst_x * 2 + dst_y * dstPitch, dstPitch, dst_w, dst_h);
- }
-
- if (_videoMode.mode == GFX_HALF && scalerProc == DownscaleAllByHalf){
- r->w = r->w / 2;
- r->h = dst_h / 2;
- } else {
- r->w = r->w;
- r->h = dst_h;
- }
-
- r->x = dst_x;
- r->y = dst_y;
-
-
-#ifdef USE_SCALERS
- if (_videoMode.aspectRatioCorrection && orig_dst_y < height && !_overlayVisible)
- r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1);
-#endif
- }
- SDL_UnlockSurface(srcSurf);
- SDL_UnlockSurface(_hwscreen);
-
- // Readjust the dirty rect list in case we are doing a full update.
- // This is necessary if shaking is active.
- if (_forceFull) {
- _dirtyRectList[0].y = 0;
- _dirtyRectList[0].h = (_videoMode.mode == GFX_HALF) ? effectiveScreenHeight()/2 : effectiveScreenHeight();
- }
-
- drawMouse();
-
-#ifdef USE_OSD
- if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
- SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0);
- }
-#endif
- // Finally, blit all our changes to the screen
- SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
- }
-
- _numDirtyRects = 0;
- _forceFull = false;
- _mouseNeedsRedraw = false;
-}
-
-void GP2XWIZSdlGraphicsManager::showOverlay() {
- if (_videoMode.mode == GFX_HALF){
- _mouseCurState.x = _mouseCurState.x / 2;
- _mouseCurState.y = _mouseCurState.y / 2;
- }
- SdlGraphicsManager::showOverlay();
-}
-
-void GP2XWIZSdlGraphicsManager::hideOverlay() {
- if (_videoMode.mode == GFX_HALF){
- _mouseCurState.x = _mouseCurState.x * 2;
- _mouseCurState.y = _mouseCurState.y * 2;
- }
- SdlGraphicsManager::hideOverlay();
-}
-
-void GP2XWIZSdlGraphicsManager::warpMouse(int x, int y) {
- if (_mouseCurState.x != x || _mouseCurState.y != y) {
- if (_videoMode.mode == GFX_HALF && !_overlayVisible){
- x = x / 2;
- y = y / 2;
- }
- }
- SdlGraphicsManager::warpMouse(x, y);
-}
-
-#endif
diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h
deleted file mode 100644
index d2ce6534e1..0000000000
--- a/backends/graphics/graphics.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_ABSTRACT_H
-#define BACKENDS_GRAPHICS_ABSTRACT_H
-
-#include "common/system.h"
-#include "common/noncopyable.h"
-#include "common/keyboard.h"
-
-/**
- * Abstract class for graphics manager. Subclasses
- * implement the real functionality.
- */
-class GraphicsManager : Common::NonCopyable {
-public:
- virtual ~GraphicsManager() {}
-
- virtual bool hasFeature(OSystem::Feature f) = 0;
- virtual void setFeatureState(OSystem::Feature f, bool enable) = 0;
- virtual bool getFeatureState(OSystem::Feature f) = 0;
-
- virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const = 0;
- virtual int getDefaultGraphicsMode() const = 0;
- virtual bool setGraphicsMode(int mode) = 0;
- virtual void resetGraphicsScale() = 0;
- virtual int getGraphicsMode() const = 0;
-#ifdef USE_RGB_COLOR
- virtual Graphics::PixelFormat getScreenFormat() const = 0;
- virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const = 0;
-#endif
- virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) = 0;
- virtual int getScreenChangeID() const = 0;
-
- virtual void beginGFXTransaction() = 0;
- virtual OSystem::TransactionError endGFXTransaction() = 0;
-
- virtual int16 getHeight() = 0;
- virtual int16 getWidth() = 0;
- virtual void setPalette(const byte *colors, uint start, uint num) = 0;
- virtual void grabPalette(byte *colors, uint start, uint num) = 0;
- virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) = 0;
- virtual Graphics::Surface *lockScreen() = 0;
- virtual void unlockScreen() = 0;
- virtual void fillScreen(uint32 col) = 0;
- virtual void updateScreen() = 0;
- virtual void setShakePos(int shakeOffset) = 0;
- virtual void setFocusRectangle(const Common::Rect& rect) = 0;
- virtual void clearFocusRectangle() = 0;
-
- virtual void showOverlay() = 0;
- virtual void hideOverlay() = 0;
- virtual Graphics::PixelFormat getOverlayFormat() const = 0;
- virtual void clearOverlay() = 0;
- virtual void grabOverlay(OverlayColor *buf, int pitch) = 0;
- virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h)= 0;
- virtual int16 getOverlayHeight() = 0;
- virtual int16 getOverlayWidth() = 0;
-
- virtual bool showMouse(bool visible) = 0;
- virtual void warpMouse(int x, int y) = 0;
- virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL) = 0;
- virtual void setCursorPalette(const byte *colors, uint start, uint num) = 0;
- virtual void disableCursorPalette(bool disable) = 0;
-
- virtual void displayMessageOnOSD(const char *msg) {}
-};
-
-#endif
diff --git a/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.h b/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.h
deleted file mode 100644
index 1b387ca189..0000000000
--- a/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_SDL_LINUXMOTO_H
-#define BACKENDS_GRAPHICS_SDL_LINUXMOTO_H
-
-#include "backends/graphics/sdl/sdl-graphics.h"
-
-class LinuxmotoSdlGraphicsManager : public SdlGraphicsManager {
-public:
- virtual void initSize(uint w, uint h);
- virtual void setGraphicsModeIntern();
- virtual bool setGraphicsMode(int mode);
- virtual void internUpdateScreen();
- virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- virtual bool loadGFXMode();
- virtual void drawMouse();
- virtual void undrawMouse();
- virtual void showOverlay();
- virtual void hideOverlay();
- virtual void warpMouse(int x, int y);
-
-protected:
- virtual void adjustMouseEvent(const Common::Event &event);
-};
-
-#endif
diff --git a/backends/graphics/null/null-graphics.h b/backends/graphics/null/null-graphics.h
deleted file mode 100644
index 4c75a9faba..0000000000
--- a/backends/graphics/null/null-graphics.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_NULL_H
-#define BACKENDS_GRAPHICS_NULL_H
-
-#include "backends/graphics/graphics.h"
-
-static const OSystem::GraphicsMode s_noGraphicsModes[] = { {0, 0, 0} };
-
-class NullGraphicsManager : GraphicsManager {
-public:
- virtual ~NullGraphicsManager() {}
-
- bool hasFeature(OSystem::Feature f) { return false; }
- void setFeatureState(OSystem::Feature f, bool enable) {}
- bool getFeatureState(OSystem::Feature f) { return false; }
-
- const OSystem::GraphicsMode *getSupportedGraphicsModes() const { return s_noGraphicsModes; }
- int getDefaultGraphicsMode() const { return 0; }
- bool setGraphicsMode(int mode) { return true; }
- int getGraphicsMode() const { return 0; }
- inline Graphics::PixelFormat getScreenFormat() const {
- return Graphics::PixelFormat::createFormatCLUT8();
- };
- inline Common::List<Graphics::PixelFormat> getSupportedFormats() {
- Common::List<Graphics::PixelFormat> list;
- list.push_back(Graphics::PixelFormat::createFormatCLUT8());
- return list;
- };
- void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) {}
- virtual int getScreenChangeID() const { return 0; }
-
- void beginGFXTransaction() {}
- OSystem::TransactionError endGFXTransaction() { return OSystem::kTransactionSuccess; }
-
- int16 getHeight() { return 0; }
- int16 getWidth() { return 0; }
- void setPalette(const byte *colors, uint start, uint num) {}
- void grabPalette(byte *colors, uint start, uint num) {}
- void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {}
- Graphics::Surface *lockScreen() { return NULL; }
- void unlockScreen() {}
- void fillScreen(uint32 col) {}
- void updateScreen() {}
- void setShakePos(int shakeOffset) {}
- void setFocusRectangle(const Common::Rect& rect) {}
- void clearFocusRectangle() {}
-
- void showOverlay() {}
- void hideOverlay() {}
- Graphics::PixelFormat getOverlayFormat() const { return Graphics::PixelFormat(); }
- void clearOverlay() {}
- void grabOverlay(OverlayColor *buf, int pitch) {}
- void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {}
- int16 getOverlayHeight() { return 0; }
- int16 getOverlayWidth() { return 0; }
-
- bool showMouse(bool visible) { return !visible; }
- void warpMouse(int x, int y) {}
- void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL) {}
- void setCursorPalette(const byte *colors, uint start, uint num) {}
- void disableCursorPalette(bool disable) {}
-};
-
-#endif
diff --git a/backends/graphics/opengl/glerrorcheck.cpp b/backends/graphics/opengl/glerrorcheck.cpp
deleted file mode 100644
index ee177f0ac5..0000000000
--- a/backends/graphics/opengl/glerrorcheck.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(DEBUG) && defined(USE_OPENGL)
-
-#include "backends/graphics/opengl/glerrorcheck.h"
-#include "common/debug.h"
-
-#ifdef WIN32
-#if defined(ARRAYSIZE) && !defined(_WINDOWS_)
-#undef ARRAYSIZE
-#endif
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef ARRAYSIZE
-#endif
-
-#ifdef MACOSX
-#include <gl.h>
-#elif defined(USE_GLES)
-#include <GLES/gl.h>
-#else
-#include <GL/gl.h>
-#endif
-
-static const char *getGlErrStr(GLenum error) {
- switch (error) {
- case GL_NO_ERROR: return "GL_NO_ERROR";
- case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
- case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
- case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW";
- case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW";
- case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
- }
-
- static char buf[40];
- snprintf(buf, sizeof(buf), "(Unknown GL error code 0x%x)", error);
- return buf;
-}
-
-void checkGlError(const char *file, int line) {
- GLenum error = glGetError();
- if (error != GL_NO_ERROR)
- warning("%s:%d: GL error: %s", file, line, getGlErrStr(error));
-}
-
-#endif
diff --git a/backends/graphics/opengl/glerrorcheck.h b/backends/graphics/opengl/glerrorcheck.h
deleted file mode 100644
index a94699ce1d..0000000000
--- a/backends/graphics/opengl/glerrorcheck.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if !defined(DEBUG)
-
-// If not in debug, do nothing
-#define CHECK_GL_ERROR() do {} while (false)
-
-#else
-
-// If in debug, check for an error after a GL call
-#define CHECK_GL_ERROR() checkGlError(__FILE__, __LINE__)
-
-void checkGlError(const char *file, int line);
-
-#endif
diff --git a/backends/graphics/opengl/gltexture.cpp b/backends/graphics/opengl/gltexture.cpp
deleted file mode 100644
index e43cbe2266..0000000000
--- a/backends/graphics/opengl/gltexture.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(USE_OPENGL)
-
-#include "backends/graphics/opengl/gltexture.h"
-#include "backends/graphics/opengl/glerrorcheck.h"
-
-#include "common/rect.h"
-#include "common/array.h"
-#include "common/util.h"
-#include "common/tokenizer.h"
-
-// Supported GL extensions
-static bool npot_supported = false;
-
-/*static inline GLint xdiv(int numerator, int denominator) {
- assert(numerator < (1 << 16));
- return (numerator << 16) / denominator;
-}*/
-
-static GLuint nextHigher2(GLuint v) {
- if (v == 0)
- return 1;
- v--;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- return ++v;
-}
-
-void GLTexture::initGLExtensions() {
- static bool inited = false;
-
- // Return if extensions were already checked
- if (inited)
- return;
-
- // Get a string with all extensions
- const char* ext_string =
- reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
- CHECK_GL_ERROR();
- Common::StringTokenizer tokenizer(ext_string, " ");
- // Iterate all string tokens
- while (!tokenizer.empty()) {
- Common::String token = tokenizer.nextToken();
- if (token == "GL_ARB_texture_non_power_of_two")
- npot_supported = true;
- }
-
- inited = true;
-}
-
-GLTexture::GLTexture(byte bpp, GLenum internalFormat, GLenum format, GLenum type)
- :
- _bytesPerPixel(bpp),
- _internalFormat(internalFormat),
- _glFormat(format),
- _glType(type),
- _textureWidth(0),
- _textureHeight(0),
- _realWidth(0),
- _realHeight(0),
- _refresh(false),
- _filter(GL_NEAREST) {
-
- // Generate the texture ID
- glGenTextures(1, &_textureName); CHECK_GL_ERROR();
-}
-
-GLTexture::~GLTexture() {
- // Delete the texture
- glDeleteTextures(1, &_textureName); CHECK_GL_ERROR();
-}
-
-void GLTexture::refresh() {
- // Delete previous texture
- glDeleteTextures(1, &_textureName); CHECK_GL_ERROR();
-
- // Generate the texture ID
- glGenTextures(1, &_textureName); CHECK_GL_ERROR();
- _refresh = true;
-}
-
-void GLTexture::allocBuffer(GLuint w, GLuint h) {
- _realWidth = w;
- _realHeight = h;
-
- if (w <= _textureWidth && h <= _textureHeight && !_refresh)
- // Already allocated a sufficiently large buffer
- return;
-
- if (npot_supported) {
- _textureWidth = w;
- _textureHeight = h;
- } else {
- _textureWidth = nextHigher2(w);
- _textureHeight = nextHigher2(h);
- }
-
- // Select this OpenGL texture
- glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR();
-
- // Set the texture parameters
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _filter); CHECK_GL_ERROR();
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _filter); CHECK_GL_ERROR();
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); CHECK_GL_ERROR();
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CHECK_GL_ERROR();
-
- // Allocate room for the texture
- glTexImage2D(GL_TEXTURE_2D, 0, _internalFormat,
- _textureWidth, _textureHeight, 0, _glFormat, _glType, NULL); CHECK_GL_ERROR();
-
- _refresh = false;
-}
-
-void GLTexture::updateBuffer(const void *buf, int pitch, GLuint x, GLuint y, GLuint w, GLuint h) {
- // Select this OpenGL texture
- glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR();
-
- // Check if the buffer has its data contiguously
- if (static_cast<int>(w) * _bytesPerPixel == pitch && w == _textureWidth) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,
- _glFormat, _glType, buf); CHECK_GL_ERROR();
- } else {
- // Update the texture row by row
- const byte *src = static_cast<const byte *>(buf);
- do {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y,
- w, 1, _glFormat, _glType, src); CHECK_GL_ERROR();
- ++y;
- src += pitch;
- } while (--h);
- }
-}
-
-void GLTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
- // Select this OpenGL texture
- glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR();
-
- // Calculate the texture rect that will be drawn
- const GLfloat texWidth = (GLfloat)_realWidth / _textureWidth;//xdiv(_surface.w, _textureWidth);
- const GLfloat texHeight = (GLfloat)_realHeight / _textureHeight;//xdiv(_surface.h, _textureHeight);
- const GLfloat texcoords[] = {
- 0, 0,
- texWidth, 0,
- 0, texHeight,
- texWidth, texHeight,
- };
- glTexCoordPointer(2, GL_FLOAT, 0, texcoords); CHECK_GL_ERROR();
-
- // Calculate the screen rect where the texture will be drawn
- const GLshort vertices[] = {
- x, y,
- x + w, y,
- x, y + h,
- x + w, y + h,
- };
- glVertexPointer(2, GL_SHORT, 0, vertices); CHECK_GL_ERROR();
-
- // Draw the texture to the screen buffer
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR();
-}
-
-#endif
diff --git a/backends/graphics/opengl/gltexture.h b/backends/graphics/opengl/gltexture.h
deleted file mode 100644
index 9864f6816c..0000000000
--- a/backends/graphics/opengl/gltexture.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef WIN32
-#if defined(ARRAYSIZE) && !defined(_WINDOWS_)
-#undef ARRAYSIZE
-#endif
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef ARRAYSIZE
-#endif
-
-#if defined(USE_GLES)
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#elif defined(MACOSX)
-#include <gl.h>
-#include <glext.h>
-#else
-#include <GL/gl.h>
-#include <GL/glext.h>
-#endif
-
-#include "graphics/surface.h"
-
-#include "common/rect.h"
-#include "common/array.h"
-
-/**
- * OpenGL texture manager class
- */
-class GLTexture {
-public:
- /**
- * Initialize OpenGL Extensions
- */
- static void initGLExtensions();
-
- GLTexture(byte bpp, GLenum internalFormat, GLenum format, GLenum type);
- virtual ~GLTexture();
-
- /**
- * Refresh the texture after a context change. The
- * process will be completed on next allocBuffer call.
- */
- virtual void refresh();
-
- /**
- * Allocates memory needed for the given size.
- */
- virtual void allocBuffer(GLuint width, GLuint height);
-
- /**
- * Updates the texture pixels.
- */
- virtual void updateBuffer(const void *buf, int pitch, GLuint x, GLuint y,
- GLuint w, GLuint h);
-
- /**
- * Draws the texture to the screen buffer.
- */
- virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
-
- /**
- * Get the texture width.
- */
- GLuint getWidth() const { return _realWidth; }
-
- /**
- * Get the texture height.
- */
- GLuint getHeight() const { return _realHeight; }
-
- /**
- * Set the texture filter.
- * @filter the filter type, GL_NEAREST or GL_LINEAR
- */
- void setFilter(GLint filter) { _filter = filter; }
-
-protected:
- const byte _bytesPerPixel;
- const GLenum _internalFormat;
- const GLenum _glFormat;
- const GLenum _glType;
-
- GLuint _realWidth;
- GLuint _realHeight;
- GLuint _textureName;
- GLuint _textureWidth;
- GLuint _textureHeight;
- GLint _filter;
- bool _refresh;
-};
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
deleted file mode 100644
index 8682c54921..0000000000
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ /dev/null
@@ -1,1304 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(USE_OPENGL)
-
-#include "backends/graphics/opengl/opengl-graphics.h"
-#include "backends/graphics/opengl/glerrorcheck.h"
-#include "common/config-manager.h"
-#include "common/file.h"
-#include "common/mutex.h"
-#include "common/translation.h"
-#include "graphics/font.h"
-#include "graphics/fontman.h"
-
-OpenGLGraphicsManager::OpenGLGraphicsManager()
- :
-#ifdef USE_OSD
- _osdTexture(0), _osdAlpha(0), _osdFadeStartTime(0),
-#endif
- _gameTexture(0), _overlayTexture(0), _cursorTexture(0),
- _screenChangeCount(1 << (sizeof(int) * 8 - 2)), _screenNeedsRedraw(false),
- _shakePos(0),
- _overlayVisible(false), _overlayNeedsRedraw(false),
- _transactionMode(kTransactionNone),
- _cursorNeedsRedraw(false), _cursorPaletteDisabled(true),
- _cursorVisible(false), _cursorKeyColor(0),
- _cursorTargetScale(1),
- _formatBGR(false),
- _displayX(0), _displayY(0), _displayWidth(0), _displayHeight(0),
- _aspectRatioCorrection(false) {
-
- memset(&_oldVideoMode, 0, sizeof(_oldVideoMode));
- memset(&_videoMode, 0, sizeof(_videoMode));
- memset(&_transactionDetails, 0, sizeof(_transactionDetails));
-
- _videoMode.mode = OpenGL::GFX_NORMAL;
- _videoMode.scaleFactor = 2;
- _videoMode.fullscreen = ConfMan.getBool("fullscreen");
- _videoMode.antialiasing = false;
-
- _gamePalette = (byte *)calloc(sizeof(byte) * 4, 256);
- _cursorPalette = (byte *)calloc(sizeof(byte) * 4, 256);
-}
-
-OpenGLGraphicsManager::~OpenGLGraphicsManager() {
- // Unregister the event observer
- if (g_system->getEventManager()->getEventDispatcher() != NULL)
- g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
-
- free(_gamePalette);
- free(_cursorPalette);
-
- if (_gameTexture != NULL)
- delete _gameTexture;
- if (_overlayTexture != NULL)
- delete _overlayTexture;
- if (_cursorTexture != NULL)
- delete _cursorTexture;
-}
-
-void OpenGLGraphicsManager::initEventObserver() {
- // Register the graphics manager as a event observer
- g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
-}
-
-//
-// Feature
-//
-
-bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) {
- return
- (f == OSystem::kFeatureAspectRatioCorrection) ||
- (f == OSystem::kFeatureCursorHasPalette);
-}
-
-void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
- switch (f) {
- case OSystem::kFeatureAspectRatioCorrection:
- _videoMode.mode = OpenGL::GFX_4_3;
- _aspectRatioCorrection = enable;
- break;
- default:
- break;
- }
-}
-
-bool OpenGLGraphicsManager::getFeatureState(OSystem::Feature f) {
- return false;
-}
-
-//
-// Screen format and modes
-//
-
-static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
- {"gl1", _s("OpenGL Normal"), OpenGL::GFX_NORMAL},
- {"gl2", _s("OpenGL Conserve"), OpenGL::GFX_CONSERVE},
- {"gl3", _s("OpenGL 4/3"), OpenGL::GFX_4_3},
- {"gl4", _s("OpenGL Original"), OpenGL::GFX_ORIGINAL},
- {0, 0, 0}
-};
-
-const OSystem::GraphicsMode *OpenGLGraphicsManager::supportedGraphicsModes() {
- return s_supportedGraphicsModes;
-}
-
-const OSystem::GraphicsMode *OpenGLGraphicsManager::getSupportedGraphicsModes() const {
- return s_supportedGraphicsModes;
-}
-
-int OpenGLGraphicsManager::getDefaultGraphicsMode() const {
- return OpenGL::GFX_NORMAL;
-}
-
-bool OpenGLGraphicsManager::setGraphicsMode(int mode) {
- assert(_transactionMode == kTransactionActive);
-
- if (_oldVideoMode.setup && _oldVideoMode.mode == mode)
- return true;
-
- switch (mode) {
- case OpenGL::GFX_NORMAL:
- case OpenGL::GFX_CONSERVE:
- case OpenGL::GFX_4_3:
- case OpenGL::GFX_ORIGINAL:
- break;
- default:
- warning("unknown gfx mode %d", mode);
- return false;
- }
-
- _videoMode.mode = mode;
- _transactionDetails.needRefresh = true;
-
- return true;
-}
-
-int OpenGLGraphicsManager::getGraphicsMode() const {
- assert (_transactionMode == kTransactionNone);
- return _videoMode.mode;
-}
-
-void OpenGLGraphicsManager::resetGraphicsScale() {
- setScale(1);
-}
-
-#ifdef USE_RGB_COLOR
-
-Graphics::PixelFormat OpenGLGraphicsManager::getScreenFormat() const {
- return _screenFormat;
-}
-
-#endif
-
-void OpenGLGraphicsManager::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
- assert(_transactionMode == kTransactionActive);
-
-#ifdef USE_RGB_COLOR
- Graphics::PixelFormat newFormat;
- if (!format)
- newFormat = Graphics::PixelFormat::createFormatCLUT8();
- else
- newFormat = *format;
-
- assert(newFormat.bytesPerPixel > 0);
-
- // Avoid redundant format changes
- if (newFormat != _videoMode.format) {
- _videoMode.format = newFormat;
- _transactionDetails.formatChanged = true;
- _screenFormat = newFormat;
- }
-#endif
-
- // Avoid redundant res changes
- if ((int)width == _videoMode.screenWidth && (int)height == _videoMode.screenHeight)
- return;
-
- _videoMode.screenWidth = width;
- _videoMode.screenHeight = height;
-
- _transactionDetails.sizeChanged = true;
-}
-
-int OpenGLGraphicsManager::getScreenChangeID() const {
- return _screenChangeCount;
-}
-
-//
-// GFX
-//
-
-void OpenGLGraphicsManager::beginGFXTransaction() {
- assert(_transactionMode == kTransactionNone);
-
- _transactionMode = kTransactionActive;
- _transactionDetails.sizeChanged = false;
- _transactionDetails.needRefresh = false;
- _transactionDetails.needUpdatescreen = false;
- _transactionDetails.filterChanged = false;
-#ifdef USE_RGB_COLOR
- _transactionDetails.formatChanged = false;
-#endif
-
- _oldVideoMode = _videoMode;
-}
-
-OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
- int errors = OSystem::kTransactionSuccess;
-
- assert(_transactionMode != kTransactionNone);
-
- if (_transactionMode == kTransactionRollback) {
- if (_videoMode.fullscreen != _oldVideoMode.fullscreen) {
- errors |= OSystem::kTransactionFullscreenFailed;
-
- _videoMode.fullscreen = _oldVideoMode.fullscreen;
- } else if (_videoMode.mode != _oldVideoMode.mode) {
- errors |= OSystem::kTransactionModeSwitchFailed;
-
- _videoMode.mode = _oldVideoMode.mode;
- _videoMode.scaleFactor = _oldVideoMode.scaleFactor;
-#ifdef USE_RGB_COLOR
- } else if (_videoMode.format != _oldVideoMode.format) {
- errors |= OSystem::kTransactionFormatNotSupported;
-
- _videoMode.format = _oldVideoMode.format;
- _screenFormat = _videoMode.format;
-#endif
- } else if (_videoMode.screenWidth != _oldVideoMode.screenWidth || _videoMode.screenHeight != _oldVideoMode.screenHeight) {
- errors |= OSystem::kTransactionSizeChangeFailed;
-
- _videoMode.screenWidth = _oldVideoMode.screenWidth;
- _videoMode.screenHeight = _oldVideoMode.screenHeight;
- _videoMode.overlayWidth = _oldVideoMode.overlayWidth;
- _videoMode.overlayHeight = _oldVideoMode.overlayHeight;
- }
-
- if (_videoMode.fullscreen == _oldVideoMode.fullscreen &&
- _videoMode.mode == _oldVideoMode.mode &&
- _videoMode.screenWidth == _oldVideoMode.screenWidth &&
- _videoMode.screenHeight == _oldVideoMode.screenHeight) {
-
- _oldVideoMode.setup = false;
- }
- }
-
- if (_transactionDetails.sizeChanged || _transactionDetails.needRefresh) {
- unloadGFXMode();
- if (!loadGFXMode()) {
- if (_oldVideoMode.setup) {
- _transactionMode = kTransactionRollback;
- errors |= endGFXTransaction();
- }
- } else {
- clearOverlay();
-
- _videoMode.setup = true;
- _screenChangeCount++;
- }
-#ifdef USE_RGB_COLOR
- } else if (_transactionDetails.filterChanged || _transactionDetails.formatChanged) {
-#else
- } else if (_transactionDetails.filterChanged) {
-#endif
- loadTextures();
- internUpdateScreen();
- } else if (_transactionDetails.needUpdatescreen) {
- internUpdateScreen();
- }
-
- _transactionMode = kTransactionNone;
- return (OSystem::TransactionError)errors;
-}
-
-//
-// Screen
-//
-
-int16 OpenGLGraphicsManager::getHeight() {
- return _videoMode.screenHeight;
-}
-
-int16 OpenGLGraphicsManager::getWidth() {
- return _videoMode.screenWidth;
-}
-
-void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
- assert(colors);
-
-#ifdef USE_RGB_COLOR
- assert(_screenFormat.bytesPerPixel == 1);
-#endif
-
- // Save the screen palette
- memcpy(_gamePalette + start * 4, colors, num * 4);
-
- _screenNeedsRedraw = true;
-
- if (_cursorPaletteDisabled)
- _cursorNeedsRedraw = true;
-}
-
-void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) {
- assert(colors);
-
-#ifdef USE_RGB_COLOR
- assert(_screenFormat.bytesPerPixel == 1);
-#endif
-
- // Copies current palette to buffer
- memcpy(colors, _gamePalette + start * 4, num * 4);
-}
-
-void OpenGLGraphicsManager::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
- assert(x >= 0 && x < _screenData.w);
- assert(y >= 0 && y < _screenData.h);
- assert(h > 0 && y + h <= _screenData.h);
- assert(w > 0 && x + w <= _screenData.w);
-
- // Copy buffer data to game screen internal buffer
- const byte *src = buf;
- byte *dst = (byte *)_screenData.pixels + y * _screenData.pitch;
- for (int i = 0; i < h; i++) {
- memcpy(dst + x * _screenData.bytesPerPixel, src, w * _screenData.bytesPerPixel);
- src += pitch;
- dst += _screenData.pitch;
- }
-
- // Extend dirty area if not full screen redraw is flagged
- if (!_screenNeedsRedraw) {
- const Common::Rect dirtyRect(x, y, x + w, y + h);
- _screenDirtyRect.extend(dirtyRect);
- }
-}
-
-Graphics::Surface *OpenGLGraphicsManager::lockScreen() {
- return &_screenData;
-}
-
-void OpenGLGraphicsManager::unlockScreen() {
- _screenNeedsRedraw = true;
-}
-
-void OpenGLGraphicsManager::fillScreen(uint32 col) {
- if (_gameTexture == NULL)
- return;
-
- if (_screenFormat.bytesPerPixel == 1) {
- memset(_screenData.pixels, col, _screenData.h * _screenData.pitch);
- } else if (_screenFormat.bytesPerPixel == 2) {
- uint16 *pixels = (uint16 *)_screenData.pixels;
- uint16 col16 = (uint16)col;
- for (int i = 0; i < _screenData.w * _screenData.h; i++) {
- pixels[i] = col16;
- }
- } else if (_screenFormat.bytesPerPixel == 3) {
- uint8 *pixels = (uint8 *)_screenData.pixels;
- byte r = (col >> 16) & 0xFF;
- byte g = (col >> 8) & 0xFF;
- byte b = col & 0xFF;
- for (int i = 0; i < _screenData.w * _screenData.h; i++) {
- pixels[0] = r;
- pixels[1] = g;
- pixels[2] = b;
- pixels += 3;
- }
- } else if (_screenFormat.bytesPerPixel == 4) {
- uint32 *pixels = (uint32 *)_screenData.pixels;
- for (int i = 0; i < _screenData.w * _screenData.h; i++) {
- pixels[i] = col;
- }
- }
-
- _screenNeedsRedraw = true;
-}
-
-void OpenGLGraphicsManager::updateScreen() {
- assert (_transactionMode == kTransactionNone);
- internUpdateScreen();
-}
-
-void OpenGLGraphicsManager::setShakePos(int shakeOffset) {
- assert (_transactionMode == kTransactionNone);
- _shakePos = shakeOffset;
-}
-
-void OpenGLGraphicsManager::setFocusRectangle(const Common::Rect& rect) {
-
-}
-
-void OpenGLGraphicsManager::clearFocusRectangle() {
-
-}
-
-//
-// Overlay
-//
-
-void OpenGLGraphicsManager::showOverlay() {
- assert (_transactionMode == kTransactionNone);
-
- if (_overlayVisible)
- return;
-
- _overlayVisible = true;
-
- clearOverlay();
-}
-
-void OpenGLGraphicsManager::hideOverlay() {
- assert (_transactionMode == kTransactionNone);
-
- if (!_overlayVisible)
- return;
-
- _overlayVisible = false;
-
- clearOverlay();
-}
-
-Graphics::PixelFormat OpenGLGraphicsManager::getOverlayFormat() const {
- return _overlayFormat;
-}
-
-void OpenGLGraphicsManager::clearOverlay() {
- // Set all pixels to 0
- memset(_overlayData.pixels, 0, _overlayData.h * _overlayData.pitch);
- _overlayNeedsRedraw = true;
-}
-
-void OpenGLGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) {
- assert(_overlayData.bytesPerPixel == sizeof(buf[0]));
- const byte *src = (byte *)_overlayData.pixels;
- for (int i = 0; i < _overlayData.h; i++) {
- // Copy overlay data to buffer
- memcpy(buf, src, _overlayData.pitch);
- buf += pitch;
- src += _overlayData.pitch;
- }
-}
-
-void OpenGLGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
- assert (_transactionMode == kTransactionNone);
-
- if (_overlayTexture == NULL)
- return;
-
- // Clip the coordinates
- if (x < 0) {
- w += x;
- buf -= x;
- x = 0;
- }
-
- if (y < 0) {
- h += y; buf -= y * pitch;
- y = 0;
- }
-
- if (w > _overlayData.w - x)
- w = _overlayData.w - x;
-
- if (h > _overlayData.h - y)
- h = _overlayData.h - y;
-
- if (w <= 0 || h <= 0)
- return;
-
- if (_overlayFormat.aBits() == 1) {
- // Copy buffer with the alpha bit on for all pixels for correct
- // overlay drawing.
- const uint16 *src = (const uint16 *)buf;
- uint16 *dst = (uint16 *)_overlayData.pixels + y * _overlayData.w + x;
- for (int i = 0; i < h; i++) {
- for (int e = 0; e < w; e++)
- dst[e] = src[e] | 0x1;
- src += pitch;
- dst += _overlayData.w;
- }
- } else {
- // Copy buffer data to internal overlay surface
- const byte *src = (const byte *)buf;
- byte *dst = (byte *)_overlayData.pixels + y * _overlayData.pitch;
- for (int i = 0; i < h; i++) {
- memcpy(dst + x * _overlayData.bytesPerPixel, src, w * _overlayData.bytesPerPixel);
- src += pitch * sizeof(buf[0]);
- dst += _overlayData.pitch;
- }
- }
-
- // Extend dirty area if not full screen redraw is flagged
- if (!_overlayNeedsRedraw) {
- const Common::Rect dirtyRect(x, y, x + w, y + h);
- _overlayDirtyRect.extend(dirtyRect);
- }
-}
-
-int16 OpenGLGraphicsManager::getOverlayHeight() {
- return _videoMode.overlayHeight;
-}
-
-int16 OpenGLGraphicsManager::getOverlayWidth() {
- return _videoMode.overlayWidth;
-}
-
-//
-// Cursor
-//
-
-bool OpenGLGraphicsManager::showMouse(bool visible) {
- if (_cursorVisible == visible)
- return visible;
-
- bool last = _cursorVisible;
- _cursorVisible = visible;
-
- return last;
-}
-
-void OpenGLGraphicsManager::setMousePos(int x, int y) {
- _cursorState.x = x;
- _cursorState.y = y;
-}
-
-void OpenGLGraphicsManager::warpMouse(int x, int y) {
- setMousePos(x, y);
-}
-
-void OpenGLGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
-#ifdef USE_RGB_COLOR
- if (format)
- _cursorFormat = *format;
- else
- _cursorFormat = Graphics::PixelFormat::createFormatCLUT8();
-#else
- assert(keycolor <= 255);
- _cursorFormat = Graphics::PixelFormat::createFormatCLUT8();
-#endif
-
- // Allocate space for cursor data
- if (_cursorData.w != w || _cursorData.h != h)
- _cursorData.create(w, h, _cursorFormat.bytesPerPixel);
-
- // Save cursor data
- memcpy(_cursorData.pixels, buf, h * _cursorData.pitch);
-
- // Set cursor info
- _cursorState.w = w;
- _cursorState.h = h;
- _cursorState.hotX = hotspotX;
- _cursorState.hotY = hotspotY;
- _cursorKeyColor = keycolor;
- _cursorTargetScale = cursorTargetScale;
- _cursorNeedsRedraw = true;
-
- refreshCursorScale();
-}
-
-void OpenGLGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) {
- assert(colors);
-
- // Save the cursor palette
- memcpy(_cursorPalette + start * 4, colors, num * 4);
-
- _cursorPaletteDisabled = false;
- _cursorNeedsRedraw = true;
-}
-
-void OpenGLGraphicsManager::disableCursorPalette(bool disable) {
- _cursorPaletteDisabled = disable;
- _cursorNeedsRedraw = true;
-}
-
-//
-// Misc
-//
-
-void OpenGLGraphicsManager::displayMessageOnOSD(const char *msg) {
- assert (_transactionMode == kTransactionNone);
- assert(msg);
-
- // The font we are going to use:
- const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kOSDFont);
-
- if (_osdSurface.w != _osdTexture->getWidth() || _osdSurface.h != _osdTexture->getHeight())
- _osdSurface.create(_osdTexture->getWidth(), _osdTexture->getHeight(), 2);
- else
- // Clear everything
- memset(_osdSurface.pixels, 0, _osdSurface.h * _osdSurface.pitch);
-
- // Split the message into separate lines.
- Common::Array<Common::String> lines;
- const char *ptr;
- for (ptr = msg; *ptr; ++ptr) {
- if (*ptr == '\n') {
- lines.push_back(Common::String(msg, ptr - msg));
- msg = ptr + 1;
- }
- }
- lines.push_back(Common::String(msg, ptr - msg));
-
- // Determine a rect which would contain the message string (clipped to the
- // screen dimensions).
- const int vOffset = 6;
- const int lineSpacing = 1;
- const int lineHeight = font->getFontHeight() + 2 * lineSpacing;
- int width = 0;
- int height = lineHeight * lines.size() + 2 * vOffset;
- for (uint i = 0; i < lines.size(); i++) {
- width = MAX(width, font->getStringWidth(lines[i]) + 14);
- }
-
- // Clip the rect
- if (width > _osdSurface.w)
- width = _osdSurface.w;
- if (height > _osdSurface.h)
- height = _osdSurface.h;
-
- int dstX = (_osdSurface.w - width) / 2;
- int dstY = (_osdSurface.h - height) / 2;
-
- // Draw a dark gray rect
- uint16 color = 0x294B;
- uint16 *dst = (uint16 *)_osdSurface.pixels + dstY * _osdSurface.w + dstX;
- for (int i = 0; i < height; i++) {
- for (int j = 0; j < width; j++)
- dst[j] = color;
- dst += _osdSurface.w;
- }
-
- // Render the message, centered, and in white
- for (uint i = 0; i < lines.size(); i++) {
- font->drawString(&_osdSurface, lines[i],
- dstX, dstY + i * lineHeight + vOffset + lineSpacing, width,
- 0xFFFF, Graphics::kTextAlignCenter);
- }
-
- // Update the texture
- _osdTexture->updateBuffer(_osdSurface.pixels, _osdSurface.pitch, 0, 0,
- _osdSurface.w, _osdSurface.h);
-
- // Init the OSD display parameters, and the fade out
- _osdAlpha = kOSDInitialAlpha;
- _osdFadeStartTime = g_system->getMillis() + kOSDFadeOutDelay;
-}
-
-//
-// Intern
-//
-
-void OpenGLGraphicsManager::refreshGameScreen() {
- if (_screenNeedsRedraw)
- _screenDirtyRect = Common::Rect(0, 0, _screenData.w, _screenData.h);
-
- int x = _screenDirtyRect.left;
- int y = _screenDirtyRect.top;
- int w = _screenDirtyRect.width();
- int h = _screenDirtyRect.height();
-
- if (_screenData.bytesPerPixel == 1) {
- // Create a temporary RGB888 surface
- byte *surface = new byte[w * h * 3];
-
- // Convert the paletted buffer to RGB888
- const byte *src = (byte *)_screenData.pixels + y * _screenData.pitch;
- src += x * _screenData.bytesPerPixel;
- byte *dst = surface;
- for (int i = 0; i < h; i++) {
- for (int j = 0; j < w; j++) {
- dst[0] = _gamePalette[src[j] * 4];
- dst[1] = _gamePalette[src[j] * 4 + 1];
- dst[2] = _gamePalette[src[j] * 4 + 2];
- dst += 3;
- }
- src += _screenData.pitch;
- }
-
- // Update the texture
- _gameTexture->updateBuffer(surface, w * 3, x, y, w, h);
-
- // Free the temp surface
- delete[] surface;
- } else {
- // Update the texture
- _gameTexture->updateBuffer((byte *)_screenData.pixels + y * _screenData.pitch +
- x * _screenData.bytesPerPixel, _screenData.pitch, x, y, w, h);
- }
-
- _screenNeedsRedraw = false;
- _screenDirtyRect = Common::Rect();
-}
-
-void OpenGLGraphicsManager::refreshOverlay() {
- if (_overlayNeedsRedraw)
- _overlayDirtyRect = Common::Rect(0, 0, _overlayData.w, _overlayData.h);
-
- int x = _overlayDirtyRect.left;
- int y = _overlayDirtyRect.top;
- int w = _overlayDirtyRect.width();
- int h = _overlayDirtyRect.height();
-
- if (_overlayData.bytesPerPixel == 1) {
- // Create a temporary RGB888 surface
- byte *surface = new byte[w * h * 3];
-
- // Convert the paletted buffer to RGB888
- const byte *src = (byte *)_overlayData.pixels + y * _overlayData.pitch;
- src += x * _overlayData.bytesPerPixel;
- byte *dst = surface;
- for (int i = 0; i < h; i++) {
- for (int j = 0; j < w; j++) {
- dst[0] = _gamePalette[src[j] * 4];
- dst[1] = _gamePalette[src[j] * 4 + 1];
- dst[2] = _gamePalette[src[j] * 4 + 2];
- dst += 3;
- }
- src += _screenData.pitch;
- }
-
- // Update the texture
- _overlayTexture->updateBuffer(surface, w * 3, x, y, w, h);
-
- // Free the temp surface
- delete[] surface;
- } else {
- // Update the texture
- _overlayTexture->updateBuffer((byte *)_overlayData.pixels + y * _overlayData.pitch +
- x * _overlayData.bytesPerPixel, _overlayData.pitch, x, y, w, h);
- }
-
- _overlayNeedsRedraw = false;
- _overlayDirtyRect = Common::Rect();
-}
-
-void OpenGLGraphicsManager::refreshCursor() {
- _cursorNeedsRedraw = false;
-
- if (_cursorFormat.bytesPerPixel == 1) {
- // Create a temporary RGBA8888 surface
- byte *surface = new byte[_cursorState.w * _cursorState.h * 4];
- memset(surface, 0, _cursorState.w * _cursorState.h * 4);
-
- // Select palette
- byte *palette;
- if (_cursorPaletteDisabled)
- palette = _gamePalette;
- else
- palette = _cursorPalette;
-
- // Convert the paletted cursor to RGBA8888
- const byte *src = (byte *)_cursorData.pixels;
- byte *dst = surface;
- for (int i = 0; i < _cursorState.w * _cursorState.h; i++) {
- // Check for keycolor
- if (src[i] != _cursorKeyColor) {
- dst[0] = palette[src[i] * 4];
- dst[1] = palette[src[i] * 4 + 1];
- dst[2] = palette[src[i] * 4 + 2];
- dst[3] = 255;
- }
- dst += 4;
- }
-
- // Allocate a texture big enough for cursor
- _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h);
-
- // Update the texture with new cursor
- _cursorTexture->updateBuffer(surface, _cursorState.w * 4, 0, 0, _cursorState.w, _cursorState.h);
-
- // Free the temp surface
- delete[] surface;
- }
-}
-
-void OpenGLGraphicsManager::refreshCursorScale() {
- // Get the window minimum scale factor. The cursor will mantain its original aspect
- // ratio, and we do not want it to get too big if only one dimension is resized
- uint screenScaleFactor = MIN(_videoMode.hardwareWidth * 10000 / _videoMode.screenWidth,
- _videoMode.hardwareHeight * 10000 / _videoMode.screenHeight);
-
- // Do not scale cursor if original size is used
- if (_videoMode.mode == OpenGL::GFX_ORIGINAL)
- screenScaleFactor = _videoMode.scaleFactor * 10000;
-
- if ((uint)_cursorTargetScale * 10000 >= screenScaleFactor && (uint)_videoMode.scaleFactor * 10000 >= screenScaleFactor) {
- // If the cursor target scale and the video mode scale factor are bigger than
- // the current window scale, do not scale the cursor for the overlay
- _cursorState.rW = _cursorState.w;
- _cursorState.rH = _cursorState.h;
- _cursorState.rHotX = _cursorState.hotX;
- _cursorState.rHotY = _cursorState.hotY;
- } else {
- // Otherwise, scale the cursor for the overlay
- int targetScaleFactor = MIN(_cursorTargetScale, _videoMode.scaleFactor);
- int actualFactor = screenScaleFactor - (targetScaleFactor - 1) * 10000;
- _cursorState.rW = (int16)(_cursorState.w * actualFactor / 10000);
- _cursorState.rH = (int16)(_cursorState.h * actualFactor / 10000);
- _cursorState.rHotX = (int16)(_cursorState.hotX * actualFactor / 10000);
- _cursorState.rHotY = (int16)(_cursorState.hotY * actualFactor / 10000);
- }
-
- // Always scale the cursor for the game
- _cursorState.vW = (int16)(_cursorState.w * screenScaleFactor / 10000);
- _cursorState.vH = (int16)(_cursorState.h * screenScaleFactor / 10000);
- _cursorState.vHotX = (int16)(_cursorState.hotX * screenScaleFactor / 10000);
- _cursorState.vHotY = (int16)(_cursorState.hotY * screenScaleFactor / 10000);
-}
-
-void OpenGLGraphicsManager::calculateDisplaySize(int &width, int &height) {
- if (_videoMode.mode == OpenGL::GFX_ORIGINAL) {
- width = _videoMode.overlayWidth;
- height = _videoMode.overlayHeight;
- } else {
- width = _videoMode.hardwareWidth;
- height = _videoMode.hardwareHeight;
-
- uint aspectRatio = (_videoMode.hardwareWidth * 10000 + 5000) / _videoMode.hardwareHeight;
- uint desiredAspectRatio = getAspectRatio();
-
- // Adjust one screen dimension for mantaining the aspect ratio
- if (aspectRatio < desiredAspectRatio)
- height = (width * 10000 + 5000) / desiredAspectRatio;
- else if (aspectRatio > desiredAspectRatio)
- width = (height * desiredAspectRatio + 5000) / 10000;
- }
-}
-
-void OpenGLGraphicsManager::refreshDisplaySize() {
- calculateDisplaySize(_displayWidth, _displayHeight);
-
- // Adjust x and y for centering the screen
- _displayX = (_videoMode.hardwareWidth - _displayWidth) / 2;
- _displayY = (_videoMode.hardwareHeight - _displayHeight) / 2;
-}
-
-void OpenGLGraphicsManager::getGLPixelFormat(Graphics::PixelFormat pixelFormat, byte &bpp, GLenum &intFormat, GLenum &glFormat, GLenum &gltype) {
- if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { // RGBA8888
- bpp = 4;
- intFormat = GL_RGBA;
- glFormat = GL_RGBA;
- gltype = GL_UNSIGNED_BYTE;
- } else if (pixelFormat == Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)) { // RGB888
- bpp = 3;
- intFormat = GL_RGB;
- glFormat = GL_RGB;
- gltype = GL_UNSIGNED_BYTE;
- } else if (pixelFormat == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) { // RGB565
- bpp = 2;
- intFormat = GL_RGB;
- glFormat = GL_RGB;
- gltype = GL_UNSIGNED_SHORT_5_6_5;
- } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)) { // RGB5551
- bpp = 2;
- intFormat = GL_RGBA;
- glFormat = GL_RGBA;
- gltype = GL_UNSIGNED_SHORT_5_5_5_1;
- } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { // RGBA4444
- bpp = 2;
- intFormat = GL_RGBA;
- glFormat = GL_RGBA;
- gltype = GL_UNSIGNED_SHORT_4_4_4_4;
- } else if (pixelFormat.bytesPerPixel == 1) { // CLUT8
- // If uses a palette, create texture as RGB888. The pixel data will be converted
- // later.
- bpp = 3;
- intFormat = GL_RGB;
- glFormat = GL_RGB;
- gltype = GL_UNSIGNED_BYTE;
-#ifndef USE_GLES
- } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)) { // ARGB8888
- bpp = 4;
- intFormat = GL_RGBA;
- glFormat = GL_BGRA;
- gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
- } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12)) { // ARGB4444
- bpp = 2;
- intFormat = GL_RGBA;
- glFormat = GL_BGRA;
- gltype = GL_UNSIGNED_SHORT_4_4_4_4_REV;
- } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)) { // ABGR8888
- bpp = 4;
- intFormat = GL_RGBA;
- glFormat = GL_RGBA;
- gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
- } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0)) { // BGRA8888
- bpp = 4;
- intFormat = GL_RGBA;
- glFormat = GL_BGRA;
- gltype = GL_UNSIGNED_BYTE;
- } else if (pixelFormat == Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0)) { // BGR888
- bpp = 3;
- intFormat = GL_RGB;
- glFormat = GL_BGR;
- gltype = GL_UNSIGNED_BYTE;
- } else if (pixelFormat == Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0)) { // BGR565
- bpp = 2;
- intFormat = GL_RGB;
- glFormat = GL_BGR;
- gltype = GL_UNSIGNED_SHORT_5_6_5;
- } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 1, 1, 6, 11, 0)) { // BGRA5551
- bpp = 2;
- intFormat = GL_RGBA;
- glFormat = GL_BGRA;
- gltype = GL_UNSIGNED_SHORT_5_5_5_1;
- } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 0, 4, 8, 12)) { // ABGR4444
- bpp = 2;
- intFormat = GL_RGBA;
- glFormat = GL_RGBA;
- gltype = GL_UNSIGNED_SHORT_4_4_4_4_REV;
- } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 4, 8, 12, 0)) { // BGRA4444
- bpp = 2;
- intFormat = GL_RGBA;
- glFormat = GL_BGRA;
- gltype = GL_UNSIGNED_SHORT_4_4_4_4;
-#endif
- } else {
- error("OpenGLGraphicsManager: Pixel format not supported");
- }
-}
-
-void OpenGLGraphicsManager::internUpdateScreen() {
- // Clear the screen buffer
- glClear(GL_COLOR_BUFFER_BIT); CHECK_GL_ERROR();
-
- if (_screenNeedsRedraw || !_screenDirtyRect.isEmpty())
- // Refresh texture if dirty
- refreshGameScreen();
-
- int scaleFactor = _videoMode.hardwareHeight / _videoMode.screenHeight;
-
- glPushMatrix();
-
- // Adjust game screen shake position
- glTranslatef(0, _shakePos * scaleFactor, 0); CHECK_GL_ERROR();
-
- // Draw the game screen
- _gameTexture->drawTexture(_displayX, _displayY, _displayWidth, _displayHeight);
-
- glPopMatrix();
-
- if (_overlayVisible) {
- if (_overlayNeedsRedraw || !_overlayDirtyRect.isEmpty())
- // Refresh texture if dirty
- refreshOverlay();
-
- // Draw the overlay
- _overlayTexture->drawTexture(_displayX, _displayY, _displayWidth, _displayHeight);
- }
-
- if (_cursorVisible) {
- if (_cursorNeedsRedraw)
- // Refresh texture if dirty
- refreshCursor();
-
- glPushMatrix();
-
- // Adjust mouse shake position, unless the overlay is visible
- glTranslatef(0, _overlayVisible ? 0 : _shakePos * scaleFactor, 0); CHECK_GL_ERROR();
-
- // Draw the cursor
- if (_overlayVisible)
- _cursorTexture->drawTexture(_cursorState.x - _cursorState.rHotX,
- _cursorState.y - _cursorState.rHotY, _cursorState.rW, _cursorState.rH);
- else
- _cursorTexture->drawTexture(_cursorState.x - _cursorState.vHotX,
- _cursorState.y - _cursorState.vHotY, _cursorState.vW, _cursorState.vH);
-
- glPopMatrix();
- }
-
-#ifdef USE_OSD
- if (_osdAlpha > 0) {
- // Update alpha value
- const int diff = g_system->getMillis() - _osdFadeStartTime;
- if (diff > 0) {
- if (diff >= kOSDFadeOutDuration) {
- // Back to full transparency
- _osdAlpha = 0;
- } else {
- // Do a fade out
- _osdAlpha = kOSDInitialAlpha - diff * kOSDInitialAlpha / kOSDFadeOutDuration;
- }
- }
- // Set the osd transparency
- glColor4f(1.0f, 1.0f, 1.0f, _osdAlpha / 100.0f); CHECK_GL_ERROR();
-
- // Draw the osd texture
- _osdTexture->drawTexture(0, 0, _videoMode.hardwareWidth, _videoMode.hardwareHeight);
-
- // Reset color
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f); CHECK_GL_ERROR();
- }
-#endif
-}
-
-void OpenGLGraphicsManager::initGL() {
- // Check available GL Extensions
- GLTexture::initGLExtensions();
-
- // Disable 3D properties
- glDisable(GL_CULL_FACE); CHECK_GL_ERROR();
- glDisable(GL_DEPTH_TEST); CHECK_GL_ERROR();
- glDisable(GL_LIGHTING); CHECK_GL_ERROR();
- glDisable(GL_FOG); CHECK_GL_ERROR();
- glDisable(GL_DITHER); CHECK_GL_ERROR();
- glShadeModel(GL_FLAT); CHECK_GL_ERROR();
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); CHECK_GL_ERROR();
-
- // Setup alpha blend (For overlay and cursor)
- glEnable(GL_BLEND); CHECK_GL_ERROR();
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CHECK_GL_ERROR();
-
- // Enable rendering with vertex and coord arrays
- glEnableClientState(GL_VERTEX_ARRAY); CHECK_GL_ERROR();
- glEnableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR();
-
- glEnable(GL_TEXTURE_2D); CHECK_GL_ERROR();
-
- // Setup the GL viewport
- glViewport(0, 0, _videoMode.hardwareWidth, _videoMode.hardwareHeight); CHECK_GL_ERROR();
-
- // Setup coordinates system
- glMatrixMode(GL_PROJECTION); CHECK_GL_ERROR();
- glLoadIdentity(); CHECK_GL_ERROR();
-#ifdef USE_GLES
- glOrthox(0, _videoMode.hardwareWidth, _videoMode.hardwareHeight, 0, -1, 1); CHECK_GL_ERROR();
-#else
- glOrtho(0, _videoMode.hardwareWidth, _videoMode.hardwareHeight, 0, -1, 1); CHECK_GL_ERROR();
-#endif
- glMatrixMode(GL_MODELVIEW); CHECK_GL_ERROR();
- glLoadIdentity(); CHECK_GL_ERROR();
-}
-
-void OpenGLGraphicsManager::loadTextures() {
-#ifdef USE_RGB_COLOR
- if (_transactionDetails.formatChanged && _gameTexture)
- delete _gameTexture;
-#endif
-
- if (!_gameTexture) {
- byte bpp;
- GLenum intformat;
- GLenum format;
- GLenum type;
-#ifdef USE_RGB_COLOR
- getGLPixelFormat(_screenFormat, bpp, intformat, format, type);
-#else
- getGLPixelFormat(Graphics::PixelFormat::createFormatCLUT8(), bpp, intformat, format, type);
-#endif
- _gameTexture = new GLTexture(bpp, intformat, format, type);
- } else
- _gameTexture->refresh();
-
- _overlayFormat = Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0);
-
- if (!_overlayTexture) {
- byte bpp;
- GLenum intformat;
- GLenum format;
- GLenum type;
- getGLPixelFormat(_overlayFormat, bpp, intformat, format, type);
- _overlayTexture = new GLTexture(bpp, intformat, format, type);
- } else
- _overlayTexture->refresh();
-
- if (!_cursorTexture)
- _cursorTexture = new GLTexture(4, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
- else
- _cursorTexture->refresh();
-
- GLint filter = _videoMode.antialiasing ? GL_LINEAR : GL_NEAREST;
- _gameTexture->setFilter(filter);
- _overlayTexture->setFilter(filter);
- _cursorTexture->setFilter(filter);
-
- // Allocate texture memory and finish refreshing
- _gameTexture->allocBuffer(_videoMode.screenWidth, _videoMode.screenHeight);
- _overlayTexture->allocBuffer(_videoMode.overlayWidth, _videoMode.overlayHeight);
- _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h);
-
- if (_transactionDetails.formatChanged ||
- _oldVideoMode.screenWidth != _videoMode.screenWidth ||
- _oldVideoMode.screenHeight != _videoMode.screenHeight)
- _screenData.create(_videoMode.screenWidth, _videoMode.screenHeight,
- _screenFormat.bytesPerPixel);
-
- if (_oldVideoMode.overlayWidth != _videoMode.overlayWidth ||
- _oldVideoMode.overlayHeight != _videoMode.overlayHeight)
- _overlayData.create(_videoMode.overlayWidth, _videoMode.overlayHeight,
- _overlayFormat.bytesPerPixel);
-
- _screenNeedsRedraw = true;
- _overlayNeedsRedraw = true;
- _cursorNeedsRedraw = true;
-
-#ifdef USE_OSD
- if (!_osdTexture)
- _osdTexture = new GLTexture(2, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
- else
- _osdTexture->refresh();
-
- _osdTexture->allocBuffer(_videoMode.overlayWidth, _videoMode.overlayHeight);
-#endif
-}
-
-bool OpenGLGraphicsManager::loadGFXMode() {
- // Initialize OpenGL settings
- initGL();
-
- loadTextures();
-
- refreshCursorScale();
-
- refreshDisplaySize();
-
- internUpdateScreen();
-
- return true;
-}
-
-void OpenGLGraphicsManager::unloadGFXMode() {
-
-}
-
-void OpenGLGraphicsManager::setScale(int newScale) {
- if (newScale == _videoMode.scaleFactor)
- return;
-
- _videoMode.scaleFactor = newScale;
- _transactionDetails.sizeChanged = true;
-}
-
-uint OpenGLGraphicsManager::getAspectRatio() {
- if (_videoMode.mode == OpenGL::GFX_NORMAL)
- return _videoMode.hardwareWidth * 10000 / _videoMode.hardwareHeight;
- else if (_videoMode.mode == OpenGL::GFX_4_3)
- return 13333;
- else
- return _videoMode.screenWidth * 10000 / _videoMode.screenHeight;
-}
-
-void OpenGLGraphicsManager::adjustMouseEvent(const Common::Event &event) {
- if (!event.synthetic) {
- Common::Event newEvent(event);
- newEvent.synthetic = true;
-
- if (_videoMode.mode == OpenGL::GFX_NORMAL) {
- if (_videoMode.hardwareWidth != _videoMode.overlayWidth)
- newEvent.mouse.x = newEvent.mouse.x * _videoMode.overlayWidth / _videoMode.hardwareWidth;
- if (_videoMode.hardwareHeight != _videoMode.overlayHeight)
- newEvent.mouse.y = newEvent.mouse.y * _videoMode.overlayHeight / _videoMode.hardwareHeight;
-
- if (!_overlayVisible) {
- newEvent.mouse.x /= _videoMode.scaleFactor;
- newEvent.mouse.y /= _videoMode.scaleFactor;
- }
-
- } else {
- newEvent.mouse.x -= _displayX;
- newEvent.mouse.y -= _displayY;
-
- if (_overlayVisible) {
- if (_displayWidth != _videoMode.overlayWidth)
- newEvent.mouse.x = newEvent.mouse.x * _videoMode.overlayWidth / _displayWidth;
- if (_displayHeight != _videoMode.overlayHeight)
- newEvent.mouse.y = newEvent.mouse.y * _videoMode.overlayHeight / _displayHeight;
- } else {
- if (_displayWidth != _videoMode.screenWidth)
- newEvent.mouse.x = newEvent.mouse.x * _videoMode.screenWidth / _displayWidth;
- if (_displayHeight != _videoMode.screenHeight)
- newEvent.mouse.y = newEvent.mouse.y * _videoMode.screenHeight / _displayHeight;
- }
- }
-
- g_system->getEventManager()->pushEvent(newEvent);
- }
-}
-
-bool OpenGLGraphicsManager::notifyEvent(const Common::Event &event) {
- switch (event.type) {
- case Common::EVENT_MOUSEMOVE:
- if (!event.synthetic)
- setMousePos(event.mouse.x, event.mouse.y);
- case Common::EVENT_LBUTTONDOWN:
- case Common::EVENT_RBUTTONDOWN:
- case Common::EVENT_WHEELUP:
- case Common::EVENT_WHEELDOWN:
- case Common::EVENT_MBUTTONDOWN:
- case Common::EVENT_LBUTTONUP:
- case Common::EVENT_RBUTTONUP:
- case Common::EVENT_MBUTTONUP:
- adjustMouseEvent(event);
- return !event.synthetic;
-
- default:
- break;
- }
-
- return false;
-}
-
-bool OpenGLGraphicsManager::saveScreenshot(const char *filename) {
- int width = _videoMode.hardwareWidth;
- int height = _videoMode.hardwareHeight;
-
- // Allocate memory for screenshot
- uint8 *pixels = new uint8[width * height * 3];
-
- // Get pixel data from OpenGL buffer
-#ifdef USE_GLES
- glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); CHECK_GL_ERROR();
-#else
- if (_formatBGR) {
- glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, pixels); CHECK_GL_ERROR();
- } else {
- glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); CHECK_GL_ERROR();
- }
-#endif
-
- // Open file
- Common::DumpFile out;
- out.open(filename);
-
- // Write BMP header
- out.writeByte('B');
- out.writeByte('M');
- out.writeUint32LE(height * width * 3 + 52);
- out.writeUint32LE(0);
- out.writeUint32LE(52);
- out.writeUint32LE(40);
- out.writeUint32LE(width);
- out.writeUint32LE(height);
- out.writeUint16LE(1);
- out.writeUint16LE(24);
- out.writeUint32LE(0);
- out.writeUint32LE(0);
- out.writeUint32LE(0);
- out.writeUint32LE(0);
- out.writeUint32LE(0);
- out.writeUint32LE(0);
-
- // Write pixel data to BMP
- out.write(pixels, width * height * 3);
-
- // Free allocated memory
- delete[] pixels;
-
- return true;
-}
-
-const char *OpenGLGraphicsManager::getCurrentModeName() {
- const char *modeName = 0;
- const OSystem::GraphicsMode *g = getSupportedGraphicsModes();
- while (g->name) {
- if (g->id == _videoMode.mode) {
- modeName = g->description;
- break;
- }
- g++;
- }
- return modeName;
-}
-
-void OpenGLGraphicsManager::switchDisplayMode(int mode) {
- if (_oldVideoMode.setup && _oldVideoMode.mode == mode)
- return;
-
- if (_transactionMode == kTransactionActive) {
- if (mode == -1) // If -1, switch to next mode
- _videoMode.mode = (_videoMode.mode + 1) % 4;
- else if (mode == -2) // If -2, switch to previous mode
- _videoMode.mode = (_videoMode.mode + 3) % 4;
- else
- _videoMode.mode = mode;
-
- _transactionDetails.needRefresh = true;
- _aspectRatioCorrection = false;
- }
-}
-
-#endif
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
deleted file mode 100644
index 9b3340aef2..0000000000
--- a/backends/graphics/opengl/opengl-graphics.h
+++ /dev/null
@@ -1,293 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_OPENGL_H
-#define BACKENDS_GRAPHICS_OPENGL_H
-
-#include "backends/graphics/opengl/gltexture.h"
-#include "backends/graphics/graphics.h"
-#include "common/events.h"
-
-// Uncomment this to enable the 'on screen display' code.
-#define USE_OSD 1
-
-namespace OpenGL {
-// The OpenGL GFX modes. They have to be inside the OpenGL namespace so they
-// do not clash with the SDL GFX modes.
-enum {
- GFX_NORMAL = 0,
- GFX_CONSERVE = 1,
- GFX_4_3 = 2,
- GFX_ORIGINAL = 3
-};
-
-}
-
-/**
- * Open GL graphics manager. This is an abstract class, it does not do the
- * window and OpenGL context initialization.
- * Derived classes should at least override internUpdateScreen for doing
- * the buffers swap, and implement loadGFXMode for handling the window/context if
- * needed. If USE_RGB_COLOR is enabled, getSupportedFormats must be implemented.
- */
-class OpenGLGraphicsManager : public GraphicsManager, public Common::EventObserver {
-public:
- OpenGLGraphicsManager();
- virtual ~OpenGLGraphicsManager();
-
- virtual void initEventObserver();
-
- virtual bool hasFeature(OSystem::Feature f);
- virtual void setFeatureState(OSystem::Feature f, bool enable);
- virtual bool getFeatureState(OSystem::Feature f);
-
- static const OSystem::GraphicsMode *supportedGraphicsModes();
- virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- virtual bool setGraphicsMode(int mode);
- virtual int getGraphicsMode() const;
- virtual void resetGraphicsScale();
-#ifdef USE_RGB_COLOR
- virtual Graphics::PixelFormat getScreenFormat() const;
- virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const = 0;
-#endif
- virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL);
- virtual int getScreenChangeID() const;
-
- virtual void beginGFXTransaction();
- virtual OSystem::TransactionError endGFXTransaction();
-
- virtual int16 getHeight();
- virtual int16 getWidth();
- virtual void setPalette(const byte *colors, uint start, uint num);
- virtual void grabPalette(byte *colors, uint start, uint num);
- virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
- virtual Graphics::Surface *lockScreen();
- virtual void unlockScreen();
- virtual void fillScreen(uint32 col);
- virtual void updateScreen();
- virtual void setShakePos(int shakeOffset);
- virtual void setFocusRectangle(const Common::Rect& rect);
- virtual void clearFocusRectangle();
-
- virtual void showOverlay();
- virtual void hideOverlay();
- virtual Graphics::PixelFormat getOverlayFormat() const;
- virtual void clearOverlay();
- virtual void grabOverlay(OverlayColor *buf, int pitch);
- virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
- virtual int16 getOverlayHeight();
- virtual int16 getOverlayWidth();
-
- virtual bool showMouse(bool visible);
- virtual void warpMouse(int x, int y);
- virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL);
- virtual void setCursorPalette(const byte *colors, uint start, uint num);
- virtual void disableCursorPalette(bool disable);
-
- virtual void displayMessageOnOSD(const char *msg);
-
- // Override from Common::EventObserver
- bool notifyEvent(const Common::Event &event);
-
-protected:
- /**
- * Setup OpenGL settings
- */
- virtual void initGL();
-
- /**
- * Creates and refreshs OpenGL textures.
- */
- virtual void loadTextures();
-
- //
- // GFX and video
- //
- enum {
- kTransactionNone = 0,
- kTransactionActive = 1,
- kTransactionRollback = 2
- };
-
- struct TransactionDetails {
- bool sizeChanged;
- bool needRefresh;
- bool needUpdatescreen;
- bool filterChanged;
-#ifdef USE_RGB_COLOR
- bool formatChanged;
-#endif
- };
- TransactionDetails _transactionDetails;
- int _transactionMode;
-
- struct VideoState {
- bool setup;
-
- bool fullscreen;
- int activeFullscreenMode;
-
- int mode;
- int scaleFactor;
- bool antialiasing;
-
- int screenWidth, screenHeight;
- int overlayWidth, overlayHeight;
- int hardwareWidth, hardwareHeight;
-#ifdef USE_RGB_COLOR
- Graphics::PixelFormat format;
-#endif
- };
- VideoState _videoMode, _oldVideoMode;
-
- /**
- * Sets the OpenGL texture format for the given pixel format. If format is not support will raise an error.
- */
- virtual void getGLPixelFormat(Graphics::PixelFormat pixelFormat, byte &bpp, GLenum &intFormat, GLenum &glFormat, GLenum &type);
-
- virtual void internUpdateScreen();
- virtual bool loadGFXMode();
- virtual void unloadGFXMode();
-
- virtual void setScale(int newScale);
-
- // Drawing coordinates for the current display mode and scale
- int _displayX;
- int _displayY;
- int _displayWidth;
- int _displayHeight;
-
- /**
- * Sets the dispaly mode.
- * @mode the dispaly mode, if -1 it will switch to next mode. If -2 to previous mode.
- */
- virtual void switchDisplayMode(int mode);
-
- virtual const char *getCurrentModeName();
-
- virtual void calculateDisplaySize(int &width, int &height);
- virtual void refreshDisplaySize();
-
- bool _aspectRatioCorrection;
-
- /**
- * Returns the current target aspect ratio x 10000
- */
- virtual uint getAspectRatio();
-
- bool _formatBGR;
-
- //
- // Game screen
- //
- GLTexture* _gameTexture;
- Graphics::Surface _screenData;
- int _screenChangeCount;
- bool _screenNeedsRedraw;
- Common::Rect _screenDirtyRect;
-
-#ifdef USE_RGB_COLOR
- Graphics::PixelFormat _screenFormat;
-#endif
- byte *_gamePalette;
-
- virtual void refreshGameScreen();
-
- // Shake mode
- int _shakePos;
-
- //
- // Overlay
- //
- GLTexture* _overlayTexture;
- Graphics::Surface _overlayData;
- Graphics::PixelFormat _overlayFormat;
- bool _overlayVisible;
- bool _overlayNeedsRedraw;
- Common::Rect _overlayDirtyRect;
-
- virtual void refreshOverlay();
-
- //
- // Mouse
- //
- struct MousePos {
- // The mouse position, using either virtual (game) or real
- // (overlay) coordinates.
- int16 x, y;
-
- // The size and hotspot of the original cursor image.
- int16 w, h;
- int16 hotX, hotY;
-
- // The size and hotspot of the scaled cursor, in real coordinates.
- int16 rW, rH;
- int16 rHotX, rHotY;
-
- // The size and hotspot of the scaled cursor, in game coordinates.
- int16 vW, vH;
- int16 vHotX, vHotY;
-
- MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0),
- rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0),
- vHotX(0), vHotY(0) {}
- };
-
- GLTexture* _cursorTexture;
- Graphics::Surface _cursorData;
- Graphics::PixelFormat _cursorFormat;
- byte *_cursorPalette;
- bool _cursorPaletteDisabled;
- MousePos _cursorState;
- bool _cursorVisible;
- uint32 _cursorKeyColor;
- int _cursorTargetScale;
- bool _cursorNeedsRedraw;
-
- virtual void refreshCursor();
- virtual void refreshCursorScale();
- virtual void adjustMouseEvent(const Common::Event &event);
- virtual void setMousePos(int x, int y);
-
- //
- // Misc
- //
- virtual bool saveScreenshot(const char *filename);
-
-#ifdef USE_OSD
- GLTexture *_osdTexture;
- Graphics::Surface _osdSurface;
- uint8 _osdAlpha;
- uint32 _osdFadeStartTime;
- enum {
- kOSDFadeOutDelay = 2 * 1000,
- kOSDFadeOutDuration = 500,
- kOSDInitialAlpha = 80
- };
-#endif
-};
-
-#endif
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp
deleted file mode 100644
index 447bc77afe..0000000000
--- a/backends/graphics/openglsdl/openglsdl-graphics.cpp
+++ /dev/null
@@ -1,671 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(SDL_BACKEND) && defined(USE_OPENGL)
-
-#include "backends/graphics/openglsdl/openglsdl-graphics.h"
-#include "backends/platform/sdl/sdl.h"
-#include "common/config-manager.h"
-
-OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager()
- :
- _hwscreen(0),
- _screenResized(false),
- _lastFullscreenModeWidth(0),
- _lastFullscreenModeHeight(0),
- _desktopWidth(0),
- _desktopHeight(0),
- _ignoreResizeFrames(0) {
-
- // Initialize SDL video subsystem
- if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
- error("Could not initialize SDL: %s", SDL_GetError());
- }
-
- // Disable OS cursor
- SDL_ShowCursor(SDL_DISABLE);
-
- // Get desktop resolution
- const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
- if (videoInfo->current_w > 0 && videoInfo->current_h > 0) {
- _desktopWidth = videoInfo->current_w;
- _desktopHeight = videoInfo->current_h;
- }
-
- if (ConfMan.hasKey("last_fullscreen_mode_width") && ConfMan.hasKey("last_fullscreen_mode_height")) {
- _lastFullscreenModeWidth = ConfMan.getInt("last_fullscreen_mode_width");
- _lastFullscreenModeHeight = ConfMan.getInt("last_fullscreen_mode_height");
- }
-}
-
-OpenGLSdlGraphicsManager::~OpenGLSdlGraphicsManager() {
-
-}
-
-
-bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) {
- return
- (f == OSystem::kFeatureFullscreenMode) ||
- (f == OSystem::kFeatureIconifyWindow) ||
- OpenGLGraphicsManager::hasFeature(f);
-}
-
-void OpenGLSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
- switch (f) {
- case OSystem::kFeatureFullscreenMode:
- setFullscreenMode(enable);
- break;
- case OSystem::kFeatureIconifyWindow:
- if (enable)
- SDL_WM_IconifyWindow();
- break;
- default:
- OpenGLGraphicsManager::setFeatureState(f, enable);
- }
-}
-
-#ifdef USE_RGB_COLOR
-
-Common::List<Graphics::PixelFormat> OpenGLSdlGraphicsManager::getSupportedFormats() const {
- assert(!_supportedFormats.empty());
- return _supportedFormats;
-}
-
-void OpenGLSdlGraphicsManager::detectSupportedFormats() {
-
- // Clear old list
- _supportedFormats.clear();
-
- // Some tables with standard formats that we always list
- // as "supported". If frontend code tries to use one of
- // these, we will perform the necessary format
- // conversion in the background. Of course this incurs a
- // performance hit, but on desktop ports this should not
- // matter. We still push the currently active format to
- // the front, so if frontend code just uses the first
- // available format, it will get one that is "cheap" to
- // use.
- const Graphics::PixelFormat RGBList[] = {
-#if defined(ENABLE_32BIT)
- Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), // RGBA8888
-#ifndef USE_GLES
- Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), // ARGB8888
-#endif
- Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), // RGB888
-#endif
- Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), // RGB565
- Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0), // RGB5551
- Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0), // RGBA4444
-#ifndef USE_GLES
- Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12) // ARGB4444
-#endif
- };
-#ifndef USE_GLES
- const Graphics::PixelFormat BGRList[] = {
-#ifdef ENABLE_32BIT
- Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), // ABGR8888
- Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0), // BGRA8888
- Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), // BGR888
-#endif
- Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0), // BGR565
- Graphics::PixelFormat(2, 5, 5, 5, 1, 1, 6, 11, 0), // BGRA5551
- Graphics::PixelFormat(2, 4, 4, 4, 4, 0, 4, 8, 12), // ABGR4444
- Graphics::PixelFormat(2, 4, 4, 4, 4, 4, 8, 12, 0) // BGRA4444
- };
-#endif
-
- Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
- if (_hwscreen) {
- // Get our currently set hardware format
- format = Graphics::PixelFormat(_hwscreen->format->BytesPerPixel,
- 8 - _hwscreen->format->Rloss, 8 - _hwscreen->format->Gloss,
- 8 - _hwscreen->format->Bloss, 8 - _hwscreen->format->Aloss,
- _hwscreen->format->Rshift, _hwscreen->format->Gshift,
- _hwscreen->format->Bshift, _hwscreen->format->Ashift);
-
- // Workaround to MacOSX SDL not providing an accurate Aloss value.
- if (_hwscreen->format->Amask == 0)
- format.aLoss = 8;
-
- // Push it first, as the prefered format if available
- for (int i = 0; i < ARRAYSIZE(RGBList); i++) {
- if (RGBList[i] == format) {
- _supportedFormats.push_back(format);
- break;
- }
- }
-#ifndef USE_GLES
- for (int i = 0; i < ARRAYSIZE(BGRList); i++) {
- if (BGRList[i] == format) {
- _supportedFormats.push_back(format);
- break;
- }
- }
-#endif
- }
-
- // Push some RGB formats
- for (int i = 0; i < ARRAYSIZE(RGBList); i++) {
- if (_hwscreen && (RGBList[i].bytesPerPixel > format.bytesPerPixel))
- continue;
- if (RGBList[i] != format)
- _supportedFormats.push_back(RGBList[i]);
- }
-#ifndef USE_GLES
- // Push some BGR formats
- for (int i = 0; i < ARRAYSIZE(BGRList); i++) {
- if (_hwscreen && (BGRList[i].bytesPerPixel > format.bytesPerPixel))
- continue;
- if (BGRList[i] != format)
- _supportedFormats.push_back(BGRList[i]);
- }
-#endif
- _supportedFormats.push_back(Graphics::PixelFormat::createFormatCLUT8());
-}
-
-#endif
-
-void OpenGLSdlGraphicsManager::warpMouse(int x, int y) {
- int scaledX = x;
- int scaledY = y;
-
- if (_videoMode.mode == OpenGL::GFX_NORMAL) {
- if (_videoMode.hardwareWidth != _videoMode.overlayWidth)
- scaledX = scaledX * _videoMode.hardwareWidth / _videoMode.overlayWidth;
- if (_videoMode.hardwareHeight != _videoMode.overlayHeight)
- scaledY = scaledY * _videoMode.hardwareHeight / _videoMode.overlayHeight;
-
- if (!_overlayVisible) {
- scaledX *= _videoMode.scaleFactor;
- scaledY *= _videoMode.scaleFactor;
- }
- } else {
- if (_overlayVisible) {
- if (_displayWidth != _videoMode.overlayWidth)
- scaledX = scaledX * _displayWidth / _videoMode.overlayWidth;
- if (_displayHeight != _videoMode.overlayHeight)
- scaledY = scaledY * _displayHeight / _videoMode.overlayHeight;
- } else {
- if (_displayWidth != _videoMode.screenWidth)
- scaledX = scaledX * _displayWidth / _videoMode.screenWidth;
- if (_displayHeight != _videoMode.screenHeight)
- scaledY = scaledY * _displayHeight / _videoMode.screenHeight;
- }
-
- scaledX += _displayX;
- scaledY += _displayY;
- }
-
- SDL_WarpMouse(scaledX, scaledY);
-
- setMousePos(scaledX, scaledY);
-}
-
-void OpenGLSdlGraphicsManager::updateScreen() {
- if (_ignoreResizeFrames)
- _ignoreResizeFrames -= 1;
-
- OpenGLGraphicsManager::updateScreen();
-}
-
-//
-// Intern
-//
-
-bool OpenGLSdlGraphicsManager::setupFullscreenMode() {
- SDL_Rect const* const*availableModes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_OPENGL);
-
- // If -2, autodetect the fullscreen mode
- // The last used fullscreen mode will be prioritized, if there is no last fullscreen
- // mode, the desktop resolution will be used, and in case the desktop resolution
- // is not available as a fullscreen mode, the one with smallest metric will be selected.
- if (_videoMode.activeFullscreenMode == -2) {
- // Desktop resolution
- int desktopModeIndex = -1;
-
- // Best metric mode
- const SDL_Rect *bestMode = availableModes[0];
- int bestModeIndex = 0;
- uint bestMetric = (uint)-1;
-
- // Iterate over all available fullscreen modes
- for (int i = 0; const SDL_Rect *mode = availableModes[i]; i++) {
- // Try to setup the last used fullscreen mode
- if (mode->w == _lastFullscreenModeWidth && mode->h == _lastFullscreenModeHeight) {
- _videoMode.hardwareWidth = _lastFullscreenModeWidth;
- _videoMode.hardwareHeight = _lastFullscreenModeHeight;
- _videoMode.activeFullscreenMode = i;
- return true;
- }
-
- if (mode->w == _desktopWidth && mode->h == _desktopHeight)
- desktopModeIndex = i;
-
- if (mode->w < _videoMode.overlayWidth)
- continue;
- if (mode->h < _videoMode.overlayHeight)
- continue;
-
- uint metric = mode->w * mode->h - _videoMode.overlayWidth * _videoMode.overlayHeight;
- if (metric < bestMetric) {
- bestMode = mode;
- bestMetric = metric;
- bestModeIndex = i;
- }
- }
-
- if (desktopModeIndex >= 0) {
- _videoMode.hardwareWidth = _desktopWidth;
- _videoMode.hardwareHeight = _desktopHeight;
-
- _videoMode.activeFullscreenMode = desktopModeIndex;
- return true;
- } else if (bestMode) {
- _videoMode.hardwareWidth = bestMode->w;
- _videoMode.hardwareHeight = bestMode->h;
-
- _videoMode.activeFullscreenMode = bestModeIndex;
- return true;
- }
- } else {
- // Use last fullscreen mode if looping backwards from the first mode
- if (_videoMode.activeFullscreenMode == -1) {
- do {
- _videoMode.activeFullscreenMode++;
- } while(availableModes[_videoMode.activeFullscreenMode]);
- _videoMode.activeFullscreenMode--;
- }
-
- // Use first fullscreen mode if looping from last mode
- if (!availableModes[_videoMode.activeFullscreenMode])
- _videoMode.activeFullscreenMode = 0;
-
- // Check if the fullscreen mode is valid
- if (availableModes[_videoMode.activeFullscreenMode]) {
- _videoMode.hardwareWidth = availableModes[_videoMode.activeFullscreenMode]->w;
- _videoMode.hardwareHeight = availableModes[_videoMode.activeFullscreenMode]->h;
- return true;
- }
- }
-
- // Could not find any suiting fullscreen mode, return false.
- return false;
-}
-
-bool OpenGLSdlGraphicsManager::loadGFXMode() {
- // Force 4/3 if feature enabled
- if (_aspectRatioCorrection)
- _videoMode.mode = OpenGL::GFX_4_3;
-
- _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
- _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
-
- // If the screen was resized, do not change its size
- if (!_screenResized) {
- _videoMode.hardwareWidth = _videoMode.overlayWidth;
- _videoMode.hardwareHeight = _videoMode.overlayHeight;
-
- int screenAspectRatio = _videoMode.screenWidth * 10000 / _videoMode.screenHeight;
- int desiredAspectRatio = getAspectRatio();
-
- // Do not downscale dimensions, only enlarge them if needed
- if (screenAspectRatio > desiredAspectRatio)
- _videoMode.hardwareHeight = (_videoMode.overlayWidth * 10000 + 5000) / desiredAspectRatio;
- else if (screenAspectRatio < desiredAspectRatio)
- _videoMode.hardwareWidth = (_videoMode.overlayHeight * desiredAspectRatio + 5000) / 10000;
-
- // Only adjust the overlay height if it is bigger than original one. If
- // the width is modified it can break the overlay.
- if (_videoMode.hardwareHeight > _videoMode.overlayHeight)
- _videoMode.overlayHeight = _videoMode.hardwareHeight;
- }
-
- _screenResized = false;
-
- // Setup OpenGL attributes for SDL
- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-
- if (_videoMode.fullscreen)
- if (!setupFullscreenMode())
- // Failed setuping a fullscreen mode
- return false;
-
- uint32 flags = SDL_OPENGL;
-
- if (_videoMode.fullscreen)
- flags |= SDL_FULLSCREEN;
- else
- flags |= SDL_RESIZABLE;
-
- // Create our window
- _hwscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 32, flags);
-#ifdef USE_RGB_COLOR
- detectSupportedFormats();
-#endif
-
- if (_hwscreen == NULL) {
- // DON'T use error(), as this tries to bring up the debug
- // console, which WON'T WORK now that _hwscreen is hosed.
-
- if (!_oldVideoMode.setup) {
- warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
- g_system->quit();
- } else
- // Cancel GFX load, and go back to last mode
- return false;
- }
-
- // Check if the screen is BGR format
- _formatBGR = _hwscreen->format->Rshift != 0;
-
- if (_videoMode.fullscreen) {
- _lastFullscreenModeWidth = _videoMode.hardwareWidth;
- _lastFullscreenModeHeight = _videoMode.hardwareHeight;
- ConfMan.setInt("last_fullscreen_mode_width", _lastFullscreenModeWidth);
- ConfMan.setInt("last_fullscreen_mode_height", _lastFullscreenModeHeight);
- }
-
- // Call and return parent implementation of this method
- return OpenGLGraphicsManager::loadGFXMode();
-}
-
-void OpenGLSdlGraphicsManager::unloadGFXMode() {
- if (_hwscreen) {
- SDL_FreeSurface(_hwscreen);
- _hwscreen = NULL;
- }
-}
-
-void OpenGLSdlGraphicsManager::internUpdateScreen() {
- // Call to parent implementation of this method
- OpenGLGraphicsManager::internUpdateScreen();
-
- // Swap OpenGL buffers
- SDL_GL_SwapBuffers();
-}
-
-#ifdef USE_OSD
-void OpenGLSdlGraphicsManager::displayModeChangedMsg() {
- const char *newModeName = getCurrentModeName();
- if (newModeName) {
- char buffer[128];
- sprintf(buffer, "Current display mode: %s\n%d x %d -> %d x %d",
- newModeName,
- _videoMode.screenWidth * _videoMode.scaleFactor,
- _videoMode.screenHeight * _videoMode.scaleFactor,
- _hwscreen->w, _hwscreen->h
- );
- displayMessageOnOSD(buffer);
- }
-}
-void OpenGLSdlGraphicsManager::displayScaleChangedMsg() {
- char buffer[128];
- sprintf(buffer, "Current scale: x%d\n%d x %d -> %d x %d",
- _videoMode.scaleFactor,
- _videoMode.screenWidth, _videoMode.screenHeight,
- _videoMode.overlayWidth, _videoMode.overlayHeight
- );
- displayMessageOnOSD(buffer);
-}
-#endif
-
-void OpenGLSdlGraphicsManager::setFullscreenMode(bool enable) {
- if (_oldVideoMode.setup && _oldVideoMode.fullscreen == enable &&
- _oldVideoMode.activeFullscreenMode == _videoMode.activeFullscreenMode)
- return;
-
- if (_transactionMode == kTransactionActive) {
- _videoMode.fullscreen = enable;
- _transactionDetails.needRefresh = true;
- }
-}
-
-bool OpenGLSdlGraphicsManager::isHotkey(const Common::Event &event) {
- if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) {
- if (event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS ||
- event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS ||
- event.kbd.keycode == 'a' || event.kbd.keycode == 'f')
- return true;
- } else if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_SHIFT)) == (Common::KBD_CTRL|Common::KBD_SHIFT)) {
- if (event.kbd.keycode == 'a' || event.kbd.keycode == 'f')
- return true;
- } else if ((event.kbd.flags & (Common::KBD_ALT)) == (Common::KBD_ALT) && event.kbd.keycode == 's') {
- return true;
- }
- return false;
-}
-
-void OpenGLSdlGraphicsManager::toggleFullScreen(int loop) {
- beginGFXTransaction();
- if (_videoMode.fullscreen && loop) {
- _videoMode.activeFullscreenMode += loop;
- setFullscreenMode(true);
- } else {
- _videoMode.activeFullscreenMode = -2;
- setFullscreenMode(!_videoMode.fullscreen);
- }
- endGFXTransaction();
-
- // Ignore resize events for the next 10 frames
- _ignoreResizeFrames = 10;
-
-#ifdef USE_OSD
- char buffer[128];
- if (_videoMode.fullscreen)
- sprintf(buffer, "Fullscreen mode\n%d x %d",
- _hwscreen->w, _hwscreen->h
- );
- else
- sprintf(buffer, "Windowed mode\n%d x %d",
- _hwscreen->w, _hwscreen->h
- );
- displayMessageOnOSD(buffer);
-#endif
-}
-
-bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
- switch ((int)event.type) {
- case Common::EVENT_KEYDOWN:
- if (event.kbd.hasFlags(Common::KBD_ALT)) {
- // Alt-Return and Alt-Enter toggle full screen mode
- if (event.kbd.keycode == Common::KEYCODE_RETURN ||
- event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER) {
- toggleFullScreen(0);
- return true;
- }
-
- // Alt-S create a screenshot
- if (event.kbd.keycode == 's') {
- char filename[20];
-
- for (int n = 0;; n++) {
- SDL_RWops *file;
-
- sprintf(filename, "scummvm%05d.bmp", n);
- file = SDL_RWFromFile(filename, "r");
- if (!file)
- break;
- SDL_RWclose(file);
- }
- if (saveScreenshot(filename))
- printf("Saved '%s'\n", filename);
- else
- printf("Could not save screenshot!\n");
- return true;
- }
- }
-
- if (event.kbd.hasFlags(Common::KBD_CTRL|Common::KBD_ALT)) {
- // Ctrl-Alt-Return and Ctrl-Alt-Enter switch between full screen modes
- if (event.kbd.keycode == Common::KEYCODE_RETURN ||
- event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER) {
- toggleFullScreen(1);
- return true;
- }
-
- // Ctrl-Alt-a switch between display modes
- if (event.kbd.keycode == 'a') {
- beginGFXTransaction();
- switchDisplayMode(-1);
- endGFXTransaction();
-#ifdef USE_OSD
- displayModeChangedMsg();
-#endif
- internUpdateScreen();
- return true;
- }
-
- // Ctrl-Alt-f toggles antialiasing
- if (event.kbd.keycode == 'f') {
- beginGFXTransaction();
- _videoMode.antialiasing = !_videoMode.antialiasing;
- _transactionDetails.filterChanged = true;
- endGFXTransaction();
-#ifdef USE_OSD
- if (_videoMode.antialiasing)
- displayMessageOnOSD("Active filter mode: Linear");
- else
- displayMessageOnOSD("Active filter mode: Nearest");
-#endif
- return true;
- }
-
- SDLKey sdlKey = (SDLKey)event.kbd.keycode;
-
- // Ctrl+Alt+Plus/Minus Increase/decrease the scale factor
- if ((sdlKey == SDLK_EQUALS || sdlKey == SDLK_PLUS || sdlKey == SDLK_MINUS ||
- sdlKey == SDLK_KP_PLUS || sdlKey == SDLK_KP_MINUS)) {
- int factor = _videoMode.scaleFactor;
- factor += (sdlKey == SDLK_MINUS || sdlKey == SDLK_KP_MINUS) ? -1 : +1;
- if (0 < factor && factor < 4) {
- // Check if the desktop resolution has been detected
- if (_desktopWidth > 0 && _desktopHeight > 0)
- // If the new scale factor is too big, do not scale
- if (_videoMode.screenWidth * factor > _desktopWidth ||
- _videoMode.screenHeight * factor > _desktopHeight)
- return false;
-
- beginGFXTransaction();
- setScale(factor);
- endGFXTransaction();
-#ifdef USE_OSD
- displayScaleChangedMsg();
-#endif
- return true;
- }
- }
-
- const bool isNormalNumber = (SDLK_1 <= sdlKey && sdlKey <= SDLK_4);
- const bool isKeypadNumber = (SDLK_KP1 <= sdlKey && sdlKey <= SDLK_KP4);
-
- // Ctrl-Alt-<number key> will change the GFX mode
- if (isNormalNumber || isKeypadNumber) {
- if (sdlKey - (isNormalNumber ? SDLK_1 : SDLK_KP1) <= 4) {
- int lastMode = _videoMode.mode;
- beginGFXTransaction();
- _videoMode.mode = sdlKey - (isNormalNumber ? SDLK_1 : SDLK_KP1);
- _transactionDetails.needRefresh = true;
- _aspectRatioCorrection = false;
- endGFXTransaction();
-#ifdef USE_OSD
- if (lastMode != _videoMode.mode)
- displayModeChangedMsg();
-#endif
- internUpdateScreen();
- }
- }
- }
-
- if (event.kbd.hasFlags(Common::KBD_CTRL|Common::KBD_SHIFT)) {
- // Ctrl-Shift-Return and Ctrl-Shift-Enter switch backwards between full screen modes
- if (event.kbd.keycode == Common::KEYCODE_RETURN ||
- event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER) {
- toggleFullScreen(-1);
- return true;
- }
-
- // Ctrl-Shift-a switch backwards between display modes
- if (event.kbd.keycode == 'a') {
- beginGFXTransaction();
- switchDisplayMode(-2);
- endGFXTransaction();
-#ifdef USE_OSD
- displayModeChangedMsg();
-#endif
- internUpdateScreen();
- return true;
- }
- }
- break;
- case Common::EVENT_KEYUP:
- return isHotkey(event);
- // HACK: Handle special SDL event
- // The new screen size is saved on the mouse event as part of HACK,
- // there is no common resize event.
- case OSystem_SDL::kSdlEventResize:
- // Do not resize if ignoring resize events.
- if (!_ignoreResizeFrames && !_videoMode.fullscreen) {
- bool scaleChanged = false;
- beginGFXTransaction();
- _videoMode.hardwareWidth = event.mouse.x;
- _videoMode.hardwareHeight = event.mouse.y;
-
- if (_videoMode.mode != OpenGL::GFX_ORIGINAL) {
- _screenResized = true;
- calculateDisplaySize(_videoMode.hardwareWidth, _videoMode.hardwareHeight);
- }
-
- int scale = MIN(_videoMode.hardwareWidth / _videoMode.screenWidth,
- _videoMode.hardwareHeight / _videoMode.screenHeight);
- if (_videoMode.scaleFactor != scale) {
- scaleChanged = true;
- _videoMode.scaleFactor = MAX(MIN(scale, 3), 1);
- }
-
- if (_videoMode.mode == OpenGL::GFX_ORIGINAL) {
- calculateDisplaySize(_videoMode.hardwareWidth, _videoMode.hardwareHeight);
- }
-
- _transactionDetails.sizeChanged = true;
- endGFXTransaction();
-#ifdef USE_OSD
- if (scaleChanged)
- displayScaleChangedMsg();
-#endif
- }
- return true;
-
- default:
- break;
- }
-
- return OpenGLGraphicsManager::notifyEvent(event);
-}
-
-#endif
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h
deleted file mode 100644
index 0854872315..0000000000
--- a/backends/graphics/openglsdl/openglsdl-graphics.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_OPENGLSDL_H
-#define BACKENDS_GRAPHICS_OPENGLSDL_H
-
-#include <SDL.h>
-#if defined(ARRAYSIZE) && !defined(_WINDOWS_)
-#undef ARRAYSIZE
-#endif
-#include <SDL_opengl.h>
-
-#include "backends/graphics/opengl/opengl-graphics.h"
-
-/**
- * SDL OpenGL graphics manager
- */
-class OpenGLSdlGraphicsManager : public OpenGLGraphicsManager {
-public:
- OpenGLSdlGraphicsManager();
- virtual ~OpenGLSdlGraphicsManager();
-
- virtual bool hasFeature(OSystem::Feature f);
- virtual void setFeatureState(OSystem::Feature f, bool enable);
-
-#ifdef USE_RGB_COLOR
- virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
-#endif
-
- virtual void warpMouse(int x, int y);
-
- virtual bool notifyEvent(const Common::Event &event);
-
- virtual void updateScreen();
-
-protected:
- virtual void internUpdateScreen();
-
- virtual bool loadGFXMode();
- virtual void unloadGFXMode();
-
- virtual void setFullscreenMode(bool enable);
-
- virtual bool isHotkey(const Common::Event &event);
-
-#ifdef USE_RGB_COLOR
- Common::List<Graphics::PixelFormat> _supportedFormats;
-
- /**
- * Update the list of supported pixel formats.
- * This method is invoked by loadGFXMode().
- */
- void detectSupportedFormats();
-#endif
-
- /**
- * Toggles fullscreen.
- * @loop loop direction for switching fullscreen mode, if 0 toggles it.
- */
- virtual void toggleFullScreen(int loop);
-
- /**
- * Setup the fullscreen mode.
- * @return false if failed finding a mode, true otherwise.
- */
- virtual bool setupFullscreenMode();
-
- int _lastFullscreenModeWidth;
- int _lastFullscreenModeHeight;
- int _desktopWidth;
- int _desktopHeight;
-
- // Hardware screen
- SDL_Surface *_hwscreen;
-
- // If screen was resized by the user
- bool _screenResized;
-
- // Ignore resize events for the number of updateScreen() calls.
- // Normaly resize events are user generated when resizing the window
- // from its borders, but in some cases a resize event can be generated
- // after a fullscreen change.
- int _ignoreResizeFrames;
-
-#ifdef USE_OSD
- /**
- * Displays a mode change message in OSD
- */
- void displayModeChangedMsg();
-
- /**
- * Displays a scale change message in OSD
- */
- void displayScaleChangedMsg();
-#endif
-};
-
-#endif
diff --git a/backends/graphics/sdl/sdl-graphics.h b/backends/graphics/sdl/sdl-graphics.h
deleted file mode 100644
index 62f87ee238..0000000000
--- a/backends/graphics/sdl/sdl-graphics.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_SDL_H
-#define BACKENDS_GRAPHICS_SDL_H
-
-#include "backends/graphics/graphics.h"
-#include "graphics/scaler.h"
-#include "common/events.h"
-#include "common/system.h"
-
-#include "backends/events/sdl/sdl-events.h"
-
-#if defined(__SYMBIAN32__)
-#include <esdl\SDL.h>
-#else
-#include <SDL.h>
-#endif
-
-#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
-// Uncomment this to enable the 'on screen display' code.
-#define USE_OSD 1
-#endif
-
-enum {
- GFX_NORMAL = 0,
- GFX_DOUBLESIZE = 1,
- GFX_TRIPLESIZE = 2,
- GFX_2XSAI = 3,
- GFX_SUPER2XSAI = 4,
- GFX_SUPEREAGLE = 5,
- GFX_ADVMAME2X = 6,
- GFX_ADVMAME3X = 7,
- GFX_HQ2X = 8,
- GFX_HQ3X = 9,
- GFX_TV2X = 10,
- GFX_DOTMATRIX = 11
-};
-
-
-class AspectRatio {
- int _kw, _kh;
-public:
- AspectRatio() { _kw = _kh = 0; }
- AspectRatio(int w, int h);
-
- bool isAuto() const { return (_kw | _kh) == 0; }
-
- int kw() const { return _kw; }
- int kh() const { return _kh; }
-};
-
-/**
- * SDL graphics manager
- */
-class SdlGraphicsManager : public GraphicsManager, public Common::EventObserver {
-public:
- SdlGraphicsManager(SdlEventSource *sdlEventSource);
- virtual ~SdlGraphicsManager();
-
- virtual void initEventObserver();
-
- virtual bool hasFeature(OSystem::Feature f);
- virtual void setFeatureState(OSystem::Feature f, bool enable);
- virtual bool getFeatureState(OSystem::Feature f);
-
- static const OSystem::GraphicsMode *supportedGraphicsModes();
- virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- virtual bool setGraphicsMode(int mode);
- virtual int getGraphicsMode() const;
- virtual void resetGraphicsScale();
-#ifdef USE_RGB_COLOR
- virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; }
- virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
-#endif
- virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL);
- virtual int getScreenChangeID() const { return _screenChangeCount; }
-
- virtual void beginGFXTransaction();
- virtual OSystem::TransactionError endGFXTransaction();
-
- virtual int16 getHeight();
- virtual int16 getWidth();
- virtual void setPalette(const byte *colors, uint start, uint num);
- virtual void grabPalette(byte *colors, uint start, uint num);
- virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
- virtual Graphics::Surface *lockScreen();
- virtual void unlockScreen();
- virtual void fillScreen(uint32 col);
- virtual void updateScreen();
- virtual void setShakePos(int shakeOffset);
- virtual void setFocusRectangle(const Common::Rect& rect) {}
- virtual void clearFocusRectangle() {}
-
- virtual void showOverlay();
- virtual void hideOverlay();
- virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; }
- virtual void clearOverlay();
- virtual void grabOverlay(OverlayColor *buf, int pitch);
- virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
- virtual int16 getOverlayHeight() { return _videoMode.overlayHeight; }
- virtual int16 getOverlayWidth() { return _videoMode.overlayWidth; }
-
- virtual bool showMouse(bool visible);
- virtual void warpMouse(int x, int y);
- virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL);
- virtual void setCursorPalette(const byte *colors, uint start, uint num);
- virtual void disableCursorPalette(bool disable);
-
-#ifdef USE_OSD
- virtual void displayMessageOnOSD(const char *msg);
-#endif
-
- // Override from Common::EventObserver
- bool notifyEvent(const Common::Event &event);
-
-protected:
- SdlEventSource *_sdlEventSource;
-
-#ifdef USE_OSD
- /** Surface containing the OSD message */
- SDL_Surface *_osdSurface;
- /** Transparency level of the OSD */
- uint8 _osdAlpha;
- /** When to start the fade out */
- uint32 _osdFadeStartTime;
- /** Enum with OSD options */
- enum {
- kOSDFadeOutDelay = 2 * 1000, /** < Delay before the OSD is faded out (in milliseconds) */
- kOSDFadeOutDuration = 500, /** < Duration of the OSD fade out (in milliseconds) */
- kOSDColorKey = 1, /** < Transparent color key */
- kOSDInitialAlpha = 80 /** < Initial alpha level, in percent */
- };
-#endif
-
- /** Hardware screen */
- SDL_Surface *_hwscreen;
-
- /** Unseen game screen */
- SDL_Surface *_screen;
-#ifdef USE_RGB_COLOR
- Graphics::PixelFormat _screenFormat;
- Graphics::PixelFormat _cursorFormat;
- Common::List<Graphics::PixelFormat> _supportedFormats;
-
- /**
- * Update the list of supported pixel formats.
- * This method is invoked by loadGFXMode().
- */
- void detectSupportedFormats();
-#endif
-
- /** Temporary screen (for scalers) */
- SDL_Surface *_tmpscreen;
- /** Temporary screen (for scalers) */
- SDL_Surface *_tmpscreen2;
-
- SDL_Surface *_overlayscreen;
- bool _overlayVisible;
- Graphics::PixelFormat _overlayFormat;
-
- enum {
- kTransactionNone = 0,
- kTransactionActive = 1,
- kTransactionRollback = 2
- };
-
- struct TransactionDetails {
- bool sizeChanged;
- bool needHotswap;
- bool needUpdatescreen;
- bool normal1xScaler;
-#ifdef USE_RGB_COLOR
- bool formatChanged;
-#endif
- };
- TransactionDetails _transactionDetails;
-
- struct VideoState {
- bool setup;
-
- bool fullscreen;
- bool aspectRatioCorrection;
- AspectRatio desiredAspectRatio;
-
- int mode;
- int scaleFactor;
-
- int screenWidth, screenHeight;
- int overlayWidth, overlayHeight;
- int hardwareWidth, hardwareHeight;
-#ifdef USE_RGB_COLOR
- Graphics::PixelFormat format;
-#endif
- };
- VideoState _videoMode, _oldVideoMode;
-
- /** Force full redraw on next updateScreen */
- bool _forceFull;
-
- ScalerProc *_scalerProc;
- int _scalerType;
- int _transactionMode;
-
- bool _screenIsLocked;
- Graphics::Surface _framebuffer;
-
- int _screenChangeCount;
-
- enum {
- NUM_DIRTY_RECT = 100,
- MAX_SCALING = 3
- };
-
- // Dirty rect management
- SDL_Rect _dirtyRectList[NUM_DIRTY_RECT];
- int _numDirtyRects;
-
- struct MousePos {
- // The mouse position, using either virtual (game) or real
- // (overlay) coordinates.
- int16 x, y;
-
- // The size and hotspot of the original cursor image.
- int16 w, h;
- int16 hotX, hotY;
-
- // The size and hotspot of the pre-scaled cursor image, in real
- // coordinates.
- int16 rW, rH;
- int16 rHotX, rHotY;
-
- // The size and hotspot of the pre-scaled cursor image, in game
- // coordinates.
- int16 vW, vH;
- int16 vHotX, vHotY;
-
- MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0),
- rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0),
- vHotX(0), vHotY(0)
- { }
- };
-
- bool _mouseVisible;
- bool _mouseNeedsRedraw;
- byte *_mouseData;
- SDL_Rect _mouseBackup;
- MousePos _mouseCurState;
-#ifdef USE_RGB_COLOR
- uint32 _mouseKeyColor;
-#else
- byte _mouseKeyColor;
-#endif
- int _cursorTargetScale;
- bool _cursorPaletteDisabled;
- SDL_Surface *_mouseOrigSurface;
- SDL_Surface *_mouseSurface;
- enum {
- kMouseColorKey = 1
- };
-
- // Shake mode
- int _currentShakePos;
- int _newShakePos;
-
- // Palette data
- SDL_Color *_currentPalette;
- uint _paletteDirtyStart, _paletteDirtyEnd;
-
- // Cursor palette data
- SDL_Color *_cursorPalette;
-
- /**
- * Mutex which prevents multiple threads from interfering with each other
- * when accessing the screen.
- */
- OSystem::MutexRef _graphicsMutex;
-
- virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false);
-
- virtual void drawMouse();
- virtual void undrawMouse();
- virtual void blitCursor();
-
- virtual void internUpdateScreen();
-
- virtual bool loadGFXMode();
- virtual void unloadGFXMode();
- virtual bool hotswapGFXMode();
-
- virtual void setFullscreenMode(bool enable);
- virtual void setAspectRatioCorrection(bool enable);
-
- virtual int effectiveScreenHeight() const;
-
- virtual void setGraphicsModeIntern();
-
- virtual bool handleScalerHotkeys(Common::KeyCode key);
- virtual bool isScalerHotkey(const Common::Event &event);
- virtual void adjustMouseEvent(const Common::Event &event);
- virtual void setMousePos(int x, int y);
- virtual void toggleFullScreen();
- virtual bool saveScreenshot(const char *filename);
-};
-
-#endif
diff --git a/backends/graphics/symbiansdl/symbiansdl-graphics.cpp b/backends/graphics/symbiansdl/symbiansdl-graphics.cpp
deleted file mode 100644
index c89c46ddd8..0000000000
--- a/backends/graphics/symbiansdl/symbiansdl-graphics.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef __SYMBIAN32__
-
-#include "backends/graphics/symbiansdl/symbiansdl-graphics.h"
-#include "backends/platform/symbian/src/SymbianActions.h"
-
-int SymbianSdlGraphicsManager::getDefaultGraphicsMode() const {
- return GFX_NORMAL;
-}
-
-static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
- {"1x", "Fullscreen", GFX_NORMAL},
- {0, 0, 0}
-};
-
-const OSystem::GraphicsMode *SymbianSdlGraphicsManager::getSupportedGraphicsModes() const {
- return s_supportedGraphicsModes;
-}
-
-// make sure we always go to normal, even if the string might be set wrong!
-bool SymbianSdlGraphicsManager::setGraphicsMode(int /*name*/) {
- // let parent OSystem_SDL handle it
- return SdlGraphicsManager::setGraphicsMode(getDefaultGraphicsMode());
-}
-
-bool SymbianSdlGraphicsManager::hasFeature(OSystem::Feature f) {
- switch (f) {
- case OSystem::kFeatureFullscreenMode:
- case OSystem::kFeatureAspectRatioCorrection:
- case OSystem::kFeatureCursorHasPalette:
-#ifdef USE_VIBRA_SE_PXXX
- case OSystem::kFeatureVibration:
-#endif
- return true;
- default:
- return false;
- }
-}
-
-void SymbianSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
- switch (f) {
- case OSystem::kFeatureVirtualKeyboard:
- break;
- case OSystem::kFeatureDisableKeyFiltering:
- GUI::Actions::Instance()->beginMapping(enable);
- break;
- default:
- SdlGraphicsManager::setFeatureState(f, enable);
- }
-}
-
-#endif
-
diff --git a/backends/graphics/symbiansdl/symbiansdl-graphics.h b/backends/graphics/symbiansdl/symbiansdl-graphics.h
deleted file mode 100644
index b0e87c8025..0000000000
--- a/backends/graphics/symbiansdl/symbiansdl-graphics.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_SYMBIAN_SDL_H
-#define BACKENDS_GRAPHICS_SYMBIAN_SDL_H
-
-#include "backends/graphics/sdl/sdl-graphics.h"
-
-class SymbianSdlGraphicsManager : public SdlGraphicsManager {
-public:
- virtual bool hasFeature(OSystem::Feature f);
- virtual void setFeatureState(OSystem::Feature f, bool enable);
-
- virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- virtual bool setGraphicsMode(int mode);
-};
-
-#endif
-
diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp
index 4f73d7384b..fd32777a1b 100644
--- a/backends/midi/alsa.cpp
+++ b/backends/midi/alsa.cpp
@@ -22,6 +22,9 @@
* $Id$
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#if defined(USE_ALSA)
diff --git a/backends/midi/camd.cpp b/backends/midi/camd.cpp
index 3486532549..7bf702de58 100644
--- a/backends/midi/camd.cpp
+++ b/backends/midi/camd.cpp
@@ -22,6 +22,9 @@
* $Id$
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#if defined(__amigaos4__)
diff --git a/backends/midi/coreaudio.cpp b/backends/midi/coreaudio.cpp
index aa0ad75f0a..97db5cb292 100644
--- a/backends/midi/coreaudio.cpp
+++ b/backends/midi/coreaudio.cpp
@@ -24,6 +24,9 @@
#ifdef MACOSX
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
// HACK to disable deprecated warnings under Mac OS X 10.5.
// Apple depracted the AUGraphNewNode & AUGraphGetNodeInfo APIs
// in favor of the new AUGraphAddNode & AUGraphNodeInfo APIs.
diff --git a/backends/midi/coremidi.cpp b/backends/midi/coremidi.cpp
index 08f36a8b0f..bca16df61a 100644
--- a/backends/midi/coremidi.cpp
+++ b/backends/midi/coremidi.cpp
@@ -24,6 +24,9 @@
#ifdef MACOSX
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/config-manager.h"
#include "common/util.h"
#include "sound/musicplugin.h"
diff --git a/backends/midi/dmedia.cpp b/backends/midi/dmedia.cpp
index 8c006b2cd9..5e4088fa17 100644
--- a/backends/midi/dmedia.cpp
+++ b/backends/midi/dmedia.cpp
@@ -29,6 +29,9 @@
#if defined(IRIX)
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#include "common/util.h"
#include "common/config-manager.h"
diff --git a/backends/midi/seq.cpp b/backends/midi/seq.cpp
index e3d2c35b39..c0098742d0 100644
--- a/backends/midi/seq.cpp
+++ b/backends/midi/seq.cpp
@@ -28,6 +28,9 @@
* both the QuickTime support and (vkeybd http://www.alsa-project.org/~iwai/alsa.html)
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#if defined(USE_SEQ_MIDI)
diff --git a/backends/midi/stmidi.cpp b/backends/midi/stmidi.cpp
index b00188dfea..01e28aa5ca 100644
--- a/backends/midi/stmidi.cpp
+++ b/backends/midi/stmidi.cpp
@@ -36,6 +36,9 @@
#if defined __MINT__
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include <osbind.h>
#include "sound/mpu401.h"
#include "common/util.h"
diff --git a/backends/midi/timidity.cpp b/backends/midi/timidity.cpp
index 16c1cc43be..d79a83809f 100644
--- a/backends/midi/timidity.cpp
+++ b/backends/midi/timidity.cpp
@@ -34,6 +34,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#if defined(USE_TIMIDITY)
diff --git a/backends/midi/windows.cpp b/backends/midi/windows.cpp
index 31f057df18..81b29219b4 100644
--- a/backends/midi/windows.cpp
+++ b/backends/midi/windows.cpp
@@ -24,6 +24,9 @@
#if defined(WIN32) && !defined(_WIN32_WCE)
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// winnt.h defines ARRAYSIZE, but we want our own one...
diff --git a/backends/mixer/doublebuffersdl/doublebuffersdl-mixer.cpp b/backends/mixer/doublebuffersdl/doublebuffersdl-mixer.cpp
deleted file mode 100644
index 6b0074862e..0000000000
--- a/backends/mixer/doublebuffersdl/doublebuffersdl-mixer.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(MACOSX) || defined(GP2X)
-
-#include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h"
-
-DoubleBufferSDLMixerManager::DoubleBufferSDLMixerManager()
- :
- _soundMutex(0), _soundCond(0), _soundThread(0),
- _soundThreadIsRunning(false), _soundThreadShouldQuit(false) {
-
-}
-
-DoubleBufferSDLMixerManager::~DoubleBufferSDLMixerManager() {
- deinitThreadedMixer();
-}
-
-void DoubleBufferSDLMixerManager::startAudio() {
- _soundThreadIsRunning = false;
- _soundThreadShouldQuit = false;
-
- // Create mutex and condition variable
- _soundMutex = SDL_CreateMutex();
- _soundCond = SDL_CreateCond();
-
- // Create two sound buffers
- _activeSoundBuf = 0;
- uint bufSize = _obtainedRate.samples * 4;
- _soundBufSize = bufSize;
- _soundBuffers[0] = (byte *)calloc(1, bufSize);
- _soundBuffers[1] = (byte *)calloc(1, bufSize);
-
- _soundThreadIsRunning = true;
-
- // Finally start the thread
- _soundThread = SDL_CreateThread(mixerProducerThreadEntry, this);
-
- SdlMixerManager::startAudio();
-}
-
-void DoubleBufferSDLMixerManager::mixerProducerThread() {
- byte nextSoundBuffer;
-
- SDL_LockMutex(_soundMutex);
- while (true) {
- // Wait till we are allowed to produce data
- SDL_CondWait(_soundCond, _soundMutex);
-
- if (_soundThreadShouldQuit)
- break;
-
- // Generate samples and put them into the next buffer
- nextSoundBuffer = _activeSoundBuf ^ 1;
- _mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize);
-
- // Swap buffers
- _activeSoundBuf = nextSoundBuffer;
- }
- SDL_UnlockMutex(_soundMutex);
-}
-
-int SDLCALL DoubleBufferSDLMixerManager::mixerProducerThreadEntry(void *arg) {
- DoubleBufferSDLMixerManager *mixer = (DoubleBufferSDLMixerManager *)arg;
- assert(mixer);
- mixer->mixerProducerThread();
- return 0;
-}
-
-void DoubleBufferSDLMixerManager::deinitThreadedMixer() {
- // Kill thread?? _soundThread
-
- if (_soundThreadIsRunning) {
- // Signal the producer thread to end, and wait for it to actually finish.
- _soundThreadShouldQuit = true;
- SDL_CondBroadcast(_soundCond);
- SDL_WaitThread(_soundThread, NULL);
-
- // Kill the mutex & cond variables.
- // Attention: AT this point, the mixer callback must not be running
- // anymore, else we will crash!
- SDL_DestroyMutex(_soundMutex);
- SDL_DestroyCond(_soundCond);
-
- _soundThreadIsRunning = false;
-
- free(_soundBuffers[0]);
- free(_soundBuffers[1]);
- }
-}
-
-void DoubleBufferSDLMixerManager::callbackHandler(byte *samples, int len) {
- assert(_mixer);
- assert((int)_soundBufSize == len);
-
- // Lock mutex, to ensure our data is not overwritten by the producer thread
- SDL_LockMutex(_soundMutex);
-
- // Copy data from the current sound buffer
- memcpy(samples, _soundBuffers[_activeSoundBuf], len);
-
- // Unlock mutex and wake up the produced thread
- SDL_UnlockMutex(_soundMutex);
- SDL_CondSignal(_soundCond);
-}
-
-#endif
diff --git a/backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h b/backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h
deleted file mode 100644
index 6304c287df..0000000000
--- a/backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_MIXER_DOUBLEBUFFERSDL_H
-#define BACKENDS_MIXER_DOUBLEBUFFERSDL_H
-
-#include "backends/mixer/sdl/sdl-mixer.h"
-
-/**
- * SDL mixer manager with double buffering support.
- */
-class DoubleBufferSDLMixerManager : public SdlMixerManager {
-public:
- DoubleBufferSDLMixerManager();
- virtual ~DoubleBufferSDLMixerManager();
-
-protected:
- SDL_mutex *_soundMutex;
- SDL_cond *_soundCond;
- SDL_Thread *_soundThread;
- bool _soundThreadIsRunning;
- bool _soundThreadShouldQuit;
-
- byte _activeSoundBuf;
- uint _soundBufSize;
- byte *_soundBuffers[2];
-
- /**
- * Handles and swap the sound buffers
- */
- void mixerProducerThread();
-
- /**
- * Finish the mixer manager
- */
- void deinitThreadedMixer();
-
- /**
- * Callback entry point for the sound thread
- */
- static int SDLCALL mixerProducerThreadEntry(void *arg);
-
- virtual void startAudio();
- virtual void callbackHandler(byte *samples, int len);
-};
-
-#endif
diff --git a/backends/mixer/sdl/sdl-mixer.cpp b/backends/mixer/sdl/sdl-mixer.cpp
deleted file mode 100644
index 3c826bfed8..0000000000
--- a/backends/mixer/sdl/sdl-mixer.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(SDL_BACKEND)
-
-#include "backends/mixer/sdl/sdl-mixer.h"
-#include "common/system.h"
-#include "common/config-manager.h"
-
-#ifdef GP2X
-#define SAMPLES_PER_SEC 11025
-#else
-#define SAMPLES_PER_SEC 22050
-#endif
-//#define SAMPLES_PER_SEC 44100
-
-SdlMixerManager::SdlMixerManager()
- :
- _mixer(0),
- _audioSuspended(false) {
-
-}
-
-SdlMixerManager::~SdlMixerManager() {
- _mixer->setReady(false);
-
- SDL_CloseAudio();
-
- delete _mixer;
-}
-
-void SdlMixerManager::init() {
- // Start SDL Audio subsystem
- if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1) {
- error("Could not initialize SDL: %s", SDL_GetError());
- }
-
- // Get the desired audio specs
- SDL_AudioSpec desired = getAudioSpec();
-
- // Start SDL audio with the desired specs
- if (SDL_OpenAudio(&desired, &_obtainedRate) != 0) {
- warning("Could not open audio device: %s", SDL_GetError());
-
- _mixer = new Audio::MixerImpl(g_system, desired.freq);
- assert(_mixer);
- _mixer->setReady(false);
- } else {
- debug(1, "Output sample rate: %d Hz", _obtainedRate.freq);
-
- _mixer = new Audio::MixerImpl(g_system, _obtainedRate.freq);
- assert(_mixer);
- _mixer->setReady(true);
-
- startAudio();
- }
-}
-
-SDL_AudioSpec SdlMixerManager::getAudioSpec() {
- SDL_AudioSpec desired;
-
- // Determine the desired output sampling frequency.
- uint32 samplesPerSec = 0;
- if (ConfMan.hasKey("output_rate"))
- samplesPerSec = ConfMan.getInt("output_rate");
- if (samplesPerSec <= 0)
- samplesPerSec = SAMPLES_PER_SEC;
-
- // Determine the sample buffer size. We want it to store enough data for
- // at least 1/16th of a second (though at most 8192 samples). Note
- // that it must be a power of two. So e.g. at 22050 Hz, we request a
- // sample buffer size of 2048.
- uint32 samples = 8192;
- while (samples * 16 > samplesPerSec * 2)
- samples >>= 1;
-
- memset(&desired, 0, sizeof(desired));
- desired.freq = samplesPerSec;
- desired.format = AUDIO_S16SYS;
- desired.channels = 2;
- desired.samples = (uint16)samples;
- desired.callback = sdlCallback;
- desired.userdata = this;
-
- return desired;
-}
-
-void SdlMixerManager::startAudio() {
- // Start the sound system
- SDL_PauseAudio(0);
-}
-
-void SdlMixerManager::callbackHandler(byte *samples, int len) {
- assert(_mixer);
- _mixer->mixCallback(samples, len);
-}
-
-void SdlMixerManager::sdlCallback(void *this_, byte *samples, int len) {
- SdlMixerManager *manager = (SdlMixerManager *)this_;
- assert(manager);
-
- manager->callbackHandler(samples, len);
-}
-
-void SdlMixerManager::suspendAudio() {
- SDL_CloseAudio();
- _audioSuspended = true;
-}
-
-int SdlMixerManager::resumeAudio() {
- if (!_audioSuspended)
- return -2;
- if (SDL_OpenAudio(&_obtainedRate, NULL) < 0){
- return -1;
- }
- SDL_PauseAudio(0);
- _audioSuspended = false;
- return 0;
-}
-
-#endif
diff --git a/backends/mixer/sdl/sdl-mixer.h b/backends/mixer/sdl/sdl-mixer.h
deleted file mode 100644
index 1b3a3543dc..0000000000
--- a/backends/mixer/sdl/sdl-mixer.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_MIXER_SDL_H
-#define BACKENDS_MIXER_SDL_H
-
-#if defined(__SYMBIAN32__)
-#include <esdl\SDL.h>
-#else
-#include <SDL.h>
-#endif
-
-#include "sound/mixer_intern.h"
-
-/**
- * SDL mixer manager. It wraps the actual implementation
- * of the Audio:Mixer used by the engine, and setups
- * the SDL audio subsystem and the callback for the
- * audio mixer implementation.
- */
-class SdlMixerManager {
-public:
- SdlMixerManager();
- virtual ~SdlMixerManager();
-
- /**
- * Initialize and setups the mixer
- */
- virtual void init();
-
- /**
- * Get the audio mixer implementation
- */
- Audio::Mixer *getMixer() { return (Audio::Mixer *)_mixer; }
-
- // Used by LinuxMoto Port
-
- /**
- * Pauses the audio system
- */
- virtual void suspendAudio();
-
- /**
- * Resumes the audio system
- */
- virtual int resumeAudio();
-
-protected:
- /** The mixer implementation */
- Audio::MixerImpl *_mixer;
-
- /**
- * The obtained audio specification after opening the
- * audio system.
- */
- SDL_AudioSpec _obtainedRate;
-
- /** State of the audio system */
- bool _audioSuspended;
-
- /**
- * Returns the desired audio specification
- */
- virtual SDL_AudioSpec getAudioSpec();
-
- /**
- * Starts SDL audio
- */
- virtual void startAudio();
-
- /**
- * Handles the audio callback
- */
- virtual void callbackHandler(byte *samples, int len);
-
- /**
- * The mixer callback entry point. Static functions can't be overrided
- * by subclasses, so it invokes the non-static function callbackHandler()
- */
- static void sdlCallback(void *this_, byte *samples, int len);
-};
-
-#endif
diff --git a/backends/mixer/symbiansdl/symbiansdl-mixer.cpp b/backends/mixer/symbiansdl/symbiansdl-mixer.cpp
deleted file mode 100644
index 0cbae85cb9..0000000000
--- a/backends/mixer/symbiansdl/symbiansdl-mixer.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef __SYMBIAN32__
-
-#include "backends/mixer/symbiansdl/symbiansdl-mixer.h"
-#include "common/system.h"
-
-#ifdef SAMPLES_PER_SEC_8000 // the GreanSymbianMMP format cannot handle values for defines :(
- #define SAMPLES_PER_SEC 8000
-#else
- #define SAMPLES_PER_SEC 16000
-#endif
-
-SymbianSdlMixerManager::SymbianSdlMixerManager()
- :
- _stereo_mix_buffer(0) {
-
-}
-
-SymbianSdlMixerManager::~SymbianSdlMixerManager() {
- delete[] _stereo_mix_buffer;
-}
-
-void SymbianSdlMixerManager::init() {
- // Start SDL Audio subsystem
- if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1) {
- error("Could not initialize SDL: %s", SDL_GetError());
- }
-
- // Get the desired audio specs
- SDL_AudioSpec desired = getAudioSpec();
-
- // Start SDL audio with the desired specs
- if (SDL_OpenAudio(&desired, &_obtainedRate) != 0) {
- warning("Could not open audio device: %s", SDL_GetError());
-
- _mixer = new Audio::MixerImpl(g_system, desired.freq);
- assert(_mixer);
- _mixer->setReady(false);
- } else {
- debug(1, "Output sample rate: %d Hz", _obtainedRate.freq);
-
- _channels = _obtainedRate.channels;
-
- // Need to create mixbuffer for stereo mix to downmix
- if (_channels != 2) {
- _stereo_mix_buffer = new byte [_obtainedRate.size * 2]; // * 2 for stereo values
- }
-
- _mixer = new Audio::MixerImpl(g_system, _obtainedRate.freq);
- assert(_mixer);
- _mixer->setReady(true);
-
- startAudio();
- }
-}
-
-void SymbianSdlMixerManager::callbackHandler(byte *samples, int len) {
-#if defined (S60) && !defined(S60V3)
- // If not stereo then we need to downmix
- if (_mixer->_channels != 2) {
- _mixer->mixCallback(_stereo_mix_buffer, len * 2);
-
- int16 *bitmixDst = (int16 *)samples;
- int16 *bitmixSrc = (int16 *)_stereo_mix_buffer;
-
- for (int loop = len / 2; loop >= 0; loop --) {
- *bitmixDst = (*bitmixSrc + *(bitmixSrc + 1)) >> 1;
- bitmixDst++;
- bitmixSrc += 2;
- }
- } else
-#else
- _mixer->mixCallback(samples, len);
-#endif
-}
-
-#endif
-
diff --git a/backends/modular-backend.cpp b/backends/modular-backend.cpp
deleted file mode 100644
index 347c5d69a0..0000000000
--- a/backends/modular-backend.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "backends/modular-backend.h"
-#include "gui/message.h"
-
-ModularBackend::ModularBackend()
- :
- _fsFactory(0),
- _eventManager(0),
- _savefileManager(0),
- _timerManager(0),
- _mutexManager(0),
- _graphicsManager(0),
- _mixer(0),
- _audiocdManager(0) {
-
-}
-
-ModularBackend::~ModularBackend() {
- delete _eventManager;
- delete _graphicsManager;
- delete _mixer;
- delete _audiocdManager;
- delete _savefileManager;
- delete _timerManager;
- delete _mutexManager;
-}
-
-bool ModularBackend::hasFeature(Feature f) {
- return _graphicsManager->hasFeature(f);
-}
-
-void ModularBackend::setFeatureState(Feature f, bool enable) {
- return _graphicsManager->setFeatureState(f, enable);
-}
-
-bool ModularBackend::getFeatureState(Feature f) {
- return _graphicsManager->getFeatureState(f);
-}
-
-GraphicsManager *ModularBackend::getGraphicsManager() {
- assert(_graphicsManager);
- return (GraphicsManager *)_graphicsManager;
-}
-
-const OSystem::GraphicsMode *ModularBackend::getSupportedGraphicsModes() const {
- return _graphicsManager->getSupportedGraphicsModes();
-}
-
-int ModularBackend::getDefaultGraphicsMode() const {
- return _graphicsManager->getDefaultGraphicsMode();
-}
-
-bool ModularBackend::setGraphicsMode(int mode) {
- return _graphicsManager->setGraphicsMode(mode);
-}
-
-int ModularBackend::getGraphicsMode() const {
- return _graphicsManager->getGraphicsMode();
-}
-
-void ModularBackend::resetGraphicsScale() {
- _graphicsManager->resetGraphicsScale();
-}
-
-#ifdef USE_RGB_COLOR
-
-Graphics::PixelFormat ModularBackend::getScreenFormat() const {
- return _graphicsManager->getScreenFormat();
-}
-
-Common::List<Graphics::PixelFormat> ModularBackend::getSupportedFormats() const {
- return _graphicsManager->getSupportedFormats();
-}
-
-#endif
-
-void ModularBackend::initSize(uint w, uint h, const Graphics::PixelFormat *format ) {
- _graphicsManager->initSize(w, h, format);
-}
-
-int ModularBackend::getScreenChangeID() const {
- return _graphicsManager->getScreenChangeID();
-}
-
-void ModularBackend::beginGFXTransaction() {
- _graphicsManager->beginGFXTransaction();
-}
-
-OSystem::TransactionError ModularBackend::endGFXTransaction() {
- return _graphicsManager->endGFXTransaction();
-}
-
-int16 ModularBackend::getHeight() {
- return _graphicsManager->getHeight();
-}
-
-int16 ModularBackend::getWidth() {
- return _graphicsManager->getWidth();
-}
-
-void ModularBackend::setPalette(const byte *colors, uint start, uint num) {
- _graphicsManager->setPalette(colors, start, num);
-}
-
-void ModularBackend::grabPalette(byte *colors, uint start, uint num) {
- _graphicsManager->grabPalette(colors, start, num);
-}
-
-void ModularBackend::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
- _graphicsManager->copyRectToScreen(buf, pitch, x, y, w, h);
-}
-
-Graphics::Surface *ModularBackend::lockScreen() {
- return _graphicsManager->lockScreen();
-}
-
-void ModularBackend::unlockScreen() {
- _graphicsManager->unlockScreen();
-}
-
-void ModularBackend::fillScreen(uint32 col) {
- _graphicsManager->fillScreen(col);
-}
-
-void ModularBackend::updateScreen() {
- _graphicsManager->updateScreen();
-}
-
-void ModularBackend::setShakePos(int shakeOffset) {
- _graphicsManager->setShakePos(shakeOffset);
-}
-void ModularBackend::setFocusRectangle(const Common::Rect& rect) {
- _graphicsManager->setFocusRectangle(rect);
-}
-
-void ModularBackend::clearFocusRectangle() {
- _graphicsManager->clearFocusRectangle();
-}
-
-void ModularBackend::showOverlay() {
- _graphicsManager->showOverlay();
-}
-
-void ModularBackend::hideOverlay() {
- _graphicsManager->hideOverlay();
-}
-
-Graphics::PixelFormat ModularBackend::getOverlayFormat() const {
- return _graphicsManager->getOverlayFormat();
-}
-
-void ModularBackend::clearOverlay() {
- _graphicsManager->clearOverlay();
-}
-
-void ModularBackend::grabOverlay(OverlayColor *buf, int pitch) {
- _graphicsManager->grabOverlay(buf, pitch);
-}
-
-void ModularBackend::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
- _graphicsManager->copyRectToOverlay(buf, pitch, x, y, w, h);
-}
-
-int16 ModularBackend::getOverlayHeight() {
- return _graphicsManager->getOverlayHeight();
-}
-
-int16 ModularBackend::getOverlayWidth() {
- return _graphicsManager->getOverlayWidth();
-}
-
-bool ModularBackend::showMouse(bool visible) {
- return _graphicsManager->showMouse(visible);
-}
-
-void ModularBackend::warpMouse(int x, int y) {
- _graphicsManager->warpMouse(x, y);
-}
-
-void ModularBackend::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
- _graphicsManager->setMouseCursor(buf, w, h, hotspotX, hotspotY, keycolor, cursorTargetScale, format);
-}
-
-void ModularBackend::setCursorPalette(const byte *colors, uint start, uint num) {
- _graphicsManager->setCursorPalette(colors, start, num);
-}
-
-void ModularBackend::disableCursorPalette(bool disable) {
- _graphicsManager->disableCursorPalette(disable);
-}
-
-Common::TimerManager *ModularBackend::getTimerManager() {
- assert(_timerManager);
- return _timerManager;
-}
-
-Common::EventManager *ModularBackend::getEventManager() {
- assert(_eventManager);
- return _eventManager;
-}
-
-OSystem::MutexRef ModularBackend::createMutex() {
- assert(_mutexManager);
- return _mutexManager->createMutex();
-}
-
-void ModularBackend::lockMutex(MutexRef mutex) {
- assert(_mutexManager);
- _mutexManager->lockMutex(mutex);
-}
-
-void ModularBackend::unlockMutex(MutexRef mutex) {
- assert(_mutexManager);
- _mutexManager->unlockMutex(mutex);
-}
-
-void ModularBackend::deleteMutex(MutexRef mutex) {
- assert(_mutexManager);
- _mutexManager->deleteMutex(mutex);
-}
-
-Audio::Mixer *ModularBackend::getMixer() {
- assert(_mixer);
- return (Audio::Mixer *)_mixer;
-}
-
-AudioCDManager *ModularBackend::getAudioCDManager() {
- assert(_audiocdManager);
- return _audiocdManager;
-}
-
-void ModularBackend::displayMessageOnOSD(const char *msg) {
-#ifdef USE_OSD
- _graphicsManager->displayMessageOnOSD(msg);
-#else
- GUI::TimedMessageDialog dialog(msg, 1500);
- dialog.runModal();
-#endif
-}
-
-Common::SaveFileManager *ModularBackend::getSavefileManager() {
- assert(_savefileManager);
- return _savefileManager;
-}
-
-FilesystemFactory *ModularBackend::getFilesystemFactory() {
- assert(_fsFactory);
- return _fsFactory;
-}
diff --git a/backends/modular-backend.h b/backends/modular-backend.h
deleted file mode 100644
index 5b031880ed..0000000000
--- a/backends/modular-backend.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_MODULAR_BACKEND_H
-#define BACKENDS_MODULAR_BACKEND_H
-
-#include "common/system.h"
-#include "common/timer.h"
-#include "common/savefile.h"
-#include "backends/events/default/default-events.h"
-#include "backends/audiocd/default/default-audiocd.h"
-#include "backends/mutex/null/null-mutex.h"
-#include "backends/graphics/null/null-graphics.h"
-
-/**
- * Base class for modular backends.
- *
- * It wraps most functions to their manager equivalent, but not
- * all OSystem functions are implemented here.
- *
- * A backend derivated from this class, will need to implement
- * these functions on its own:
- * OSystem::pollEvent()
- * OSystem::createConfigReadStream()
- * OSystem::createConfigWriteStream()
- * OSystem::getMillis()
- * OSystem::delayMillis()
- * OSystem::getTimeAndDate()
- *
- * And, it should also initialize all the managers variables
- * declared in this class, or override their related functions.
- */
-class ModularBackend : public OSystem {
-public:
- ModularBackend();
- virtual ~ModularBackend();
-
- /** @name Features */
- //@{
-
- virtual bool hasFeature(Feature f);
- virtual void setFeatureState(Feature f, bool enable);
- virtual bool getFeatureState(Feature f);
-
- //@}
-
- /** @name Graphics */
- //@{
-
- virtual GraphicsManager *getGraphicsManager();
- virtual const GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- virtual bool setGraphicsMode(int mode);
- virtual int getGraphicsMode() const;
- virtual void resetGraphicsScale();
-#ifdef USE_RGB_COLOR
- virtual Graphics::PixelFormat getScreenFormat() const;
- virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
-#endif
- virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL);
- virtual int getScreenChangeID() const;
-
- virtual void beginGFXTransaction();
- virtual OSystem::TransactionError endGFXTransaction();
-
- virtual int16 getHeight();
- virtual int16 getWidth();
- virtual void setPalette(const byte *colors, uint start, uint num);
- virtual void grabPalette(byte *colors, uint start, uint num);
- virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
- virtual Graphics::Surface *lockScreen();
- virtual void unlockScreen();
- virtual void fillScreen(uint32 col);
- virtual void updateScreen();
- virtual void setShakePos(int shakeOffset);
- virtual void setFocusRectangle(const Common::Rect& rect);
- virtual void clearFocusRectangle();
-
- virtual void showOverlay();
- virtual void hideOverlay();
- virtual Graphics::PixelFormat getOverlayFormat() const;
- virtual void clearOverlay();
- virtual void grabOverlay(OverlayColor *buf, int pitch);
- virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
- virtual int16 getOverlayHeight();
- virtual int16 getOverlayWidth();
-
- virtual bool showMouse(bool visible);
- virtual void warpMouse(int x, int y);
- virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL);
- virtual void setCursorPalette(const byte *colors, uint start, uint num);
- virtual void disableCursorPalette(bool disable);
-
- //@}
-
- /** @name Events and Time */
- //@{
-
- virtual Common::TimerManager *getTimerManager();
- virtual Common::EventManager *getEventManager();
- virtual Common::HardwareKeySet *getHardwareKeySet() { return 0; }
-
- //@}
-
- /** @name Mutex handling */
- //@{
-
- virtual MutexRef createMutex();
- virtual void lockMutex(MutexRef mutex);
- virtual void unlockMutex(MutexRef mutex);
- virtual void deleteMutex(MutexRef mutex);
-
- //@}
-
- /** @name Sound */
- //@{
-
- virtual Audio::Mixer *getMixer();
-
- //@}
-
- /** @name Audio CD */
- //@{
-
- virtual AudioCDManager *getAudioCDManager();
-
- //@}
-
- /** @name Miscellaneous */
- //@{
-
- virtual Common::SaveFileManager *getSavefileManager();
- virtual FilesystemFactory *getFilesystemFactory();
- virtual void quit() { exit(0); }
- virtual void setWindowCaption(const char *caption) {}
- virtual void displayMessageOnOSD(const char *msg);
-
- //@}
-
-protected:
- /** @name Managers variables */
- //@{
-
- FilesystemFactory *_fsFactory;
- Common::EventManager *_eventManager;
- Common::SaveFileManager *_savefileManager;
- Common::TimerManager *_timerManager;
- MutexManager *_mutexManager;
- GraphicsManager *_graphicsManager;
- Audio::Mixer *_mixer;
- AudioCDManager *_audiocdManager;
-
- //@}
-};
-
-#endif
diff --git a/backends/module.mk b/backends/module.mk
index 8cada4d94f..db03e803d8 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -2,32 +2,15 @@ MODULE := backends
MODULE_OBJS := \
base-backend.o \
- modular-backend.o \
audiocd/default/default-audiocd.o \
audiocd/sdl/sdl-audiocd.o \
events/default/default-events.o \
- events/dinguxsdl/dinguxsdl-events.o \
- events/gp2xsdl/gp2xsdl-events.o \
- events/linuxmotosdl/linuxmotosdl-events.o \
- events/samsungtvsdl/samsungtvsdl-events.o \
- events/sdl/sdl-events.o \
- events/symbiansdl/symbiansdl-events.o \
fs/abstract-fs.o \
fs/stdiostream.o \
fs/amigaos4/amigaos4-fs-factory.o \
fs/posix/posix-fs-factory.o \
fs/symbian/symbian-fs-factory.o \
fs/windows/windows-fs-factory.o \
- graphics/dinguxsdl/dinguxsdl-graphics.o \
- graphics/gp2xsdl/gp2xsdl-graphics.o \
- graphics/gp2xwizsdl/gp2xwizsdl-graphics.o \
- graphics/linuxmotosdl/linuxmotosdl-graphics.o \
- graphics/opengl/glerrorcheck.o \
- graphics/opengl/gltexture.o \
- graphics/opengl/opengl-graphics.o \
- graphics/openglsdl/openglsdl-graphics.o \
- graphics/sdl/sdl-graphics.o \
- graphics/symbiansdl/symbiansdl-graphics.o \
keymapper/action.o \
keymapper/keymap.o \
keymapper/keymapper.o \
@@ -41,10 +24,13 @@ MODULE_OBJS := \
midi/timidity.o \
midi/dmedia.o \
midi/windows.o \
- mixer/doublebuffersdl/doublebuffersdl-mixer.o \
- mixer/sdl/sdl-mixer.o \
- mixer/symbiansdl/symbiansdl-mixer.o \
- mutex/sdl/sdl-mutex.o \
+ plugins/elf/elf-loader.o \
+ plugins/elf/mips-loader.o \
+ plugins/elf/shorts-segment-manager.o \
+ plugins/elf/ppc-loader.o \
+ plugins/elf/arm-loader.o \
+ plugins/elf/elf-provider.o \
+ plugins/elf/version.o \
plugins/posix/posix-provider.o \
plugins/sdl/sdl-provider.o \
plugins/win32/win32-provider.o \
@@ -52,7 +38,6 @@ MODULE_OBJS := \
saves/default/default-saves.o \
saves/posix/posix-saves.o \
timer/default/default-timer.o \
- timer/sdl/sdl-timer.o \
vkeybd/image-map.o \
vkeybd/polygon.o \
vkeybd/virtual-keyboard.o \
@@ -67,7 +52,8 @@ endif
ifeq ($(BACKEND),ds)
MODULE_OBJS += \
fs/ds/ds-fs-factory.o \
- fs/ds/ds-fs.o
+ fs/ds/ds-fs.o \
+ plugins/ds/ds-provider.o
endif
ifeq ($(BACKEND),n64)
@@ -78,7 +64,8 @@ endif
ifeq ($(BACKEND),ps2)
MODULE_OBJS += \
- fs/ps2/ps2-fs-factory.o
+ fs/ps2/ps2-fs-factory.o \
+ plugins/ps2/ps2-provider.o
endif
ifeq ($(BACKEND),psp)
@@ -92,7 +79,8 @@ endif
ifeq ($(BACKEND),wii)
MODULE_OBJS += \
- fs/wii/wii-fs-factory.o
+ fs/wii/wii-fs-factory.o \
+ plugins/wii/wii-provider.o
endif
# Include common rules
diff --git a/backends/mutex/mutex.h b/backends/mutex/mutex.h
deleted file mode 100644
index ddf27d5932..0000000000
--- a/backends/mutex/mutex.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_MUTEX_ABSTRACT_H
-#define BACKENDS_MUTEX_ABSTRACT_H
-
-#include "common/system.h"
-#include "common/noncopyable.h"
-
-/**
- * Abstract class for mutex manager. Subclasses
- * implement the real functionality.
- */
-class MutexManager : Common::NonCopyable {
-public:
- virtual ~MutexManager() {}
-
- virtual OSystem::MutexRef createMutex() = 0;
- virtual void lockMutex(OSystem::MutexRef mutex) = 0;
- virtual void unlockMutex(OSystem::MutexRef mutex) = 0;
- virtual void deleteMutex(OSystem::MutexRef mutex) = 0;
-};
-
-#endif
diff --git a/backends/mutex/null/null-mutex.h b/backends/mutex/null/null-mutex.h
deleted file mode 100644
index 54b8f5ce96..0000000000
--- a/backends/mutex/null/null-mutex.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_MUTEX_NULL_H
-#define BACKENDS_MUTEX_NULL_H
-
-#include "backends/mutex/mutex.h"
-
-/**
- * Null mutex manager
- */
-class NullMutexManager : MutexManager {
-public:
- virtual OSystem::MutexRef createMutex() { return OSystem::MutexRef(); }
- virtual void lockMutex(OSystem::MutexRef mutex) {}
- virtual void unlockMutex(OSystem::MutexRef mutex) {}
- virtual void deleteMutex(OSystem::MutexRef mutex) {}
-};
-
-#endif
diff --git a/backends/mutex/sdl/sdl-mutex.cpp b/backends/mutex/sdl/sdl-mutex.cpp
deleted file mode 100644
index 737126057c..0000000000
--- a/backends/mutex/sdl/sdl-mutex.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(SDL_BACKEND)
-
-#include "backends/mutex/sdl/sdl-mutex.h"
-
-#if defined(__SYMBIAN32__)
-#include <esdl\SDL.h>
-#else
-#include <SDL.h>
-#endif
-
-OSystem::MutexRef SdlMutexManager::createMutex() {
- return (OSystem::MutexRef) SDL_CreateMutex();
-}
-
-void SdlMutexManager::lockMutex(OSystem::MutexRef mutex) {
- SDL_mutexP((SDL_mutex *) mutex);
-}
-
-void SdlMutexManager::unlockMutex(OSystem::MutexRef mutex) {
- SDL_mutexV((SDL_mutex *) mutex);
-}
-
-void SdlMutexManager::deleteMutex(OSystem::MutexRef mutex) {
- SDL_DestroyMutex((SDL_mutex *) mutex);
-}
-
-#endif
diff --git a/backends/platform/android/README.build b/backends/platform/android/README.build
index 1c407bd469..f3fb77cbcf 100644
--- a/backends/platform/android/README.build
+++ b/backends/platform/android/README.build
@@ -82,7 +82,8 @@ Then build ScummVM:
export ANDROID_TOP=<root of built Android source>
- ./configure --backend=android --host=android --enable-zlib #and any other flags
+ ./configure --backend=android --host=android --enable-zlib --disable-timidity
+ # ... and any other configure flags you want
make scummvm.apk
This will build a "monolithic" ScummVM package, with the engines
diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index dcc4e37458..38f387b201 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -109,7 +109,7 @@ static void JNU_ThrowByName(JNIEnv* env, const char* name, const char* msg) {
env->DeleteLocalRef(cls);
}
-// floating point. use sparingly.
+// floating point. use sparingly.
template <class T>
static inline T scalef(T in, float numerator, float denominator) {
return static_cast<float>(in) * numerator / denominator;
@@ -177,7 +177,6 @@ private:
GLESPaletteTexture* _game_texture;
int _shake_offset;
Common::Rect _focus_rect;
- bool _full_screen_dirty;
// Overlay layer
GLES4444Texture* _overlay_texture;
@@ -320,7 +319,6 @@ OSystem_Android::OSystem_Android(jobject am)
_fsFactory(new POSIXFilesystemFactory()),
_asset_archive(new AndroidAssetArchive(am)),
_shake_offset(0),
- _full_screen_dirty(false),
_event_queue_lock(createMutex()) {
}
@@ -862,6 +860,9 @@ void OSystem_Android::hideOverlay() {
void OSystem_Android::clearOverlay() {
ENTER("clearOverlay()");
_overlay_texture->fillBuffer(0);
+
+ // Shouldn't need this, but works around a 'blank screen' bug on Nexus1
+ updateScreen();
}
void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) {
@@ -887,6 +888,9 @@ void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch,
// This 'pitch' is pixels not bytes
_overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0]));
+
+ // Shouldn't need this, but works around a 'blank screen' bug on Nexus1?
+ updateScreen();
}
int16 OSystem_Android::getOverlayHeight() {
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
index d39aa363ef..6986f3988d 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
@@ -23,6 +23,8 @@ import javax.microedition.khronos.egl.EGLSurface;
import java.io.File;
import java.util.concurrent.Semaphore;
+import java.util.Map;
+import java.util.LinkedHashMap;
// At least in Android 2.1, eglCreateWindowSurface() requires an
@@ -109,6 +111,51 @@ public class ScummVM implements SurfaceHolder.Callback {
}
}
+ // For debugging
+ private static final Map<String, Integer> attribs;
+ static {
+ attribs = new LinkedHashMap<String, Integer>();
+ attribs.put("CONFIG_ID", EGL10.EGL_CONFIG_ID);
+ attribs.put("BUFFER_SIZE", EGL10.EGL_BUFFER_SIZE);
+ attribs.put("RED_SIZE", EGL10.EGL_RED_SIZE);
+ attribs.put("GREEN_SIZE", EGL10.EGL_GREEN_SIZE);
+ attribs.put("BLUE_SIZE", EGL10.EGL_BLUE_SIZE);
+ attribs.put("ALPHA_SIZE", EGL10.EGL_ALPHA_SIZE);
+ //attribs.put("BIND_TO_RGB", EGL10.EGL_BIND_TO_TEXTURE_RGB);
+ //attribs.put("BIND_TO_RGBA", EGL10.EGL_BIND_TO_TEXTURE_RGBA);
+ attribs.put("CONFIG_CAVEAT", EGL10.EGL_CONFIG_CAVEAT);
+ attribs.put("DEPTH_SIZE", EGL10.EGL_DEPTH_SIZE);
+ attribs.put("LEVEL", EGL10.EGL_LEVEL);
+ attribs.put("MAX_PBUFFER_WIDTH", EGL10.EGL_MAX_PBUFFER_WIDTH);
+ attribs.put("MAX_PBUFFER_HEIGHT", EGL10.EGL_MAX_PBUFFER_HEIGHT);
+ attribs.put("MAX_PBUFFER_PIXELS", EGL10.EGL_MAX_PBUFFER_PIXELS);
+ //attribs.put("MAX_SWAP_INTERVAL", EGL10.EGL_MAX_SWAP_INTERVAL);
+ //attribs.put("MIN_SWAP_INTERVAL", EGL10.EGL_MIN_SWAP_INTERVAL);
+ attribs.put("NATIVE_RENDERABLE", EGL10.EGL_NATIVE_RENDERABLE);
+ attribs.put("NATIVE_VISUAL_ID", EGL10.EGL_NATIVE_VISUAL_ID);
+ attribs.put("NATIVE_VISUAL_TYPE", EGL10.EGL_NATIVE_VISUAL_TYPE);
+ attribs.put("SAMPLE_BUFFERS", EGL10.EGL_SAMPLE_BUFFERS);
+ attribs.put("SAMPLES", EGL10.EGL_SAMPLES);
+ attribs.put("STENCIL_SIZE", EGL10.EGL_STENCIL_SIZE);
+ attribs.put("SURFACE_TYPE", EGL10.EGL_SURFACE_TYPE);
+ attribs.put("TRANSPARENT_TYPE", EGL10.EGL_TRANSPARENT_TYPE);
+ attribs.put("TRANSPARENT_RED_VALUE", EGL10.EGL_TRANSPARENT_RED_VALUE);
+ attribs.put("TRANSPARENT_GREEN_VALUE", EGL10.EGL_TRANSPARENT_GREEN_VALUE);
+ attribs.put("TRANSPARENT_BLUE_VALUE", EGL10.EGL_TRANSPARENT_BLUE_VALUE);
+ }
+ private void dumpEglConfig(EGLConfig config) {
+ int[] value = new int[1];
+ for (Map.Entry<String, Integer> entry : attribs.entrySet()) {
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ entry.getValue(), value);
+ if (value[0] == EGL10.EGL_NONE)
+ Log.d(LOG_TAG, entry.getKey() + ": NONE");
+ else
+ Log.d(LOG_TAG, String.format("%s: %d",
+ entry.getKey(), value[0]));
+ }
+ }
+
// Called by ScummVM thread (from initBackend)
private void createScummVMGLContext() {
egl = (EGL10)EGLContext.getEGL();
@@ -125,10 +172,75 @@ public class ScummVM implements SurfaceHolder.Callback {
EGLConfig[] configs = new EGLConfig[numConfigs];
egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs,
num_config);
- eglConfig = configs[0];
+
+ if (false) {
+ Log.d(LOG_TAG,
+ String.format("Found %d EGL configurations.", numConfigs));
+ for (EGLConfig config : configs)
+ dumpEglConfig(config);
+ }
+
+ // Android's eglChooseConfig is busted in several versions and
+ // devices so we have to filter/rank the configs again ourselves.
+ eglConfig = chooseEglConfig(configs);
+ if (false) {
+ Log.d(LOG_TAG,
+ String.format("Chose EGL config from %d possibilities.", numConfigs));
+ dumpEglConfig(eglConfig);
+ }
eglContext = egl.eglCreateContext(eglDisplay, eglConfig,
EGL10.EGL_NO_CONTEXT, null);
+ if (eglContext == EGL10.EGL_NO_CONTEXT)
+ throw new RuntimeException("Failed to create context");
+ }
+
+ private EGLConfig chooseEglConfig(EGLConfig[] configs) {
+ int best = 0;
+ int bestScore = -1;
+ int[] value = new int[1];
+ for (int i = 0; i < configs.length; i++) {
+ EGLConfig config = configs[i];
+ int score = 10000;
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ EGL10.EGL_SURFACE_TYPE, value);
+ if ((value[0] & EGL10.EGL_WINDOW_BIT) == 0)
+ continue; // must have
+
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ EGL10.EGL_CONFIG_CAVEAT, value);
+ if (value[0] != EGL10.EGL_NONE)
+ score -= 1000;
+
+ // Must be at least 555, but then smaller is better
+ final int[] colorBits = {EGL10.EGL_RED_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_ALPHA_SIZE};
+ for (int component : colorBits) {
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ component, value);
+ if (value[0] >= 5)
+ score += 10; // boost if >5 bits accuracy
+ score -= value[0]; // penalize for wasted bits
+ }
+
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ EGL10.EGL_DEPTH_SIZE, value);
+ score -= value[0]; // penalize for wasted bits
+
+ if (score > bestScore) {
+ best = i;
+ bestScore = score;
+ }
+ }
+
+ if (bestScore < 0) {
+ Log.e(LOG_TAG, "Unable to find an acceptable EGL config, expect badness.");
+ return configs[0];
+ }
+
+ return configs[best];
}
// Called by ScummVM thread
@@ -137,12 +249,13 @@ public class ScummVM implements SurfaceHolder.Callback {
try {
surfaceLock.acquire();
} catch (InterruptedException e) {
- Log.e(this.toString(),
- "Interrupted while waiting for surface lock", e);
+ Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e);
return;
}
eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig,
nativeSurface, null);
+ if (eglSurface == EGL10.EGL_NO_SURFACE)
+ Log.e(LOG_TAG, "CreateWindowSurface failed!");
egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
GL10 gl = (GL10)eglContext.getGL();
@@ -302,8 +415,8 @@ public class ScummVM implements SurfaceHolder.Callback {
if (buf_size < 0) {
int guess = AUDIO_FRAME_SIZE * sample_rate / 100; // 10ms of audio
Log.w(LOG_TAG, String.format(
- "Unable to get min audio buffer size (error %d). Guessing %dB.",
- buf_size, guess));
+ "Unable to get min audio buffer size (error %d). Guessing %dB.",
+ buf_size, guess));
buf_size = guess;
}
Log.d(LOG_TAG, String.format("Using %dB buffer for %dHZ audio",
diff --git a/backends/platform/android/video.cpp b/backends/platform/android/video.cpp
index d4c002fbd0..81a8f7fbc7 100644
--- a/backends/platform/android/video.cpp
+++ b/backends/platform/android/video.cpp
@@ -38,6 +38,9 @@
#include "backends/platform/android/video.h"
+// Unfortunately, Android devices are too varied to make broad assumptions :/
+#define TEXSUBIMAGE_IS_EXPENSIVE 0
+
#undef LOG_TAG
#define LOG_TAG "ScummVM-video"
@@ -158,13 +161,11 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {
// later (perhaps with multiple TexSubImage2D operations).
CHECK_GL_ERROR();
glBindTexture(GL_TEXTURE_2D, _texture_name);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
CHECK_GL_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- CHECK_GL_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- CHECK_GL_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- CHECK_GL_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
CHECK_GL_ERROR();
glTexImage2D(GL_TEXTURE_2D, 0, glFormat(),
@@ -177,6 +178,7 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
const void* buf, int pitch) {
ENTER("updateBuffer(%u, %u, %u, %u, %p, %d)", x, y, w, h, buf, pitch);
glBindTexture(GL_TEXTURE_2D, _texture_name);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
setDirtyRect(Common::Rect(x, y, x+w, y+h));
@@ -185,7 +187,25 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
glFormat(), glType(), buf);
} else {
// GLES removed the ability to specify pitch, so we
- // have to do this row by row.
+ // have to do this ourselves.
+ if (h == 0)
+ return;
+
+#if TEXSUBIMAGE_IS_EXPENSIVE
+ byte tmpbuf[w * h * bytesPerPixel()];
+ const byte* src = static_cast<const byte*>(buf);
+ byte* dst = tmpbuf;
+ GLuint count = h;
+ do {
+ memcpy(dst, src, w * bytesPerPixel());
+ dst += w * bytesPerPixel();
+ src += pitch;
+ } while (--count);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,
+ glFormat(), glType(), tmpbuf);
+#else
+ // This version avoids the intermediate copy at the expense of
+ // repeat glTexSubImage2D calls. On some devices this is worse.
const byte* src = static_cast<const byte*>(buf);
do {
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y,
@@ -193,16 +213,15 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
++y;
src += pitch;
} while (--h);
+#endif
}
}
void GLESTexture::fillBuffer(byte x) {
- byte tmpbuf[_surface.h * _surface.w * bytesPerPixel()];
- memset(tmpbuf, 0, _surface.h * _surface.w * bytesPerPixel());
- glBindTexture(GL_TEXTURE_2D, _texture_name);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _surface.w, _surface.h,
- glFormat(), glType(), tmpbuf);
- setDirty();
+ int rowbytes = _surface.w * bytesPerPixel();
+ byte tmpbuf[_surface.h * rowbytes];
+ memset(tmpbuf, x, _surface.h * rowbytes);
+ updateBuffer(0, 0, _surface.w, _surface.h, tmpbuf, rowbytes);
}
void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
@@ -215,6 +234,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
//glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const GLint crop[4] = {0, _surface.h, _surface.w, -_surface.h};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glColor4ub(0xff, 0xff, 0xff, 0xff); // Android GLES bug?
glDrawTexiOES(x, y, 0, w, h);
} else
#endif
diff --git a/backends/events/dinguxsdl/dinguxsdl-events.cpp b/backends/platform/dingux/dingux-events.cpp
index 1eed96acfe..f9b519623d 100644
--- a/backends/events/dinguxsdl/dinguxsdl-events.cpp
+++ b/backends/platform/dingux/dingux-events.cpp
@@ -23,10 +23,11 @@
*
*/
-#if defined(DINGUX)
+#include "backends/platform/dingux/dingux.h"
-#include "backends/events/dinguxsdl/dinguxsdl-events.h"
-#include "graphics/scaler/aspect.h" // for aspect2Real
+#include "graphics/scaler/aspect.h" // for aspect2Real
+
+#if defined (DINGUX)
#define PAD_UP SDLK_UP
#define PAD_DOWN SDLK_DOWN
@@ -58,11 +59,7 @@ static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) {
return key;
}
-DINGUXSdlEventSource::DINGUXSdlEventSource() : SdlEventSource() {
- ;
-}
-
-bool DINGUXSdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL_Dingux::remapKey(SDL_Event &ev, Common::Event &event) {
if (ev.key.keysym.sym == PAD_UP) {
if (ev.type == SDL_KEYDOWN) {
_km.y_vel = -1;
@@ -182,8 +179,8 @@ bool DINGUXSdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
return false;
}
-void DINGUXSdlEventSource::fillMouseEvent(Common::Event &event, int x, int y) {
- if (_grpMan->getVideoMode()->mode == GFX_HALF && !(_grpMan->isOverlayVisible())) {
+void OSystem_SDL_Dingux::fillMouseEvent(Common::Event &event, int x, int y) {
+ if (_videoMode.mode == GFX_HALF && !_overlayVisible) {
event.mouse.x = x * 2;
event.mouse.y = y * 2;
} else {
@@ -196,31 +193,23 @@ void DINGUXSdlEventSource::fillMouseEvent(Common::Event &event, int x, int y) {
_km.y = y;
// Adjust for the screen scaling
- if (!(_grpMan->isOverlayVisible())) {
- event.mouse.x /= (_grpMan->getVideoMode())->scaleFactor;
- event.mouse.y /= (_grpMan->getVideoMode())->scaleFactor;
-#if 0
- if (_grpMan->getVideoMode()->aspectRatioCorrection)
+ if (!_overlayVisible) {
+ event.mouse.x /= _videoMode.scaleFactor;
+ event.mouse.y /= _videoMode.scaleFactor;
+ if (_videoMode.aspectRatioCorrection)
event.mouse.y = aspect2Real(event.mouse.y);
-#endif
}
}
-void DINGUXSdlEventSource::warpMouse(int x, int y) {
- int mouse_cur_x = _grpMan->getMouseCurState()->x;
- int mouse_cur_y = _grpMan->getMouseCurState()->y;
-
- if ((mouse_cur_x != x) || (mouse_cur_y != y)) {
- if (_grpMan->getVideoMode()->mode == GFX_HALF && !(_grpMan->isOverlayVisible())) {
+void OSystem_SDL_Dingux::warpMouse(int x, int y) {
+ if (_mouseCurState.x != x || _mouseCurState.y != y) {
+ if (_videoMode.mode == GFX_HALF && !_overlayVisible) {
x = x / 2;
y = y / 2;
}
}
- SDL_WarpMouse(x, y);
+ OSystem_SDL::warpMouse(x, y);
}
-void DINGUXSdlEventSource::setCurrentGraphMan(DINGUXSdlGraphicsManager *_graphicManager) {
- _grpMan = _graphicManager;
-}
+#endif
-#endif /* DINGUX */
diff --git a/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp b/backends/platform/dingux/dingux-graphics.cpp
index c38d53e86b..bbd4a58636 100644
--- a/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp
+++ b/backends/platform/dingux/dingux-graphics.cpp
@@ -23,30 +23,30 @@
*
*/
-#if defined (DINGUX)
+#include "backends/platform/dingux/dingux.h"
-#include "backends/graphics/dinguxsdl/dinguxsdl-graphics.h"
-#include "backends/events/dinguxsdl/dinguxsdl-events.h"
+#include "common/mutex.h"
+#include "graphics/scaler.h"
#include "graphics/scaler/aspect.h"
+#include "graphics/scaler/downscaler.h"
+#include "graphics/surface.h"
+
+#if defined (DINGUX)
static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
{"1x", "Standard", GFX_NORMAL},
{0, 0, 0}
};
-DINGUXSdlGraphicsManager::DINGUXSdlGraphicsManager(SdlEventSource *boss) : SdlGraphicsManager(boss) {
- _evSrc = boss;
+int OSystem_SDL_Dingux::getDefaultGraphicsMode() const {
+ return GFX_NORMAL;
}
-const OSystem::GraphicsMode *DINGUXSdlGraphicsManager::getSupportedGraphicsModes() const {
+const OSystem::GraphicsMode *OSystem_SDL_Dingux::getSupportedGraphicsModes() const {
return s_supportedGraphicsModes;
}
-int DINGUXSdlGraphicsManager::getDefaultGraphicsMode() const {
- return GFX_NORMAL;
-}
-
-bool DINGUXSdlGraphicsManager::setGraphicsMode(int mode) {
+bool OSystem_SDL_Dingux::setGraphicsMode(int mode) {
Common::StackLock lock(_graphicsMutex);
assert(_transactionMode == kTransactionActive);
@@ -80,7 +80,7 @@ bool DINGUXSdlGraphicsManager::setGraphicsMode(int mode) {
return true;
}
-void DINGUXSdlGraphicsManager::setGraphicsModeIntern() {
+void OSystem_SDL_Dingux::setGraphicsModeIntern() {
Common::StackLock lock(_graphicsMutex);
ScalerProc *newScalerProc = 0;
@@ -109,7 +109,7 @@ void DINGUXSdlGraphicsManager::setGraphicsModeIntern() {
blitCursor();
}
-void DINGUXSdlGraphicsManager::initSize(uint w, uint h) {
+void OSystem_SDL_Dingux::initSize(uint w, uint h) {
assert(_transactionMode == kTransactionActive);
// Avoid redundant res changes
@@ -121,13 +121,13 @@ void DINGUXSdlGraphicsManager::initSize(uint w, uint h) {
if (w > 320 || h > 240) {
setGraphicsMode(GFX_HALF);
setGraphicsModeIntern();
- _evSrc->toggleMouseGrab();
+ toggleMouseGrab();
}
_transactionDetails.sizeChanged = true;
}
-void DINGUXSdlGraphicsManager::drawMouse() {
+void OSystem_SDL_Dingux::drawMouse() {
if (!_mouseVisible || !_mouseSurface) {
_mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
return;
@@ -193,7 +193,7 @@ void DINGUXSdlGraphicsManager::drawMouse() {
addDirtyRect(dst.x, dst.y, dst.w, dst.h, true);
}
-void DINGUXSdlGraphicsManager::undrawMouse() {
+void OSystem_SDL_Dingux::undrawMouse() {
const int x = _mouseBackup.x;
const int y = _mouseBackup.y;
@@ -211,7 +211,7 @@ void DINGUXSdlGraphicsManager::undrawMouse() {
}
}
-void DINGUXSdlGraphicsManager::internUpdateScreen() {
+void OSystem_SDL_Dingux::internUpdateScreen() {
SDL_Surface *srcSurf, *origSurf;
int height, width;
ScalerProc *scalerProc;
@@ -409,23 +409,23 @@ void DINGUXSdlGraphicsManager::internUpdateScreen() {
_mouseNeedsRedraw = false;
}
-void DINGUXSdlGraphicsManager::showOverlay() {
+void OSystem_SDL_Dingux::showOverlay() {
if (_videoMode.mode == GFX_HALF) {
_mouseCurState.x = _mouseCurState.x / 2;
_mouseCurState.y = _mouseCurState.y / 2;
}
- SdlGraphicsManager::showOverlay();
+ OSystem_SDL::showOverlay();
}
-void DINGUXSdlGraphicsManager::hideOverlay() {
+void OSystem_SDL_Dingux::hideOverlay() {
if (_videoMode.mode == GFX_HALF) {
_mouseCurState.x = _mouseCurState.x * 2;
_mouseCurState.y = _mouseCurState.y * 2;
}
- SdlGraphicsManager::hideOverlay();
+ OSystem_SDL::hideOverlay();
}
-bool DINGUXSdlGraphicsManager::loadGFXMode() {
+bool OSystem_SDL_Dingux::loadGFXMode() {
// Forcefully disable aspect ratio correction for games
// which starts with a native 240px height resolution.
@@ -461,46 +461,8 @@ bool DINGUXSdlGraphicsManager::loadGFXMode() {
}
- return SdlGraphicsManager::loadGFXMode();
-}
-
-bool DINGUXSdlGraphicsManager::hasFeature(OSystem::Feature f) {
- return
- (f == OSystem::kFeatureAspectRatioCorrection) ||
- (f == OSystem::kFeatureCursorHasPalette);
-}
-
-void DINGUXSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
- switch (f) {
- case OSystem::kFeatureAspectRatioCorrection:
- setAspectRatioCorrection(enable);
- break;
- default:
- break;
- }
-}
-
-bool DINGUXSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
- assert(_transactionMode == kTransactionNone);
-
- switch (f) {
- case OSystem::kFeatureAspectRatioCorrection:
- return _videoMode.aspectRatioCorrection;
- default:
- return false;
- }
-}
-
-SdlGraphicsManager::MousePos* DINGUXSdlGraphicsManager::getMouseCurState() {
- return &_mouseCurState;
-}
-
-SdlGraphicsManager::VideoState* DINGUXSdlGraphicsManager::getVideoMode() {
- return &_videoMode;
-}
-
-bool DINGUXSdlGraphicsManager::isOverlayVisible() {
- return _overlayVisible;
+ return OSystem_SDL::loadGFXMode();
}
#endif
+
diff --git a/backends/platform/dingux/dingux.cpp b/backends/platform/dingux/dingux.cpp
index 98bf51f49c..cdf10600ce 100644
--- a/backends/platform/dingux/dingux.cpp
+++ b/backends/platform/dingux/dingux.cpp
@@ -23,25 +23,35 @@
*
*/
+#include "backends/platform/dingux/dingux.h"
+
#if defined(DINGUX)
-#include "backends/platform/dingux/dingux.h"
-#include "backends/events/dinguxsdl/dinguxsdl-events.h"
-#include "backends/graphics/dinguxsdl/dinguxsdl-graphics.h"
-
-void OSystem_SDL_Dingux::initBackend() {
- // Create the events manager
- if (_eventSource == 0)
- _eventSource = new DINGUXSdlEventSource();
-
- // Create the graphics manager
- if (_graphicsManager == 0) {
- _graphicsManager = new DINGUXSdlGraphicsManager(_eventSource);
- ((DINGUXSdlEventSource*)_eventSource)->setCurrentGraphMan((DINGUXSdlGraphicsManager*)_graphicsManager);
+bool OSystem_SDL_Dingux::hasFeature(Feature f) {
+ return
+ (f == kFeatureAspectRatioCorrection) ||
+ (f == kFeatureCursorHasPalette);
+}
+
+void OSystem_SDL_Dingux::setFeatureState(Feature f, bool enable) {
+ switch (f) {
+ case kFeatureAspectRatioCorrection:
+ setAspectRatioCorrection(enable);
+ break;
+ default:
+ break;
}
+}
- // Call parent implementation of this method
- OSystem_POSIX::initBackend();
+bool OSystem_SDL_Dingux::getFeatureState(Feature f) {
+ assert(_transactionMode == kTransactionNone);
+
+ switch (f) {
+ case kFeatureAspectRatioCorrection:
+ return _videoMode.aspectRatioCorrection;
+ default:
+ return false;
+ }
}
#endif
diff --git a/backends/platform/dingux/dingux.h b/backends/platform/dingux/dingux.h
index 80b2ecae5f..846ad3faf9 100644
--- a/backends/platform/dingux/dingux.h
+++ b/backends/platform/dingux/dingux.h
@@ -26,21 +26,44 @@
#ifndef SDL_DINGUX_COMMON_H
#define SDL_DINGUX_COMMON_H
-#if defined(DINGUX)
-
#include <SDL.h>
+
#include "backends/base-backend.h"
#include "backends/platform/sdl/sdl.h"
-#include "backends/platform/sdl/posix/posix.h"
-#include "backends/graphics/dinguxsdl/dinguxsdl-graphics.h"
-#include "backends/events/dinguxsdl/dinguxsdl-events.h"
-class OSystem_SDL_Dingux : public OSystem_POSIX {
+#if defined(DINGUX)
+
+enum {
+ GFX_HALF = 12
+};
+
+class OSystem_SDL_Dingux : public OSystem_SDL {
public:
- void initBackend();
+ virtual bool hasFeature(Feature f);
+ virtual void setFeatureState(Feature f, bool enable);
+ virtual bool getFeatureState(Feature f);
+ virtual int getDefaultGraphicsMode() const;
+
+ void initSize(uint w, uint h);
+ const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
+ bool setGraphicsMode(const char *name);
+ bool setGraphicsMode(int mode);
+ void setGraphicsModeIntern();
+ void internUpdateScreen();
+ void showOverlay();
+ void hideOverlay();
+ bool loadGFXMode();
+ void drawMouse();
+ void undrawMouse();
+ void warpMouse(int, int);
+ void fillMouseEvent(Common::Event&, int, int);
+
+protected:
+ virtual bool remapKey(SDL_Event &ev, Common::Event &event);
};
-#endif /* DINGUX */
-#endif /* SDL_DINGUX_COMMON_H */
+#endif
+
+#endif
diff --git a/backends/platform/dingux/main.cpp b/backends/platform/dingux/main.cpp
index 587c65334e..7b02151c1a 100644
--- a/backends/platform/dingux/main.cpp
+++ b/backends/platform/dingux/main.cpp
@@ -24,7 +24,8 @@
*/
#include "backends/platform/dingux/dingux.h"
-#include "backends/plugins/posix/posix-provider.h"
+#include "backends/plugins/sdl/sdl-provider.h"
+//#include "backends/plugins/posix/posix-provider.h"
#include "base/main.h"
#if defined(DINGUX)
@@ -36,17 +37,16 @@ int main(int argc, char* argv[]) {
g_system = new OSystem_SDL_Dingux();
assert(g_system);
- ((OSystem_SDL_Dingux *)g_system)->init();
-
#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new POSIXPluginProvider());
+ PluginManager::instance().addPluginProvider(new SDLPluginProvider());
+// PluginManager::instance().addPluginProvider(new POSIXPluginProvider());
#endif
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
- ((OSystem_SDL_Dingux *)g_system)->deinit();
-
+ ((OSystem_SDL *)g_system)->deinit();
return res;
+
}
#endif
diff --git a/backends/platform/dingux/module.mk b/backends/platform/dingux/module.mk
index 2247625a04..309fb94442 100644
--- a/backends/platform/dingux/module.mk
+++ b/backends/platform/dingux/module.mk
@@ -2,7 +2,9 @@ MODULE := backends/platform/dingux
MODULE_OBJS := \
main.o \
- dingux.o
+ dingux.o \
+ dingux-events.o \
+ dingux-graphics.o \
MODULE_DIRS += \
backends/platform/dingux/
diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp
index 1525647c2e..a9dc05b89c 100644
--- a/backends/platform/ds/arm9/source/dsmain.cpp
+++ b/backends/platform/ds/arm9/source/dsmain.cpp
@@ -105,6 +105,7 @@
#endif
#include "engine.h"
+#include "backends/plugins/ds/ds-provider.h"
#include "backends/fs/ds/ds-fs.h"
#include "base/version.h"
#include "common/util.h"
@@ -3213,6 +3214,9 @@ int main(void) {
const char *argv[] = {"/scummvmds"};
#endif
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new DSPluginProvider());
+#endif
while (1) {
scummvm_main(ARRAYSIZE(argv), (char **) &argv);
diff --git a/backends/platform/ds/build-ds.sh b/backends/platform/ds/build-ds.sh
new file mode 100755
index 0000000000..d56af5a092
--- /dev/null
+++ b/backends/platform/ds/build-ds.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# build-ds.sh -- script for building a ds build with every usable dynamic engine plugin
+
+make clean
+
+#Set up a static build with only engines usable by DS enabled
+./configure --host=ds --disable-debug --disable-all-engines --enable-scumm --enable-sky --enable-queen --enable-agos --enable-gob --enable-cine --enable-agi --enable-kyra --enable-lure --enable-parallaction --enable-made --enable-cruise
+
+make clean
+
+make
+
+#Dump all symbols used in this garbage-collected static build into a file
+rm -f ds.syms
+arm-eabi-objdump -t scummvm.elf > ds.syms
+
+make clean
+
+#Set up a dynamic build with only engines usable by the DS enabled
+./configure --host=ds --enable-plugins --default-dynamic --disable-debug --disable-all-engines --enable-scumm --enable-sky --enable-queen --enable-gob --enable-cine --enable-agos --enable-agi --enable-kyra --enable-lure --enable-parallaction --enable-made --enable-cruise
+
+make clean
+
+#Make this final build, which is selectively stripped with the assistance of the ds.syms file that was generated earlier
+make
diff --git a/backends/platform/gp2x/build/README-GP2X b/backends/platform/gp2x/build/README-GP2X
index dc93a9f1c9..3c6591d369 100644
--- a/backends/platform/gp2x/build/README-GP2X
+++ b/backends/platform/gp2x/build/README-GP2X
@@ -1,19 +1,10 @@
-ScummVM - GP2X SPECIFIC README - HEAD SVN
+ScummVM - GP2X SPECIFIC README
------------------------------------------------------------------------
Contents:
* About the backend/port <#About_the_backendport>
- * Game compatability <#Game_compatibility>
- * Included engines <#Included_engines>
* Supported audio options <#Supported_audio_options>
- * Supported cut-scene options <#Supported_cut-scene_options>
- * Recent changes <#Recent_changes>
- * How to save <#How_to_save>
- * Controller mappings <#Controller_mappings>
- * Know issues <#Know_issues>
- * TODO's <#Major_TODOs>
- * Additional resources/links <#Additional_resourceslinks>
* Credits <#Credits>
------------------------------------------------------------------------
@@ -26,47 +17,24 @@ WiKi: <http://wiki.scummvm.org/index.php/GP2X>
for the most current information on the port and any updates to this
documentation.
+The wiki includes detailed instructions on how to use the port and
+control information.
+
------------------------------------------------------------------------
About the backend/port
-This is the readme for the offficial GP2X ScummVM backend (also known as
+This is the readme for the official GP2X ScummVM backend (also known as
the GP2X port).
This is an SVN test release of ScummVM for the GP2X, it would be
appreciated if this SVN test distribution was not mirrored and that
-people be directed to http://www.distant-earth.com/scummvm instead for
+people be directed to http://scummvm.distant-earth.com/ instead for
updated SVN builds.
Full supported official releases of the GP2X ScummVM backend are made in
line with main official releases and are avalalble from the ScummVM
downloads page <http://www.scummvm.org/downloads.php>.
-This build is in an active state of development and as such no
-?expected? behavior can be guaranteed ;).
-
-SVN builds are quickly tested with firmware 2.0.0 for reference.
-
-Please refer to the GP2X ScummVM forum
-<http://forums.scummvm.org/viewforum.php?f=14> and WiKi
-<http://wiki.scummvm.org/index.php/GP2X> for the latest information on
-the port.
-
-------------------------------------------------------------------------
-Game compatibility
-
-For information on the compatability of a specific game please refer to
-the GP2X compatability section of the ScummVM WiKi
-<http://wiki.scummvm.org/index.php/GP2X#Compatibility_List>.
-
-Please note the version and date of the ScummVM build you are running
-when reviewing the above list.
-
-------------------------------------------------------------------------
-Included engines
-
-Just because an engine is included does not mean any/all of its games
-are supported. Please check game compatability for more infomation.
-
------------------------------------------------------------------------
Supported audio options
@@ -79,106 +47,6 @@ FLAC audio is currently unsupported.
For best results use uncompressed audio in games.
------------------------------------------------------------------------
-Supported cut-scene options
-
-No cut scene compression options are currently supported.
-
-DXA video support will be added as soon as it is stable.
-
-------------------------------------------------------------------------
-Recent changes
-
-Refined audio hacks to reduce audio delay a little more.
-Enabled hardware scalar code.
-Now built using SDL 1.2.9 for the parts of the port that use SDL (some
-parts now hit the hardware directly).
-Enabled new launcher - (Ensure defaulttheme.zip is in the same folder as
-the executable).
-Aspect Ratio Correction can now be disabled ?per game?. When adding a
-game you can find this option on the GFX tab.
-Note: This will cause the game to run with a black border at the bottom
-as it will be rendered to a 320*200 frame.
-
-------------------------------------------------------------------------
-How to save
-
-NOTE: Everything is saved to the SD card, saves are stored in the saves
-folder under your main ScummVM executable unless you set another save
-location.
-
-The configiration file for ScummVM (.scummvmrc) is stored in the same
-place as the ScummVM executable.
-
-The save process below is for Scumm engine games but the principle is
-the same for all.
-
-In Game.
-
-1. Right Trigger
-2. Select SAVE with B
-3. Select a position with B
-4. Right trigger puts ? in the name box for some text.
-5. Press B to save
-
-Basically the emulated keys you can use are equivelent to the values
-buttons are mapped to,
-
-I have a virtual keyboard like the GP32 one (left/right on the stick to
-pick chars) to add in at some point ;-)
-
-------------------------------------------------------------------------
-Controller mappings
-
-Mouse emulation:
-
-Stick: Move Pointer
-Stick Click: ?light? Left Click
-B: Left click
-X: Right click
-
-Keyboard emulation:
-
-Start: Return
-Select: Escape
-Y: Space Bar (Pause)
-Right Trigger: Game Menu (Save, Load, Quit etc.)
-Volume Buttons: Increase and Decrease volume (5% per press)
-
-Fancy button combos:
-
-NOTE: To use button combos press and hold the Left Trigger then...
-
-Y: Toggle "zoom" mode - Try it in larger games like Broken Sword.
-Volume Buttons: Increase and Decrease subtitle speed (In SCUMM games)
-Right Trigger: 0 (For skipping the copy protection in Monkey Island 2)
-Select: Exit ScummVM completely (and gracefully)
-
-------------------------------------------------------------------------
-Know issues
-
-Possible random crash (well SegFault). I have had this happen twice and
-have not tracked down the cause.
-It happens very infrequently, both times it was in the DOTT CD intro.
-Saving often is never a bad idea anyhow.
-
-------------------------------------------------------------------------
-TODO's
-
-Fix save support when using the Sky engine (Beneath a Steel Sky) - You
-CAN'T save at the moment but auto save works.
-
-------------------------------------------------------------------------
-Additional resources/links
-
- * ScummVM WiKi GP2X page <http://wiki.scummvm.org/index.php/GP2X>
- * ScummVM forums GP2X forum
- <http://forums.scummvm.org/viewforum.php?f=14>
- * My own ScummVM page <http://scummvm.distant-earth.com/> (for
- SVN/test builds)
- * Main ScummVM site <http://www.scummvm.org> (for official supported
- release builds)
-
-------------------------------------------------------------------------
Credits
Core ScummVM code (c) The ScummVM Team
diff --git a/backends/platform/gp2x/build/config.sh b/backends/platform/gp2x/build/config.sh
index 2bc49564f7..e0a1bf1209 100755
--- a/backends/platform/gp2x/build/config.sh
+++ b/backends/platform/gp2x/build/config.sh
@@ -18,6 +18,7 @@ export DEFINES=-DNDEBUG
# Edit the configure line to suit.
cd ../../../..
./configure --backend=gp2x --disable-mt32emu --host=gp2x --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-vkeybd
-#--enable-plugins --default-dynamic
+# --disable-release --enable-debug
+# --enable-plugins --default-dynamic
echo Generating config for GP2X complete. Check for errors.
diff --git a/backends/platform/gp2x/build/scummvm.gpe b/backends/platform/gp2x/build/scummvm.gpe
index 1e69c149b9..c6b051831c 100755
--- a/backends/platform/gp2x/build/scummvm.gpe
+++ b/backends/platform/gp2x/build/scummvm.gpe
@@ -4,7 +4,7 @@
mount -o sync,remount /dev/mmcsd/disc0/part1 /mnt/sd/
# Run ScummVM, important this bit.
-./scummvm.gp2x
+./scummvm.gph
# Sync the SD card to check that everything is written.
sync
diff --git a/backends/events/gp2xsdl/gp2xsdl-events.cpp b/backends/platform/gp2x/events.cpp
index f52007e746..08553968d2 100644
--- a/backends/events/gp2xsdl/gp2xsdl-events.cpp
+++ b/backends/platform/gp2x/events.cpp
@@ -23,17 +23,16 @@
*
*/
-#if defined(GP2X) || defined(GP2XWIZ)
+/*
+ * GP2X: Common::Event Handling.
+ *
+ */
-#include "backends/events/gp2xsdl/gp2xsdl-events.h"
-#if defined(GP2X)
+#include "backends/platform/gp2x/gp2x-common.h"
#include "backends/platform/gp2x/gp2x-hw.h"
-#include "backends/graphics/gp2xsdl/gp2xsdl-graphics.h"
-#else
-#include "backends/platform/gp2xwiz/gp2xwiz-hw.h"
-#endif
-
-#include "backends/platform/sdl/sdl.h"
+#include "common/util.h"
+#include "common/events.h"
+#include "graphics/scaler/aspect.h" // for aspect2Real
// FIXME move joystick defines out and replace with confile file options
// we should really allow users to map any key to a joystick button using the keymapper.
@@ -84,14 +83,111 @@ enum {
TAPMODE_HOVER = 2
};
-GP2XSdlEventManager::GP2XSdlEventManager(Common::EventSource *boss)
- :
- _buttonStateL(false),
- SdlEventManager(boss) {
+static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) {
+ if (key >= SDLK_F1 && key <= SDLK_F9) {
+ return key - SDLK_F1 + Common::ASCII_F1;
+ } else if (key >= SDLK_KP0 && key <= SDLK_KP9) {
+ return key - SDLK_KP0 + '0';
+ } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) {
+ return key;
+ } else if (unicode) {
+ return unicode;
+ } else if (key >= 'a' && key <= 'z' && (mod & KMOD_SHIFT)) {
+ return key & ~0x20;
+ } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) {
+ return 0;
+ }
+ return key;
+}
+
+void OSystem_GP2X::fillMouseEvent(Common::Event &event, int x, int y) {
+ event.mouse.x = x;
+ event.mouse.y = y;
+
+ // Update the "keyboard mouse" coords
+ _km.x = x;
+ _km.y = y;
+
+ // Adjust for the screen scaling
+ if (!_overlayVisible) {
+ event.mouse.x /= _videoMode.scaleFactor;
+ event.mouse.y /= _videoMode.scaleFactor;
+ if (_videoMode.aspectRatioCorrection)
+ event.mouse.y = aspect2Real(event.mouse.y);
+ }
+}
+
+void OSystem_GP2X::handleKbdMouse() {
+ uint32 curTime = getMillis();
+ if (curTime >= _km.last_time + _km.delay_time) {
+ _km.last_time = curTime;
+ if (_km.x_down_count == 1) {
+ _km.x_down_time = curTime;
+ _km.x_down_count = 2;
+ }
+ if (_km.y_down_count == 1) {
+ _km.y_down_time = curTime;
+ _km.y_down_count = 2;
+ }
+ if (_km.x_vel || _km.y_vel) {
+ if (_km.x_down_count) {
+ if (curTime > _km.x_down_time + _km.delay_time * 12) {
+ if (_km.x_vel > 0)
+ _km.x_vel++;
+ else
+ _km.x_vel--;
+ } else if (curTime > _km.x_down_time + _km.delay_time * 8) {
+ if (_km.x_vel > 0)
+ _km.x_vel = 5;
+ else
+ _km.x_vel = -5;
+ }
+ }
+ if (_km.y_down_count) {
+ if (curTime > _km.y_down_time + _km.delay_time * 12) {
+ if (_km.y_vel > 0)
+ _km.y_vel++;
+ else
+ _km.y_vel--;
+ } else if (curTime > _km.y_down_time + _km.delay_time * 8) {
+ if (_km.y_vel > 0)
+ _km.y_vel = 5;
+ else
+ _km.y_vel = -5;
+ }
+ }
+
+ _km.x += _km.x_vel;
+ _km.y += _km.y_vel;
+
+ if (_km.x < 0) {
+ _km.x = 0;
+ _km.x_vel = -1;
+ _km.x_down_count = 1;
+ } else if (_km.x > _km.x_max) {
+ _km.x = _km.x_max;
+ _km.x_vel = 1;
+ _km.x_down_count = 1;
+ }
+
+ if (_km.y < 0) {
+ _km.y = 0;
+ _km.y_vel = -1;
+ _km.y_down_count = 1;
+ } else if (_km.y > _km.y_max) {
+ _km.y = _km.y_max;
+ _km.y_vel = 1;
+ _km.y_down_count = 1;
+ }
+
+ SDL_WarpMouse((Uint16)_km.x, (Uint16)_km.y);
+ }
+ }
}
-void GP2XSdlEventManager::SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event) {
+static void SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event) {
+
event.kbd.flags = 0;
if (mod & KMOD_SHIFT)
@@ -108,7 +204,7 @@ void GP2XSdlEventManager::SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &eve
event.kbd.flags |= Common::KBD_CAPS;
}
-void GP2XSdlEventManager::moveStick() {
+void OSystem_GP2X::moveStick() {
bool stickBtn[32];
memcpy(stickBtn, _stickBtn, sizeof(stickBtn));
@@ -116,14 +212,14 @@ void GP2XSdlEventManager::moveStick() {
if ((stickBtn[0])||(stickBtn[2])||(stickBtn[4])||(stickBtn[6]))
stickBtn[1] = stickBtn[3] = stickBtn[5] = stickBtn[7] = 0;
- if ((stickBtn[1])||(stickBtn[2])||(stickBtn[3])) {
- if (_km.x_down_count!=2) {
+ if ((stickBtn[1])||(stickBtn[2])||(stickBtn[3])){
+ if (_km.x_down_count!=2){
_km.x_vel = -1;
_km.x_down_count = 1;
- } else
+ }else
_km.x_vel = -4;
- } else if ((stickBtn[5])||(stickBtn[6])||(stickBtn[7])) {
- if (_km.x_down_count!=2) {
+ } else if ((stickBtn[5])||(stickBtn[6])||(stickBtn[7])){
+ if (_km.x_down_count!=2){
_km.x_vel = 1;
_km.x_down_count = 1;
} else
@@ -133,14 +229,14 @@ void GP2XSdlEventManager::moveStick() {
_km.x_down_count = 0;
}
- if ((stickBtn[0])||(stickBtn[1])||(stickBtn[7])) {
- if (_km.y_down_count!=2) {
+ if ((stickBtn[0])||(stickBtn[1])||(stickBtn[7])){
+ if (_km.y_down_count!=2){
_km.y_vel = -1;
_km.y_down_count = 1;
- } else
+ }else
_km.y_vel = -4;
- } else if ((stickBtn[3])||(stickBtn[4])||(stickBtn[5])) {
- if (_km.y_down_count!=2) {
+ } else if ((stickBtn[3])||(stickBtn[4])||(stickBtn[5])){
+ if (_km.y_down_count!=2){
_km.y_vel = 1;
_km.y_down_count = 1;
} else
@@ -151,47 +247,127 @@ void GP2XSdlEventManager::moveStick() {
}
}
-/* GP2X Input mappings.
-Single Button
-
-Movement:
-
-GP2X_BUTTON_UP Cursor Up
-GP2X_BUTTON_DOWN Cursor Down
-GP2X_BUTTON_LEFT Cursor Left
-GP2X_BUTTON_RIGHT Cursor Right
-
-GP2X_BUTTON_UPLEFT Cursor Up Left
-GP2X_BUTTON_UPRIGHT Cursor Up Right
-GP2X_BUTTON_DOWNLEFT Cursor Down Left
-GP2X_BUTTON_DOWNRIGHT Cursor Down Right
-
-Button Emulation:
-
-GP2X_BUTTON_CLICK Left Mouse Click (GP2X only)
-GP2X_BUTTON_A . (Period)
-GP2X_BUTTON_B Left Mouse Click
-GP2X_BUTTON_Y Space Bar
-GP2X_BUTTON_X Right Mouse Click
-GP2X_BUTTON_L Combo Modifier (Left Trigger)
-GP2X_BUTTON_R Return (Right Trigger)
-GP2X_BUTTON_MENU F5 (Game Menu)
-GP2X_BUTTON_SELECT Escape
-GP2X_BUTTON_VOLUP /dev/mixer Global Volume Up
-GP2X_BUTTON_VOLDOWN /dev/mixer Global Volume Down
-
-Combos:
-
-GP2X_BUTTON_VOLUP & GP2X_BUTTON_VOLDOWN 0 (For Monkey 2 CP) or Virtual Keyboard if enabled
-GP2X_BUTTON_L & GP2X_BUTTON_SELECT Common::EVENT_QUIT (Calls Sync() to make sure SD is flushed)
-GP2X_BUTTON_L & GP2X_BUTTON_MENU Common::EVENT_MAINMENU (ScummVM Global Main Menu)
-GP2X_BUTTON_L & GP2X_BUTTON_A Common::EVENT_PREDICTIVE_DIALOG for predictive text entry box (AGI games)
-GP2X_BUTTON_L & GP2X_BUTTON_Y Toggles setZoomOnMouse() for larger then 320*240 games to scale to the point + raduis. (GP2X only)
-*/
-
-bool GP2XSdlEventManager::handleKeyDown(SDL_Event &ev, Common::Event &event) {
+bool OSystem_GP2X::pollEvent(Common::Event &event) {
+ SDL_Event ev;
+ ev.type = SDL_NOEVENT;
+
+ handleKbdMouse();
+
+ // If the screen mode changed, send an Common::EVENT_SCREEN_CHANGED
+ if (_modeChanged) {
+ _modeChanged = false;
+ event.type = Common::EVENT_SCREEN_CHANGED;
+ return true;
+ }
+
+ while (SDL_PollEvent(&ev)) {
+ preprocessEvents(&ev);
+ if (dispatchSDLEvent(ev, event))
+ return true;
+ }
+ return false;
+}
+
+bool OSystem_GP2X::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
+ switch (ev.type) {
+ case SDL_KEYDOWN:
+ return handleKeyDown(ev, event);
+ case SDL_KEYUP:
+ return handleKeyUp(ev, event);
+ case SDL_MOUSEMOTION:
+ return handleMouseMotion(ev, event);
+ case SDL_MOUSEBUTTONDOWN:
+ return handleMouseButtonDown(ev, event);
+ case SDL_MOUSEBUTTONUP:
+ return handleMouseButtonUp(ev, event);
+ case SDL_JOYBUTTONDOWN:
+ return handleJoyButtonDown(ev, event);
+ case SDL_JOYBUTTONUP:
+ return handleJoyButtonUp(ev, event);
+ case SDL_JOYAXISMOTION:
+ return handleJoyAxisMotion(ev, event);
+
+ case SDL_VIDEOEXPOSE:
+ _forceFull = true;
+ break;
+
+ case SDL_QUIT:
+ event.type = Common::EVENT_QUIT;
+ return true;
+
+ }
+
+ return false;
+}
+
+bool OSystem_GP2X::handleKeyDown(SDL_Event &ev, Common::Event &event) {
+
SDLModToOSystemKeyFlags(SDL_GetModState(), event);
+ // Handle scroll lock as a key modifier
+ if (ev.key.keysym.sym == SDLK_SCROLLOCK)
+ _scrollLock = !_scrollLock;
+
+ if (_scrollLock)
+ event.kbd.flags |= Common::KBD_SCRL;
+
+ // Alt-Return and Alt-Enter toggle full screen mode
+ if (event.kbd.hasFlags(Common::KBD_ALT) && (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_KP_ENTER)) {
+ beginGFXTransaction();
+ setFullscreenMode(!_videoMode.fullscreen);
+ endGFXTransaction();
+#ifdef USE_OSD
+ if (_videoMode.fullscreen)
+ displayMessageOnOSD("Fullscreen mode");
+ else
+ displayMessageOnOSD("Windowed mode");
+#endif
+
+ return false;
+ }
+
+ // Alt-S: Create a screenshot
+ if (event.kbd.hasFlags(Common::KBD_ALT) && ev.key.keysym.sym == 's') {
+ char filename[20];
+
+ for (int n = 0;; n++) {
+ SDL_RWops *file;
+
+ sprintf(filename, "scummvm%05d.bmp", n);
+ file = SDL_RWFromFile(filename, "r");
+ if (!file)
+ break;
+ SDL_RWclose(file);
+ }
+ if (saveScreenshot(filename))
+ printf("Saved '%s'\n", filename);
+ else
+ printf("Could not save screenshot!\n");
+ return false;
+ }
+
+ // Ctrl-m toggles mouse capture
+ if (event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'm') {
+ toggleMouseGrab();
+ return false;
+ }
+
+ if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'q') {
+ event.type = Common::EVENT_QUIT;
+ return true;
+ }
+
+ if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'u') {
+ event.type = Common::EVENT_MUTE;
+ return true;
+ }
+
+ // Ctrl-Alt-<key> will change the GFX mode
+ if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) {
+ if (handleScalerHotkeys(ev.key))
+ return false;
+ }
+
if (remapKey(ev, event))
return true;
@@ -202,7 +378,7 @@ bool GP2XSdlEventManager::handleKeyDown(SDL_Event &ev, Common::Event &event) {
return true;
}
-bool GP2XSdlEventManager::handleKeyUp(SDL_Event &ev, Common::Event &event) {
+bool OSystem_GP2X::handleKeyUp(SDL_Event &ev, Common::Event &event) {
if (remapKey(ev, event))
return true;
@@ -224,7 +400,80 @@ bool GP2XSdlEventManager::handleKeyUp(SDL_Event &ev, Common::Event &event) {
return true;
}
-bool GP2XSdlEventManager::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
+bool OSystem_GP2X::handleMouseMotion(SDL_Event &ev, Common::Event &event) {
+ event.type = Common::EVENT_MOUSEMOVE;
+ fillMouseEvent(event, ev.motion.x, ev.motion.y);
+
+ setMousePos(event.mouse.x, event.mouse.y);
+ return true;
+}
+
+/* Custom handleMouseButtonDown/handleMouseButtonUp to deal with 'Tap Mode' for the touchscreen */
+
+bool OSystem_GP2X::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
+ if (ev.button.button == SDL_BUTTON_LEFT){
+ if (BUTTON_STATE_L == true) /* BUTTON_STATE_L = Left Trigger Held, force Right Click */
+ event.type = Common::EVENT_RBUTTONDOWN;
+ else if (GPH::tapmodeLevel == TAPMODE_LEFT) /* TAPMODE_LEFT = Left Click Tap Mode */
+ event.type = Common::EVENT_LBUTTONDOWN;
+ else if (GPH::tapmodeLevel == TAPMODE_RIGHT) /* TAPMODE_RIGHT = Right Click Tap Mode */
+ event.type = Common::EVENT_RBUTTONDOWN;
+ else if (GPH::tapmodeLevel == TAPMODE_HOVER) /* TAPMODE_HOVER = Hover (No Click) Tap Mode */
+ event.type = Common::EVENT_MOUSEMOVE;
+ else
+ event.type = Common::EVENT_LBUTTONDOWN; /* For normal mice etc. */
+ }
+ else if (ev.button.button == SDL_BUTTON_RIGHT)
+ event.type = Common::EVENT_RBUTTONDOWN;
+#if defined(SDL_BUTTON_WHEELUP) && defined(SDL_BUTTON_WHEELDOWN)
+ else if (ev.button.button == SDL_BUTTON_WHEELUP)
+ event.type = Common::EVENT_WHEELUP;
+ else if (ev.button.button == SDL_BUTTON_WHEELDOWN)
+ event.type = Common::EVENT_WHEELDOWN;
+#endif
+#if defined(SDL_BUTTON_MIDDLE)
+ else if (ev.button.button == SDL_BUTTON_MIDDLE)
+ event.type = Common::EVENT_MBUTTONDOWN;
+#endif
+ else
+ return false;
+
+ fillMouseEvent(event, ev.button.x, ev.button.y);
+
+ return true;
+}
+
+bool OSystem_GP2X::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
+ if (ev.button.button == SDL_BUTTON_LEFT){
+ if (BUTTON_STATE_L == true) /* BUTTON_STATE_L = Left Trigger Held, force Right Click */
+ event.type = Common::EVENT_RBUTTONUP;
+ else if (GPH::tapmodeLevel == TAPMODE_LEFT) /* TAPMODE_LEFT = Left Click Tap Mode */
+ event.type = Common::EVENT_LBUTTONUP;
+ else if (GPH::tapmodeLevel == TAPMODE_RIGHT) /* TAPMODE_RIGHT = Right Click Tap Mode */
+ event.type = Common::EVENT_RBUTTONUP;
+ else if (GPH::tapmodeLevel == TAPMODE_HOVER) /* TAPMODE_HOVER = Hover (No Click) Tap Mode */
+ event.type = Common::EVENT_MOUSEMOVE;
+ else
+ event.type = Common::EVENT_LBUTTONUP; /* For normal mice etc. */
+
+ }
+ else if (ev.button.button == SDL_BUTTON_RIGHT)
+ event.type = Common::EVENT_RBUTTONUP;
+#if defined(SDL_BUTTON_MIDDLE)
+ else if (ev.button.button == SDL_BUTTON_MIDDLE)
+ event.type = Common::EVENT_MBUTTONUP;
+#endif
+ else
+ return false;
+
+ fillMouseEvent(event, ev.button.x, ev.button.y);
+
+ return true;
+}
+
+/* Custom handleJoyButtonDown/handleJoyButtonUp to deal with the joystick buttons on GPH devices */
+
+bool OSystem_GP2X::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
_stickBtn[ev.jbutton.button] = 1;
event.kbd.flags = 0;
@@ -245,7 +494,7 @@ bool GP2XSdlEventManager::handleJoyButtonDown(SDL_Event &ev, Common::Event &even
case BUTTON_B:
case BUTTON_CLICK:
if (BUTTON_STATE_L == true) {
- ((GP2XSdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->toogleZoomOnMouse();
+ setZoomOnMouse();
fillMouseEvent(event, _km.x, _km.y);
} else {
event.type = Common::EVENT_LBUTTONDOWN;
@@ -298,12 +547,12 @@ bool GP2XSdlEventManager::handleJoyButtonDown(SDL_Event &ev, Common::Event &even
if (BUTTON_STATE_L == true) {
GPH::ToggleTapMode();
if (GPH::tapmodeLevel == TAPMODE_LEFT) {
- g_system->displayMessageOnOSD("Touchscreen 'Tap Mode' - Left Click");
+ displayMessageOnOSD("Touchscreen 'Tap Mode' - Left Click");
} else if (GPH::tapmodeLevel == TAPMODE_RIGHT) {
- g_system->displayMessageOnOSD("Touchscreen 'Tap Mode' - Right Click");
+ displayMessageOnOSD("Touchscreen 'Tap Mode' - Right Click");
} else if (GPH::tapmodeLevel == TAPMODE_HOVER) {
- g_system->displayMessageOnOSD("Touchscreen 'Tap Mode' - Hover (No Click)");
- }
+ displayMessageOnOSD("Touchscreen 'Tap Mode' - Hover (No Click)");
+ }
} else {
event.kbd.keycode = Common::KEYCODE_SPACE;
event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0);
@@ -322,18 +571,18 @@ bool GP2XSdlEventManager::handleJoyButtonDown(SDL_Event &ev, Common::Event &even
case BUTTON_VOLUP:
GP2X_HW::mixerMoveVolume(2);
if (GP2X_HW::volumeLevel == 100) {
- g_system->displayMessageOnOSD("Maximum Volume");
+ displayMessageOnOSD("Maximum Volume");
} else {
- g_system->displayMessageOnOSD("Increasing Volume");
+ displayMessageOnOSD("Increasing Volume");
}
break;
case BUTTON_VOLDOWN:
GP2X_HW::mixerMoveVolume(1);
if (GP2X_HW::volumeLevel == 0) {
- g_system->displayMessageOnOSD("Minimal Volume");
+ displayMessageOnOSD("Minimal Volume");
} else {
- g_system->displayMessageOnOSD("Decreasing Volume");
+ displayMessageOnOSD("Decreasing Volume");
}
break;
case BUTTON_HOLD:
@@ -342,18 +591,18 @@ bool GP2XSdlEventManager::handleJoyButtonDown(SDL_Event &ev, Common::Event &even
case BUTTON_HELP2:
GPH::ToggleTapMode();
if (GPH::tapmodeLevel == TAPMODE_LEFT) {
- g_system->displayMessageOnOSD("Touchscreen 'Tap Mode': Left Click");
+ displayMessageOnOSD("Touchscreen 'Tap Mode': Left Click");
} else if (GPH::tapmodeLevel == TAPMODE_RIGHT) {
- g_system->displayMessageOnOSD("Touchscreen 'Tap Mode': Right Click");
+ displayMessageOnOSD("Touchscreen 'Tap Mode': Right Click");
} else if (GPH::tapmodeLevel == TAPMODE_HOVER) {
- g_system->displayMessageOnOSD("Touchscreen 'Tap Mode': Hover (No Click)");
+ displayMessageOnOSD("Touchscreen 'Tap Mode': Hover (No Click)");
}
break;
}
return true;
}
-bool GP2XSdlEventManager::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
+bool OSystem_GP2X::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
_stickBtn[ev.jbutton.button] = 0;
event.kbd.flags = 0;
@@ -436,10 +685,10 @@ bool GP2XSdlEventManager::handleJoyButtonUp(SDL_Event &ev, Common::Event &event)
case BUTTON_HELP2:
break;
}
- return true;
+return true;
}
-bool GP2XSdlEventManager::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
+bool OSystem_GP2X::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
int axis = ev.jaxis.value;
if ( axis > JOY_DEADZONE) {
axis -= JOY_DEADZONE;
@@ -463,7 +712,7 @@ bool GP2XSdlEventManager::handleJoyAxisMotion(SDL_Event &ev, Common::Event &even
_km.x_down_count = 0;
}
#endif
-
+
} else if (ev.jaxis.axis == JOY_YAXIS) {
#ifndef JOY_INVERT_Y
axis = -axis;
@@ -483,12 +732,11 @@ bool GP2XSdlEventManager::handleJoyAxisMotion(SDL_Event &ev, Common::Event &even
}
fillMouseEvent(event, _km.x, _km.y);
+
return true;
}
-bool GP2XSdlEventManager::remapKey(SDL_Event &ev, Common::Event &event) {
+
+bool OSystem_GP2X::remapKey(SDL_Event &ev, Common::Event &event) {
return false;
}
-
-
-#endif
diff --git a/backends/platform/gp2x/gp2x-common.h b/backends/platform/gp2x/gp2x-common.h
index 4d2a9c33cc..1c8708a8b1 100644
--- a/backends/platform/gp2x/gp2x-common.h
+++ b/backends/platform/gp2x/gp2x-common.h
@@ -23,23 +23,384 @@
*
*/
-#ifndef PLATFORM_SDL_GP2X_H
-#define PLATFORM_SDL_GP2X_H
+#ifndef GP2X_COMMON_H
+#define GP2X_COMMON_H
-#include "backends/platform/sdl/posix/posix.h"
+#include <SDL.h>
+#include <SDL_gp2x.h>
+
+#include "backends/base-backend.h"
+#include "graphics/scaler.h"
+
+#define __GP2X__
+#define USE_OSD
+#define MIXER_DOUBLE_BUFFERING 1
+
+namespace Audio {
+ class MixerImpl;
+}
+
+enum {
+ GFX_NORMAL = 0
+};
-#ifndef PATH_MAX
- #define PATH_MAX 255
-#endif
-class OSystem_GP2X : public OSystem_POSIX {
+class OSystem_GP2X : public BaseBackend {
public:
+ OSystem_GP2X();
+ virtual ~OSystem_GP2X();
+
virtual void initBackend();
- virtual void quit();
+
+ void beginGFXTransaction(void);
+ TransactionError endGFXTransaction(void);
+
+ // Set the size of the video bitmap.
+ // Typically, 320x200
+ void initSize(uint w, uint h, const Graphics::PixelFormat *format);
+
+ int getScreenChangeID() const { return _screenChangeCount; }
+
+ // Set colors of the palette
+ void setPalette(const byte *colors, uint start, uint num);
+
+ // Get colors of the palette
+ void grabPalette(byte *colors, uint start, uint num);
+
+ // Draw a bitmap to screen.
+ // The screen will not be updated to reflect the new bitmap
+ void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h);
+
+ virtual Graphics::Surface *lockScreen();
+ virtual void unlockScreen();
+
+ // Update the dirty areas of the screen
+ void updateScreen();
+
+ // Either show or hide the mouse cursor
+ bool showMouse(bool visible);
+
+ // Warp the mouse cursor. Where set_mouse_pos() only informs the
+ // backend of the mouse cursor's current position, this function
+ // actually moves the cursor to the specified position.
+ void warpMouse(int x, int y);
+
+ // Set the bitmap that's used when drawing the cursor.
+ void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format);
+
+ // Set colors of cursor palette
+ void setCursorPalette(const byte *colors, uint start, uint num);
+
+ // Disables or enables cursor palette
+ void disableCursorPalette(bool disable) {
+ _cursorPaletteDisabled = disable;
+ blitCursor();
+ }
+
+ // Shaking is used in SCUMM. Set current shake position.
+ void setShakePos(int shake_pos);
+
+ // Get the number of milliseconds since the program was started.
+ uint32 getMillis();
+
+ // Delay for a specified amount of milliseconds
+ void delayMillis(uint msecs);
+
+ // Get the next event.
+ // Returns true if an event was retrieved.
+ virtual bool pollEvent(Common::Event &event); // overloaded by CE backend
+
+ // Sets up the keymapper with the backends hardware key set
+ void setupKeymapper();
+
+protected:
+ virtual bool dispatchSDLEvent(SDL_Event &ev, Common::Event &event);
+
+ // Handlers for specific SDL events, called by pollEvent.
+ // This way, if a backend inherits fromt the SDL backend, it can
+ // change the behavior of only a single event, without having to override all
+ // of pollEvent.
+ virtual bool handleKeyDown(SDL_Event &ev, Common::Event &event);
+ virtual bool handleKeyUp(SDL_Event &ev, Common::Event &event);
+ virtual bool handleMouseMotion(SDL_Event &ev, Common::Event &event);
+ virtual bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event);
+ virtual bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event);
+ virtual bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event);
+ virtual bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event);
+ virtual bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event);
+
+public:
+
+ // Set function that generates samples
+ void setupMixer();
+ static void mixCallback(void *s, byte *samples, int len);
+
+ void closeMixer();
+
+ virtual Audio::Mixer *getMixer();
+
+ // Quit
+ void quit();
+
+ void getTimeAndDate(TimeDate &t) const;
+ virtual Common::TimerManager *getTimerManager();
+
+ // Mutex handling
+ MutexRef createMutex();
+ void lockMutex(MutexRef mutex);
+ void unlockMutex(MutexRef mutex);
+ void deleteMutex(MutexRef mutex);
+
+ // Overlay
+ Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; }
+ void showOverlay();
+ void hideOverlay();
+ void clearOverlay();
+ void grabOverlay(OverlayColor *buf, int pitch);
+ void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
+ int16 getHeight();
+ int16 getWidth();
+ int16 getOverlayHeight() { return _videoMode.overlayHeight; }
+ int16 getOverlayWidth() { return _videoMode.overlayWidth; }
+
+ const GraphicsMode *getSupportedGraphicsModes() const;
+ int getDefaultGraphicsMode() const;
+ bool setGraphicsMode(int mode);
+ int getGraphicsMode() const;
+
+ bool hasFeature(Feature f);
+ void setFeatureState(Feature f, bool enable);
+ bool getFeatureState(Feature f);
+ void preprocessEvents(SDL_Event *event) {}
+
+ void displayMessageOnOSD(const char *msg);
+
+ virtual Common::SaveFileManager *getSavefileManager();
+ virtual FilesystemFactory *getFilesystemFactory();
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
+ virtual Common::SeekableReadStream *createConfigReadStream();
+ virtual Common::WriteStream *createConfigWriteStream();
+
protected:
- virtual void initSDL();
-};
+ bool _inited;
+
+ SDL_Surface *_osdSurface;
+ Uint8 _osdAlpha; // Transparency level of the OSD
+ uint32 _osdFadeStartTime; // When to start the fade out
+ enum {
+ kOSDFadeOutDelay = 2 * 1000, // Delay before the OSD is faded out (in milliseconds)
+ kOSDFadeOutDuration = 500, // Duration of the OSD fade out (in milliseconds)
+ kOSDColorKey = 1,
+ kOSDInitialAlpha = 80 // Initial alpha level, in percent
+ };
+
+ // hardware screen
+ SDL_Surface *_hwscreen;
+
+ // unseen game screen
+ SDL_Surface *_screen;
+
+ // temporary screen (for scalers)
+ SDL_Surface *_tmpscreen;
+ SDL_Surface *_tmpscreen2;
+ // overlay
+ SDL_Surface *_overlayscreen;
+ bool _overlayVisible;
+ Graphics::PixelFormat _overlayFormat;
+
+ enum {
+ kTransactionNone = 0,
+ kTransactionActive = 1,
+ kTransactionRollback = 2
+ };
+
+ struct TransactionDetails {
+ bool sizeChanged;
+ bool needHotswap;
+ bool needUpdatescreen;
+ bool normal1xScaler;
+ };
+ TransactionDetails _transactionDetails;
+
+ struct VideoState {
+ bool setup;
+
+ bool fullscreen;
+ bool aspectRatioCorrection;
+
+ int mode;
+ int scaleFactor;
+
+ int screenWidth, screenHeight;
+ int overlayWidth, overlayHeight;
+ };
+ VideoState _videoMode, _oldVideoMode;
+
+ virtual void setGraphicsModeIntern(); // overloaded by CE backend
+
+ /** Force full redraw on next updateScreen */
+ bool _forceFull;
+ ScalerProc *_scalerProc;
+ int _scalerType;
+ int _transactionMode;
+
+ bool _screenIsLocked;
+ Graphics::Surface _framebuffer;
+
+ /** Current video mode flags (see DF_* constants) */
+ bool _modeChanged;
+ int _screenChangeCount;
+
+ /* True if zoom on mouse is enabled. (only set by > 240 high games) */
+ bool _adjustZoomOnMouse;
+
+ enum {
+ NUM_DIRTY_RECT = 100,
+ MAX_MOUSE_W = 80,
+ MAX_MOUSE_H = 80,
+ MAX_SCALING = 3
+ };
+
+ // Dirty rect management
+ SDL_Rect _dirtyRectList[NUM_DIRTY_RECT];
+ int _numDirtyRects;
+
+ // Keyboard mouse emulation. Disabled by fingolfin 2004-12-18.
+ // I am keeping the rest of the code in for now, since the joystick
+ // code (or rather, "hack") uses it, too.
+ struct KbdMouse {
+ int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count;
+ uint32 last_time, delay_time, x_down_time, y_down_time;
+ };
+
+ struct MousePos {
+ // The mouse position, using either virtual (game) or real
+ // (overlay) coordinates.
+ int16 x, y;
+
+ // The size and hotspot of the original cursor image.
+ int16 w, h;
+ int16 hotX, hotY;
+
+ // The size and hotspot of the pre-scaled cursor image, in real
+ // coordinates.
+ int16 rW, rH;
+ int16 rHotX, rHotY;
+
+ // The size and hotspot of the pre-scaled cursor image, in game
+ // coordinates.
+ int16 vW, vH;
+ int16 vHotX, vHotY;
+
+ MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0),
+ rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0),
+ vHotX(0), vHotY(0)
+ { }
+ };
+
+ // mouse
+ KbdMouse _km;
+ bool _mouseVisible;
+ bool _mouseNeedsRedraw;
+ byte *_mouseData;
+ SDL_Rect _mouseBackup;
+ MousePos _mouseCurState;
+ byte _mouseKeyColor;
+ int _cursorTargetScale;
+ bool _cursorPaletteDisabled;
+ SDL_Surface *_mouseOrigSurface;
+ SDL_Surface *_mouseSurface;
+ enum {
+ kMouseColorKey = 1
+ };
+
+ // Scroll lock state - since SDL doesn't track it
+ bool _scrollLock;
+
+ // joystick
+ SDL_Joystick *_joystick;
+ bool _stickBtn[32];
+
+ // Shake mode
+ int _currentShakePos;
+ int _newShakePos;
+
+ // Palette data
+ SDL_Color *_currentPalette;
+ uint _paletteDirtyStart, _paletteDirtyEnd;
+
+ // Cursor palette data
+ SDL_Color *_cursorPalette;
+
+ /**
+ * Mutex which prevents multiple threads from interfering with each other
+ * when accessing the screen.
+ */
+ MutexRef _graphicsMutex;
+
+#ifdef MIXER_DOUBLE_BUFFERING
+ SDL_mutex *_soundMutex;
+ SDL_cond *_soundCond;
+ SDL_Thread *_soundThread;
+ bool _soundThreadIsRunning;
+ bool _soundThreadShouldQuit;
+
+ byte _activeSoundBuf;
+ uint _soundBufSize;
+ byte *_soundBuffers[2];
+
+ void mixerProducerThread();
+ static int SDLCALL mixerProducerThreadEntry(void *arg);
+ void initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize);
+ void deinitThreadedMixer();
#endif
+
+ FilesystemFactory *_fsFactory;
+ Common::SaveFileManager *_savefile;
+ Audio::MixerImpl *_mixer;
+
+ SDL_TimerID _timerID;
+ Common::TimerManager *_timer;
+
+protected:
+ virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false);
+
+ void drawMouse();
+ void undrawMouse();
+ void blitCursor();
+
+ /** Set the position of the virtual mouse cursor. */
+ void setMousePos(int x, int y);
+ void fillMouseEvent(Common::Event &event, int x, int y);
+ void toggleMouseGrab();
+
+ void internUpdateScreen();
+
+ bool loadGFXMode();
+ void unloadGFXMode();
+ bool hotswapGFXMode();
+
+ void setFullscreenMode(bool enable);
+ void setAspectRatioCorrection(bool enable);
+
+ void setZoomOnMouse(); // GP2X: On > 240 high games zooms on the mouse + radius.
+
+ bool saveScreenshot(const char *filename);
+
+ int effectiveScreenHeight() const;
+
+ void setupIcon();
+ void handleKbdMouse();
+
+ virtual bool remapKey(SDL_Event &ev, Common::Event &event);
+
+ bool handleScalerHotkeys(const SDL_KeyboardEvent &key);
+ bool isScalerHotkey(const Common::Event &event);
+
+ void moveStick();
+ int _gp2xInputType;
+};
+
+#endif // GP2X_COMMON_H
diff --git a/backends/platform/gp2x/gp2x-hw.cpp b/backends/platform/gp2x/gp2x-hw.cpp
index 75e4ca6471..8818ff9fe9 100644
--- a/backends/platform/gp2x/gp2x-hw.cpp
+++ b/backends/platform/gp2x/gp2x-hw.cpp
@@ -30,6 +30,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "gp2x-common.h"
#include "gp2x-hw.h"
@@ -48,6 +51,10 @@
#include <sys/time.h>
#include <unistd.h>
+extern "C" {
+static unsigned long gp2x_dev[8]={0,0,0,0,0,0,0,0};//, gp2x_ticks_per_second;
+}
+
namespace GP2X_HW {
enum {
diff --git a/backends/platform/gp2x/gp2x-main.cpp b/backends/platform/gp2x/gp2x-main.cpp
deleted file mode 100644
index 8dc5be764b..0000000000
--- a/backends/platform/gp2x/gp2x-main.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "backends/platform/gp2x/gp2x-sdl.h"
-#include "backends/plugins/posix/posix-provider.h"
-#include "base/main.h"
-
-int main(int argc, char *argv[]) {
-
- // Create our OSystem instance
- g_system = new OSystem_GP2X();
- assert(g_system);
-
- // Pre initialize the backend
- ((OSystem_GP2X *)g_system)->init();
-
-#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new POSIXPluginProvider());
-#endif
-
- // Invoke the actual ScummVM main entry point:
- int res = scummvm_main(argc, argv);
-
- // Free OSystem
- delete (OSystem_GP2X *)g_system;
-
- return res;
-}
diff --git a/backends/platform/gp2x/gp2x-mem.cpp b/backends/platform/gp2x/gp2x-mem.cpp
index 97a34ffb6a..0968087cfd 100644
--- a/backends/platform/gp2x/gp2x-mem.cpp
+++ b/backends/platform/gp2x/gp2x-mem.cpp
@@ -28,6 +28,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
@@ -39,8 +42,11 @@
#include "backends/platform/gp2x/gp2x-mem.h"
-void SetClock (unsigned c)
-{
+extern "C" {
+static volatile unsigned short *gp2x_memregs;
+}
+
+void SetClock (unsigned c) {
unsigned v;
unsigned mdiv,pdiv=3,scale=0;
@@ -54,8 +60,7 @@ void SetClock (unsigned c)
gp2x_memregs[0x910>>1] = v;
}
-void patchMMU (void)
-{
+void patchMMU (void) {
//volatile unsigned int *secbuf = (unsigned int *)malloc (204800);
printf ("Reconfiguring cached memory regions...\n");
@@ -68,19 +73,15 @@ void patchMMU (void)
int mmufd = open("/dev/mmuhack", O_RDWR);
- if(mmufd < 0)
- {
+ if(mmufd < 0) {
printf ("Upper memory uncached (attempt failed, access to upper memory will be slower)...\n");
- }
- else
- {
+ } else {
printf ("Upper memory cached...\n");
close(mmufd);
}
}
-void unpatchMMU (void)
-{
+void unpatchMMU (void) {
printf ("Restoreing cached memory regions...\n");
system("/sbin/rmmod mmuhack");
}
diff --git a/backends/platform/gp2x/gp2x-mem.h b/backends/platform/gp2x/gp2x-mem.h
index 24b2a3f569..aa49444164 100644
--- a/backends/platform/gp2x/gp2x-mem.h
+++ b/backends/platform/gp2x/gp2x-mem.h
@@ -47,9 +47,6 @@ extern void unpatchMMU (void);
#define SYS_CLK_FREQ 7372800
-static unsigned long gp2x_dev[8]={0,0,0,0,0,0,0,0};//, gp2x_ticks_per_second;
-static volatile unsigned short *gp2x_ram, *gp2x_memregs;
-
#ifdef __cplusplus
}
#endif
diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp
index c297a45833..0811380be9 100644
--- a/backends/platform/gp2x/gp2x.cpp
+++ b/backends/platform/gp2x/gp2x.cpp
@@ -23,19 +23,32 @@
*
*/
+/*
+ * GP2X: Main backend.
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/platform/gp2x/gp2x-common.h"
#include "backends/platform/gp2x/gp2x-hw.h"
#include "backends/platform/gp2x/gp2x-mem.h"
-
-#include "backends/graphics/gp2xsdl/gp2xsdl-graphics.h"
-#include "backends/events/gp2xsdl/gp2xsdl-events.h"
-#include "backends/saves/default/default-saves.h"
-
+#include "common/archive.h"
#include "common/config-manager.h"
#include "common/debug.h"
+#include "common/EventRecorder.h"
+#include "common/events.h"
+#include "common/util.h"
-// Disable for normal serial logging.
-#define DUMP_STDOUT
+#include "common/file.h"
+#include "base/main.h"
+
+#include "backends/saves/default/default-saves.h"
+
+#include "backends/timer/default/default-timer.h"
+#include "backends/plugins/posix/posix-provider.h"
+#include "sound/mixer_intern.h"
#include <stdio.h>
#include <stdlib.h>
@@ -43,14 +56,69 @@
#include <limits.h>
#include <errno.h>
#include <sys/stat.h>
+#include <time.h> // for getTimeAndDate()
+
+// Disable for normal serial logging.
+#define DUMP_STDOUT
+
+#define SAMPLES_PER_SEC 11025
+//#define SAMPLES_PER_SEC 22050
+//#define SAMPLES_PER_SEC 44100
+
+#define DEFAULT_CONFIG_FILE ".scummvmrc"
+
+#include "backends/fs/posix/posix-fs-factory.h"
+
+static Uint32 timer_handler(Uint32 interval, void *param) {
+ ((DefaultTimerManager *)param)->handler();
+ return interval;
+}
+
+int main(int argc, char *argv[]) {
+ g_system = new OSystem_GP2X();
+ assert(g_system);
+
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new POSIXPluginProvider());
+#endif
+
+ // Invoke the actual ScummVM main entry point:
+ int res = scummvm_main(argc, argv);
+ g_system->quit();
+ return res;
+}
+
+OSystem *OSystem_GP2X_create() {
+ return new OSystem_GP2X();
+}
void OSystem_GP2X::initBackend() {
+ assert(!_inited);
+
+ ConfMan.setInt("joystick_num", 0);
+ int joystick_num = ConfMan.getInt("joystick_num");
+ uint32 sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_EVENTTHREAD;
+
+ if (ConfMan.hasKey("disable_sdl_parachute"))
+ sdlFlags |= SDL_INIT_NOPARACHUTE;
+
+ if (joystick_num > -1)
+ sdlFlags |= SDL_INIT_JOYSTICK;
+
+ if (SDL_Init(sdlFlags) == -1) {
+ error("Could not initialize SDL: %s", SDL_GetError());
+ }
+
// Setup default save path to be workingdir/saves
- char savePath[PATH_MAX + 1];
- char workDirName[PATH_MAX + 1];
+ #ifndef PATH_MAX
+ #define PATH_MAX 255
+ #endif
+
+ char savePath[PATH_MAX+1];
+ char workDirName[PATH_MAX+1];
if (getcwd(workDirName, PATH_MAX) == NULL) {
- error("Could not obtain current working directory");
+ error("Could not obtain current working directory.");
} else {
printf("Current working directory: %s\n", workDirName);
}
@@ -69,8 +137,8 @@ void OSystem_GP2X::initBackend() {
#ifdef DUMP_STDOUT
// The GP2X has a serial console but most users do not use this so we
// output all our STDOUT and STDERR to files for debug purposes.
- char STDOUT_FILE[PATH_MAX + 1];
- char STDERR_FILE[PATH_MAX + 1];
+ char STDOUT_FILE[PATH_MAX+1];
+ char STDERR_FILE[PATH_MAX+1];
strcpy(STDOUT_FILE, workDirName);
strcpy(STDERR_FILE, workDirName);
@@ -110,7 +178,12 @@ void OSystem_GP2X::initBackend() {
printf("%s\n", "Debug: STDOUT and STDERR redirected to text files.");
#endif /* DUMP_STDOUT */
+ _graphicsMutex = createMutex();
+
+ SDL_ShowCursor(SDL_DISABLE);
+
// Setup other defaults.
+
ConfMan.registerDefault("aspect_ratio", true);
/* Up default volume values as we use a seperate system level volume anyway. */
@@ -119,50 +192,146 @@ void OSystem_GP2X::initBackend() {
ConfMan.registerDefault("speech_volume", 192);
ConfMan.registerDefault("autosave_period", 3 * 60); // Trigger autosave every 3 minutes - On low batts 4 mins is about your warning time.
+ memset(&_oldVideoMode, 0, sizeof(_oldVideoMode));
+ memset(&_videoMode, 0, sizeof(_videoMode));
+ memset(&_transactionDetails, 0, sizeof(_transactionDetails));
+
+ _videoMode.mode = GFX_NORMAL;
+ _videoMode.scaleFactor = 1;
+ _scalerProc = Normal1x;
+ _videoMode.aspectRatioCorrection = ConfMan.getBool("aspect_ratio");
+ _scalerType = 0;
+ _adjustZoomOnMouse = false;
ConfMan.setBool("FM_low_quality", true);
+ // enable joystick
+ if (joystick_num > -1 && SDL_NumJoysticks() > 0) {
+ _joystick = SDL_JoystickOpen(joystick_num);
+ }
+
+ _savefile = new DefaultSaveFileManager();
+ // Create and hook up the mixer, if none exists yet (we check for this to
+ // allow subclasses to provide their own).
+ if (_mixer == 0) {
+ setupMixer();
+ }
+
+ // Create and hook up the timer manager, if none exists yet (we check for
+ // this to allow subclasses to provide their own).
+ if (_timer == 0) {
+ // Note: We could implement a custom SDLTimerManager by using
+ // SDL_AddTimer. That might yield better timer resolution, but it would
+ // also change the semantics of a timer: Right now, ScummVM timers
+ // *never* run in parallel, due to the way they are implemented. If we
+ // switched to SDL_AddTimer, each timer might run in a separate thread.
+ // However, not all our code is prepared for that, so we can't just
+ // switch. Still, it's a potential future change to keep in mind.
+ _timer = new DefaultTimerManager();
+ _timerID = SDL_AddTimer(10, &timer_handler, _timer);
+ }
+
/* Initialise any GP2X specific stuff we may want (Batt Status, scaler etc.) */
GP2X_HW::deviceInit();
/* Set Default hardware mixer volume to a preset level (VOLUME_INITIAL). This is done to 'reset' volume level if set by other apps. */
GP2X_HW::mixerMoveVolume(0);
- // Create the events manager
- if (_eventManager == 0)
- _eventManager = new GP2XSdlEventManager(this);
+ OSystem::initBackend();
- // Create the graphics manager
- if (_graphicsManager == 0)
- _graphicsManager = new GP2XSdlGraphicsManager();
+ _inited = true;
+}
- // Call parent implementation of this method
- OSystem_POSIX::initBackend();
+OSystem_GP2X::OSystem_GP2X()
+ :
+ _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0),
+ _hwscreen(0), _screen(0), _tmpscreen(0),
+ _overlayVisible(false),
+ _overlayscreen(0), _tmpscreen2(0),
+ _scalerProc(0), _modeChanged(false), _screenChangeCount(0),
+ _mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0),
+ _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true),
+ _joystick(0),
+ _currentShakePos(0), _newShakePos(0),
+ _paletteDirtyStart(0), _paletteDirtyEnd(0),
+#ifdef MIXER_DOUBLE_BUFFERING
+ _soundMutex(0), _soundCond(0), _soundThread(0),
+ _soundThreadIsRunning(false), _soundThreadShouldQuit(false),
+#endif
+ _fsFactory(0),
+ _savefile(0),
+ _mixer(0),
+ _timer(0),
+ _screenIsLocked(false),
+ _graphicsMutex(0), _transactionMode(kTransactionNone) {
+
+ // allocate palette storage
+ _currentPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
+ _cursorPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
+
+ _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
+
+ // reset mouse state
+ memset(&_km, 0, sizeof(_km));
+ memset(&_mouseCurState, 0, sizeof(_mouseCurState));
+
+ _inited = false;
+ _fsFactory = new POSIXFilesystemFactory();
}
-void OSystem_GP2X::initSDL() {
- // Check if SDL has not been initialized
- if (!_initedSDL) {
- uint32 sdlFlags = SDL_INIT_EVENTTHREAD;
- if (ConfMan.hasKey("disable_sdl_parachute"))
- sdlFlags |= SDL_INIT_NOPARACHUTE;
+OSystem_GP2X::~OSystem_GP2X() {
+ SDL_RemoveTimer(_timerID);
+ closeMixer();
- // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers)
- if (SDL_Init(sdlFlags) == -1)
- error("Could not initialize SDL: %s", SDL_GetError());
+ free(_currentPalette);
+ free(_cursorPalette);
+ free(_mouseData);
- // Enable unicode support if possible
- SDL_EnableUNICODE(1);
+ delete _savefile;
+ delete _timer;
+}
- _initedSDL = true;
- }
+uint32 OSystem_GP2X::getMillis() {
+ uint32 millis = SDL_GetTicks();
+ g_eventRec.processMillis(millis);
+ return millis;
+}
+
+void OSystem_GP2X::delayMillis(uint msecs) {
+ SDL_Delay(msecs);
+}
+
+void OSystem_GP2X::getTimeAndDate(TimeDate &td) const {
+ time_t curTime = time(0);
+ struct tm t = *localtime(&curTime);
+ td.tm_sec = t.tm_sec;
+ td.tm_min = t.tm_min;
+ td.tm_hour = t.tm_hour;
+ td.tm_mday = t.tm_mday;
+ td.tm_mon = t.tm_mon;
+ td.tm_year = t.tm_year;
+}
+
+Common::TimerManager *OSystem_GP2X::getTimerManager() {
+ assert(_timer);
+ return _timer;
+}
+
+Common::SaveFileManager *OSystem_GP2X::getSavefileManager() {
+ assert(_savefile);
+ return _savefile;
+}
+
+FilesystemFactory *OSystem_GP2X::getFilesystemFactory() {
+ assert(_fsFactory);
+ return _fsFactory;
}
void OSystem_GP2X::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
/* Setup default extra data paths for engine data files and plugins */
- char workDirName[PATH_MAX + 1];
+ char workDirName[PATH_MAX+1];
if (getcwd(workDirName, PATH_MAX) == NULL) {
- error("Error: Could not obtain current working directory");
+ error("Error: Could not obtain current working directory.");
}
Common::FSNode workdirNode(workDirName);
@@ -191,14 +360,283 @@ void OSystem_GP2X::addSysArchivesToSearchSet(Common::SearchSet &s, int priority)
}
}
+static Common::String getDefaultConfigFileName() {
+ char configFile[MAXPATHLEN];
+ strcpy(configFile, DEFAULT_CONFIG_FILE);
+ return configFile;
+}
+
+Common::SeekableReadStream *OSystem_GP2X::createConfigReadStream() {
+ Common::FSNode file(getDefaultConfigFileName());
+ return file.createReadStream();
+}
+
+Common::WriteStream *OSystem_GP2X::createConfigWriteStream() {
+ Common::FSNode file(getDefaultConfigFileName());
+ return file.createWriteStream();
+}
+
+bool OSystem_GP2X::hasFeature(Feature f) {
+ return
+ (f == kFeatureFullscreenMode) ||
+ (f == kFeatureAspectRatioCorrection) ||
+ (f == kFeatureCursorHasPalette);
+}
+
+void OSystem_GP2X::setFeatureState(Feature f, bool enable) {
+ switch (f) {
+ case kFeatureFullscreenMode:
+ return;
+ case kFeatureAspectRatioCorrection:
+ setAspectRatioCorrection(enable);
+ break;
+ case kFeatureDisableKeyFiltering:
+ // TODO: Extend as more support for this is added to engines.
+ return;
+ default:
+ break;
+ }
+}
+
+bool OSystem_GP2X::getFeatureState(Feature f) {
+ assert (_transactionMode == kTransactionNone);
+
+ switch (f) {
+ case kFeatureFullscreenMode:
+ return false;
+ case kFeatureAspectRatioCorrection:
+ return _videoMode.aspectRatioCorrection;
+ default:
+ return false;
+ }
+}
+
void OSystem_GP2X::quit() {
+ unloadGFXMode();
+ deleteMutex(_graphicsMutex);
+
+ if (_joystick)
+ SDL_JoystickClose(_joystick);
GP2X_HW::deviceDeinit();
+ SDL_RemoveTimer(_timerID);
+ closeMixer();
+
+ free(_currentPalette);
+ free(_cursorPalette);
+ free(_mouseData);
+
+ delete _timer;
+ SDL_ShowCursor(SDL_ENABLE);
+ SDL_Quit();
+
+ delete getEventManager();
+ delete _savefile;
+
#ifdef DUMP_STDOUT
printf("%s\n", "Debug: STDOUT and STDERR text files closed.");
fclose(stdout);
fclose(stderr);
#endif /* DUMP_STDOUT */
- OSystem_POSIX::quit();
+ exit(0);
+}
+
+OSystem::MutexRef OSystem_GP2X::createMutex(void) {
+ return (MutexRef) SDL_CreateMutex();
+}
+
+void OSystem_GP2X::lockMutex(MutexRef mutex) {
+ SDL_mutexP((SDL_mutex *) mutex);
+}
+
+void OSystem_GP2X::unlockMutex(MutexRef mutex) {
+ SDL_mutexV((SDL_mutex *) mutex);
+}
+
+void OSystem_GP2X::deleteMutex(MutexRef mutex) {
+ SDL_DestroyMutex((SDL_mutex *) mutex);
+}
+
+#pragma mark -
+#pragma mark --- Audio ---
+#pragma mark -
+
+#ifdef MIXER_DOUBLE_BUFFERING
+
+void OSystem_GP2X::mixerProducerThread() {
+ byte nextSoundBuffer;
+
+ SDL_LockMutex(_soundMutex);
+ while (true) {
+ // Wait till we are allowed to produce data
+ SDL_CondWait(_soundCond, _soundMutex);
+
+ if (_soundThreadShouldQuit)
+ break;
+
+ // Generate samples and put them into the next buffer
+ nextSoundBuffer = _activeSoundBuf ^ 1;
+ _mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize);
+
+ // Swap buffers
+ _activeSoundBuf = nextSoundBuffer;
+ }
+ SDL_UnlockMutex(_soundMutex);
+}
+
+int SDLCALL OSystem_GP2X::mixerProducerThreadEntry(void *arg) {
+ OSystem_GP2X *this_ = (OSystem_GP2X *)arg;
+ assert(this_);
+ this_->mixerProducerThread();
+ return 0;
+}
+
+
+void OSystem_GP2X::initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize) {
+ _soundThreadIsRunning = false;
+ _soundThreadShouldQuit = false;
+
+ // Create mutex and condition variable
+ _soundMutex = SDL_CreateMutex();
+ _soundCond = SDL_CreateCond();
+
+ // Create two sound buffers
+ _activeSoundBuf = 0;
+ _soundBufSize = bufSize;
+ _soundBuffers[0] = (byte *)calloc(1, bufSize);
+ _soundBuffers[1] = (byte *)calloc(1, bufSize);
+
+ _soundThreadIsRunning = true;
+
+ // Finally start the thread
+ _soundThread = SDL_CreateThread(mixerProducerThreadEntry, this);
+}
+
+void OSystem_GP2X::deinitThreadedMixer() {
+ // Kill thread?? _soundThread
+
+ if (_soundThreadIsRunning) {
+ // Signal the producer thread to end, and wait for it to actually finish.
+ _soundThreadShouldQuit = true;
+ SDL_CondBroadcast(_soundCond);
+ SDL_WaitThread(_soundThread, NULL);
+
+ // Kill the mutex & cond variables.
+ // Attention: AT this point, the mixer callback must not be running
+ // anymore, else we will crash!
+ SDL_DestroyMutex(_soundMutex);
+ SDL_DestroyCond(_soundCond);
+
+ _soundThreadIsRunning = false;
+
+ free(_soundBuffers[0]);
+ free(_soundBuffers[1]);
+ }
+}
+
+
+void OSystem_GP2X::mixCallback(void *arg, byte *samples, int len) {
+ OSystem_GP2X *this_ = (OSystem_GP2X *)arg;
+ assert(this_);
+ assert(this_->_mixer);
+
+ assert((int)this_->_soundBufSize == len);
+
+ // Lock mutex, to ensure our data is not overwritten by the producer thread
+ SDL_LockMutex(this_->_soundMutex);
+
+ // Copy data from the current sound buffer
+ memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len);
+
+ // Unlock mutex and wake up the produced thread
+ SDL_UnlockMutex(this_->_soundMutex);
+ SDL_CondSignal(this_->_soundCond);
+}
+
+#else
+
+void OSystem_GP2X::mixCallback(void *sys, byte *samples, int len) {
+ OSystem_GP2X *this_ = (OSystem_GP2X *)sys;
+ assert(this_);
+ assert(this_->_mixer);
+
+ this_->_mixer->mixCallback(samples, len);
+}
+
+#endif
+
+void OSystem_GP2X::setupMixer() {
+ SDL_AudioSpec desired;
+ SDL_AudioSpec obtained;
+
+ // Determine the desired output sampling frequency.
+ uint32 samplesPerSec = 0;
+ if (ConfMan.hasKey("output_rate"))
+ samplesPerSec = ConfMan.getInt("output_rate");
+ if (samplesPerSec <= 0)
+ samplesPerSec = SAMPLES_PER_SEC;
+
+ // Determine the sample buffer size. We want it to store enough data for
+ // at least 1/16th of a second (though at most 8192 samples). Note
+ // that it must be a power of two. So e.g. at 22050 Hz, we request a
+ // sample buffer size of 2048.
+ uint32 samples = 8192;
+ while (samples * 16 > samplesPerSec * 2)
+ samples >>= 1;
+
+ memset(&desired, 0, sizeof(desired));
+ desired.freq = samplesPerSec;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ //desired.samples = (uint16)samples;
+ desired.samples = 128; // Samples hack
+ desired.callback = mixCallback;
+ desired.userdata = this;
+
+ assert(!_mixer);
+ if (SDL_OpenAudio(&desired, &obtained) != 0) {
+ warning("Could not open audio device: %s", SDL_GetError());
+ _mixer = new Audio::MixerImpl(this, samplesPerSec);
+ assert(_mixer);
+ _mixer->setReady(false);
+ } else {
+ // Note: This should be the obtained output rate, but it seems that at
+ // least on some platforms SDL will lie and claim it did get the rate
+ // even if it didn't. Probably only happens for "weird" rates, though.
+ samplesPerSec = obtained.freq;
+ debug(1, "Output sample rate: %d Hz", samplesPerSec);
+
+ // Create the mixer instance and start the sound processing
+ _mixer = new Audio::MixerImpl(this, samplesPerSec);
+ assert(_mixer);
+ _mixer->setReady(true);
+
+#ifdef MIXER_DOUBLE_BUFFERING
+ initThreadedMixer(_mixer, obtained.samples * 4);
+#endif
+
+ // start the sound system
+ SDL_PauseAudio(0);
+ }
+}
+
+void OSystem_GP2X::closeMixer() {
+ if (_mixer)
+ _mixer->setReady(false);
+
+ SDL_CloseAudio();
+
+ delete _mixer;
+ _mixer = 0;
+
+#ifdef MIXER_DOUBLE_BUFFERING
+ deinitThreadedMixer();
+#endif
+
+}
+
+Audio::Mixer *OSystem_GP2X::getMixer() {
+ assert(_mixer);
+ return _mixer;
}
diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp
new file mode 100644
index 0000000000..d776db218e
--- /dev/null
+++ b/backends/platform/gp2x/graphics.cpp
@@ -0,0 +1,1701 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * GP2X: Graphics handling.
+ *
+ */
+
+#include "backends/platform/gp2x/gp2x-common.h"
+#include "common/util.h"
+#include "common/mutex.h"
+#include "common/str-array.h"
+#include "graphics/font.h"
+#include "graphics/fontman.h"
+#include "graphics/scaler.h"
+#include "graphics/scaler/aspect.h"
+#include "graphics/surface.h"
+
+static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+ {"Fullscreen", "1x", GFX_NORMAL},
+ {0, 0, 0}
+};
+
+// Table of relative scalers magnitudes
+// [definedScale - 1][_scaleFactor - 1]
+static ScalerProc *scalersMagn[3][3] = {
+ { Normal1x, Normal1x, Normal1x },
+ { Normal1x, Normal1x, Normal1x },
+ { Normal1x, Normal1x, Normal1x }
+};
+
+static const int s_gfxModeSwitchTable[][4] = {
+ { GFX_NORMAL }
+ };
+
+static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY);
+
+const OSystem::GraphicsMode *OSystem_GP2X::getSupportedGraphicsModes() const {
+ return s_supportedGraphicsModes;
+}
+
+int OSystem_GP2X::getDefaultGraphicsMode() const {
+ return GFX_NORMAL;
+}
+
+void OSystem_GP2X::beginGFXTransaction(void) {
+ assert(_transactionMode == kTransactionNone);
+
+ _transactionMode = kTransactionActive;
+
+ _transactionDetails.sizeChanged = false;
+
+ _transactionDetails.needHotswap = false;
+ _transactionDetails.needUpdatescreen = false;
+
+ _transactionDetails.normal1xScaler = false;
+
+ _oldVideoMode = _videoMode;
+}
+
+OSystem::TransactionError OSystem_GP2X::endGFXTransaction(void) {
+ int errors = kTransactionSuccess;
+
+ assert(_transactionMode != kTransactionNone);
+
+ if (_transactionMode == kTransactionRollback) {
+ if (_videoMode.fullscreen != _oldVideoMode.fullscreen) {
+ errors |= kTransactionFullscreenFailed;
+
+ _videoMode.fullscreen = _oldVideoMode.fullscreen;
+ } else if (_videoMode.aspectRatioCorrection != _oldVideoMode.aspectRatioCorrection) {
+ errors |= kTransactionAspectRatioFailed;
+
+ _videoMode.aspectRatioCorrection = _oldVideoMode.aspectRatioCorrection;
+ } else if (_videoMode.mode != _oldVideoMode.mode) {
+ errors |= kTransactionModeSwitchFailed;
+
+ _videoMode.mode = _oldVideoMode.mode;
+ _videoMode.scaleFactor = _oldVideoMode.scaleFactor;
+ } else if (_videoMode.screenWidth != _oldVideoMode.screenWidth || _videoMode.screenHeight != _oldVideoMode.screenHeight) {
+ errors |= kTransactionSizeChangeFailed;
+
+ _videoMode.screenWidth = _oldVideoMode.screenWidth;
+ _videoMode.screenHeight = _oldVideoMode.screenHeight;
+ _videoMode.overlayWidth = _oldVideoMode.overlayWidth;
+ _videoMode.overlayHeight = _oldVideoMode.overlayHeight;
+ }
+
+ if (_videoMode.fullscreen == _oldVideoMode.fullscreen &&
+ _videoMode.aspectRatioCorrection == _oldVideoMode.aspectRatioCorrection &&
+ _videoMode.mode == _oldVideoMode.mode &&
+ _videoMode.screenWidth == _oldVideoMode.screenWidth &&
+ _videoMode.screenHeight == _oldVideoMode.screenHeight) {
+
+ // Our new video mode would now be exactly the same as the
+ // old one. Since we still can not assume SDL_SetVideoMode
+ // to be working fine, we need to invalidate the old video
+ // mode, so loadGFXMode would error out properly.
+ _oldVideoMode.setup = false;
+ }
+ }
+
+ if (_transactionDetails.sizeChanged) {
+ unloadGFXMode();
+ if (!loadGFXMode()) {
+ if (_oldVideoMode.setup) {
+ _transactionMode = kTransactionRollback;
+ errors |= endGFXTransaction();
+ }
+ } else {
+ setGraphicsModeIntern();
+ clearOverlay();
+
+ _videoMode.setup = true;
+ _modeChanged = true;
+ // OSystem_SDL::pollEvent used to update the screen change count,
+ // but actually it gives problems when a video mode was changed
+ // but OSystem_SDL::pollEvent was not called. This for example
+ // caused a crash under certain circumstances when doing an RTL.
+ // To fix this issue we update the screen change count right here.
+ _screenChangeCount++;
+ }
+ } else if (_transactionDetails.needHotswap) {
+ setGraphicsModeIntern();
+ if (!hotswapGFXMode()) {
+ if (_oldVideoMode.setup) {
+ _transactionMode = kTransactionRollback;
+ errors |= endGFXTransaction();
+ }
+ } else {
+ _videoMode.setup = true;
+ _modeChanged = true;
+ // OSystem_SDL::pollEvent used to update the screen change count,
+ // but actually it gives problems when a video mode was changed
+ // but OSystem_SDL::pollEvent was not called. This for example
+ // caused a crash under certain circumstances when doing an RTL.
+ // To fix this issue we update the screen change count right here.
+ _screenChangeCount++;
+
+ if (_transactionDetails.needUpdatescreen)
+ internUpdateScreen();
+ }
+ } else if (_transactionDetails.needUpdatescreen) {
+ setGraphicsModeIntern();
+ internUpdateScreen();
+ }
+
+ _transactionMode = kTransactionNone;
+ return (TransactionError)errors;
+}
+
+bool OSystem_GP2X::setGraphicsMode(int mode) {
+ Common::StackLock lock(_graphicsMutex);
+
+ assert(_transactionMode == kTransactionActive);
+
+ if (_oldVideoMode.setup && _oldVideoMode.mode == mode)
+ return true;
+
+ int newScaleFactor = 1;
+
+ switch (mode) {
+ case GFX_NORMAL:
+ newScaleFactor = 1;
+ break;
+ default:
+ warning("unknown gfx mode %d", mode);
+ return false;
+ }
+
+ _transactionDetails.normal1xScaler = (mode == GFX_NORMAL);
+ if (_oldVideoMode.setup && _oldVideoMode.scaleFactor != newScaleFactor)
+ _transactionDetails.needHotswap = true;
+
+ _transactionDetails.needUpdatescreen = true;
+
+ _videoMode.mode = mode;
+ _videoMode.scaleFactor = newScaleFactor;
+
+ return true;
+}
+
+void OSystem_GP2X::setGraphicsModeIntern() {
+ Common::StackLock lock(_graphicsMutex);
+ ScalerProc *newScalerProc = 0;
+
+ switch (_videoMode.mode) {
+ case GFX_NORMAL:
+ newScalerProc = Normal1x;
+ break;
+
+ default:
+ error("Unknown gfx mode %d", _videoMode.mode);
+ }
+
+ _scalerProc = newScalerProc;
+
+ if (_videoMode.mode != GFX_NORMAL) {
+ for (int i = 0; i < ARRAYSIZE(s_gfxModeSwitchTable); i++) {
+ if (s_gfxModeSwitchTable[i][1] == _videoMode.mode || s_gfxModeSwitchTable[i][2] == _videoMode.mode) {
+ _scalerType = i;
+ break;
+ }
+ }
+ }
+
+ if (!_screen || !_hwscreen)
+ return;
+
+ // Blit everything to the screen
+ _forceFull = true;
+
+ // Even if the old and new scale factors are the same, we may have a
+ // different scaler for the cursor now.
+ blitCursor();
+}
+
+int OSystem_GP2X::getGraphicsMode() const {
+ assert (_transactionMode == kTransactionNone);
+ return _videoMode.mode;
+}
+
+void OSystem_GP2X::initSize(uint w, uint h, const Graphics::PixelFormat *format) {
+ assert(_transactionMode == kTransactionActive);
+
+#ifdef USE_RGB_COLOR
+ //avoid redundant format changes
+ Graphics::PixelFormat newFormat;
+ if (!format)
+ newFormat = Graphics::PixelFormat::createFormatCLUT8();
+ else
+ newFormat = *format;
+
+ assert(newFormat.bytesPerPixel > 0);
+
+ if (newFormat != _videoMode.format)
+ {
+ _videoMode.format = newFormat;
+ _transactionDetails.formatChanged = true;
+ _screenFormat = newFormat;
+ }
+#endif
+
+ // Avoid redundant res changes
+ if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight)
+ return;
+
+ _videoMode.screenWidth = w;
+ _videoMode.screenHeight = h;
+
+ _transactionDetails.sizeChanged = true;
+}
+
+int OSystem_GP2X::effectiveScreenHeight() const {
+ return (_videoMode.aspectRatioCorrection ? real2Aspect(_videoMode.screenHeight) : _videoMode.screenHeight)
+ * _videoMode.scaleFactor;
+}
+
+
+bool OSystem_GP2X::loadGFXMode() {
+ assert(_inited);
+ _forceFull = true;
+
+ int hwW, hwH;
+
+ _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
+ _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
+
+ if (_videoMode.screenHeight != 200 && _videoMode.screenHeight != 400)
+ _videoMode.aspectRatioCorrection = false;
+
+ if (_videoMode.aspectRatioCorrection)
+ _videoMode.overlayHeight = real2Aspect(_videoMode.overlayHeight);
+
+ hwW = _videoMode.screenWidth * _videoMode.scaleFactor;
+
+ if (_videoMode.screenHeight == 200) {
+ hwH = 240;
+ } else if (_videoMode.screenHeight == 400) {
+ hwH = 480;
+ } else {
+ hwH = _videoMode.screenHeight;
+ }
+
+ printf ("Game Screen Height: %d\n", hwH);
+
+ //
+ // Create the surface that contains the game data
+ //
+
+ _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, hwH, 8, 0, 0, 0, 0);
+ if (_screen == NULL)
+ error("allocating _screen failed");
+
+ //
+ // Create the surface that contains the scaled graphics in 16 bit mode
+ //
+
+ _hwscreen = SDL_SetVideoMode(hwW, hwH, 16, SDL_SWSURFACE | SDL_NOFRAME | SDL_FULLSCREEN);
+ if (_hwscreen == NULL) {
+ // DON'T use error(), as this tries to bring up the debug
+ // console, which WON'T WORK now that _hwscreen is hosed.
+
+ if (!_oldVideoMode.setup) {
+ warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
+ quit();
+ } else {
+ return false;
+ }
+ }
+
+ // GP2X Specific, must be called after any SDL_SetVideoMode to ensure the hardware cursor is off.
+ // Note: On the GP2X SDL_SetVideoMode recalls SDL_Init().
+ SDL_ShowCursor(SDL_DISABLE);
+
+ //
+ // Create the surface used for the graphics in 16 bit before scaling, and also the overlay
+ //
+
+ // Need some extra bytes around when using 2xSaI
+ _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + 3, _videoMode.screenHeight + 3,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_tmpscreen == NULL)
+ error("allocating _tmpscreen failed");
+
+ _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_overlayscreen == NULL)
+ error("allocating _overlayscreen failed");
+
+ _overlayFormat.bytesPerPixel = _overlayscreen->format->BytesPerPixel;
+
+ _overlayFormat.rLoss = _overlayscreen->format->Rloss;
+ _overlayFormat.gLoss = _overlayscreen->format->Gloss;
+ _overlayFormat.bLoss = _overlayscreen->format->Bloss;
+ _overlayFormat.aLoss = _overlayscreen->format->Aloss;
+
+ _overlayFormat.rShift = _overlayscreen->format->Rshift;
+ _overlayFormat.gShift = _overlayscreen->format->Gshift;
+ _overlayFormat.bShift = _overlayscreen->format->Bshift;
+ _overlayFormat.aShift = _overlayscreen->format->Ashift;
+
+ _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_tmpscreen2 == NULL)
+ error("allocating _tmpscreen2 failed");
+
+ _osdSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
+ _hwscreen->w,
+ _hwscreen->h,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+ if (_osdSurface == NULL)
+ error("allocating _osdSurface failed");
+ SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey);
+
+ // keyboard cursor control, some other better place for it?
+ _km.x_max = _videoMode.screenWidth * _videoMode.scaleFactor - 1;
+ _km.y_max = effectiveScreenHeight() - 1;
+ _km.delay_time = 25;
+ _km.last_time = 0;
+
+ // Distinguish 555 and 565 mode
+ if (_hwscreen->format->Rmask == 0x7C00)
+ InitScalers(555);
+ else
+ InitScalers(565);
+
+ return true;
+}
+
+void OSystem_GP2X::unloadGFXMode() {
+ if (_screen) {
+ SDL_FreeSurface(_screen);
+ _screen = NULL;
+ }
+
+ if (_hwscreen) {
+ SDL_FreeSurface(_hwscreen);
+ _hwscreen = NULL;
+ }
+
+ if (_tmpscreen) {
+ SDL_FreeSurface(_tmpscreen);
+ _tmpscreen = NULL;
+ }
+
+ if (_tmpscreen2) {
+ SDL_FreeSurface(_tmpscreen2);
+ _tmpscreen2 = NULL;
+ }
+
+ if (_overlayscreen) {
+ SDL_FreeSurface(_overlayscreen);
+ _overlayscreen = NULL;
+ }
+
+ if (_osdSurface) {
+ SDL_FreeSurface(_osdSurface);
+ _osdSurface = NULL;
+ }
+ DestroyScalers();
+}
+
+bool OSystem_GP2X::hotswapGFXMode() {
+ if (!_screen)
+ return false;
+
+ // Keep around the old _screen & _overlayscreen so we can restore the screen data
+ // after the mode switch.
+ SDL_Surface *old_screen = _screen;
+ SDL_Surface *old_overlayscreen = _overlayscreen;
+ _screen = NULL;
+ _overlayscreen = NULL;
+
+ // Release the HW screen surface
+ SDL_FreeSurface(_hwscreen); _hwscreen = NULL;
+
+ SDL_FreeSurface(_tmpscreen); _tmpscreen = NULL;
+ SDL_FreeSurface(_tmpscreen2); _tmpscreen2 = NULL;
+
+ // Release the OSD surface
+ SDL_FreeSurface(_osdSurface); _osdSurface = NULL;
+
+ // Setup the new GFX mode
+ if (!loadGFXMode()) {
+ unloadGFXMode();
+
+ _screen = old_screen;
+ _overlayscreen = old_overlayscreen;
+
+ return false;
+ }
+
+ // reset palette
+ SDL_SetColors(_screen, _currentPalette, 0, 256);
+
+ // Restore old screen content
+ SDL_BlitSurface(old_screen, NULL, _screen, NULL);
+ SDL_BlitSurface(old_overlayscreen, NULL, _overlayscreen, NULL);
+
+ // Free the old surfaces
+ SDL_FreeSurface(old_screen);
+ SDL_FreeSurface(old_overlayscreen);
+
+ // Update cursor to new scale
+ blitCursor();
+
+ // Blit everything to the screen
+ internUpdateScreen();
+
+ return true;
+}
+
+void OSystem_GP2X::updateScreen() {
+ assert (_transactionMode == kTransactionNone);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+ internUpdateScreen();
+}
+
+void OSystem_GP2X::internUpdateScreen() {
+ SDL_Surface *srcSurf, *origSurf;
+ int height, width;
+ ScalerProc *scalerProc;
+ int scale1;
+
+#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
+ assert(_hwscreen != NULL);
+ assert(_hwscreen->map->sw_data != NULL);
+#endif
+
+ // If the shake position changed, fill the dirty area with blackness
+ if (_currentShakePos != _newShakePos) {
+ SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _videoMode.scaleFactor, _newShakePos * _videoMode.scaleFactor};
+
+ if (_videoMode.aspectRatioCorrection && !_overlayVisible)
+ blackrect.h = real2Aspect(blackrect.h - 1) + 1;
+
+ SDL_FillRect(_hwscreen, &blackrect, 0);
+
+ _currentShakePos = _newShakePos;
+
+ _forceFull = true;
+ }
+
+ // Check whether the palette was changed in the meantime and update the
+ // screen surface accordingly.
+ if (_screen && _paletteDirtyEnd != 0) {
+ SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart,
+ _paletteDirtyStart,
+ _paletteDirtyEnd - _paletteDirtyStart);
+
+ _paletteDirtyEnd = 0;
+
+ _forceFull = true;
+ }
+ // OSD visible (i.e. non-transparent)?
+ if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
+ // Updated alpha value
+ const int diff = SDL_GetTicks() - _osdFadeStartTime;
+ if (diff > 0) {
+ if (diff >= kOSDFadeOutDuration) {
+ // Back to full transparency
+ _osdAlpha = SDL_ALPHA_TRANSPARENT;
+ } else {
+ // Do a linear fade out...
+ const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
+ _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration;
+ }
+ SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha);
+ _forceFull = true;
+ }
+ }
+
+ if (!_overlayVisible) {
+ origSurf = _screen;
+ srcSurf = _tmpscreen;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
+ scalerProc = _scalerProc;
+ scale1 = _videoMode.scaleFactor;
+ } else {
+ origSurf = _overlayscreen;
+ srcSurf = _tmpscreen2;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
+ scalerProc = Normal1x;
+
+ scale1 = 1;
+ }
+
+ // Add the area covered by the mouse cursor to the list of dirty rects if
+ // we have to redraw the mouse.
+ if (_mouseNeedsRedraw)
+ undrawMouse();
+
+ // Force a full redraw if requested
+ if (_forceFull) {
+ _numDirtyRects = 1;
+ _dirtyRectList[0].x = 0;
+ _dirtyRectList[0].y = 0;
+ _dirtyRectList[0].w = width;
+ _dirtyRectList[0].h = height;
+ }
+
+ // Only draw anything if necessary
+ if (_numDirtyRects > 0 || _mouseNeedsRedraw) {
+ SDL_Rect *r;
+ SDL_Rect dst;
+ uint32 srcPitch, dstPitch;
+ SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects;
+
+ for (r = _dirtyRectList; r != lastRect; ++r) {
+ dst = *r;
+ dst.x++; // Shift rect by one since 2xSai needs to access the data around
+ dst.y++; // any pixel to scale it, and we want to avoid mem access crashes.
+
+ if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+ }
+
+ SDL_LockSurface(srcSurf);
+ SDL_LockSurface(_hwscreen);
+
+ srcPitch = srcSurf->pitch;
+ dstPitch = _hwscreen->pitch;
+
+ for (r = _dirtyRectList; r != lastRect; ++r) {
+ register int dst_y = r->y + _currentShakePos;
+ register int dst_h = 0;
+ register int orig_dst_y = 0;
+ register int rx1 = r->x * scale1;
+
+ if (dst_y < height) {
+ dst_h = r->h;
+ if (dst_h > height - dst_y)
+ dst_h = height - dst_y;
+
+ orig_dst_y = dst_y;
+ dst_y = dst_y * scale1;
+
+ if (_videoMode.aspectRatioCorrection && !_overlayVisible)
+ dst_y = real2Aspect(dst_y);
+
+ assert(scalerProc != NULL);
+ scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
+ (byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h);
+ }
+
+ r->x = rx1;
+ r->y = dst_y;
+ r->w = r->w * scale1;
+ r->h = dst_h * scale1;
+
+ if (_videoMode.aspectRatioCorrection && orig_dst_y < height && !_overlayVisible)
+ r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1);
+ }
+ SDL_UnlockSurface(srcSurf);
+ SDL_UnlockSurface(_hwscreen);
+
+ // Readjust the dirty rect list in case we are doing a full update.
+ // This is necessary if shaking is active.
+ if (_forceFull) {
+ _dirtyRectList[0].y = 0;
+ _dirtyRectList[0].h = effectiveScreenHeight();
+ }
+
+ drawMouse();
+
+ if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
+ SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0);
+ }
+
+ // Finally, blit all our changes to the screen
+ SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
+ }
+
+ _numDirtyRects = 0;
+ _forceFull = false;
+ _mouseNeedsRedraw = false;
+}
+
+bool OSystem_GP2X::saveScreenshot(const char *filename) {
+ assert(_hwscreen != NULL);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+ return SDL_SaveBMP(_hwscreen, filename) == 0;
+}
+
+void OSystem_GP2X::setFullscreenMode(bool enable) {
+ Common::StackLock lock(_graphicsMutex);
+
+ if (_oldVideoMode.setup && _oldVideoMode.fullscreen == enable)
+ return;
+
+ if (_transactionMode == kTransactionActive) {
+ _videoMode.fullscreen = enable;
+ _transactionDetails.needHotswap = true;
+ }
+}
+
+void OSystem_GP2X::setAspectRatioCorrection(bool enable) {
+ Common::StackLock lock(_graphicsMutex);
+
+ if (_oldVideoMode.setup && _oldVideoMode.aspectRatioCorrection == enable)
+ return;
+
+ if (_transactionMode == kTransactionActive) {
+ _videoMode.aspectRatioCorrection = enable;
+ _transactionDetails.needHotswap = true;
+ }
+}
+
+void OSystem_GP2X::setZoomOnMouse() {
+ if (_adjustZoomOnMouse == true) {
+ _adjustZoomOnMouse = false;
+ return;
+ } else {
+ _adjustZoomOnMouse = true;
+ return;
+ }
+}
+
+void OSystem_GP2X::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
+ assert (_transactionMode == kTransactionNone);
+ assert(src);
+
+ if (_screen == NULL) {
+ warning("OSystem_GP2X::copyRectToScreen: _screen == NULL");
+ return;
+ }
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+ assert(x >= 0 && x < _videoMode.screenWidth);
+ assert(y >= 0 && y < _videoMode.screenHeight);
+ assert(h > 0 && y + h <= _videoMode.screenHeight);
+ assert(w > 0 && x + w <= _videoMode.screenWidth);
+
+ /* Clip the coordinates */
+ if (x < 0) {
+ w += x;
+ src -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ src -= y * pitch;
+ y = 0;
+ }
+
+ if (w > _videoMode.screenWidth - x) {
+ w = _videoMode.screenWidth - x;
+ }
+
+ if (h > _videoMode.screenHeight - y) {
+ h = _videoMode.screenHeight - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ addDirtyRect(x, y, w, h);
+
+ // Try to lock the screen surface
+ if (SDL_LockSurface(_screen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;
+
+ if (_videoMode.screenWidth == pitch && pitch == w) {
+ memcpy(dst, src, h*w);
+ } else {
+ do {
+ memcpy(dst, src, w);
+ src += pitch;
+ dst += _videoMode.screenWidth;
+ } while (--h);
+ }
+
+ // Unlock the screen surface
+ SDL_UnlockSurface(_screen);
+}
+
+Graphics::Surface *OSystem_GP2X::lockScreen() {
+ assert (_transactionMode == kTransactionNone);
+
+ // Lock the graphics mutex
+ lockMutex(_graphicsMutex);
+
+ // paranoia check
+ assert(!_screenIsLocked);
+ _screenIsLocked = true;
+
+ // Try to lock the screen surface
+ if (SDL_LockSurface(_screen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ _framebuffer.pixels = _screen->pixels;
+ _framebuffer.w = _screen->w;
+ _framebuffer.h = _screen->h;
+ _framebuffer.pitch = _screen->pitch;
+ _framebuffer.bytesPerPixel = 1;
+
+ return &_framebuffer;
+}
+
+void OSystem_GP2X::unlockScreen() {
+ assert (_transactionMode == kTransactionNone);
+
+ // paranoia check
+ assert(_screenIsLocked);
+ _screenIsLocked = false;
+
+ // Unlock the screen surface
+ SDL_UnlockSurface(_screen);
+
+ // Trigger a full screen update
+ _forceFull = true;
+
+ // Finally unlock the graphics mutex
+ unlockMutex(_graphicsMutex);
+}
+
+void OSystem_GP2X::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) {
+ if (_forceFull)
+ return;
+
+ if (_numDirtyRects == NUM_DIRTY_RECT) {
+ _forceFull = true;
+ return;
+ }
+
+ int height, width;
+
+ if (!_overlayVisible && !realCoordinates) {
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
+ } else {
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
+ }
+
+ // Extend the dirty region by 1 pixel for scalers
+ // that "smear" the screen, e.g. 2xSAI
+ if (!realCoordinates) {
+ x--;
+ y--;
+ w+=2;
+ h+=2;
+ }
+
+ // clip
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ y=0;
+ }
+
+ if (w > width - x) {
+ w = width - x;
+ }
+
+ if (h > height - y) {
+ h = height - y;
+ }
+
+ if (_videoMode.aspectRatioCorrection && !_overlayVisible && !realCoordinates) {
+ makeRectStretchable(x, y, w, h);
+ }
+
+ if (w == width && h == height) {
+ _forceFull = true;
+ return;
+ }
+
+ if (w > 0 && h > 0) {
+ SDL_Rect *r = &_dirtyRectList[_numDirtyRects++];
+
+ r->x = x;
+ r->y = y;
+ r->w = w;
+ r->h = h;
+ }
+}
+
+int16 OSystem_GP2X::getHeight() {
+ return _videoMode.screenHeight;
+}
+
+int16 OSystem_GP2X::getWidth() {
+ return _videoMode.screenWidth;
+}
+
+void OSystem_GP2X::setPalette(const byte *colors, uint start, uint num) {
+ assert(colors);
+
+ // Setting the palette before _screen is created is allowed - for now -
+ // since we don't actually set the palette until the screen is updated.
+ // But it could indicate a programming error, so let's warn about it.
+
+ if (!_screen)
+ warning("OSystem_SDL::setPalette: _screen == NULL");
+
+ const byte *b = colors;
+ uint i;
+ SDL_Color *base = _currentPalette + start;
+ for (i = 0; i < num; i++) {
+ base[i].r = b[0];
+ base[i].g = b[1];
+ base[i].b = b[2];
+ b += 4;
+ }
+
+ if (start < _paletteDirtyStart)
+ _paletteDirtyStart = start;
+
+ if (start + num > _paletteDirtyEnd)
+ _paletteDirtyEnd = start + num;
+
+ // Some games blink cursors with palette
+ if (_cursorPaletteDisabled)
+ blitCursor();
+}
+
+void OSystem_GP2X::grabPalette(byte *colors, uint start, uint num) {
+ assert(colors);
+ const SDL_Color *base = _currentPalette + start;
+
+ for (uint i = 0; i < num; ++i) {
+ colors[i * 4] = base[i].r;
+ colors[i * 4 + 1] = base[i].g;
+ colors[i * 4 + 2] = base[i].b;
+ colors[i * 4 + 3] = 0xFF;
+ }
+}
+
+void OSystem_GP2X::setCursorPalette(const byte *colors, uint start, uint num) {
+ assert(colors);
+ const byte *b = colors;
+ uint i;
+ SDL_Color *base = _cursorPalette + start;
+ for (i = 0; i < num; i++) {
+ base[i].r = b[0];
+ base[i].g = b[1];
+ base[i].b = b[2];
+ b += 4;
+ }
+
+ _cursorPaletteDisabled = false;
+
+ blitCursor();
+}
+
+void OSystem_GP2X::setShakePos(int shake_pos) {
+ assert (_transactionMode == kTransactionNone);
+
+ _newShakePos = shake_pos;
+}
+
+#pragma mark -
+#pragma mark --- Overlays ---
+#pragma mark -
+
+void OSystem_GP2X::showOverlay() {
+ assert (_transactionMode == kTransactionNone);
+
+ int x, y;
+
+ if (_overlayVisible)
+ return;
+
+ _overlayVisible = true;
+
+ // Since resolution could change, put mouse to adjusted position
+ // Fixes bug #1349059
+ x = _mouseCurState.x * _videoMode.scaleFactor;
+ if (_videoMode.aspectRatioCorrection)
+ y = real2Aspect(_mouseCurState.y) * _videoMode.scaleFactor;
+ else
+ y = _mouseCurState.y * _videoMode.scaleFactor;
+
+ warpMouse(x, y);
+
+ clearOverlay();
+}
+
+void OSystem_GP2X::hideOverlay() {
+ assert (_transactionMode == kTransactionNone);
+
+ if (!_overlayVisible)
+ return;
+
+ int x, y;
+
+ _overlayVisible = false;
+
+ // Since resolution could change, put mouse to adjusted position
+ // Fixes bug #1349059
+ x = _mouseCurState.x / _videoMode.scaleFactor;
+ y = _mouseCurState.y / _videoMode.scaleFactor;
+ if (_videoMode.aspectRatioCorrection)
+ y = aspect2Real(y);
+
+ warpMouse(x, y);
+
+ clearOverlay();
+
+ _forceFull = true;
+}
+
+void OSystem_GP2X::clearOverlay() {
+ //assert (_transactionMode == kTransactionNone);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+ if (!_overlayVisible)
+ return;
+
+ // Clear the overlay by making the game screen "look through" everywhere.
+ SDL_Rect src, dst;
+ src.x = src.y = 0;
+ dst.x = dst.y = 1;
+ src.w = dst.w = _videoMode.screenWidth;
+ src.h = dst.h = _videoMode.screenHeight;
+ if (SDL_BlitSurface(_screen, &src, _tmpscreen, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+
+ SDL_LockSurface(_tmpscreen);
+ SDL_LockSurface(_overlayscreen);
+ _scalerProc((byte *)(_tmpscreen->pixels) + _tmpscreen->pitch + 2, _tmpscreen->pitch,
+ (byte *)_overlayscreen->pixels, _overlayscreen->pitch, _videoMode.screenWidth, _videoMode.screenHeight);
+
+#ifdef USE_SCALERS
+ if (_videoMode.aspectRatioCorrection)
+ stretch200To240((uint8 *)_overlayscreen->pixels, _overlayscreen->pitch,
+ _videoMode.overlayWidth, _videoMode.screenHeight * _videoMode.scaleFactor, 0, 0, 0);
+#endif
+ SDL_UnlockSurface(_tmpscreen);
+ SDL_UnlockSurface(_overlayscreen);
+
+ _forceFull = true;
+}
+
+void OSystem_GP2X::grabOverlay(OverlayColor *buf, int pitch) {
+ assert (_transactionMode == kTransactionNone);
+
+ if (_overlayscreen == NULL)
+ return;
+
+ if (SDL_LockSurface(_overlayscreen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *src = (byte *)_overlayscreen->pixels;
+ int h = _videoMode.overlayHeight;
+ do {
+ memcpy(buf, src, _videoMode.overlayWidth * 2);
+ src += _overlayscreen->pitch;
+ buf += pitch;
+ } while (--h);
+
+ SDL_UnlockSurface(_overlayscreen);
+}
+
+void OSystem_GP2X::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
+ assert (_transactionMode == kTransactionNone);
+
+ if (_overlayscreen == NULL)
+ return;
+
+ // Clip the coordinates
+ if (x < 0) {
+ w += x;
+ buf -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y; buf -= y * pitch;
+ y = 0;
+ }
+
+ if (w > _videoMode.overlayWidth - x) {
+ w = _videoMode.overlayWidth - x;
+ }
+
+ if (h > _videoMode.overlayHeight - y) {
+ h = _videoMode.overlayHeight - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ // Mark the modified region as dirty
+ addDirtyRect(x, y, w, h);
+
+ if (SDL_LockSurface(_overlayscreen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * 2;
+ do {
+ memcpy(dst, buf, w * 2);
+ dst += _overlayscreen->pitch;
+ buf += pitch;
+ } while (--h);
+
+ SDL_UnlockSurface(_overlayscreen);
+}
+
+
+#pragma mark -
+#pragma mark --- Mouse ---
+#pragma mark -
+
+bool OSystem_GP2X::showMouse(bool visible) {
+ if (_mouseVisible == visible)
+ return visible;
+
+ bool last = _mouseVisible;
+ _mouseVisible = visible;
+ _mouseNeedsRedraw = true;
+
+ return last;
+}
+
+void OSystem_GP2X::setMousePos(int x, int y) {
+ if (x != _mouseCurState.x || y != _mouseCurState.y) {
+ _mouseNeedsRedraw = true;
+ _mouseCurState.x = x;
+ _mouseCurState.y = y;
+ }
+}
+
+void OSystem_GP2X::warpMouse(int x, int y) {
+ int y1 = y;
+
+ if (_videoMode.aspectRatioCorrection && !_overlayVisible)
+ y1 = real2Aspect(y);
+
+ if (_mouseCurState.x != x || _mouseCurState.y != y) {
+ if (!_overlayVisible)
+ SDL_WarpMouse(x * _videoMode.scaleFactor, y1 * _videoMode.scaleFactor);
+ else
+ SDL_WarpMouse(x, y1);
+
+ // SDL_WarpMouse() generates a mouse movement event, so
+ // setMousePos() would be called eventually. However, the
+ // cannon script in CoMI calls this function twice each time
+ // the cannon is reloaded. Unless we update the mouse position
+ // immediately the second call is ignored, causing the cannon
+ // to change its aim.
+
+ setMousePos(x, y);
+ }
+}
+
+void OSystem_GP2X::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
+#ifdef USE_RGB_COLOR
+ if (!format)
+ _cursorFormat = Graphics::PixelFormat::createFormatCLUT8();
+ else if (format->bytesPerPixel <= _screenFormat.bytesPerPixel)
+ _cursorFormat = *format;
+ keycolor &= (1 << (_cursorFormat.bytesPerPixel << 3)) - 1;
+#else
+ keycolor &= 0xFF;
+#endif
+
+ if (w == 0 || h == 0)
+ return;
+
+ _mouseCurState.hotX = hotspot_x;
+ _mouseCurState.hotY = hotspot_y;
+
+ _mouseKeyColor = keycolor;
+
+ _cursorTargetScale = cursorTargetScale;
+
+ if (_mouseCurState.w != (int)w || _mouseCurState.h != (int)h) {
+ _mouseCurState.w = w;
+ _mouseCurState.h = h;
+
+ if (_mouseOrigSurface)
+ SDL_FreeSurface(_mouseOrigSurface);
+
+ // Allocate bigger surface because AdvMame2x adds black pixel at [0,0]
+ _mouseOrigSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
+ _mouseCurState.w + 2,
+ _mouseCurState.h + 2,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_mouseOrigSurface == NULL)
+ error("allocating _mouseOrigSurface failed");
+ SDL_SetColorKey(_mouseOrigSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey);
+ }
+
+ free(_mouseData);
+#ifdef USE_RGB_COLOR
+ _mouseData = (byte *)malloc(w * h * _cursorFormat.bytesPerPixel);
+ memcpy(_mouseData, buf, w * h * _cursorFormat.bytesPerPixel);
+#else
+ _mouseData = (byte *)malloc(w * h);
+ memcpy(_mouseData, buf, w * h);
+#endif
+
+ blitCursor();
+}
+
+void OSystem_GP2X::blitCursor() {
+ byte *dstPtr;
+ const byte *srcPtr = _mouseData;
+#ifdef USE_RGB_COLOR
+ uint32 color;
+ uint32 colormask = (1 << (_cursorFormat.bytesPerPixel << 3)) - 1;
+#else
+ byte color;
+#endif
+ int w, h, i, j;
+
+ if (!_mouseOrigSurface || !_mouseData)
+ return;
+
+ _mouseNeedsRedraw = true;
+
+ w = _mouseCurState.w;
+ h = _mouseCurState.h;
+
+ SDL_LockSurface(_mouseOrigSurface);
+
+ // Make whole surface transparent
+ for (i = 0; i < h + 2; i++) {
+ dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch * i;
+ for (j = 0; j < w + 2; j++) {
+ *(uint16 *)dstPtr = kMouseColorKey;
+ dstPtr += 2;
+ }
+ }
+
+ // Draw from [1,1] since AdvMame2x adds artefact at 0,0
+ dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2;
+
+ SDL_Color *palette;
+
+ if (_cursorPaletteDisabled)
+ palette = _currentPalette;
+ else
+ palette = _cursorPalette;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+#ifdef USE_RGB_COLOR
+ if (_cursorFormat.bytesPerPixel > 1) {
+ color = (*(uint32 *) srcPtr) & colormask;
+ if (color != _mouseKeyColor) { // transparent, don't draw
+ uint8 r,g,b;
+ _cursorFormat.colorToRGB(color,r,g,b);
+ *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format,
+ r, g, b);
+ }
+ dstPtr += 2;
+ srcPtr += _cursorFormat.bytesPerPixel;
+ } else {
+#endif
+ color = *srcPtr;
+ if (color != _mouseKeyColor) { // transparent, don't draw
+ *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format,
+ palette[color].r, palette[color].g, palette[color].b);
+ }
+ dstPtr += 2;
+ srcPtr++;
+#ifdef USE_RGB_COLOR
+ }
+#endif
+ }
+ dstPtr += _mouseOrigSurface->pitch - w * 2;
+ }
+
+ int rW, rH;
+
+ if (_cursorTargetScale >= _videoMode.scaleFactor) {
+ // The cursor target scale is greater or equal to the scale at
+ // which the rest of the screen is drawn. We do not downscale
+ // the cursor image, we draw it at its original size. It will
+ // appear too large on screen.
+
+ rW = w;
+ rH = h;
+ _mouseCurState.rHotX = _mouseCurState.hotX;
+ _mouseCurState.rHotY = _mouseCurState.hotY;
+
+ // The virtual dimensions may be larger than the original.
+
+ _mouseCurState.vW = w * _cursorTargetScale / _videoMode.scaleFactor;
+ _mouseCurState.vH = h * _cursorTargetScale / _videoMode.scaleFactor;
+ _mouseCurState.vHotX = _mouseCurState.hotX * _cursorTargetScale /
+ _videoMode.scaleFactor;
+ _mouseCurState.vHotY = _mouseCurState.hotY * _cursorTargetScale /
+ _videoMode.scaleFactor;
+ } else {
+ // The cursor target scale is smaller than the scale at which
+ // the rest of the screen is drawn. We scale up the cursor
+ // image to make it appear correct.
+
+ rW = w * _videoMode.scaleFactor / _cursorTargetScale;
+ rH = h * _videoMode.scaleFactor / _cursorTargetScale;
+ _mouseCurState.rHotX = _mouseCurState.hotX * _videoMode.scaleFactor /
+ _cursorTargetScale;
+ _mouseCurState.rHotY = _mouseCurState.hotY * _videoMode.scaleFactor /
+ _cursorTargetScale;
+
+ // The virtual dimensions will be the same as the original.
+
+ _mouseCurState.vW = w;
+ _mouseCurState.vH = h;
+ _mouseCurState.vHotX = _mouseCurState.hotX;
+ _mouseCurState.vHotY = _mouseCurState.hotY;
+ }
+
+ int rH1 = rH; // store original to pass to aspect-correction function later
+
+ if (_videoMode.aspectRatioCorrection && _cursorTargetScale == 1) {
+ rH = real2Aspect(rH - 1) + 1;
+ _mouseCurState.rHotY = real2Aspect(_mouseCurState.rHotY);
+ }
+
+ if (_mouseCurState.rW != rW || _mouseCurState.rH != rH) {
+ _mouseCurState.rW = rW;
+ _mouseCurState.rH = rH;
+
+ if (_mouseSurface)
+ SDL_FreeSurface(_mouseSurface);
+
+ _mouseSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
+ _mouseCurState.rW,
+ _mouseCurState.rH,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_mouseSurface == NULL)
+ error("allocating _mouseSurface failed");
+
+ SDL_SetColorKey(_mouseSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey);
+ }
+
+ SDL_LockSurface(_mouseSurface);
+
+ ScalerProc *scalerProc;
+
+ if (_cursorTargetScale == 1 && _videoMode.screenWidth > 320) {
+ scalerProc = scalersMagn[_cursorTargetScale + 1][_videoMode.scaleFactor + 1];
+ } else {
+ scalerProc = scalersMagn[_cursorTargetScale - 1][_videoMode.scaleFactor - 1];
+ }
+
+ scalerProc((byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2,
+ _mouseOrigSurface->pitch, (byte *)_mouseSurface->pixels, _mouseSurface->pitch,
+ _mouseCurState.w, _mouseCurState.h);
+
+ if (_videoMode.aspectRatioCorrection && _cursorTargetScale == 1)
+ cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, rW, rH1, 0, 0, 0);
+
+ SDL_UnlockSurface(_mouseSurface);
+ SDL_UnlockSurface(_mouseOrigSurface);
+}
+
+// Basically it is kVeryFastAndUglyAspectMode of stretch200To240 from
+// common/scale/aspect.cpp
+static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY) {
+ int maxDstY = real2Aspect(origSrcY + height - 1);
+ int y;
+ const uint8 *startSrcPtr = buf + srcX * 2 + (srcY - origSrcY) * pitch;
+ uint8 *dstPtr = buf + srcX * 2 + maxDstY * pitch;
+
+ for (y = maxDstY; y >= srcY; y--) {
+ const uint8 *srcPtr = startSrcPtr + aspect2Real(y) * pitch;
+
+ if (srcPtr == dstPtr)
+ break;
+ memcpy(dstPtr, srcPtr, width * 2);
+ dstPtr -= pitch;
+ }
+
+ return 1 + maxDstY - srcY;
+}
+
+void OSystem_GP2X::toggleMouseGrab() {
+ if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF)
+ SDL_WM_GrabInput(SDL_GRAB_ON);
+ else
+ SDL_WM_GrabInput(SDL_GRAB_OFF);
+}
+
+void OSystem_GP2X::undrawMouse() {
+ const int x = _mouseBackup.x;
+ const int y = _mouseBackup.y;
+
+ // When we switch bigger overlay off mouse jumps. Argh!
+ // This is intended to prevent undrawing offscreen mouse
+ if (!_overlayVisible && (x >= _videoMode.screenWidth || y >= _videoMode.screenHeight))
+ return;
+
+ if (_mouseBackup.w != 0 && _mouseBackup.h != 0)
+ addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h);
+}
+
+void OSystem_GP2X::drawMouse() {
+ if (!_mouseVisible || !_mouseSurface) {
+ _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
+ return;
+ }
+
+ SDL_Rect zoomdst;
+ SDL_Rect dst;
+ int scale;
+ int hotX, hotY;
+ int tmpScreenWidth, tmpScreenHeight;
+
+ // Temp vars to ensure we zoom to the LCD resolution or greater.
+ tmpScreenWidth = _videoMode.screenWidth;
+ tmpScreenHeight = _videoMode.screenHeight;
+
+ if (_videoMode.screenHeight <= 240) {
+ tmpScreenHeight = 240;
+ }
+
+ if (_videoMode.screenWidth <= 320) {
+ tmpScreenWidth = 320;
+ }
+
+ dst.x = _mouseCurState.x;
+ dst.y = _mouseCurState.y;
+
+ if (!_overlayVisible) {
+ scale = _videoMode.scaleFactor;
+ dst.w = _mouseCurState.vW;
+ dst.h = _mouseCurState.vH;
+ hotX = _mouseCurState.vHotX;
+ hotY = _mouseCurState.vHotY;
+ } else {
+ scale = 1;
+ dst.w = _mouseCurState.rW;
+ dst.h = _mouseCurState.rH;
+ hotX = _mouseCurState.rHotX;
+ hotY = _mouseCurState.rHotY;
+ }
+
+ // The mouse is undrawn using virtual coordinates, i.e. they may be
+ // scaled and aspect-ratio corrected.
+
+ _mouseBackup.x = dst.x - hotX;
+ _mouseBackup.y = dst.y - hotY;
+ _mouseBackup.w = dst.w;
+ _mouseBackup.h = dst.h;
+
+ // We draw the pre-scaled cursor image, so now we need to adjust for
+ // scaling, shake position and aspect ratio correction manually.
+
+ if (!_overlayVisible) {
+ dst.y += _currentShakePos;
+ }
+
+ if (_videoMode.aspectRatioCorrection && !_overlayVisible)
+ dst.y = real2Aspect(dst.y);
+
+ dst.x = scale * dst.x - _mouseCurState.rHotX;
+ dst.y = scale * dst.y - _mouseCurState.rHotY;
+ dst.w = _mouseCurState.rW;
+ dst.h = _mouseCurState.rH;
+
+ // Hacking about with the zoom around mouse pointer stuff.
+ if (_adjustZoomOnMouse == true){
+
+ zoomdst.w = (tmpScreenWidth / 2);
+ zoomdst.h = (tmpScreenHeight / 2);
+
+ // Create a zoomed rect centered on the mouse pointer.
+ // Will pan 1/4 of the screen.
+
+ if (dst.x > ((tmpScreenWidth / 4) * 3)) {
+ zoomdst.x = (tmpScreenWidth / 2);
+ } else {
+ zoomdst.x = (dst.x - (tmpScreenWidth / 4));
+ if (zoomdst.x < 0) {
+ zoomdst.x = 0;
+ }
+ }
+
+ if (dst.y > ((tmpScreenHeight / 4) * 3)) {
+ zoomdst.y = (tmpScreenHeight / 2);
+ } else {
+ zoomdst.y = (dst.y - (tmpScreenHeight / 4));
+ if (zoomdst.y < 0) {
+ zoomdst.y = 0;
+ }
+ }
+ SDL_GP2X_Display(&zoomdst);
+ } else {
+
+ // Make sure we are looking at the whole screen otherwise.
+
+ zoomdst.x = 0;
+ zoomdst.y = 0;
+ zoomdst.w = (tmpScreenWidth);
+ zoomdst.h = (tmpScreenHeight);
+
+ SDL_GP2X_Display(&zoomdst);
+ };
+
+ // Note that SDL_BlitSurface() and addDirtyRect() will both perform any
+ // clipping necessary
+
+ if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+
+ // The screen will be updated using real surface coordinates, i.e.
+ // they will not be scaled or aspect-ratio corrected.
+
+ addDirtyRect(dst.x, dst.y, dst.w, dst.h, true);
+}
+
+#pragma mark -
+#pragma mark --- On Screen Display ---
+#pragma mark -
+
+void OSystem_GP2X::displayMessageOnOSD(const char *msg) {
+ assert (_transactionMode == kTransactionNone);
+ assert(msg);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+ uint i;
+
+ // Lock the OSD surface for drawing
+ if (SDL_LockSurface(_osdSurface))
+ error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError());
+
+ Graphics::Surface dst;
+ dst.pixels = _osdSurface->pixels;
+ dst.w = _osdSurface->w;
+ dst.h = _osdSurface->h;
+ dst.pitch = _osdSurface->pitch;
+ dst.bytesPerPixel = _osdSurface->format->BytesPerPixel;
+
+ // The font we are going to use:
+ const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kOSDFont);
+
+ // Clear everything with the "transparent" color, i.e. the colorkey
+ SDL_FillRect(_osdSurface, 0, kOSDColorKey);
+
+ // Split the message into separate lines.
+ Common::StringArray lines;
+ const char *ptr;
+ for (ptr = msg; *ptr; ++ptr) {
+ if (*ptr == '\n') {
+ lines.push_back(Common::String(msg, ptr - msg));
+ msg = ptr + 1;
+ }
+ }
+ lines.push_back(Common::String(msg, ptr - msg));
+
+ // Determine a rect which would contain the message string (clipped to the
+ // screen dimensions).
+ const int vOffset = 6;
+ const int lineSpacing = 1;
+ const int lineHeight = font->getFontHeight() + 2 * lineSpacing;
+ int width = 0;
+ int height = lineHeight * lines.size() + 2 * vOffset;
+ for (i = 0; i < lines.size(); i++) {
+ width = MAX(width, font->getStringWidth(lines[i]) + 14);
+ }
+
+ // Clip the rect
+ if (width > dst.w)
+ width = dst.w;
+ if (height > dst.h)
+ height = dst.h;
+
+ // Draw a dark gray rect
+ // TODO: Rounded corners ? Border?
+ SDL_Rect osdRect;
+ osdRect.x = (dst.w - width) / 2;
+ osdRect.y = (dst.h - height) / 2;
+ osdRect.w = width;
+ osdRect.h = height;
+ SDL_FillRect(_osdSurface, &osdRect, SDL_MapRGB(_osdSurface->format, 64, 64, 64));
+
+ // Render the message, centered, and in white
+ for (i = 0; i < lines.size(); i++) {
+ font->drawString(&dst, lines[i],
+ osdRect.x, osdRect.y + i * lineHeight + vOffset + lineSpacing, osdRect.w,
+ SDL_MapRGB(_osdSurface->format, 255, 255, 255),
+ Graphics::kTextAlignCenter);
+ }
+
+ // Finished drawing, so unlock the OSD surface again
+ SDL_UnlockSurface(_osdSurface);
+
+ // Init the OSD display parameters, and the fade out
+ _osdAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
+ _osdFadeStartTime = SDL_GetTicks() + kOSDFadeOutDelay;
+ SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha);
+
+ // Ensure a full redraw takes place next time the screen is updated
+ _forceFull = true;
+}
+
+#pragma mark -
+#pragma mark --- Misc ---
+#pragma mark -
+
+bool OSystem_GP2X::handleScalerHotkeys(const SDL_KeyboardEvent &key) {
+ // Ctrl-Alt-a toggles aspect ratio correction
+ if (key.keysym.sym == 'a') {
+ beginGFXTransaction();
+ setFeatureState(kFeatureAspectRatioCorrection, !_videoMode.aspectRatioCorrection);
+ endGFXTransaction();
+ char buffer[128];
+ if (_videoMode.aspectRatioCorrection)
+ sprintf(buffer, "Enabled aspect ratio correction\n%d x %d -> %d x %d",
+ _videoMode.screenWidth, _videoMode.screenHeight,
+ _hwscreen->w, _hwscreen->h
+ );
+ else
+ sprintf(buffer, "Disabled aspect ratio correction\n%d x %d -> %d x %d",
+ _videoMode.screenWidth, _videoMode.screenHeight,
+ _hwscreen->w, _hwscreen->h
+ );
+ displayMessageOnOSD(buffer);
+
+ internUpdateScreen();
+ return true;
+ }
+
+ int newMode = -1;
+ int factor = _videoMode.scaleFactor - 1;
+
+ // Increase/decrease the scale factor
+ if (key.keysym.sym == SDLK_EQUALS || key.keysym.sym == SDLK_PLUS || key.keysym.sym == SDLK_MINUS ||
+ key.keysym.sym == SDLK_KP_PLUS || key.keysym.sym == SDLK_KP_MINUS) {
+ factor += (key.keysym.sym == SDLK_MINUS || key.keysym.sym == SDLK_KP_MINUS) ? -1 : +1;
+ if (0 <= factor && factor <= 3) {
+ newMode = s_gfxModeSwitchTable[_scalerType][factor];
+ }
+ }
+
+ const bool isNormalNumber = (SDLK_1 <= key.keysym.sym && key.keysym.sym <= SDLK_9);
+ const bool isKeypadNumber = (SDLK_KP1 <= key.keysym.sym && key.keysym.sym <= SDLK_KP9);
+ if (isNormalNumber || isKeypadNumber) {
+ _scalerType = key.keysym.sym - (isNormalNumber ? SDLK_1 : SDLK_KP1);
+ if (_scalerType >= ARRAYSIZE(s_gfxModeSwitchTable))
+ return false;
+
+ while (s_gfxModeSwitchTable[_scalerType][factor] < 0) {
+ assert(factor > 0);
+ factor--;
+ }
+ newMode = s_gfxModeSwitchTable[_scalerType][factor];
+ }
+
+ if (newMode >= 0) {
+ beginGFXTransaction();
+ setGraphicsMode(newMode);
+ endGFXTransaction();
+
+ if (_osdSurface) {
+ const char *newScalerName = 0;
+ const GraphicsMode *g = getSupportedGraphicsModes();
+ while (g->name) {
+ if (g->id == _videoMode.mode) {
+ newScalerName = g->description;
+ break;
+ }
+ g++;
+ }
+ if (newScalerName) {
+ char buffer[128];
+ sprintf(buffer, "Active graphics filter: %s\n%d x %d -> %d x %d",
+ newScalerName,
+ _videoMode.screenWidth, _videoMode.screenHeight,
+ _hwscreen->w, _hwscreen->h
+ );
+ displayMessageOnOSD(buffer);
+ }
+ }
+ internUpdateScreen();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool OSystem_GP2X::isScalerHotkey(const Common::Event &event) {
+ if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) {
+ const bool isNormalNumber = (Common::KEYCODE_1 <= event.kbd.keycode && event.kbd.keycode <= Common::KEYCODE_9);
+ const bool isKeypadNumber = (Common::KEYCODE_KP1 <= event.kbd.keycode && event.kbd.keycode <= Common::KEYCODE_KP9);
+ const bool isScaleKey = (event.kbd.keycode == Common::KEYCODE_EQUALS || event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS ||
+ event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS);
+
+ if (isNormalNumber || isKeypadNumber) {
+ int keyValue = event.kbd.keycode - (isNormalNumber ? Common::KEYCODE_1 : Common::KEYCODE_KP1);
+ if (keyValue >= ARRAYSIZE(s_gfxModeSwitchTable))
+ return false;
+ }
+ return (isScaleKey || event.kbd.keycode == 'a');
+ }
+ return false;
+}
diff --git a/backends/platform/gp2x/module.mk b/backends/platform/gp2x/module.mk
index 837ad99d7b..d4f145c64f 100644
--- a/backends/platform/gp2x/module.mk
+++ b/backends/platform/gp2x/module.mk
@@ -2,9 +2,10 @@ MODULE := backends/platform/gp2x
MODULE_OBJS := \
gp2x-hw.o \
- gp2x-main.o \
gp2x-mem.o \
- gp2x.o
+ events.o \
+ graphics.o \
+ gp2x.o \
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/gph/build/README-GP2XWIZ b/backends/platform/gph/build/README-GP2XWIZ
deleted file mode 100644
index 269fa901c9..0000000000
--- a/backends/platform/gph/build/README-GP2XWIZ
+++ /dev/null
@@ -1,140 +0,0 @@
-ScummVM - GP2X WIZ SPECIFIC README - HEAD SVN
-------------------------------------------------------------------------
-
-Contents:
-
- * About the backend/port <#About_the_backendport>
- * Game compatability <#Game_compatibility>
- * Included engines <#Included_engines>
- * Supported audio options <#Supported_audio_options>
- * Supported cut-scene options <#Supported_cut-scene_options>
- * Recent changes <#Recent_changes>
- * How to save <#How_to_save>
- * Controller mappings <#Controller_mappings>
- * Known issues <#Knonw_issues>
- * Additional resources/links <#Additional_resourceslinks>
- * Credits <#Credits>
-
-------------------------------------------------------------------------
-
-Please refer to the:
-
-GP2X/GP2XWiz ScummVM Forum: <http://forums.scummvm.org/viewforum.php?f=14>
-WiKi: <http://wiki.scummvm.org/index.php/GP2XWiz>
-
-for the most current information on the port and any updates to this
-documentation.
-
-------------------------------------------------------------------------
-About the backend/port
-
-This is the readme for the official GP2XWiz ScummVM backend (also known as
-the GP2XWiz port).
-
-This is an SVN test release of ScummVM for the GP2XWiz, it would be
-appreciated if this SVN test distribution was not mirrored and that
-people be directed to http://scummvm.distant-earth.com/ instead for
-updated SVN builds.
-
-Full supported official releases of the GP2X WIZ ScummVM backend are made in
-line with main official releases and are avalalble from the ScummVM
-downloads page <http://www.scummvm.org/downloads.php>.
-
-This build is in an active state of development and as such no
-"expected" behavior can be guaranteed ;).
-
-------------------------------------------------------------------------
-Game compatibility
-
-For information on the compatability of a specific game please refer to
-the GP2XWiz compatability section of the ScummVM WiKi
-<http://wiki.scummvm.org/index.php/GP2XWiz#Compatibility_List>.
-
-Please note the version and date of the ScummVM build you are running
-when reviewing the above list.
-
-------------------------------------------------------------------------
-Supported audio options
-
-Raw audio.
-MP3 audio.
-OGG Vorbis audio.
-
-FLAC audio is currently unsupported.
-
-For best results use uncompressed audio in games.
-
-------------------------------------------------------------------------
-How to save
-
-NOTE: Everything is saved to the SD card, saves are stored in the saves
-folder under your main ScummVM executable unless you set another save
-location.
-
-The configiration file for ScummVM (.scummvmrc) is stored in the same
-place as the ScummVM executable.
-
-The save process below is for Scumm engine games but the principle is
-the same for all.
-
-In Game.
-
-1. Menu Button
-2. Select SAVE with B
-3. Select a position with B
-4. Right trigger puts 0 in the name box for some text.
-5. Press B to save
-
-Basically the emulated keys you can use are equivelent to the values
-buttons are mapped to,
-
-------------------------------------------------------------------------
-Controller mappings
-
-Touch screen:
-Touch: Move Pointer and Left click
-
-Mouse emulation:
-
-dPad: Move Pointer
-B: Left click
-X: Right click
-
-Keyboard emulation:
-
-Right Trigger: Return
-Select: Escape
-Y: Space Bar (Pause)
-Menu: Game Menu (Save, Load, Quit etc.)
-Volume Buttons: Increase and Decrease volume
-
-Fancy button combos:
-
-NOTE: To use button combos press and hold the Left Trigger then...
-
-Right Trigger: Display Virtual Keyboard
-Menu: Bring up the Global main menu for ScummVM
-Select: Exit ScummVM completely (and gracefully)
-
-------------------------------------------------------------------------
-Known issues
-
-No major known issues
-
-------------------------------------------------------------------------
-Additional resources/links
-
- * ScummVM WiKi GP2X page <http://wiki.scummvm.org/index.php/GP2X>
- * ScummVM forums GP2X forum
- <http://forums.scummvm.org/viewforum.php?f=14>
- * My own ScummVM page <http://scummvm.distant-earth.com/> (for
- SVN/test builds)
- * Main ScummVM site <http://www.scummvm.org> (for official supported
- release builds)
-
-------------------------------------------------------------------------
-Credits
-
-Core ScummVM code (c) The ScummVM Team
-GP2X Wiz backend (c) John Willis
-Detailed (c) information can be found within the source code
diff --git a/backends/platform/gph/build/README-GPH b/backends/platform/gph/build/README-GPH
new file mode 100644
index 0000000000..64b9fcb76b
--- /dev/null
+++ b/backends/platform/gph/build/README-GPH
@@ -0,0 +1,60 @@
+ScummVM - GPH SPECIFIC README
+------------------------------------------------------------------------
+
+Contents:
+
+ * About the backend/port <#About_the_backendport>
+ * Supported audio options <#Supported_audio_options>
+ * Credits <#Credits>
+
+------------------------------------------------------------------------
+
+Please refer to the:
+
+GPH ScummVM Forum: <http://forums.scummvm.org/viewforum.php?f=14>
+
+WiKi: (Select your device)
+
+<http://wiki.scummvm.org/index.php/GP2X>
+<http://wiki.scummvm.org/index.php/GP2XWiz>
+<http://wiki.scummvm.org/index.php/Caanoo>
+
+for the most current information on the port and any updates to this
+documentation.
+
+The wiki includes detailed instructions on how to use the port and
+control information.
+
+------------------------------------------------------------------------
+About the backend/port
+
+This is the readme for the official GPH ScummVM backend (also known as
+the GP2X port/GP2XWiz port and Caanoo port).
+
+This is an SVN test release of ScummVM for GPH devices, it would be
+appreciated if this SVN test distribution was not mirrored and that
+people be directed to http://scummvm.distant-earth.com/ instead for
+updated SVN builds.
+
+Fully supported official releases of the GPH ScummVM backend are made in
+line with main official releases and are avalalble from the ScummVM
+downloads page <http://www.scummvm.org/downloads.php> for the GP2X,
+GP2XWiz and Caanoo.
+
+------------------------------------------------------------------------
+Supported audio options
+
+Raw audio.
+MP3 audio.
+OGG Vorbis audio.
+
+FLAC audio is currently unsupported.
+
+For best results use uncompressed audio in games.
+
+------------------------------------------------------------------------
+Credits
+
+Core ScummVM code (c) The ScummVM Team
+Portions of the GPH backend (c) John Willis
+Detailed (c) information can be found within the source code
diff --git a/backends/platform/gph/build/config-alleng.sh b/backends/platform/gph/build/config-alleng.sh
index cfed463edf..9ec8a09cd2 100755
--- a/backends/platform/gph/build/config-alleng.sh
+++ b/backends/platform/gph/build/config-alleng.sh
@@ -13,10 +13,15 @@ export CXX=arm-open2x-linux-g++
export CXXFLAGS="-mcpu=arm926ej-s -mtune=arm926ej-s"
export CPPFLAGS=-I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include
export LDFLAGS=-L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib
-export DEFINES=-DNDEBUG
# Edit the configure line to suit.
cd ../../../..
-./configure --backend=gp2xwiz --disable-mt32emu --host=gp2xwiz --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-all-engines --enable-vkeybd --enable-plugins --default-dynamic
+./configure --backend=gph --disable-mt32emu --host=gp2xwiz --disable-flac --disable-nasm --disable-hq-scalers \
+ --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-png --with-png-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-vkeybd --enable-all-engines --enable-plugins --default-dynamic
echo Generating config for GP2X Wiz complete. Check for errors.
diff --git a/backends/platform/gph/build/config.sh b/backends/platform/gph/build/config.sh
index 25c3a83da0..ac7c34ad12 100755
--- a/backends/platform/gph/build/config.sh
+++ b/backends/platform/gph/build/config.sh
@@ -13,10 +13,15 @@ export CXX=arm-open2x-linux-g++
export CXXFLAGS="-mcpu=arm926ej-s -mtune=arm926ej-s"
export CPPFLAGS=-I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include
export LDFLAGS=-L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib
-export DEFINES=-DNDEBUG
# Edit the configure line to suit.
cd ../../../..
-./configure --backend=gp2xwiz --disable-mt32emu --host=gp2xwiz --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-vkeybd --enable-plugins --default-dynamic
+./configure --backend=gph --disable-mt32emu --host=gp2xwiz --disable-flac --disable-nasm --disable-hq-scalers \
+ --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-png --with-png-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \
+ --enable-vkeybd --enable-plugins --default-dynamic
echo Generating config for GP2X Wiz complete. Check for errors.
diff --git a/backends/platform/gph/build/scummvm-gdb.gpe b/backends/platform/gph/build/scummvm-gdb.gpe
index f486c288ee..63ce193ca8 100755
--- a/backends/platform/gph/build/scummvm-gdb.gpe
+++ b/backends/platform/gph/build/scummvm-gdb.gpe
@@ -6,7 +6,7 @@ export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH
# Run ScummVM via GDB (so make sure you have a terminal open or serial).
# Oh, and GDB installed of course ;)
-gdb --args ./scummvm.wiz --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc
+gdb --args ./scummvm.gph --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc
# Sync the SD card to check that everything is written.
sync
diff --git a/backends/platform/gph/build/scummvm.gpe b/backends/platform/gph/build/scummvm.gpe
index 2866825e91..59ff562aeb 100755
--- a/backends/platform/gph/build/scummvm.gpe
+++ b/backends/platform/gph/build/scummvm.gpe
@@ -5,7 +5,7 @@
export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH
# Run ScummVM, important this bit.
-./scummvm.wiz --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc
+./scummvm.gph --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc
# Sync the SD card to check that everything is written.
sync
diff --git a/backends/platform/gph/caanoo-bundle.mk b/backends/platform/gph/caanoo-bundle.mk
index c411310688..b7b3c9e188 100755
--- a/backends/platform/gph/caanoo-bundle.mk
+++ b/backends/platform/gph/caanoo-bundle.mk
@@ -17,7 +17,7 @@ caanoo-bundle: $(EXECUTABLE)
$(CP) $(srcdir)/backends/platform/gph/caanoo/scummvm.gpe $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.png $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvmb.png $(bundle_name)/scummvm/
- $(CP) $(srcdir)/backends/platform/gph/build/README-GP2XWIZ $(bundle_name)/scummvm/README-CAANOO
+ $(CP) $(srcdir)/backends/platform/gph/build/README-GPH $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.ini $(bundle_name)/
$(INSTALL) -c -m 644 $(DIST_FILES_DOCS) $(bundle_name)/scummvm/
@@ -48,7 +48,7 @@ caanoo-bundle-debug: $(EXECUTABLE)
$(CP) $(srcdir)/backends/platform/gph/caanoo/scummvm-gdb.gpe $(bundle_name)/scummvm/scummvm.gpe
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.png $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvmb.png $(bundle_name)/scummvm/
- $(CP) $(srcdir)/backends/platform/gph/build/README-GP2XWIZ $(bundle_name)/scummvm/README-CAANOO
+ $(CP) $(srcdir)/backends/platform/gph/build/README-GPH $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.ini $(bundle_name)/
$(INSTALL) -c -m 644 $(DIST_FILES_DOCS) $(bundle_name)/scummvm/
diff --git a/backends/platform/gph/caanoo/config-alleng.sh b/backends/platform/gph/caanoo/config-alleng.sh
index 7a097c268b..97fed942fa 100755
--- a/backends/platform/gph/caanoo/config-alleng.sh
+++ b/backends/platform/gph/caanoo/config-alleng.sh
@@ -3,14 +3,19 @@
echo Quick script to make running configure all the time less painful
echo and let all the build work be done from the backend/build folder.
-# Assume Caanoo toolchain/build env.
+# Assume Caanoo toolchain/build env and source it.
. /opt/arm-caanoo/environment-setup
-# Export the tool names for cross-compiling
-export DEFINES=-DNDEBUG
-
# Edit the configure line to suit.
cd ../../../..
-./configure --backend=caanoo --disable-mt32emu --host=caanoo --disable-alsa --disable-flac --disable-nasm --disable-vorbis --disable-hq-scalers --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-mad --with-mad-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-all-engines --enable-vkeybd --enable-plugins --default-dynamic
+./configure --backend=caanoo --disable-mt32emu --host=caanoo --disable-alsa --disable-flac \
+ --disable-nasm --disable-vorbis --disable-hq-scalers \
+ --with-sdl-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr/bin \
+ --with-mpeg2-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-tremor --with-tremor-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-zlib --with-zlib-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-mad --with-mad-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-png --with-png-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-all-engines --enable-vkeybd --enable-plugins --default-dynamic
-echo Generating config for GP2X Caanoo complete. Check for errors.
+echo Generating config for Caanoo complete. Check for errors.
diff --git a/backends/platform/gph/caanoo/config.sh b/backends/platform/gph/caanoo/config.sh
index 82e3774dbf..11d597481a 100755
--- a/backends/platform/gph/caanoo/config.sh
+++ b/backends/platform/gph/caanoo/config.sh
@@ -6,11 +6,16 @@ echo and let all the build work be done from the backend/build folder.
# Assume Caanoo toolchain/build env.
. /opt/arm-caanoo/environment-setup
-# Export the tool names for cross-compiling
-export DEFINES=-DNDEBUG
-
# Edit the configure line to suit.
cd ../../../..
-./configure --backend=caanoo --disable-mt32emu --host=caanoo --disable-alsa --disable-flac --disable-nasm --disable-vorbis --disable-hq-scalers --with-sdl-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr/bin --with-mpeg2-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-tremor --with-tremor-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-zlib --with-zlib-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-mad --with-mad-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-vkeybd --enable-plugins --default-dynamic
+./configure --backend=caanoo --disable-mt32emu --host=caanoo --disable-alsa --disable-flac \
+ --disable-nasm --disable-vorbis --disable-hq-scalers \
+ --with-sdl-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr/bin \
+ --with-mpeg2-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-tremor --with-tremor-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-zlib --with-zlib-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-mad --with-mad-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-png --with-png-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \
+ --enable-vkeybd --enable-plugins --default-dynamic
echo Generating config for GP2X Caanoo complete. Check for errors.
diff --git a/backends/platform/gph/caanoo/scummvm-gdb.gpe b/backends/platform/gph/caanoo/scummvm-gdb.gpe
index 2d776f1bc3..63ce193ca8 100755
--- a/backends/platform/gph/caanoo/scummvm-gdb.gpe
+++ b/backends/platform/gph/caanoo/scummvm-gdb.gpe
@@ -6,7 +6,7 @@ export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH
# Run ScummVM via GDB (so make sure you have a terminal open or serial).
# Oh, and GDB installed of course ;)
-gdb --args ./scummvm.caanoo --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc
+gdb --args ./scummvm.gph --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc
# Sync the SD card to check that everything is written.
sync
diff --git a/backends/platform/gph/caanoo/scummvm.gpe b/backends/platform/gph/caanoo/scummvm.gpe
index 52bb7a98cd..37d0f65d18 100755
--- a/backends/platform/gph/caanoo/scummvm.gpe
+++ b/backends/platform/gph/caanoo/scummvm.gpe
@@ -5,7 +5,7 @@
export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH
# Run ScummVM, important this bit.
-./scummvm.caanoo --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc
+./scummvm.gph --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc
# Sync the SD card to check that everything is written.
sync
diff --git a/backends/platform/gph/gp2xwiz-bundle.mk b/backends/platform/gph/gp2xwiz-bundle.mk
index 5ca6c0a9c7..df4cae7f4f 100755
--- a/backends/platform/gph/gp2xwiz-bundle.mk
+++ b/backends/platform/gph/gp2xwiz-bundle.mk
@@ -17,7 +17,7 @@ gp2xwiz-bundle: $(EXECUTABLE)
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.gpe $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.png $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvmb.png $(bundle_name)/scummvm/
- $(CP) $(srcdir)/backends/platform/gph/build/README-GP2XWIZ $(bundle_name)/scummvm/
+ $(CP) $(srcdir)/backends/platform/gph/build/README-GPH $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.ini $(bundle_name)/
$(INSTALL) -c -m 644 $(DIST_FILES_DOCS) $(bundle_name)/scummvm/
@@ -51,7 +51,7 @@ gp2xwiz-bundle-debug: $(EXECUTABLE)
$(CP) $(srcdir)/backends/platform/gph/build/scummvm-gdb.gpe $(bundle_name)/scummvm/scummvm.gpe
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.png $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvmb.png $(bundle_name)/scummvm/
- $(CP) $(srcdir)/backends/platform/gph/build/README-GP2XWIZ $(bundle_name)/scummvm/
+ $(CP) $(srcdir)/backends/platform/gph/build/README-GPH $(bundle_name)/scummvm/
$(CP) $(srcdir)/backends/platform/gph/build/scummvm.ini $(bundle_name)/
$(INSTALL) -c -m 644 $(DIST_FILES_DOCS) $(bundle_name)/scummvm/
diff --git a/backends/platform/gph/gph-events.cpp b/backends/platform/gph/gph-events.cpp
index 91ea30bdc9..2a6237c794 100644
--- a/backends/platform/gph/gph-events.cpp
+++ b/backends/platform/gph/gph-events.cpp
@@ -253,7 +253,6 @@ bool OSystem_GPH::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
event.type = Common::EVENT_MOUSEMOVE;
else
event.type = Common::EVENT_LBUTTONUP; /* For normal mice etc. */
-
}
else if (ev.button.button == SDL_BUTTON_RIGHT)
event.type = Common::EVENT_RBUTTONUP;
diff --git a/backends/platform/gph/gph-hw.cpp b/backends/platform/gph/gph-hw.cpp
index b43324b547..fa52526f01 100644
--- a/backends/platform/gph/gph-hw.cpp
+++ b/backends/platform/gph/gph-hw.cpp
@@ -28,6 +28,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/platform/gph/gph-hw.h"
#include <fcntl.h>
diff --git a/backends/platform/gph/gph-main.cpp b/backends/platform/gph/gph-main.cpp
index 727d599cc8..c433ba9f3f 100644
--- a/backends/platform/gph/gph-main.cpp
+++ b/backends/platform/gph/gph-main.cpp
@@ -23,9 +23,13 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#include <SDL/SDL.h>
+// #include "backends/platform/gph/gph-options.h"
#include "backends/platform/gph/gph-sdl.h"
#include "backends/platform/gph/gph-hw.h"
#include "backends/plugins/posix/posix-provider.h"
@@ -78,7 +82,7 @@ void OSystem_GPH::initBackend() {
char workDirName[PATH_MAX+1];
if (getcwd(workDirName, PATH_MAX) == NULL) {
- error("Could not obtain current working directory");
+ error("Could not obtain current working directory.");
} else {
printf("Current working directory: %s\n", workDirName);
}
@@ -158,6 +162,9 @@ void OSystem_GPH::initBackend() {
/* Make sure SDL knows that we have a joystick we want to use. */
ConfMan.setInt("joystick_num", 0);
+ /* Now setup any device specific user options (Left handed mode, that sort of thing). */
+ // GPH::setOptions();
+
printf("%s\n", "Passing to OSystem::SDL initBackend.");
/* Pass to SDL backend to do the heavy lifting */
@@ -170,7 +177,7 @@ void OSystem_GPH::addSysArchivesToSearchSet(Common::SearchSet &s, int priority)
char workDirName[PATH_MAX+1];
if (getcwd(workDirName, PATH_MAX) == NULL) {
- error("Error: Could not obtain current working directory");
+ error("Error: Could not obtain current working directory.");
}
Common::FSNode workdirNode(workDirName);
diff --git a/backends/platform/iphone/osys_events.cpp b/backends/platform/iphone/osys_events.cpp
index 22f529dfac..c30e34dd05 100644
--- a/backends/platform/iphone/osys_events.cpp
+++ b/backends/platform/iphone/osys_events.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "gui/message.h"
#include "common/translation.h"
diff --git a/backends/platform/iphone/osys_main.cpp b/backends/platform/iphone/osys_main.cpp
index a1fb8f0d5e..9dc4e202c4 100644
--- a/backends/platform/iphone/osys_main.cpp
+++ b/backends/platform/iphone/osys_main.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include <unistd.h>
#include <pthread.h>
diff --git a/backends/platform/iphone/osys_sound.cpp b/backends/platform/iphone/osys_sound.cpp
index 55892580f6..cd364f57ac 100644
--- a/backends/platform/iphone/osys_sound.cpp
+++ b/backends/platform/iphone/osys_sound.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "osys_main.h"
void OSystem_IPHONE::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) {
diff --git a/backends/platform/iphone/osys_video.cpp b/backends/platform/iphone/osys_video.cpp
index d30a412a9f..88368a0eec 100644
--- a/backends/platform/iphone/osys_video.cpp
+++ b/backends/platform/iphone/osys_video.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "osys_main.h"
const OSystem::GraphicsMode* OSystem_IPHONE::getSupportedGraphicsModes() const {
diff --git a/backends/events/linuxmotosdl/linuxmotosdl-events.cpp b/backends/platform/linuxmoto/linuxmoto-events.cpp
index abd8ad2da8..eb1bbc9394 100644
--- a/backends/events/linuxmotosdl/linuxmotosdl-events.cpp
+++ b/backends/platform/linuxmoto/linuxmoto-events.cpp
@@ -23,46 +23,49 @@
*
*/
-#if defined(LINUXMOTO)
-
-#include "backends/events/linuxmotosdl/linuxmotosdl-events.h"
#include "backends/platform/linuxmoto/linuxmoto-sdl.h"
+#include "graphics/scaler/aspect.h" // for aspect2Real
+
+static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) {
+ if (key >= SDLK_F1 && key <= SDLK_F9) {
+ return key - SDLK_F1 + Common::ASCII_F1;
+ } else if (key >= SDLK_KP0 && key <= SDLK_KP9) {
+ return key - SDLK_KP0 + '0';
+ } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) {
+ return key;
+ } else if (unicode) {
+ return unicode;
+ } else if (key >= 'a' && key <= 'z' && (mod & KMOD_SHIFT)) {
+ return key & ~0x20;
+ } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) {
+ return 0;
+ }
+ return key;
+}
-enum {
- GFX_HALF = 12
-};
-
-LinuxmotoSdlEventManager::LinuxmotoSdlEventManager(Common::EventSource *boss)
- :
- SdlEventManager(boss) {
+void OSystem_LINUXMOTO::fillMouseEvent(Common::Event &event, int x, int y) {
+ if (_videoMode.mode == GFX_HALF && !_overlayVisible) {
+ event.mouse.x = x*2;
+ event.mouse.y = y*2;
+ } else {
+ event.mouse.x = x;
+ event.mouse.y = y;
+ }
-}
+ // Update the "keyboard mouse" coords
+ _km.x = x;
+ _km.y = y;
-void LinuxmotoSdlEventManager::preprocessEvents(SDL_Event *event) {
- if (event->type == SDL_ACTIVEEVENT) {
- if (event->active.state == SDL_APPINPUTFOCUS && !event->active.gain) {
- ((OSystem_SDL* )g_system)->getMixerManager()->suspendAudio();
- for (;;) {
- if (!SDL_WaitEvent(event)) {
- SDL_Delay(10);
- continue;
- }
- if (event->type == SDL_QUIT)
- return;
- if (event->type != SDL_ACTIVEEVENT)
- continue;
- if (event->active.state == SDL_APPINPUTFOCUS && event->active.gain) {
- ((OSystem_SDL* )g_system)->getMixerManager()->resumeAudio();
- return;
- }
- }
- }
+ // Adjust for the screen scaling
+ if (!_overlayVisible) {
+ event.mouse.x /= _videoMode.scaleFactor;
+ event.mouse.y /= _videoMode.scaleFactor;
+ if (_videoMode.aspectRatioCorrection)
+ event.mouse.y = aspect2Real(event.mouse.y);
}
}
-bool LinuxmotoSdlEventManager::remapKey(SDL_Event &ev, Common::Event &event) {
- if (false) {}
-
+bool OSystem_LINUXMOTO::remapKey(SDL_Event &ev, Common::Event &event) {
// Motorol A1200/E6/A1600 remapkey by Lubomyr
#ifdef MOTOEZX
// Quit on MOD+Camera Key on A1200
@@ -223,5 +226,3 @@ bool LinuxmotoSdlEventManager::remapKey(SDL_Event &ev, Common::Event &event) {
return false;
}
-
-#endif
diff --git a/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.cpp b/backends/platform/linuxmoto/linuxmoto-graphics.cpp
index dbedb2e1a7..a39416ebc4 100644
--- a/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.cpp
+++ b/backends/platform/linuxmoto/linuxmoto-graphics.cpp
@@ -23,10 +23,8 @@
*
*/
-#ifdef LINUXMOTO
+#include "backends/platform/linuxmoto/linuxmoto-sdl.h"
-#include "backends/graphics/linuxmotosdl/linuxmotosdl-graphics.h"
-#include "backends/events/linuxmotosdl/linuxmotosdl-events.h"
#include "common/mutex.h"
#include "graphics/font.h"
#include "graphics/fontman.h"
@@ -35,25 +33,22 @@
#include "graphics/scaler/downscaler.h"
#include "graphics/surface.h"
-enum {
- GFX_HALF = 12
-};
-
static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
{"1x", "Fullscreen", GFX_NORMAL},
{"½x", "Downscale", GFX_HALF},
{0, 0, 0}
};
-const OSystem::GraphicsMode *LinuxmotoSdlGraphicsManager::getSupportedGraphicsModes() const {
+
+const OSystem::GraphicsMode *OSystem_LINUXMOTO::getSupportedGraphicsModes() const {
return s_supportedGraphicsModes;
}
-int LinuxmotoSdlGraphicsManager::getDefaultGraphicsMode() const {
+int OSystem_LINUXMOTO::getDefaultGraphicsMode() const {
return GFX_NORMAL;
}
-bool LinuxmotoSdlGraphicsManager::setGraphicsMode(int mode) {
+bool OSystem_LINUXMOTO::setGraphicsMode(int mode) {
Common::StackLock lock(_graphicsMutex);
assert(_transactionMode == kTransactionActive);
@@ -87,7 +82,7 @@ bool LinuxmotoSdlGraphicsManager::setGraphicsMode(int mode) {
return true;
}
-void LinuxmotoSdlGraphicsManager::setGraphicsModeIntern() {
+void OSystem_LINUXMOTO::setGraphicsModeIntern() {
Common::StackLock lock(_graphicsMutex);
ScalerProc *newScalerProc = 0;
@@ -117,7 +112,7 @@ void LinuxmotoSdlGraphicsManager::setGraphicsModeIntern() {
}
-void LinuxmotoSdlGraphicsManager::initSize(uint w, uint h) {
+void OSystem_LINUXMOTO::initSize(uint w, uint h) {
assert(_transactionMode == kTransactionActive);
// Avoid redundant res changes
@@ -130,13 +125,13 @@ void LinuxmotoSdlGraphicsManager::initSize(uint w, uint h) {
if (w > 320 || h > 240) {
setGraphicsMode(GFX_HALF);
setGraphicsModeIntern();
- ((LinuxmotoSdlEventManager *)g_system->getEventManager())->toggleMouseGrab();
+ toggleMouseGrab();
}
_transactionDetails.sizeChanged = true;
}
-bool LinuxmotoSdlGraphicsManager::loadGFXMode() {
+bool OSystem_LINUXMOTO::loadGFXMode() {
printf("Game ScreenMode = %d*%d\n",_videoMode.screenWidth, _videoMode.screenHeight);
if (_videoMode.screenWidth > 320 || _videoMode.screenHeight > 240) {
_videoMode.aspectRatioCorrection = false;
@@ -162,10 +157,10 @@ bool LinuxmotoSdlGraphicsManager::loadGFXMode() {
_videoMode.hardwareHeight = effectiveScreenHeight();
}
- return SdlGraphicsManager::loadGFXMode();
+ return OSystem_SDL::loadGFXMode();
}
-void LinuxmotoSdlGraphicsManager::drawMouse() {
+void OSystem_LINUXMOTO::drawMouse() {
if (!_mouseVisible || !_mouseSurface) {
_mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
return;
@@ -231,7 +226,7 @@ void LinuxmotoSdlGraphicsManager::drawMouse() {
addDirtyRect(dst.x, dst.y, dst.w, dst.h, true);
}
-void LinuxmotoSdlGraphicsManager::undrawMouse() {
+void OSystem_LINUXMOTO::undrawMouse() {
const int x = _mouseBackup.x;
const int y = _mouseBackup.y;
@@ -249,13 +244,13 @@ void LinuxmotoSdlGraphicsManager::undrawMouse() {
}
}
-void LinuxmotoSdlGraphicsManager::internUpdateScreen() {
+void OSystem_LINUXMOTO::internUpdateScreen() {
SDL_Surface *srcSurf, *origSurf;
int height, width;
ScalerProc *scalerProc;
int scale1;
-#if defined (DEBUG) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
+#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
assert(_hwscreen != NULL);
assert(_hwscreen->map->sw_data != NULL);
#endif
@@ -448,48 +443,28 @@ void LinuxmotoSdlGraphicsManager::internUpdateScreen() {
_mouseNeedsRedraw = false;
}
-void LinuxmotoSdlGraphicsManager::showOverlay() {
+void OSystem_LINUXMOTO::showOverlay() {
if (_videoMode.mode == GFX_HALF) {
_mouseCurState.x = _mouseCurState.x / 2;
_mouseCurState.y = _mouseCurState.y / 2;
}
- SdlGraphicsManager::showOverlay();
+ OSystem_SDL::showOverlay();
}
-void LinuxmotoSdlGraphicsManager::hideOverlay() {
+void OSystem_LINUXMOTO::hideOverlay() {
if (_videoMode.mode == GFX_HALF) {
_mouseCurState.x = _mouseCurState.x * 2;
_mouseCurState.y = _mouseCurState.y * 2;
}
- SdlGraphicsManager::hideOverlay();
+ OSystem_SDL::hideOverlay();
}
-void LinuxmotoSdlGraphicsManager::warpMouse(int x, int y) {
+void OSystem_LINUXMOTO::warpMouse(int x, int y) {
if (_mouseCurState.x != x || _mouseCurState.y != y) {
if (_videoMode.mode == GFX_HALF && !_overlayVisible) {
x = x / 2;
y = y / 2;
}
}
- SdlGraphicsManager::warpMouse(x, y);
-}
-
-void LinuxmotoSdlGraphicsManager::adjustMouseEvent(const Common::Event &event) {
- if (!event.synthetic) {
- Common::Event newEvent(event);
- newEvent.synthetic = true;
- if (!_overlayVisible) {
- if (_videoMode.mode == GFX_HALF) {
- event.mouse.x *= 2;
- event.mouse.y *= 2;
- }
- newEvent.mouse.x /= _videoMode.scaleFactor;
- newEvent.mouse.y /= _videoMode.scaleFactor;
- if (_videoMode.aspectRatioCorrection)
- newEvent.mouse.y = aspect2Real(newEvent.mouse.y);
- }
- g_system->getEventManager()->pushEvent(newEvent);
- }
+ OSystem_SDL::warpMouse(x, y);
}
-
-#endif
diff --git a/backends/platform/linuxmoto/linuxmoto-main.cpp b/backends/platform/linuxmoto/linuxmoto-main.cpp
index e9f2e661de..09b03c31d6 100644
--- a/backends/platform/linuxmoto/linuxmoto-main.cpp
+++ b/backends/platform/linuxmoto/linuxmoto-main.cpp
@@ -23,23 +23,24 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/scummsys.h"
+#include "common/system.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_syswm.h>
+
#include "backends/platform/linuxmoto/linuxmoto-sdl.h"
#include "base/main.h"
int main(int argc, char *argv[]) {
-
- // Create our OSystem instance
g_system = new OSystem_LINUXMOTO();
assert(g_system);
-
- // Pre initialize the backend
- ((OSystem_POSIX *)g_system)->init();
-
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
-
- // Free OSystem
- delete (OSystem_LINUXMOTO *)g_system;
+ g_system->quit(); // TODO: Consider removing / replacing this!
return res;
}
diff --git a/backends/platform/linuxmoto/linuxmoto-sdl.cpp b/backends/platform/linuxmoto/linuxmoto-sdl.cpp
index 6ef03ed3ac..ad1af455c3 100644
--- a/backends/platform/linuxmoto/linuxmoto-sdl.cpp
+++ b/backends/platform/linuxmoto/linuxmoto-sdl.cpp
@@ -25,17 +25,44 @@
#include "backends/platform/linuxmoto/linuxmoto-sdl.h"
-#include "backends/graphics/linuxmotosdl/linuxmotosdl-graphics.h"
-#include "backends/events/linuxmotosdl/linuxmotosdl-events.h"
+void OSystem_LINUXMOTO::preprocessEvents(SDL_Event *event) {
+ if (event->type == SDL_ACTIVEEVENT) {
+ if (event->active.state == SDL_APPINPUTFOCUS && !event->active.gain) {
+ suspendAudio();
+ for (;;) {
+ if (!SDL_WaitEvent(event)) {
+ SDL_Delay(10);
+ continue;
+ }
+ if (event->type == SDL_QUIT)
+ return;
+ if (event->type != SDL_ACTIVEEVENT)
+ continue;
+ if (event->active.state == SDL_APPINPUTFOCUS && event->active.gain) {
+ resumeAudio();
+ return;
+ }
+ }
+ }
+ }
+}
-void OSystem_LINUXMOTO::initBackend() {
- // Create the backend custom managers
- if (_eventManager == 0)
- _eventManager = new LinuxmotoSdlEventManager(this);
+void OSystem_LINUXMOTO::suspendAudio() {
+ SDL_CloseAudio();
+ _audioSuspended = true;
+}
- if (_graphicsManager == 0)
- _graphicsManager = new LinuxmotoSdlGraphicsManager();
+int OSystem_LINUXMOTO::resumeAudio() {
+ if (!_audioSuspended)
+ return -2;
+ if (SDL_OpenAudio(&_obtainedRate, NULL) < 0){
+ return -1;
+ }
+ SDL_PauseAudio(0);
+ _audioSuspended = false;
+ return 0;
+}
- // Call parent implementation of this method
- OSystem_POSIX::initBackend();
+void OSystem_LINUXMOTO::setupMixer() {
+ OSystem_SDL::setupMixer();
}
diff --git a/backends/platform/linuxmoto/linuxmoto-sdl.h b/backends/platform/linuxmoto/linuxmoto-sdl.h
index 78b9f81fd2..c01d375603 100644
--- a/backends/platform/linuxmoto/linuxmoto-sdl.h
+++ b/backends/platform/linuxmoto/linuxmoto-sdl.h
@@ -23,17 +23,43 @@
*
*/
-#ifndef PLATFORM_SDL_LINUXMOTO_H
-#define PLATFORM_SDL_LINUXMOTO_H
+#ifndef LINUXMOTO_SDL
+#define LINUXMOTO_SDL
-#include "backends/platform/sdl/posix/posix.h"
+#include "backends/platform/sdl/sdl.h"
-class OSystem_LINUXMOTO : public OSystem_POSIX {
+// FIXME: For now keep hacks in this header to save polluting the SDL backend.
+enum {
+ GFX_HALF = 12
+};
+
+class OSystem_LINUXMOTO : public OSystem_SDL {
+private:
+ bool _audioSuspended;
public:
- virtual void initBackend();
+ /* Graphics */
+ void initSize(uint w, uint h);
+ void setGraphicsModeIntern();
+ bool setGraphicsMode(int mode);
+ void internUpdateScreen();
+ const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
+ bool setGraphicsMode(const char *name);
+ int getDefaultGraphicsMode() const;
+ bool loadGFXMode();
+ void drawMouse();
+ void undrawMouse();
+ void showOverlay();
+ void hideOverlay();
- // FIXME: This just calls parent methods, is it needed?
+ /* Event Stuff */
+ virtual bool remapKey(SDL_Event &ev, Common::Event &event);
+ virtual void preprocessEvents(SDL_Event *event);
+ virtual void setupMixer();
virtual Common::HardwareKeySet *getHardwareKeySet();
+ void fillMouseEvent(Common::Event&, int, int);
+ void suspendAudio();
+ int resumeAudio();
+ void warpMouse(int, int);
};
#endif
diff --git a/backends/platform/linuxmoto/module.mk b/backends/platform/linuxmoto/module.mk
index c604d69da1..316ecbf78e 100644
--- a/backends/platform/linuxmoto/module.mk
+++ b/backends/platform/linuxmoto/module.mk
@@ -1,6 +1,8 @@
MODULE := backends/platform/linuxmoto
MODULE_OBJS := \
+ linuxmoto-events.o \
+ linuxmoto-graphics.o \
linuxmoto-main.o \
linuxmoto-sdl.o \
hardwarekeys.o
diff --git a/backends/platform/null/null.cpp b/backends/platform/null/null.cpp
index d888e632d6..51166baae7 100644
--- a/backends/platform/null/null.cpp
+++ b/backends/platform/null/null.cpp
@@ -23,14 +23,22 @@
*
*/
-#include "backends/modular-backend.h"
+#include "backends/base-backend.h"
#include "base/main.h"
#if defined(USE_NULL_DRIVER)
+
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+#include "common/rect.h"
+#include "graphics/colormasks.h"
+
#include "backends/saves/default/default-saves.h"
#include "backends/timer/default/default-timer.h"
#include "sound/mixer_intern.h"
-#include "common/scummsys.h"
/*
* Include header files needed for the getFilesystemFactory() method.
@@ -43,24 +51,82 @@
#include "backends/fs/windows/windows-fs-factory.h"
#endif
-class OSystem_NULL : public ModularBackend {
+class OSystem_NULL : public BaseBackend {
+protected:
+ Common::SaveFileManager *_savefile;
+ Audio::MixerImpl *_mixer;
+ Common::TimerManager *_timer;
+ FilesystemFactory *_fsFactory;
+
+ timeval _startTime;
public:
+
OSystem_NULL();
virtual ~OSystem_NULL();
virtual void initBackend();
- virtual bool pollEvent(Common::Event &event);
+ virtual bool hasFeature(Feature f);
+ virtual void setFeatureState(Feature f, bool enable);
+ virtual bool getFeatureState(Feature f);
+ virtual const GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ bool setGraphicsMode(const char *name);
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+ virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format);
+ virtual int16 getHeight();
+ virtual int16 getWidth();
+ virtual void setPalette(const byte *colors, uint start, uint num);
+ virtual void grabPalette(byte *colors, uint start, uint num);
+ virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
+ virtual void updateScreen();
+ virtual Graphics::Surface *lockScreen();
+ virtual void unlockScreen();
+ virtual void setShakePos(int shakeOffset);
+ virtual void showOverlay();
+ virtual void hideOverlay();
+ virtual void clearOverlay();
+ virtual void grabOverlay(OverlayColor *buf, int pitch);
+ virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
+ virtual int16 getOverlayHeight();
+ virtual int16 getOverlayWidth();
+ virtual Graphics::PixelFormat getOverlayFormat() const { return Graphics::createPixelFormat<565>(); }
+
+ virtual bool showMouse(bool visible);
+
+ virtual void warpMouse(int x, int y);
+ virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format);
+
+ virtual bool pollEvent(Common::Event &event);
virtual uint32 getMillis();
- virtual void delayMillis(uint msecs) {}
- virtual void getTimeAndDate(TimeDate &t) const {}
+ virtual void delayMillis(uint msecs);
+
+ virtual MutexRef createMutex(void);
+ virtual void lockMutex(MutexRef mutex);
+ virtual void unlockMutex(MutexRef mutex);
+ virtual void deleteMutex(MutexRef mutex);
+
+ virtual void quit();
+
+ virtual Common::SaveFileManager *getSavefileManager();
+ virtual Audio::Mixer *getMixer();
+ virtual void getTimeAndDate(TimeDate &t) const;
+ virtual Common::TimerManager *getTimerManager();
+ FilesystemFactory *getFilesystemFactory();
- virtual Common::SeekableReadStream *createConfigReadStream();
- virtual Common::WriteStream *createConfigWriteStream();
+};
+
+static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+ {0, 0, 0}
};
OSystem_NULL::OSystem_NULL() {
+ _savefile = 0;
+ _mixer = 0;
+ _timer = 0;
+
#if defined(__amigaos4__)
_fsFactory = new AmigaOSFilesystemFactory();
#elif defined(UNIX)
@@ -73,18 +139,20 @@ OSystem_NULL::OSystem_NULL() {
}
OSystem_NULL::~OSystem_NULL() {
+ delete _savefile;
+ delete _mixer;
+ delete _timer;
+ delete _fsFactory;
}
void OSystem_NULL::initBackend() {
- _mutexManager = (MutexManager *)new NullMutexManager();
- _timerManager = new DefaultTimerManager();
- _eventManager = new DefaultEventManager(this);
- _savefileManager = new DefaultSaveFileManager();
- _graphicsManager = (GraphicsManager *)new NullGraphicsManager();
- _audiocdManager = (AudioCDManager *)new DefaultAudioCDManager();
+ _savefile = new DefaultSaveFileManager();
_mixer = new Audio::MixerImpl(this, 22050);
-
- ((Audio::MixerImpl *)_mixer)->setReady(false);
+ _timer = new DefaultTimerManager();
+
+ _mixer->setReady(false);
+
+ gettimeofday(&_startTime, NULL);
// Note that both the mixer and the timer manager are useless
// this way; they need to be hooked into the system somehow to
@@ -93,38 +161,163 @@ void OSystem_NULL::initBackend() {
OSystem::initBackend();
}
-bool OSystem_NULL::pollEvent(Common::Event &event) {
+bool OSystem_NULL::hasFeature(Feature f) {
return false;
}
-uint32 OSystem_NULL::getMillis() {
+void OSystem_NULL::setFeatureState(Feature f, bool enable) {
+}
+
+bool OSystem_NULL::getFeatureState(Feature f) {
+ return false;
+}
+
+const OSystem::GraphicsMode* OSystem_NULL::getSupportedGraphicsModes() const {
+ return s_supportedGraphicsModes;
+}
+
+
+int OSystem_NULL::getDefaultGraphicsMode() const {
+ return -1;
+}
+
+bool OSystem_NULL::setGraphicsMode(const char *mode) {
+ return true;
+}
+
+bool OSystem_NULL::setGraphicsMode(int mode) {
+ return true;
+}
+
+int OSystem_NULL::getGraphicsMode() const {
+ return -1;
+}
+
+void OSystem_NULL::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
+}
+
+int16 OSystem_NULL::getHeight() {
+ return 200;
+}
+
+int16 OSystem_NULL::getWidth() {
+ return 320;
+}
+
+void OSystem_NULL::setPalette(const byte *colors, uint start, uint num) {
+}
+
+void OSystem_NULL::grabPalette(byte *colors, uint start, uint num) {
+
+}
+
+void OSystem_NULL::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
+}
+
+void OSystem_NULL::updateScreen() {
+}
+
+Graphics::Surface *OSystem_NULL::lockScreen() {
return 0;
}
-#if defined(UNIX)
-#if defined(SAMSUNGTV)
-#define DEFAULT_CONFIG_FILE "/dtv/usb/sda1/.scummvmrc"
+void OSystem_NULL::unlockScreen() {
+}
+
+void OSystem_NULL::setShakePos(int shakeOffset) {
+}
+
+void OSystem_NULL::showOverlay() {
+}
+
+void OSystem_NULL::hideOverlay() {
+}
+
+void OSystem_NULL::clearOverlay() {
+}
+
+void OSystem_NULL::grabOverlay(OverlayColor *buf, int pitch) {
+}
+
+void OSystem_NULL::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
+}
+
+int16 OSystem_NULL::getOverlayHeight() {
+ return getHeight();
+}
+
+int16 OSystem_NULL::getOverlayWidth() {
+ return getWidth();
+}
+
+
+bool OSystem_NULL::showMouse(bool visible) {
+ return true;
+}
+
+void OSystem_NULL::warpMouse(int x, int y) {
+}
+
+void OSystem_NULL::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
+}
+
+bool OSystem_NULL::pollEvent(Common::Event &event) {
+ return false;
+}
+
+uint32 OSystem_NULL::getMillis() {
+#ifdef UNIX
+ timeval curTime;
+ gettimeofday(&curTime, NULL);
+ return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \
+ ((curTime.tv_usec - _startTime.tv_usec) / 1000));
#else
-#define DEFAULT_CONFIG_FILE ".scummvmrc"
-#endif
+ return 0;
#endif
+}
-#if !defined(UNIX)
-#define DEFAULT_CONFIG_FILE "scummvm.ini"
+void OSystem_NULL::delayMillis(uint msecs) {
+#ifdef UNIX
+ usleep(msecs * 1000);
#endif
+}
-Common::SeekableReadStream *OSystem_NULL::createConfigReadStream() {
- Common::FSNode file(DEFAULT_CONFIG_FILE);
- return file.createReadStream();
+OSystem::MutexRef OSystem_NULL::createMutex(void) {
+ return NULL;
}
-Common::WriteStream *OSystem_NULL::createConfigWriteStream() {
-#ifdef __DC__
- return 0;
-#else
- Common::FSNode file(DEFAULT_CONFIG_FILE);
- return file.createWriteStream();
-#endif
+void OSystem_NULL::lockMutex(MutexRef mutex) {
+}
+
+void OSystem_NULL::unlockMutex(MutexRef mutex) {
+}
+
+void OSystem_NULL::deleteMutex(MutexRef mutex) {
+}
+
+void OSystem_NULL::quit() {
+}
+
+Common::SaveFileManager *OSystem_NULL::getSavefileManager() {
+ assert(_savefile);
+ return _savefile;
+}
+
+Audio::Mixer *OSystem_NULL::getMixer() {
+ assert(_mixer);
+ return _mixer;
+}
+
+Common::TimerManager *OSystem_NULL::getTimerManager() {
+ assert(_timer);
+ return _timer;
+}
+
+void OSystem_NULL::getTimeAndDate(TimeDate &t) const {
+}
+
+FilesystemFactory *OSystem_NULL::getFilesystemFactory() {
+ return _fsFactory;
}
OSystem *OSystem_NULL_create() {
@@ -137,7 +330,7 @@ int main(int argc, char *argv[]) {
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
- delete (OSystem_NULL *)g_system;
+ g_system->quit(); // TODO: Consider removing / replacing this!
return res;
}
diff --git a/backends/platform/openpandora/build/README-OPENPANDORA b/backends/platform/openpandora/build/README-OPENPANDORA
index c3aa5e8ea9..c8aabcbb7a 100755
--- a/backends/platform/openpandora/build/README-OPENPANDORA
+++ b/backends/platform/openpandora/build/README-OPENPANDORA
@@ -1,4 +1,4 @@
-ScummVM - OPENPANDORA SPECIFIC README - HEAD SVN
+ScummVM - OPENPANDORA SPECIFIC README
------------------------------------------------------------------------
Please refer to the:
diff --git a/backends/platform/openpandora/build/config-alleng.sh b/backends/platform/openpandora/build/config-alleng.sh
index cd9a17ef40..f3fa1a0f94 100755
--- a/backends/platform/openpandora/build/config-alleng.sh
+++ b/backends/platform/openpandora/build/config-alleng.sh
@@ -17,6 +17,13 @@ export DEFINES=-DNDEBUG
# Edit the configure line to suit.
cd ../../../..
-./configure --backend=openpandora --host=openpandora --disable-nasm --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --disable-vorbis --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-mad --with-mad-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-all-engines --enable-plugins --default-dynamic
+./configure --backend=openpandora --host=openpandora --disable-nasm \
+ --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin \
+ --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --disable-vorbis --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --enable-mad --with-mad-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --enable-png --with-png-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --enable-all-engines --enable-plugins --default-dynamic
echo Generating config for OpenPandora complete. Check for errors.
diff --git a/backends/platform/openpandora/build/config.sh b/backends/platform/openpandora/build/config.sh
index 8be16f1317..9bc52a9bc4 100755
--- a/backends/platform/openpandora/build/config.sh
+++ b/backends/platform/openpandora/build/config.sh
@@ -17,6 +17,13 @@ export DEFINES=-DNDEBUG
# Edit the configure line to suit.
cd ../../../..
-./configure --backend=openpandora --host=openpandora --disable-nasm --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --disable-vorbis --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-mad --with-mad-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-plugins --default-dynamic
+./configure --backend=openpandora --host=openpandora --disable-nasm \
+ --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin \
+ --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --disable-vorbis --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --enable-mad --with-mad-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --enable-png --with-png-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \
+ --enable-plugins --default-dynamic
echo Generating config for OpenPandora complete. Check for errors.
diff --git a/backends/platform/openpandora/op-main.cpp b/backends/platform/openpandora/op-main.cpp
index 4febd404c3..3f4208a95a 100755
--- a/backends/platform/openpandora/op-main.cpp
+++ b/backends/platform/openpandora/op-main.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#include <SDL/SDL.h>
diff --git a/backends/platform/ps2/fileio.cpp b/backends/platform/ps2/fileio.cpp
index 8c10156aaf..826a2578e4 100644
--- a/backends/platform/ps2/fileio.cpp
+++ b/backends/platform/ps2/fileio.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/platform/ps2/fileio.h"
#include <tamtypes.h>
diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp
index 7659d5194d..1b3ae6ba47 100644
--- a/backends/platform/ps2/systemps2.cpp
+++ b/backends/platform/ps2/systemps2.cpp
@@ -23,6 +23,12 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include <kernel.h>
#include <stdio.h>
#include <stdlib.h>
@@ -59,6 +65,8 @@
#include "backends/platform/ps2/ps2debug.h"
#include "backends/fs/ps2/ps2-fs-factory.h"
+#include "backends/plugins/ps2/ps2-provider.h"
+
#include "backends/saves/default/default-saves.h"
#include "common/config-manager.h"
@@ -105,7 +113,6 @@ extern "C" int scummvm_main(int argc, char *argv[]);
extern "C" int main(int argc, char *argv[]) {
SifInitRpc(0);
-
ee_thread_t thisThread;
int tid = GetThreadId();
ReferThreadStatus(tid, &thisThread);
@@ -130,8 +137,11 @@ extern "C" int main(int argc, char *argv[]) {
sioprintf("Creating system\n");
g_system = g_systemPs2 = new OSystem_PS2(argv[0]);
- g_systemPs2->init();
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new PS2PluginProvider());
+#endif
+ g_systemPs2->init();
sioprintf("init done. starting ScummVM.\n");
int res = scummvm_main(argc, argv);
sioprintf("scummvm_main terminated: %d\n", res);
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile
index 7f9ae153eb..dab3c34b51 100644
--- a/backends/platform/psp/Makefile
+++ b/backends/platform/psp/Makefile
@@ -67,7 +67,7 @@ endif
# Variables for common Scummvm makefile
CXX = psp-g++
CXXFLAGS = -O3 -Wall -Wno-multichar -fno-exceptions -fno-rtti
-DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR
+DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR -DUSE_ELF_LOADER -DMIPS_TARGET
LDFLAGS :=
INCDIR := $(srcdir) . $(srcdir)/engines/ $(PSPSDK)/include
@@ -87,8 +87,8 @@ CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP
# Variables for dynamic plugin building
PLUGIN_PREFIX =
PLUGIN_SUFFIX = .plg
-PLUGIN_EXTRA_DEPS = plugin.syms scummvm-psp.elf
-PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-Tplugin.ld,--retain-symbols-file,plugin.syms -lstdc++ -lc
+PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/elf/plugin.syms scummvm-psp.elf
+PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-T$(srcdir)/backends/plugins/psp/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -lstdc++ -lc
# PSP-specific variables
STRIP = psp-strip
@@ -126,7 +126,8 @@ endif
# PSP LIBS
PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \
-lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \
- -lpspkernel
+ -lpspkernel -lpspnet_inet
+
# Add in PSPSDK includes and libraries.
LIBS += -lpng -lz -lstdc++ -lc -lm $(PSPLIBS)
@@ -142,14 +143,16 @@ OBJS := powerman.o \
input.o \
cursor.o \
trace.o \
- psploader.o \
pspkeyboard.o \
audio.o \
thread.o \
rtc.o \
mp3.o \
png_loader.o \
- tests.o
+ image_viewer.o \
+ tests.o \
+ dummy.o
+
BACKEND := psp
@@ -167,7 +170,7 @@ PSP_EBOOT_PIC1 = pic1.png
PSP_EBOOT_SND0 = NULL
PSP_EBOOT_PSAR = NULL
-LDFLAGS += -Wl,-Tmain_prog.ld
+LDFLAGS += -Wl,-T../../plugins/psp/main_prog.ld
all: $(PSP_EBOOT)
diff --git a/backends/platform/psp/README.PSP b/backends/platform/psp/README.PSP
index 0849d68c78..b83f1cab6d 100644
--- a/backends/platform/psp/README.PSP
+++ b/backends/platform/psp/README.PSP
@@ -6,6 +6,7 @@ Installation
- Copy the relevant game datafiles to your memory stick (location doesn't matter).
- Install ScummVM like any other homebrew.
- Run ScummVM and use the launcher to add games and run them.
+ - Press Start to return to the launcher and play another game.
Controls
========
@@ -20,9 +21,10 @@ Cross - Left Mouse Button (usually the main button)
Circle - Right Mouse Button (secondary button in some games)
Square - '.' (skip dialogue in some games e.g. Scumm)
Right trigger + Square - Spacebar (useful in Gobli*ns and SCI games)
-Start - Global Menu. Allows you to 'Return To Launcher' to play another game
Right trigger + Start - F5 (Main Menu in some games)
Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen (with D-Pad).
+Right trigger + Select - Show Image Viewer (see below)
+Start - Global Menu. Allows you to 'Return To Launcher' to play another game
Virtual Keyboard Mode
=====================
@@ -37,6 +39,34 @@ Buttons/Triggers - Choose a specific character in the square. The four center c
Analog - Moves in a direction (left/right/up/down) (Useful to keep moving
while typing in AGI games among other things)
+
+Image Viewer
+============
+For your convenience, I've included a simple image viewer in the PSP port.
+You can view anything you want while playing a game.
+There are a few simple rules to follow:
+
+- Images must be of PNG format. If you have images in another format, many
+ graphics utilities will convert them for you.
+- Images must be named psp_image1.png, psp_image2.png etc. This is to make
+ sure there's no possible conflict between image files and game files.
+- Images must be placed in the game directories. When using the image viewer,
+ only the images of the particular game being played will be available for viewing.
+- Don't place any images in the ScummVM directory, or you won't be able to see
+ the images in the game directories.
+- There's no guarantee that you'll be able to view your image. This is because
+ big images take a lot of memory (more than the size of the image on disk). If there
+ isn't enough memory left to show the image, ScummVM will tell you so. Try to make the
+ image smaller by either shrinking it or reducing the colors to 256 color palette mode.
+
+Image Viewer Controls:
+=====================
+Left/Right - previous/next image (e.g. go from psp_image1.png to psp_image2.png)
+Up/down - zoom in/out
+Analog - move around the image
+Triggers, Start: - exit image viewer
+
+
1st Person Game Mode (Can be ignored by most users)
====================
This is a special mode built for 1st person games like Lands of Lore. If you don't have these games you can
@@ -49,9 +79,12 @@ Square - Is the modifier key instead of Right Trigger.
Left/Right Trigger - Strafe left/right
D-Pad Left/Right - Turn left/right
Square + D-Pad - F1/F2/F3/F4
+Square + Select - Image Viewer
Square + Start - Esc (shows game menu)
+
+
Notes
=====
- Notice that you can switch between games! This is much faster than quitting
diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp
index 916b6c1aae..9d4f573e28 100644
--- a/backends/platform/psp/display_client.cpp
+++ b/backends/platform/psp/display_client.cpp
@@ -347,7 +347,6 @@ void Buffer::copyFromRect(const byte *buf, uint32 pitch, int destX, int destY, u
PspMemory::fastCopy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth));
} else {
do {
- //memcpy(dst, buf, recWidthInBytes);
if (_pixelFormat.swapRB)
PspMemorySwap::fastSwap(dst, buf, recWidthInBytes, _pixelFormat);
else
@@ -379,45 +378,45 @@ void Buffer::copyToArray(byte *dst, int pitch) {
} while (--h);
}
-/* We can size the buffer either by texture size (multiple of 2^n) or source size. The GU can
- really handle both, but is supposed to get only 2^n size buffers */
void Buffer::setSize(uint32 width, uint32 height, HowToSize textureOrSource/*=kSizeByTextureSize*/) {
DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("w[%u], h[%u], %s\n", width, height, textureOrSource ? "size by source" : "size by texture");
-
+
+ // We can size the buffer either by texture size (multiple of 2^n) or source size.
+ // At higher sizes, increasing the texture size to 2^n is a waste of space. At these sizes kSizeBySourceSize should be used.
+
_sourceSize.width = width;
_sourceSize.height = height;
- _textureSize.width = scaleUpToPowerOfTwo(width);
+ _textureSize.width = scaleUpToPowerOfTwo(width); // can only scale up to 512
_textureSize.height = scaleUpToPowerOfTwo(height);
-
+
if (textureOrSource == kSizeByTextureSize) {
_width = _textureSize.width;
_height = _textureSize.height;
- } else { /* kSizeBySourceSize */
- _width = _sourceSize.width;
+ } else { // sizeBySourceSize
+ _width = _sourceSize.width;
_height = _sourceSize.height;
+
+ // adjust allocated width to be divisible by 32.
+ // The GU can only handle multiples of 16 bytes. A 4 bit image x 32 will give us 16 bytes
+ // We don't necessarily know the depth of the pixels here. So just make it divisible by 32.
+ uint32 checkDiv = _width & 31;
+ if (checkDiv)
+ _width += 32 - checkDiv;
}
+
+ PSP_DEBUG_PRINT("width[%u], height[%u], texW[%u], texH[%u], sourceW[%d], sourceH[%d] %s\n", _width, _height, _textureSize.width, _textureSize.height, _sourceSize.width, _sourceSize.height, textureOrSource ? "size by source" : "size by texture");
}
-/* Scale a dimension (width/height) up to power of 2 for the texture */
+// Scale a dimension (width/height) up to power of 2 for the texture
+// Will only go up to 512 since that's the maximum PSP texture size
uint32 Buffer::scaleUpToPowerOfTwo(uint32 size) {
- uint32 textureDimension = 0;
- if (size <= 16)
- textureDimension = 16;
- else if (size <= 32)
- textureDimension = 32;
- else if (size <= 64)
- textureDimension = 64;
- else if (size <= 128)
- textureDimension = 128;
- else if (size <= 256)
- textureDimension = 256;
- else
- textureDimension = 512;
+ uint32 textureDimension = 16;
+ while (size > textureDimension && textureDimension < 512)
+ textureDimension <<= 1;
- PSP_DEBUG_PRINT("power of 2 = %u\n", textureDimension);
+ PSP_DEBUG_PRINT("size[%u]. power of 2[%u]\n", size, textureDimension);
return textureDimension;
}
@@ -540,51 +539,41 @@ void GuRenderer::render() {
DEBUG_ENTER_FUNC();
PSP_DEBUG_PRINT("Buffer[%p] Palette[%p]\n", _buffer->getPixels(), _palette->getRawValues());
- setMaxTextureOffsetByIndex(0, 0);
-
guProgramDrawBehavior();
if (_buffer->hasPalette())
guLoadPalette();
guProgramTextureFormat();
- guLoadTexture();
-
- Vertex *vertices = guGetVertices();
- fillVertices(vertices);
-
- guDrawVertices(vertices);
-
- if (_buffer->getSourceWidth() > 512) {
- setMaxTextureOffsetByIndex(1, 0);
- guLoadTexture();
-
- vertices = guGetVertices();
- fillVertices(vertices);
-
- guDrawVertices(vertices);
+ // Loop over patches of 512x512 pixel textures and draw them
+ for (uint32 j = 0; j < _buffer->getSourceHeight(); j += 512) {
+ _textureLoadOffset.y = j;
+
+ for (uint32 i = 0; i < _buffer->getSourceWidth(); i += 512) {
+ _textureLoadOffset.x = i;
+
+ guLoadTexture();
+ Vertex *vertices = guGetVertices();
+ fillVertices(vertices);
+
+ guDrawVertices(vertices);
+ }
}
}
-inline void GuRenderer::setMaxTextureOffsetByIndex(uint32 x, uint32 y) {
- DEBUG_ENTER_FUNC();
- const uint32 maxTextureSizeShift = 9; /* corresponds to 512 = max texture size*/
-
- _maxTextureOffset.x = x << maxTextureSizeShift; /* x times 512 */
- _maxTextureOffset.y = y << maxTextureSizeShift; /* y times 512 */
-}
-
inline void GuRenderer::guProgramDrawBehavior() {
DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n", _blending ? "on" : "off", _colorTest ? "on" : "off", _alphaReverse ? "on" : "off", _keyColor);
+ PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n",
+ _blending ? "on" : "off", _colorTest ? "on" : "off",
+ _alphaReverse ? "on" : "off", _keyColor);
if (_blending) {
sceGuEnable(GU_BLEND);
- if (_alphaReverse) // Reverse the alpha value (0 is 1)
+ if (_alphaReverse) // Reverse the alpha value (ie. 0 is 1) easier to do in some cases
sceGuBlendFunc(GU_ADD, GU_ONE_MINUS_SRC_ALPHA, GU_SRC_ALPHA, 0, 0);
- else // Normal alpha values
+ else // Normal alpha values
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
} else
@@ -592,7 +581,9 @@ inline void GuRenderer::guProgramDrawBehavior() {
if (_colorTest) {
sceGuEnable(GU_COLOR_TEST);
- sceGuColorFunc(GU_NOTEQUAL, _keyColor, 0x00ffffff);
+ sceGuColorFunc(GU_NOTEQUAL, // show only colors not equal to this color
+ _keyColor,
+ 0x00ffffff); // match everything but alpha
} else
sceGuDisable(GU_COLOR_TEST);
}
@@ -613,7 +604,8 @@ inline void GuRenderer::guLoadPalette() {
PSP_DEBUG_PRINT("bpp[%d], pixelformat[%d], mask[%x]\n", _buffer->getBitsPerPixel(), _palette->getPixelFormat(), mask);
sceGuClutMode(convertToGuPixelFormat(_palette->getPixelFormat()), 0, mask, 0);
- sceGuClutLoad(_palette->getNumOfEntries() >> 3, _palette->getRawValues());
+ sceGuClutLoad(_palette->getNumOfEntries() >> 3, // it's in batches of 8 for some reason
+ _palette->getRawValues());
}
inline void GuRenderer::guProgramTextureFormat() {
@@ -659,7 +651,17 @@ inline uint32 GuRenderer::convertToGuPixelFormat(PSPPixelFormat::Type format) {
inline void GuRenderer::guLoadTexture() {
DEBUG_ENTER_FUNC();
- sceGuTexImage(0, _buffer->getTextureWidth(), _buffer->getTextureHeight(), _buffer->getWidth(), _buffer->getPixels() + _buffer->_pixelFormat.pixelsToBytes(_maxTextureOffset.x));
+ byte *startPoint = _buffer->getPixels();
+ if (_textureLoadOffset.x)
+ startPoint += _buffer->_pixelFormat.pixelsToBytes(_textureLoadOffset.x);
+ if (_textureLoadOffset.y)
+ startPoint += _buffer->getWidthInBytes() * _textureLoadOffset.y;
+
+ sceGuTexImage(0,
+ _buffer->getTextureWidth(), // texture width (must be power of 2)
+ _buffer->getTextureHeight(), // texture height (must be power of 2)
+ _buffer->getWidth(), // width of a line of the image (to get to the next line)
+ startPoint); // where to start reading
}
inline Vertex *GuRenderer::guGetVertices() {
@@ -677,40 +679,40 @@ void GuRenderer::fillVertices(Vertex *vertices) {
uint32 outputWidth = _displayManager->getOutputWidth();
uint32 outputHeight = _displayManager->getOutputHeight();
- float textureStartX, textureStartY, textureEndX, textureEndY;
-
// Texture adjustments for eliminating half-pixel artifacts from scaling
// Not necessary if we don't scale
- float textureAdjustment = 0.0f;
+ float textureFix = 0.0f;
if (_useGlobalScaler &&
- (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleX() != 1.0f))
- textureAdjustment = 0.5f;
-
- textureStartX = textureAdjustment + _offsetInBuffer.x; //debug
- textureStartY = textureAdjustment + _offsetInBuffer.y;
- // We subtract maxTextureOffset because our shifted texture starts at 512 and will go to 640
- textureEndX = _offsetInBuffer.x + _drawSize.width - textureAdjustment - _maxTextureOffset.x;
- textureEndY = _offsetInBuffer.y + _drawSize.height - textureAdjustment;
-
+ (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleY() != 1.0f))
+ textureFix = 0.5f;
+
+ // These coordinates describe an area within the texture. ie. we already loaded a square of texture,
+ // now the coordinates within it are 0 to the edge of the area of the texture we want to draw
+ float textureStartX = textureFix + _offsetInBuffer.x;
+ float textureStartY = textureFix + _offsetInBuffer.y;
+ // even when we draw one of several textures, we use the whole drawsize of the image. The GU
+ // will draw what it can with the texture it has and scale it properly for us.
+ float textureEndX = -textureFix + _offsetInBuffer.x + _drawSize.width - _textureLoadOffset.x;
+ float textureEndY = -textureFix + _offsetInBuffer.y + _drawSize.height - _textureLoadOffset.y;
// For scaling to the final image size, calculate the gaps on both sides
uint32 gapX = _useGlobalScaler ? (PSP_SCREEN_WIDTH - outputWidth) >> 1 : 0;
uint32 gapY = _useGlobalScaler ? (PSP_SCREEN_HEIGHT - outputHeight) >> 1 : 0;
// Save scaled offset on screen
- float scaledOffsetOnScreenX = scaleSourceToOutputX(_offsetOnScreen.x);
- float scaledOffsetOnScreenY = scaleSourceToOutputY(_offsetOnScreen.y);
-
- float imageStartX, imageStartY, imageEndX, imageEndY;
+ float scaledOffsetOnScreenX = scaleSourceToOutput(true, _offsetOnScreen.x);
+ float scaledOffsetOnScreenY = scaleSourceToOutput(false, _offsetOnScreen.y);
- imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutputX(_maxTextureOffset.x));
- imageStartY = gapY + scaledOffsetOnScreenY;
+ float imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutput(true, stretch(true, _textureLoadOffset.x)));
+ float imageStartY = gapY + scaledOffsetOnScreenY + (scaleSourceToOutput(false, stretch(false, _textureLoadOffset.y)));
+ float imageEndX, imageEndY;
+
if (_fullScreen) { // shortcut
imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX;
imageEndY = PSP_SCREEN_HEIGHT - gapY + scaledOffsetOnScreenY; // needed for screen shake
} else { /* !fullScreen */
- imageEndX = imageStartX + scaleSourceToOutputX(_drawSize.width);
- imageEndY = imageStartY + scaleSourceToOutputY(_drawSize.height);
+ imageEndX = gapX + scaledOffsetOnScreenX + scaleSourceToOutput(true, stretch(true, _drawSize.width));
+ imageEndY = gapY + scaledOffsetOnScreenY + scaleSourceToOutput(false, stretch(false, _drawSize.height));
}
vertices[0].u = textureStartX;
@@ -729,8 +731,8 @@ void GuRenderer::fillVertices(Vertex *vertices) {
PSP_DEBUG_PRINT("ImageStart: X[%f] Y[%f] ImageEnd: X[%.1f] Y[%.1f]\n", imageStartX, imageStartY, imageEndX, imageEndY);
}
-/* Scale the input X offset to appear in proper position on the screen */
-inline float GuRenderer::scaleSourceToOutputX(float offset) {
+/* Scale the input X/Y offset to appear in proper position on the screen */
+inline float GuRenderer::scaleSourceToOutput(bool x, float offset) {
float result;
if (!_useGlobalScaler)
@@ -738,28 +740,22 @@ inline float GuRenderer::scaleSourceToOutputX(float offset) {
else if (!offset)
result = 0.0f;
else
- result = offset * _displayManager->getScaleX();
+ result = x ? offset * _displayManager->getScaleX() : offset * _displayManager->getScaleY();
return result;
}
-/* Scale the input Y offset to appear in proper position on the screen */
-inline float GuRenderer::scaleSourceToOutputY(float offset) {
- float result;
-
- if (!_useGlobalScaler)
- result = offset;
- else if (!offset)
- result = 0.0f;
- else
- result = offset * _displayManager->getScaleY();
-
- return result;
+/* Scale the input X/Y offset to appear in proper position on the screen */
+inline float GuRenderer::stretch(bool x, float size) {
+ if (!_stretch)
+ return size;
+ return (x ? size * _stretchX : size * _stretchY);
}
inline void GuRenderer::guDrawVertices(Vertex *vertices) {
DEBUG_ENTER_FUNC();
+ // This function shouldn't need changing. The '32' here refers to floating point vertices.
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices);
}
diff --git a/backends/platform/psp/display_client.h b/backends/platform/psp/display_client.h
index feec477282..005fc76c7c 100644
--- a/backends/platform/psp/display_client.h
+++ b/backends/platform/psp/display_client.h
@@ -174,8 +174,13 @@ protected:
class GuRenderer {
public:
// Constructors
- GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {}
- GuRenderer(Buffer *buffer, Palette *palette) : _useGlobalScaler(false), _buffer(buffer), _palette(palette), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {}
+ GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0),
+ _blending(false), _alphaReverse(false), _colorTest(false),
+ _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {}
+ GuRenderer(Buffer *buffer, Palette *palette) :
+ _useGlobalScaler(false), _buffer(buffer), _palette(palette),
+ _blending(false), _alphaReverse(false), _colorTest(false),
+ _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {}
static void setDisplayManager(DisplayManager *dm) { _displayManager = dm; } // Called by the Display Manager
// Setters
@@ -190,8 +195,7 @@ public:
}
void setBuffer(Buffer *buffer) { _buffer = buffer; }
void setPalette(Palette *palette) { _palette = palette; }
- void setMaxTextureOffsetByIndex(uint32 x, uint32 y); // For drawing multiple textures
- void setOffsetOnScreen(uint32 x, uint32 y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; }
+ void setOffsetOnScreen(int x, int y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; }
void setOffsetInBuffer(uint32 x, uint32 y) { _offsetInBuffer.x = x; _offsetInBuffer.y = y; }
void setColorTest(bool value) { _colorTest = value; }
void setKeyColor(uint32 value) { _keyColor = _buffer->_pixelFormat.convertTo32BitColor(value); }
@@ -199,6 +203,8 @@ public:
void setAlphaReverse(bool value) { _alphaReverse = value; }
void setFullScreen(bool value) { _fullScreen = value; } // Shortcut for rendering
void setUseGlobalScaler(bool value) { _useGlobalScaler = value; } // Scale to screen
+ void setStretch(bool active) { _stretch = active; }
+ void setStretchXY(float x, float y) { _stretchX = x; _stretchY = y; }
static void cacheInvalidate(void *pointer, uint32 size);
@@ -216,11 +222,11 @@ protected:
void guDrawVertices(Vertex *vertices);
uint32 convertToGuPixelFormat(PSPPixelFormat::Type format);
- float scaleSourceToOutputX(float offset);
- float scaleSourceToOutputY(float offset);
+ float scaleSourceToOutput(bool x, float offset);
+ float stretch(bool x, float size);
friend class MasterGuRenderer;
- Point _maxTextureOffset; ///> For rendering textures > 512 pixels
+ Point _textureLoadOffset; ///> For rendering textures > 512 pixels
Point _offsetOnScreen; ///> Where on screen to draw
Point _offsetInBuffer; ///> Where in the texture to draw
bool _useGlobalScaler; ///> Scale to the output size on screen
@@ -233,6 +239,8 @@ protected:
bool _colorTest;
uint32 _keyColor; ///> Color to test against for color test. in 32 bits.
bool _fullScreen; ///> Speeds up for fullscreen rendering
+ bool _stretch; ///> Whether zooming is activated
+ float _stretchX, _stretchY;
};
#endif /* PSP_SCREEN_H */
diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp
index 5d75ac531e..2c94882a63 100644
--- a/backends/platform/psp/display_manager.cpp
+++ b/backends/platform/psp/display_manager.cpp
@@ -34,6 +34,7 @@
#include "backends/platform/psp/default_display_client.h"
#include "backends/platform/psp/cursor.h"
#include "backends/platform/psp/pspkeyboard.h"
+#include "backends/platform/psp/image_viewer.h"
#define USE_DISPLAY_CALLBACK // to use callback for finishing the render
#include "backends/platform/psp/display_manager.h"
@@ -385,10 +386,12 @@ bool DisplayManager::renderAll() {
#endif /* USE_DISPLAY_CALLBACK */
// This is cheaper than checking time, so we do it first
+ // Any one of these being dirty causes everything to draw
if (!_screen->isDirty() &&
- (!_overlay->isDirty()) &&
- (!_cursor->isDirty()) &&
- (!_keyboard->isDirty())) {
+ !_overlay->isDirty() &&
+ !_cursor->isDirty() &&
+ !_keyboard->isDirty() &&
+ !_imageViewer->isDirty()) {
PSP_DEBUG_PRINT("Nothing dirty\n");
return true; // nothing to render
}
@@ -396,34 +399,35 @@ bool DisplayManager::renderAll() {
if (!isTimeToUpdate())
return false; // didn't render
- PSP_DEBUG_PRINT("screen[%s], overlay[%s], cursor[%s], keyboard[%s]\n",
+ PSP_DEBUG_PRINT("dirty: screen[%s], overlay[%s], cursor[%s], keyboard[%s], imageViewer[%s]\n",
_screen->isDirty() ? "true" : "false",
_overlay->isDirty() ? "true" : "false",
_cursor->isDirty() ? "true" : "false",
- _keyboard->isDirty() ? "true" : "false"
+ _keyboard->isDirty() ? "true" : "false",
+ _imageViewer->isDirty() ? "true" : "false",
);
_masterGuRenderer.guPreRender(); // Set up rendering
_screen->render();
-
_screen->setClean(); // clean out dirty bit
+
+ if (_imageViewer->isVisible())
+ _imageViewer->render();
+ _imageViewer->setClean();
if (_overlay->isVisible())
- _overlay->render();
-
+ _overlay->render();
_overlay->setClean();
if (_cursor->isVisible())
_cursor->render();
-
_cursor->setClean();
if (_keyboard->isVisible())
_keyboard->render();
-
_keyboard->setClean();
-
+
_masterGuRenderer.guPostRender();
return true; // rendered successfully
diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h
index 00d3851243..4537af0096 100644
--- a/backends/platform/psp/display_manager.h
+++ b/backends/platform/psp/display_manager.h
@@ -96,6 +96,7 @@ class Screen;
class Overlay;
class Cursor;
class PSPKeyboard;
+class ImageViewer;
/**
* Class that manages all display clients
@@ -107,7 +108,8 @@ public:
KEEP_ASPECT_RATIO,
STRETCHED_FULL_SCREEN
};
- DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), _lastUpdateTime(0), _graphicsMode(0) {}
+ DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0),
+ _imageViewer(0), _lastUpdateTime(0), _graphicsMode(0) {}
~DisplayManager();
void init();
@@ -118,11 +120,13 @@ public:
uint32 getDefaultGraphicsMode() const { return STRETCHED_FULL_SCREEN; }
const OSystem::GraphicsMode* getSupportedGraphicsModes() const { return _supportedModes; }
- // Setters
+ // Setters for pointers
void setScreen(Screen *screen) { _screen = screen; }
void setCursor(Cursor *cursor) { _cursor = cursor; }
void setOverlay(Overlay *overlay) { _overlay = overlay; }
void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; }
+ void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; }
+
void setSizeAndPixelFormat(uint width, uint height, const Graphics::PixelFormat *format);
// Getters
@@ -148,6 +152,7 @@ private:
Cursor *_cursor;
Overlay *_overlay;
PSPKeyboard *_keyboard;
+ ImageViewer *_imageViewer;
MasterGuRenderer _masterGuRenderer;
uint32 _lastUpdateTime; // For limiting FPS
diff --git a/backends/platform/psp/dummy.cpp b/backends/platform/psp/dummy.cpp
new file mode 100644
index 0000000000..4236734d4b
--- /dev/null
+++ b/backends/platform/psp/dummy.cpp
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+ //#include "common/scummsys.h"
+ #include <time.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <png.h>
+ #include <sys/socket.h>
+
+//void userWriteFn(png_structp png_ptr, png_bytep data, png_size_t length) {
+//}
+
+//void userFlushFn(png_structp png_ptr) {
+//}
+
+ // Dummy functions are pulled in so that we don't need to build the plugins with certain libs
+
+ int dummyFunc() {
+
+ // For Broken Sword 2.5
+ volatile int i;
+ i = clock();
+ rename("dummyA", "dummyB");
+
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
+ png_infop info_ptr;
+ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ // For lua's usage of libc: very heavy usage so it pulls in sockets?
+ setsockopt(0, 0, 0, NULL, 0);
+ getsockopt(0, 0, 0, NULL, NULL);
+
+ return i;
+} \ No newline at end of file
diff --git a/backends/platform/psp/elf32.h b/backends/platform/psp/elf32.h
deleted file mode 100644
index 616cc4b4d2..0000000000
--- a/backends/platform/psp/elf32.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef BACKENDS_ELF_H
-#define BACKENDS_ELF_H
-
-/* ELF stuff */
-
-typedef unsigned short Elf32_Half, Elf32_Section;
-typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off;
-typedef signed int Elf32_Sword;
-typedef Elf32_Half Elf32_Versym;
-
-#define EI_NIDENT (16)
-#define SELFMAG 6
-
-/* ELF File format structures. Look up ELF structure for more details */
-
-// ELF header (contains info about the file)
-typedef struct {
- unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
- Elf32_Half e_type; /* Object file type */
- Elf32_Half e_machine; /* Architecture */
- Elf32_Word e_version; /* Object file version */
- Elf32_Addr e_entry; /* Entry point virtual address */
- Elf32_Off e_phoff; /* Program header table file offset */
- Elf32_Off e_shoff; /* Section header table file offset */
- Elf32_Word e_flags; /* Processor-specific flags */
- Elf32_Half e_ehsize; /* ELF header size in bytes */
- Elf32_Half e_phentsize; /* Program header table entry size */
- Elf32_Half e_phnum; /* Program header table entry count */
- Elf32_Half e_shentsize; /* Section header table entry size */
- Elf32_Half e_shnum; /* Section header table entry count */
- Elf32_Half e_shstrndx; /* Section header string table index */
-} Elf32_Ehdr;
-
-// Should be in e_ident
-#define ELFMAG "\177ELF\1\1" /* ELF Magic number */
-
-// e_type values
-#define ET_NONE 0 /* no file type */
-#define ET_REL 1 /* relocatable */
-#define ET_EXEC 2 /* executable */
-#define ET_DYN 3 /* shared object */
-#define ET_CORE 4 /* core file */
-
-// e_machine values
-#define EM_MIPS 8
-
-
-// Program header (contains info about segment)
-typedef struct {
- Elf32_Word p_type; /* Segment type */
- Elf32_Off p_offset; /* Segment file offset */
- Elf32_Addr p_vaddr; /* Segment virtual address */
- Elf32_Addr p_paddr; /* Segment physical address */
- Elf32_Word p_filesz; /* Segment size in file */
- Elf32_Word p_memsz; /* Segment size in memory */
- Elf32_Word p_flags; /* Segment flags */
- Elf32_Word p_align; /* Segment alignment */
-} Elf32_Phdr;
-
-// p_type values
-#define PT_NULL 0 /* ignored */
-#define PT_LOAD 1 /* loadable segment */
-#define PT_DYNAMIC 2 /* dynamic linking info */
-#define PT_INTERP 3 /* info about interpreter */
-#define PT_NOTE 4 /* note segment */
-#define PT_SHLIB 5 /* reserved */
-#define PT_PHDR 6 /* Program header table */
-#define PT_MIPS_REGINFO 0x70000000 /* register usage info */
-
-// p_flags value
-#define PF_X 1 /* execute */
-#define PF_W 2 /* write */
-#define PF_R 4 /* read */
-
-// Section header (contains info about section)
-typedef struct {
- Elf32_Word sh_name; /* Section name (string tbl index) */
- Elf32_Word sh_type; /* Section type */
- Elf32_Word sh_flags; /* Section flags */
- Elf32_Addr sh_addr; /* Section virtual addr at execution */
- Elf32_Off sh_offset; /* Section file offset */
- Elf32_Word sh_size; /* Section size in bytes */
- Elf32_Word sh_link; /* Link to another section */
- Elf32_Word sh_info; /* Additional section information */
- Elf32_Word sh_addralign; /* Section alignment */
- Elf32_Word sh_entsize; /* Entry size if section holds table */
-} Elf32_Shdr;
-
-// sh_type values
-#define SHT_NULL 0 /* Inactive section */
-#define SHT_PROGBITS 1 /* Proprietary */
-#define SHT_SYMTAB 2 /* Symbol table */
-#define SHT_STRTAB 3 /* String table */
-#define SHT_RELA 4 /* Relocation entries with addend */
-#define SHT_HASH 5 /* Symbol hash table */
-#define SHT_DYNAMIC 6 /* Info for dynamic linking */
-#define SHT_NOTE 7 /* Note section */
-#define SHT_NOBITS 8 /* Occupies no space */
-#define SHT_REL 9 /* Relocation entries without addend */
-#define SHT_SHLIB 10 /* Reserved */
-#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */
-#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs */
-#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects */
-#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table */
-
-// sh_flags values
-#define SHF_WRITE 0 /* writable section */
-#define SHF_ALLOC 2 /* section occupies memory */
-#define SHF_EXECINSTR 4 /* machine instructions */
-#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area */
-
-
-// Symbol entry (contain info about a symbol)
-typedef struct {
- Elf32_Word st_name; /* Symbol name (string tbl index) */
- Elf32_Addr st_value; /* Symbol value */
- Elf32_Word st_size; /* Symbol size */
- unsigned char st_info; /* Symbol type and binding */
- unsigned char st_other; /* Symbol visibility */
- Elf32_Section st_shndx; /* Section index */
-} Elf32_Sym;
-
-// Extract from the st_info
-#define SYM_TYPE(x) ((x)&0xF)
-#define SYM_BIND(x) ((x)>>4)
-
-
-// Symbol binding values from st_info
-#define STB_LOCAL 0 /* Symbol not visible outside object */
-#define STB_GLOBAL 1 /* Symbol visible to all object files */
-#define STB_WEAK 2 /* Similar to STB_GLOBAL */
-
-// Symbol type values from st_info
-#define STT_NOTYPE 0 /* Not specified */
-#define STT_OBJECT 1 /* Data object e.g. variable */
-#define STT_FUNC 2 /* Function */
-#define STT_SECTION 3 /* Section */
-#define STT_FILE 4 /* Source file associated with object file */
-
-// Special section header index values from st_shndex
-#define SHN_UNDEF 0
-#define SHN_LOPROC 0xFF00 /* Extended values */
-#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */
-#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */
-#define SHN_HIPROC 0xFF1F
-#define SHN_HIRESERVE 0xFFFF
-
-// Relocation entry (info about how to relocate)
-typedef struct {
- Elf32_Addr r_offset; /* Address */
- Elf32_Word r_info; /* Relocation type and symbol index */
-} Elf32_Rel;
-
-// Access macros for the relocation info
-#define REL_TYPE(x) ((x)&0xFF) /* Extract relocation type */
-#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */
-
-// MIPS relocation types
-#define R_MIPS_NONE 0
-#define R_MIPS_16 1
-#define R_MIPS_32 2
-#define R_MIPS_REL32 3
-#define R_MIPS_26 4
-#define R_MIPS_HI16 5
-#define R_MIPS_LO16 6
-#define R_MIPS_GPREL16 7
-#define R_MIPS_LITERAL 8
-#define R_MIPS_GOT16 9
-#define R_MIPS_PC16 10
-#define R_MIPS_CALL16 11
-#define R_MIPS_GPREL32 12
-#define R_MIPS_GOTHI16 13
-#define R_MIPS_GOTLO16 14
-#define R_MIPS_CALLHI16 15
-#define R_MIPS_CALLLO16 16
-
-// Mock function to get value of global pointer
-#define getGP() ({ \
- unsigned int __valgp; \
- __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \
- __valgp; \
-})
-
-#endif /* BACKENDS_ELF_H */
diff --git a/backends/platform/psp/image_viewer.cpp b/backends/platform/psp/image_viewer.cpp
new file mode 100644
index 0000000000..26b7f31c97
--- /dev/null
+++ b/backends/platform/psp/image_viewer.cpp
@@ -0,0 +1,327 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/archive.h"
+#include "common/events.h"
+#include "common/ptr.h"
+#include "gui/message.h"
+#include "engines/engine.h"
+#include "backends/platform/psp/input.h"
+#include "backends/platform/psp/display_manager.h"
+#include "backends/platform/psp/display_client.h"
+#include "backends/platform/psp/image_viewer.h"
+#include "backends/platform/psp/png_loader.h"
+#include "backends/platform/psp/thread.h"
+
+static const char *imageName = "psp_image";
+#define PSP_SCREEN_HEIGHT 272
+#define PSP_SCREEN_WIDTH 480
+
+bool ImageViewer::load(int imageNum) {
+ if (_init)
+ unload();
+
+ // build string
+ char number[8];
+ sprintf(number, "%d", imageNum);
+ Common::String imageNameStr(imageName);
+ Common::String specificImageName = imageNameStr + Common::String(number) + Common::String(".png");
+
+ // search for image file
+ if (!SearchMan.hasFile(specificImageName)) {
+ PSP_ERROR("file %s not found\n", specificImageName.c_str());
+ return false;
+ }
+
+ Common::ScopedPtr<Common::SeekableReadStream> file(SearchMan.createReadStreamForMember(specificImageName));
+
+ _buffer = new Buffer();
+ _palette = new Palette();
+ _renderer = new GuRenderer();
+
+ assert(_buffer);
+ assert(_palette);
+ assert(_renderer);
+
+ // Load a PNG into our buffer and palette. Size it by the actual size of the image
+ PngLoader image(file, *_buffer, *_palette, Buffer::kSizeBySourceSize);
+
+ PngLoader::Status status = image.allocate(); // allocate the buffers for the file
+
+ char error[100];
+ if (status == PngLoader::BAD_FILE) {
+ sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str());
+ GUI::TimedMessageDialog dialog(error, 4000);
+ dialog.runModal();
+ return false;
+ } else if (status == PngLoader::OUT_OF_MEMORY) {
+ sprintf(error, "Out of memory loading %s. Try making the image smaller", specificImageName.c_str());
+ GUI::TimedMessageDialog dialog(error, 4000);
+ dialog.runModal();
+ return false;
+ }
+ // try to load the image file
+ if (!image.load()) {
+ sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str());
+ GUI::TimedMessageDialog dialog(error, 4000);
+ dialog.runModal();
+ return false;
+ }
+
+ setConstantRendererOptions();
+ setFullScreenImageParams(); // prepare renderer for full screen view
+
+ _imageNum = imageNum; // now we can say we displayed this image
+ _init = true;
+
+ return true;
+}
+
+void ImageViewer::setConstantRendererOptions() {
+ _renderer->setBuffer(_buffer);
+ _renderer->setPalette(_palette);
+
+ _renderer->setAlphaBlending(false);
+ _renderer->setColorTest(false);
+ _renderer->setUseGlobalScaler(false);
+ _renderer->setStretch(true);
+ _renderer->setOffsetInBuffer(0, 0);
+ _renderer->setDrawWholeBuffer();
+}
+
+void ImageViewer::unload() {
+ _init = false;
+ delete _buffer;
+ delete _palette;
+ delete _renderer;
+ _buffer = 0;
+ _palette = 0;
+ _renderer = 0;
+}
+
+void ImageViewer::resetOnEngineDone() {
+ _imageNum = 0;
+}
+
+void ImageViewer::setVisible(bool visible) {
+ DEBUG_ENTER_FUNC();
+
+ if (_visible == visible)
+ return;
+
+ // from here on, we're making the loader visible
+ if (visible && g_engine) { // we can only run the image viewer when there's an engine
+ g_engine->pauseEngine(true);
+
+ load(_imageNum ? _imageNum : 1); // load the 1st image or the current
+ }
+
+ if (visible && _init) { // we managed to load
+ _visible = true;
+ setViewerButtons(true);
+
+ { // so dialog goes out of scope, destroying all allocations
+ GUI::TimedMessageDialog dialog("Image Viewer", 1000);
+ dialog.runModal();
+ }
+
+ runLoop(); // only listen to viewer events
+ } else { // we were asked to make invisible or failed to load
+ _visible = false;
+ unload();
+ setViewerButtons(false);
+
+ if (g_engine && g_engine->isPaused())
+ g_engine->pauseEngine(false);
+ }
+ setDirty();
+}
+
+// This is the only way we can truly pause the games
+// Sad but true.
+void ImageViewer::runLoop() {
+ while (_visible) {
+ Common::Event event;
+ PspThread::delayMillis(30);
+ _inputHandler->getAllInputs(event);
+ _displayManager->renderAll();
+ }
+}
+
+void ImageViewer::setViewerButtons(bool active) {
+ _inputHandler->setImageViewerMode(active);
+}
+
+void ImageViewer::loadNextImage() {
+ if (!load(_imageNum+1)) { // try to load the next image
+ if (!load(_imageNum)) // we failed, so reload the current image
+ setVisible(false); // just hide
+ }
+ setDirty();
+}
+
+void ImageViewer::loadLastImage() {
+ if (_imageNum - 1 > 0) {
+ if (!load(_imageNum-1))
+ if (!load(_imageNum))
+ setVisible(false); // we can't even show the old image so hide
+ }
+ setDirty();
+}
+
+void ImageViewer::setFullScreenImageParams() {
+ // we try to fit the image fullscreen at least in one dimension
+ uint32 width = _buffer->getSourceWidth();
+ uint32 height = _buffer->getSourceHeight();
+
+ _centerX = PSP_SCREEN_WIDTH / 2.0f;
+ _centerY = PSP_SCREEN_HEIGHT / 2.0f;
+
+ // see if we fit width wise
+ if (PSP_SCREEN_HEIGHT >= (int)((height * PSP_SCREEN_WIDTH) / (float)width)) {
+ setZoom(PSP_SCREEN_WIDTH / (float)width);
+ } else {
+ setZoom(PSP_SCREEN_HEIGHT / (float)height);
+ }
+}
+
+void ImageViewer::render() {
+ if (_init) {
+ assert(_buffer);
+ assert(_renderer);
+
+ // move the image slightly. Note that we count on the renderer's timing
+ switch (_movement) {
+ case EVENT_MOVE_LEFT:
+ moveImageX(-_visibleWidth / 100.0f);
+ break;
+ case EVENT_MOVE_UP:
+ moveImageY(-_visibleHeight / 100.0f);
+ break;
+ case EVENT_MOVE_RIGHT:
+ moveImageX(_visibleWidth / 100.0f);
+ break;
+ case EVENT_MOVE_DOWN:
+ moveImageY(_visibleHeight / 100.0f);
+ break;
+ default:
+ break;
+ }
+ _renderer->render();
+ }
+}
+
+void ImageViewer::modifyZoom(bool up) {
+ float factor = _zoomFactor;
+ if (up)
+ factor += 0.1f;
+ else // down
+ factor -= 0.1f;
+
+ setZoom(factor);
+}
+
+void ImageViewer::setZoom(float value) {
+ if (value <= 0.0f) // don't want 0 or negative zoom
+ return;
+
+ _zoomFactor = value;
+ _renderer->setStretchXY(value, value);
+ setOffsetParams();
+}
+
+void ImageViewer::moveImageX(float val) {
+ float newVal = _centerX + val;
+
+ if (newVal - (_visibleWidth / 2) > PSP_SCREEN_WIDTH - 4 || newVal + (_visibleWidth / 2) < 4)
+ return;
+ _centerX = newVal;
+ setOffsetParams();
+}
+
+void ImageViewer::moveImageY(float val) {
+ float newVal = _centerY + val;
+
+ if (newVal - (_visibleHeight / 2) > PSP_SCREEN_HEIGHT - 4 || newVal + (_visibleHeight / 2) < 4)
+ return;
+ _centerY = newVal;
+ setOffsetParams();
+}
+
+// Set the renderer with the proper offset on the screen
+//
+void ImageViewer::setOffsetParams() {
+ _visibleWidth = _zoomFactor * _buffer->getSourceWidth();
+ _visibleHeight = _zoomFactor * _buffer->getSourceHeight();
+
+ int offsetX = _centerX - (int)(_visibleWidth * 0.5f);
+ int offsetY = _centerY - (int)(_visibleHeight * 0.5f);
+
+ _renderer->setOffsetOnScreen(offsetX, offsetY);
+ setDirty();
+}
+
+// Handler events coming in from the inputHandler
+//
+void ImageViewer::handleEvent(uint32 event) {
+ DEBUG_ENTER_FUNC();
+
+ switch (event) {
+ case EVENT_HIDE:
+ setVisible(false);
+ break;
+ case EVENT_SHOW:
+ setVisible(true);
+ break;
+ case EVENT_ZOOM_IN:
+ modifyZoom(true);
+ break;
+ case EVENT_ZOOM_OUT:
+ modifyZoom(false);
+ break;
+ case EVENT_MOVE_LEFT:
+ case EVENT_MOVE_UP:
+ case EVENT_MOVE_RIGHT:
+ case EVENT_MOVE_DOWN:
+ case EVENT_MOVE_STOP:
+ _movement = (Event)event;
+ break;
+ case EVENT_NEXT_IMAGE:
+ loadNextImage();
+ break;
+ case EVENT_LAST_IMAGE:
+ loadLastImage();
+ break;
+ default:
+ PSP_ERROR("Unknown event %d\n", event);
+ break;
+ }
+} \ No newline at end of file
diff --git a/backends/platform/psp/image_viewer.h b/backends/platform/psp/image_viewer.h
new file mode 100644
index 0000000000..ef8b196dbe
--- /dev/null
+++ b/backends/platform/psp/image_viewer.h
@@ -0,0 +1,105 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+#ifndef PSP_IMAGE_VIEWER_H
+#define PSP_IMAGE_VIEWER_H
+
+class InputHandler;
+
+class ImageViewer : public DisplayClient {
+public:
+ enum Event {
+ EVENT_NONE = -1,
+ EVENT_HIDE = 0,
+ EVENT_SHOW = 1,
+ EVENT_ZOOM_IN,
+ EVENT_ZOOM_OUT,
+ EVENT_MOVE_LEFT,
+ EVENT_MOVE_UP,
+ EVENT_MOVE_RIGHT,
+ EVENT_MOVE_DOWN,
+ EVENT_MOVE_STOP,
+ EVENT_NEXT_IMAGE,
+ EVENT_LAST_IMAGE,
+ };
+
+private:
+ Buffer *_buffer;
+ Palette *_palette;
+ GuRenderer *_renderer;
+ bool _visible;
+ bool _dirty;
+ bool _init;
+ uint32 _imageNum; // current image number
+ float _zoomFactor; // how much we're zooming in/out on the image
+ float _visibleHeight, _visibleWidth;
+ float _centerX, _centerY;
+ Event _movement;
+
+ InputHandler *_inputHandler;
+ DisplayManager *_displayManager;
+
+ void setFullScreenImageParams();
+ void loadNextImage();
+ void loadLastImage();
+ void setViewerButtons(bool active);
+ void setConstantRendererOptions();
+ void moveImageX(float val);
+ void moveImageY(float val);
+ bool load(int imageNum);
+ void unload();
+ void runLoop(); // to get total pausing we have to do our own loop
+
+ void setZoom(float value);
+ void setOffsetParams();
+ void modifyZoom(bool up); // up or down
+ void setVisible(bool visible);
+
+public:
+
+ ImageViewer() : _buffer(0), _palette(0), _visible(false),
+ _dirty(false), _init(false), _imageNum(0),
+ _zoomFactor(0.0f), _visibleHeight(0.0f), _visibleWidth(0.0f),
+ _centerX(0.0f), _centerY(0.0f), _movement(EVENT_MOVE_STOP),
+ _inputHandler(0), _displayManager(0) {}
+ ~ImageViewer() { unload(); } // deallocate images
+ bool load();
+ void render();
+ bool isVisible() { return _visible; }
+ bool isDirty() { return _dirty; }
+ void setDirty() { _dirty = true; }
+ void setClean() { if (!_visible) // otherwise we want to keep rendering
+ _dirty = false;
+ }
+ void resetOnEngineDone();
+
+ void handleEvent(uint32 event);
+
+ // pointer setters
+ void setInputHandler(InputHandler *inputHandler) { _inputHandler = inputHandler; }
+ void setDisplayManager(DisplayManager *displayManager) { _displayManager = displayManager; }
+};
+
+#endif /* PSP_IMAGE_VIEWER_H */ \ No newline at end of file
diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp
index ed868ef375..0dad31e5ae 100644
--- a/backends/platform/psp/input.cpp
+++ b/backends/platform/psp/input.cpp
@@ -95,7 +95,7 @@ const uint32 ButtonPad::_buttonMap[] = {
};
ButtonPad::ButtonPad() : _prevButtonState(0), _shifted(UNSHIFTED), _padMode(PAD_MODE_NORMAL),
- _comboMode(false) {
+ _comboMode(false), _combosEnabled(true) {
for (int i = UNSHIFTED; i < SHIFTED_MODE_LAST; i++)
_buttonsChanged[i] = 0;
clearButtons();
@@ -154,6 +154,7 @@ void ButtonPad::initButtonsNormalMode() {
_button[BTN_START][SHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5);
_button[BTN_START][UNSHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5, Common::KBD_CTRL);
_button[BTN_SELECT][UNSHIFTED].setPspEvent(PSP_EVENT_SHOW_VIRTUAL_KB, true, PSP_EVENT_NONE, 0);
+ _button[BTN_SELECT][SHIFTED].setPspEvent(PSP_EVENT_IMAGE_VIEWER, true, PSP_EVENT_NONE, 0);
}
void ButtonPad::initButtonsLolMode() {
@@ -199,7 +200,8 @@ bool ButtonPad::getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &
uint32 curButtonState = PSP_ALL_BUTTONS & pad.Buttons; // we only care about these
- modifyButtonsForCombos(pad); // change buttons for combos
+ if (_combosEnabled)
+ modifyButtonsForCombos(pad); // change buttons for combos
return getEventFromButtonState(event, pspEvent, curButtonState);
}
@@ -369,6 +371,7 @@ void InputHandler::init() {
sceCtrlSetSamplingMode(1); // analog
_buttonPad.initButtons();
+ _nub.init();
}
bool InputHandler::getAllInputs(Common::Event &event) {
@@ -460,6 +463,12 @@ bool InputHandler::handlePspEvent(Common::Event &event, PspEvent &pspEvent) {
/*case PSP_EVENT_CHANGE_SPEED:
handleSpeedChange(pspEvent.data);
break;*/
+ case PSP_EVENT_IMAGE_VIEWER:
+ _imageViewer->handleEvent(pspEvent.data);
+ break;
+ case PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS:
+ setImageViewerMode(pspEvent.data);
+ break;
default:
PSP_ERROR("Unhandled PSP Event[%d]\n", pspEvent.type);
break;
@@ -509,3 +518,56 @@ void InputHandler::handleSpeedChange(bool up) {
GUI::TimedMessageDialog dialog(_padModeText[_padMode], 1500);
dialog.runModal();
}*/
+
+void InputHandler::setImageViewerMode(bool active) {
+ if (_buttonPad.isButtonDown() || _nub.isButtonDown()) { // can't switch yet
+ PSP_DEBUG_PRINT("postponing image viewer on event\n");
+ _pendingPspEvent.type = PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS; // queue it to be done later
+ _pendingPspEvent.data = active;
+ } else if (active) {
+ _nub.setDpadMode(true);
+ _buttonPad.enableCombos(false); // disable combos
+ setButtonsForImageViewer();
+ } else { // deactivate
+ _nub.setDpadMode(false);
+ _nub.init();
+ _buttonPad.enableCombos(true); // re-enable combos
+ _buttonPad.initButtons();
+ }
+}
+
+void InputHandler::setButtonsForImageViewer() {
+ DEBUG_ENTER_FUNC();
+
+ // Dpad
+ _buttonPad.clearButtons();
+ _buttonPad.getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_IN,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_OUT,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_LAST_IMAGE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_NEXT_IMAGE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_LTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_RTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_START, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_SELECT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE,
+ PSP_EVENT_NONE, false);
+
+ //Nub
+ _nub.getPad().clearButtons();
+ _nub.getPad().getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_UP,
+ PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP);
+ _nub.getPad().getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_DOWN,
+ PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP);
+ _nub.getPad().getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_LEFT,
+ PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP);
+ _nub.getPad().getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_RIGHT,
+ PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP);
+}
+
+
diff --git a/backends/platform/psp/input.h b/backends/platform/psp/input.h
index acca04f376..9a1ab6faab 100644
--- a/backends/platform/psp/input.h
+++ b/backends/platform/psp/input.h
@@ -30,6 +30,7 @@
#include "common/events.h"
#include "backends/platform/psp/pspkeyboard.h"
#include "backends/platform/psp/cursor.h"
+#include "backends/platform/psp/image_viewer.h"
#include <pspctrl.h>
enum PspEventType {
@@ -40,10 +41,11 @@ enum PspEventType {
PSP_EVENT_RBUTTON,
PSP_EVENT_MODE_SWITCH,
PSP_EVENT_CHANGE_SPEED,
+ PSP_EVENT_IMAGE_VIEWER,
+ PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS,
PSP_EVENT_LAST
};
-
struct PspEvent {
PspEventType type;
uint32 data;
@@ -112,59 +114,77 @@ private:
ShiftMode _shifted;
PspPadMode _padMode;
bool _comboMode; // are we in the middle of combos
- static const uint32 _buttonMap[]; // maps the buttons to their values
+ bool _combosEnabled; // can we do combos
+ static const uint32 _buttonMap[]; // maps the buttons to their values
void initButtonsNormalMode();
void initButtonsLolMode();
void modifyButtonsForCombos(SceCtrlData &pad);
- void clearButtons();
public:
ButtonPad();
+ void initButtons(); // set the buttons to the mode that's selected
+ void clearButtons(); // empty the buttons of all events
+
bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad);
bool getEventFromButtonState(Common::Event &event, PspEvent &pspEvent, uint32 buttonState);
+
void setShifted(ShiftMode shifted) { _shifted = shifted; }
void setPadMode(PspPadMode mode) { _padMode = mode; }
bool isButtonDown() { return _prevButtonState; }
- void initButtons();
+
+ void enableCombos(bool value) { _combosEnabled = value; }
+ Button &getButton(ButtonType type, ShiftMode mode) { return _button[type][mode]; }
};
class Nub {
private:
Cursor *_cursor; // to enable changing/getting cursor position
- ButtonPad _buttonPad; // private buttonpad for dpad mode
ShiftMode _shifted;
bool _dpadMode;
-
+
+ ButtonPad _buttonPad; // private buttonpad for dpad mode
+
+ int32 modifyNubAxisMotion(int32 input);
+ void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data
public:
- Nub() : _shifted(UNSHIFTED), _dpadMode(false) { _buttonPad.initButtons(); }
+ Nub() : _shifted(UNSHIFTED), _dpadMode(false) { }
+ void init() { _buttonPad.initButtons(); }
void setCursor(Cursor *cursor) { _cursor = cursor; }
+
+ // setters
void setDpadMode(bool active) { _dpadMode = active; }
void setShifted(ShiftMode shifted) { _shifted = shifted; }
- bool isButtonDown();
+ // getters
+ bool isButtonDown();
bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad);
- int32 modifyNubAxisMotion(int32 input);
- void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data
+ ButtonPad &getPad() { return _buttonPad; }
};
class InputHandler {
public:
- InputHandler() : _keyboard(0), _cursor(0), _padMode(PAD_MODE_NORMAL), _lastPadCheckTime(0) {}
+ InputHandler() : _keyboard(0), _cursor(0), _imageViewer(0), _padMode(PAD_MODE_NORMAL),
+ _lastPadCheckTime(0) {}
+ // pointer setters
void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; }
void setCursor(Cursor *cursor) { _cursor = cursor; _nub.setCursor(cursor); }
+ void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; }
void init();
bool getAllInputs(Common::Event &event);
+ void setImageViewerMode(bool active);
private:
+ Nub _nub;
+ ButtonPad _buttonPad;
+
+ // Pointers to relevant other classes
PSPKeyboard *_keyboard;
Cursor *_cursor;
-
- Nub _nub;
- ButtonPad _buttonPad;
+ ImageViewer *_imageViewer;
PspPadMode _padMode; // whice mode we're in
PspEvent _pendingPspEvent; // an event that can't be handled yet
@@ -176,6 +196,7 @@ private:
void handleMouseEvent(Common::Event &event, Common::EventType type, const char *string);
void handleShiftEvent(ShiftMode shifted);
void handleModeSwitchEvent();
+ void setButtonsForImageViewer();
};
#endif /* PSP_INPUT_H */
diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk
index f96c4ef583..e3eac153dd 100644
--- a/backends/platform/psp/module.mk
+++ b/backends/platform/psp/module.mk
@@ -11,14 +11,15 @@ MODULE_OBJS := powerman.o \
input.o \
cursor.o \
trace.o \
- psploader.o \
pspkeyboard.o \
audio.o \
thread.o \
rtc.o \
mp3.o \
png_loader.o \
- tests.o
+ image_viewer.o \
+ tests.o \
+ dummy.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp
index 047ec1957f..40c074ae00 100644
--- a/backends/platform/psp/osys_psp.cpp
+++ b/backends/platform/psp/osys_psp.cpp
@@ -76,12 +76,18 @@ void OSystem_PSP::initBackend() {
_displayManager.setScreen(&_screen);
_displayManager.setOverlay(&_overlay);
_displayManager.setKeyboard(&_keyboard);
+ _displayManager.setImageViewer(&_imageViewer);
_displayManager.init();
// Set pointers for input handler
_inputHandler.setCursor(&_cursor);
_inputHandler.setKeyboard(&_keyboard);
+ _inputHandler.setImageViewer(&_imageViewer);
_inputHandler.init();
+
+ // Set pointers for image viewer
+ _imageViewer.setInputHandler(&_inputHandler);
+ _imageViewer.setDisplayManager(&_displayManager);
_savefile = new PSPSaveFileManager;
@@ -97,6 +103,12 @@ void OSystem_PSP::initBackend() {
OSystem::initBackend();
}
+// Let's us know an engine
+void OSystem_PSP::engineDone() {
+ // for now, all we need is to reset the image number on the viewer
+ _imageViewer.resetOnEngineDone();
+}
+
bool OSystem_PSP::hasFeature(Feature f) {
return (f == kFeatureOverlaySupportsAlpha || f == kFeatureCursorHasPalette);
}
diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h
index 5721296c94..52b8f4e887 100644
--- a/backends/platform/psp/osys_psp.h
+++ b/backends/platform/psp/osys_psp.h
@@ -32,10 +32,12 @@
#include "sound/mixer_intern.h"
#include "backends/base-backend.h"
#include "backends/fs/psp/psp-fs-factory.h"
+
#include "backends/platform/psp/display_client.h"
#include "backends/platform/psp/default_display_client.h"
#include "backends/platform/psp/cursor.h"
#include "backends/platform/psp/pspkeyboard.h"
+#include "backends/platform/psp/image_viewer.h"
#include "backends/platform/psp/display_manager.h"
#include "backends/platform/psp/input.h"
#include "backends/platform/psp/audio.h"
@@ -60,6 +62,7 @@ private:
InputHandler _inputHandler;
PspAudio _audio;
PspTimer _pspTimer;
+ ImageViewer _imageViewer;
public:
OSystem_PSP() : _savefile(0), _mixer(0), _timer(0), _pendingUpdate(false), _pendingUpdateCounter(0) {}
@@ -146,6 +149,7 @@ public:
Common::SaveFileManager *getSavefileManager() { return _savefile; }
FilesystemFactory *getFilesystemFactory() { return &PSPFilesystemFactory::instance(); }
void getTimeAndDate(TimeDate &t) const;
+ virtual void engineDone();
void quit();
diff --git a/backends/platform/psp/png_loader.cpp b/backends/platform/psp/png_loader.cpp
index 978db3eaf9..08f370f36d 100644
--- a/backends/platform/psp/png_loader.cpp
+++ b/backends/platform/psp/png_loader.cpp
@@ -23,32 +23,43 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#include "common/stream.h"
#include "backends/platform/psp/psppixelformat.h"
#include "backends/platform/psp/display_client.h"
#include "backends/platform/psp/png_loader.h"
+//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
+//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
+
+#include "backends/platform/psp/trace.h"
+
PngLoader::Status PngLoader::allocate() {
+ DEBUG_ENTER_FUNC();
+
if (!findImageDimensions()) {
PSP_ERROR("failed to get image dimensions\n");
return BAD_FILE;
}
- PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d]\n", _width, _height, _paletteSize, _bitDepth);
_buffer->setSize(_width, _height, _sizeBy);
+ uint32 bitsPerPixel = _bitDepth * _channels;
+
if (_paletteSize) { // 8 or 4-bit image
- if (_paletteSize <= 16) { // 4 bit
+ if (bitsPerPixel == 4) {
_buffer->setPixelFormat(PSPPixelFormat::Type_Palette_4bit);
_palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_4bit);
- _paletteSize = 16;
- } else if (_paletteSize <= 256) { // 8-bit image
- _paletteSize = 256;
+ _paletteSize = 16; // round up
+ } else if (bitsPerPixel == 8) { // 8-bit image
_buffer->setPixelFormat(PSPPixelFormat::Type_Palette_8bit);
_palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit);
+ _paletteSize = 256; // round up
} else {
- PSP_ERROR("palette of %d too big!\n", _paletteSize);
+ PSP_ERROR("too many bits per pixel[%d] for a palette\n", bitsPerPixel);
return BAD_FILE;
}
@@ -60,7 +71,7 @@ PngLoader::Status PngLoader::allocate() {
PSP_ERROR("failed to allocate buffer\n");
return OUT_OF_MEMORY;
}
- if (!_palette->allocate()) {
+ if (_buffer->hasPalette() && !_palette->allocate()) {
PSP_ERROR("failed to allocate palette\n");
return OUT_OF_MEMORY;
}
@@ -68,6 +79,7 @@ PngLoader::Status PngLoader::allocate() {
}
bool PngLoader::load() {
+ DEBUG_ENTER_FUNC();
// Try to load the image
_file->seek(0); // Go back to start
@@ -98,6 +110,7 @@ void PngLoader::libReadFunc(png_structp pngPtr, png_bytep data, png_size_t lengt
}
bool PngLoader::basicImageLoad() {
+ DEBUG_ENTER_FUNC();
_pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!_pngPtr)
return false;
@@ -119,7 +132,8 @@ bool PngLoader::basicImageLoad() {
int interlaceType;
png_get_IHDR(_pngPtr, _infoPtr, (png_uint_32 *)&_width, (png_uint_32 *)&_height, &_bitDepth,
&_colorType, &interlaceType, int_p_NULL, int_p_NULL);
-
+ _channels = png_get_channels(_pngPtr, _infoPtr);
+
if (_colorType & PNG_COLOR_MASK_PALETTE)
_paletteSize = _infoPtr->num_palette;
@@ -130,11 +144,11 @@ bool PngLoader::basicImageLoad() {
bool PngLoader::findImageDimensions() {
DEBUG_ENTER_FUNC();
- if (!basicImageLoad())
- return false;
+ bool status = basicImageLoad();
+ PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d], channels[%d], rowBytes[%d]\n", _width, _height, _paletteSize, _bitDepth, _channels, _infoPtr->rowbytes);
png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL);
- return true;
+ return status;
}
//
@@ -143,16 +157,16 @@ bool PngLoader::findImageDimensions() {
bool PngLoader::loadImageIntoBuffer() {
DEBUG_ENTER_FUNC();
- if (!basicImageLoad())
+ if (!basicImageLoad()) {
+ png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL);
return false;
-
- // Strip off 16 bit channels. Not really needed but whatever
- png_set_strip_16(_pngPtr);
+ }
+ png_set_strip_16(_pngPtr); // Strip off 16 bit channels in case they occur
if (_paletteSize) {
// Copy the palette
png_colorp srcPal = _infoPtr->palette;
- for (int i = 0; i < (int)_paletteSize; i++) {
+ for (int i = 0; i < _infoPtr->num_palette; i++) {
unsigned char alphaVal = (i < _infoPtr->num_trans) ? _infoPtr->trans[i] : 0xFF; // Load alpha if it's there
_palette->setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal);
srcPal++;
@@ -163,10 +177,21 @@ bool PngLoader::loadImageIntoBuffer() {
if (png_get_valid(_pngPtr, _infoPtr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(_pngPtr); // Convert trans channel to alpha for 32 bits
- png_set_filler(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha?
+ png_set_add_alpha(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha if none exists
}
- unsigned char *line = (unsigned char*) malloc(_infoPtr->rowbytes);
+ uint32 rowBytes = png_get_rowbytes(_pngPtr, _infoPtr);
+
+ // there seems to be a bug in libpng where it doesn't increase the rowbytes or the
+ // channel even after we add the alpha channel
+ if (_channels == 3 && (rowBytes / _width) == 3) {
+ _channels = 4;
+ rowBytes = _width * _channels;
+ }
+
+ PSP_DEBUG_PRINT("rowBytes[%d], channels[%d]\n", rowBytes, _channels);
+
+ unsigned char *line = (unsigned char*) malloc(rowBytes);
if (!line) {
png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL);
PSP_ERROR("Couldn't allocate line\n");
@@ -175,11 +200,9 @@ bool PngLoader::loadImageIntoBuffer() {
for (size_t y = 0; y < _height; y++) {
png_read_row(_pngPtr, line, png_bytep_NULL);
- _buffer->copyFromRect(line, _infoPtr->rowbytes, 0, y, _width, 1); // Copy into buffer
+ _buffer->copyFromRect(line, rowBytes, 0, y, _width, 1); // Copy into buffer
}
-
free(line);
-
png_read_end(_pngPtr, _infoPtr);
png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL);
diff --git a/backends/platform/psp/png_loader.h b/backends/platform/psp/png_loader.h
index 6b0282621a..4119bfef2b 100644
--- a/backends/platform/psp/png_loader.h
+++ b/backends/platform/psp/png_loader.h
@@ -44,11 +44,14 @@ private:
uint32 _width;
uint32 _height;
uint32 _paletteSize;
- int _bitDepth;
Buffer::HowToSize _sizeBy;
+
+ // PNG lib values
+ int _bitDepth;
png_structp _pngPtr;
png_infop _infoPtr;
int _colorType;
+ uint32 _channels;
public:
enum Status {
@@ -61,7 +64,8 @@ public:
Buffer::HowToSize sizeBy = Buffer::kSizeByTextureSize) :
_file(file), _buffer(&buffer), _palette(&palette),
_width(0), _height(0), _paletteSize(0),
- _bitDepth(0), _sizeBy(sizeBy), _pngPtr(0), _infoPtr(0), _colorType(0) {}
+ _bitDepth(0), _sizeBy(sizeBy), _pngPtr(0),
+ _infoPtr(0), _colorType(0), _channels(0) {}
PngLoader::Status allocate();
bool load();
diff --git a/backends/platform/psp/psp.spec b/backends/platform/psp/psp.spec
index ac325b7fd6..7177413373 100644
--- a/backends/platform/psp/psp.spec
+++ b/backends/platform/psp/psp.spec
@@ -1,3 +1,3 @@
%rename lib old_lib
*lib:
-%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel
+%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel -lpspnet_inet
diff --git a/backends/platform/psp/pspkeyboard.cpp b/backends/platform/psp/pspkeyboard.cpp
index 3dd5e9789b..f210726692 100644
--- a/backends/platform/psp/pspkeyboard.cpp
+++ b/backends/platform/psp/pspkeyboard.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
//#define PSP_KB_SHELL /* Need a hack to properly load the keyboard from the PSP shell */
#ifdef PSP_KB_SHELL
@@ -78,9 +81,9 @@ short PSPKeyboard::_modeChar[MODE_COUNT][5][6] = {
},
{ //numbers
{ K('1'), K('2'), K('3'), K('4'), K(0), K(0) },
- { C(F5), C(F8), C(F7), C(F6), C(F9), C(F10) },
+ { C(F5), C(F6), C(F7), C(F8), C(F9), C(F10) },
{ K('5'), K('6'), K('7'), K('8'), K(0), K(0) },
- { C(F1), C(F4), C(F3), C(F2), K(0), K(0) },
+ { C(F1), C(F2), C(F3), C(F4), K(0), K(0) },
{ K('\b'), K('0'), K(' '), K('9'), K(0), K(0) }
},
{ //symbols
diff --git a/backends/platform/psp/psploader.cpp b/backends/platform/psp/psploader.cpp
deleted file mode 100644
index 464e20770c..0000000000
--- a/backends/platform/psp/psploader.cpp
+++ /dev/null
@@ -1,732 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(DYNAMIC_MODULES) && defined(__PSP__)
-
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <malloc.h>
-#include <unistd.h>
-#include <sys/_default_fcntl.h>
-
-#include <psputils.h>
-
-#include "backends/platform/psp/psploader.h"
-#include "backends/platform/psp/powerman.h"
-
-//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
-//#define __PSP_DEBUG_PRINT__
-
-#include "backends/platform/psp/trace.h"
-
-extern char __plugin_hole_start; // Indicates start of hole in program file for shorts
-extern char __plugin_hole_end; // Indicates end of hole in program file
-extern char _gp[]; // Value of gp register
-
-DECLARE_SINGLETON(ShortSegmentManager) // For singleton
-
-// Get rid of symbol table in memory
-void DLObject::discard_symtab() {
- DEBUG_ENTER_FUNC();
- free(_symtab);
- free(_strtab);
- _symtab = NULL;
- _strtab = NULL;
- _symbol_cnt = 0;
-}
-
-// Unload all objects from memory
-void DLObject::unload() {
- DEBUG_ENTER_FUNC();
- discard_symtab();
- free(_segment);
- _segment = NULL;
-
- if (_shortsSegment) {
- ShortsMan.deleteSegment(_shortsSegment);
- _shortsSegment = NULL;
- }
-}
-
-/**
- * Follow the instruction of a relocation section.
- *
- * @param fd File Descriptor
- * @param offset Offset into the File
- * @param size Size of relocation section
- * @param relSegment Base address of relocated segment in memory (memory offset)
- *
- */
-bool DLObject::relocate(int fd, unsigned long offset, unsigned long size, void *relSegment) {
- DEBUG_ENTER_FUNC();
- Elf32_Rel *rel = NULL; // relocation entry
-
- // Allocate memory for relocation table
- if (!(rel = (Elf32_Rel *)malloc(size))) {
- PSP_ERROR("Out of memory.");
- return false;
- }
-
- // Read in our relocation table
- if (lseek(fd, offset, SEEK_SET) < 0 ||
- read(fd, rel, size) != (ssize_t)size) {
- PSP_ERROR("Relocation table load failed.");
- free(rel);
- return false;
- }
-
- // Treat each relocation entry. Loop over all of them
- int cnt = size / sizeof(*rel);
-
- PSP_DEBUG_PRINT("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
-
- bool seenHi16 = false; // For treating HI/LO16 commands
- int firstHi16 = -1; // Mark the point of the first hi16 seen
- Elf32_Addr ahl = 0; // Calculated addend
- int a = 0; // Addend: taken from the target
-
- unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives
- unsigned int relocation = 0;
- int debugRelocs[10] = {0}; // For debugging
- int extendedHi16 = 0; // Count extended hi16 treatments
- Elf32_Addr lastHiSymVal = 0;
- bool hi16InShorts = false;
-
-#define DEBUG_NUM 2
-
- // Loop over relocation entries
- for (int i = 0; i < cnt; i++) {
- // Get the symbol this relocation entry is referring to
- Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
-
- // Get the target instruction in the code
- unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset);
-
- PSP_DEBUG_DO(unsigned int origTarget = *target); // Save for debugging
-
- // Act differently based on the type of relocation
- switch (REL_TYPE(rel[i].r_info)) {
-
- case R_MIPS_HI16: // Absolute addressing.
- if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index)
- firstHi16 < 0) { // Only process first in block of HI16s
- firstHi16 = i; // Keep the first Hi16 we saw
- seenHi16 = true;
- ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up
-
- lastHiSymVal = sym->st_value;
- hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments
- if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number
- PSP_DEBUG_PRINT("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n",
- i, rel[i].r_offset, ahl, *target);
- }
- break;
-
- case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it
- if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index)
- if (!seenHi16) { // We MUST have seen HI16 first
- PSP_ERROR("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i);
- free(rel);
- return false;
- }
-
- // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment)
- // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section
- // and will be screened out above
- bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value);
-
- // Correct the bug by getting the proper value in ahl (taken from the current symbol)
- if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) {
- ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset
- ahl += (sym->st_value & 0xffff0000);
- }
-
- ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s
- a = *target & 0xffff; // Take lower 16 bits of the target
- a = (a << 16) >> 16; // Sign extend them
- ahl += a; // Add lower 16 bits. AHL is now complete
-
- // Fix: we can have LO16 access to the short segment sometimes
- if (lo16InShorts) {
- relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset
- } else // It's in the regular segment
- relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment
-
- if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now
- for (int j = firstHi16; j < i; j++) {
- if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s
-
- lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target
- *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target
- *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation
- if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case
- }
- firstHi16 = -1; // Reset so we'll know we treated it
- } else {
- extendedHi16++;
- }
-
- *target &= 0xffff0000; // Clear the lower 16 bits of current target
- *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation
-
- if (debugRelocs[1]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
- i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
- if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
- i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
- }
- break;
-
- case R_MIPS_26: // Absolute addressing (for jumps and branches only)
- if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment
- a = *target & 0x03ffffff; // Get 26 bits' worth of the addend
- a = (a << 6) >> 6; // Sign extend a
- relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset
- *target &= 0xfc000000; // Clean lower 26 target bits
- *target |= (relocation & 0x03ffffff);
-
- if (debugRelocs[3]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
- i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
- } else {
- if (debugRelocs[4]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
- i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
- }
- break;
-
- case R_MIPS_GPREL16: // GP Relative addressing
- if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section
- ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole
- a = *target & 0xffff; // Get 16 bits' worth of the addend
- a = (a << 16) >> 16; // Sign extend it
-
- relocation = a + _shortsSegment->getOffset();
-
- *target &= 0xffff0000; // Clear the lower 16 bits of the target
- *target |= relocation & 0xffff;
-
- if (debugRelocs[5]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n",
- i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset());
- }
-
- break;
-
- case R_MIPS_32: // Absolute addressing
- if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
- a = *target; // Get full 32 bits of addend
-
- if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment
- relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset
- else // We're in the main section
- relocation = a + (Elf32_Addr)_segment; // Shift by main offset
- *target = relocation;
-
- if (debugRelocs[6]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
- }
- break;
-
- default:
- PSP_ERROR("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i);
- free(rel);
- return false;
- }
- }
-
- PSP_DEBUG_PRINT("Done with relocation. extendedHi16=%d\n\n", extendedHi16);
-
- free(rel);
- return true;
-}
-
-bool DLObject::readElfHeader(int fd, Elf32_Ehdr *ehdr) {
- DEBUG_ENTER_FUNC();
- // Start reading the elf header. Check for errors
- if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr) ||
- memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC
- ehdr->e_type != ET_EXEC || // Check for executable
- ehdr->e_machine != EM_MIPS || // Check for MIPS machine type
- ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header
- ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header
- PSP_ERROR("Invalid file type.");
- return false;
- }
-
- PSP_DEBUG_PRINT("phoff = %d, phentsz = %d, phnum = %d\n",
- ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum);
-
- return true;
-}
-
-bool DLObject::readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) {
- DEBUG_ENTER_FUNC();
- // Read program header
- if (lseek(fd, ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 ||
- read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) {
- PSP_ERROR("Program header load failed.");
- return false;
- }
-
- // Check program header values
- if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) {
- PSP_ERROR("Invalid program header.");
- return false;
- }
-
- PSP_DEBUG_PRINT("offs = %x, filesz = %x, memsz = %x, align = %x\n",
- phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align);
-
- return true;
-
-}
-
-bool DLObject::loadSegment(int fd, Elf32_Phdr *phdr) {
- DEBUG_ENTER_FUNC();
-
- char *baseAddress = 0;
-
- // We need to take account of non-allocated segment for shorts
- if (phdr->p_flags & PF_X) { // This is a relocated segment
-
- // Attempt to allocate memory for segment
- int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here
- PSP_DEBUG_PRINT("extra mem is %x\n", extra);
-
- if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI
-
- if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) {
- PSP_ERROR("Out of memory.\n");
- return false;
- }
- PSP_DEBUG_PRINT("allocated segment @ %p\n", _segment);
-
- // Get offset to load segment into
- baseAddress = (char *)_segment + phdr->p_vaddr;
- _segmentSize = phdr->p_memsz + extra;
- } else { // This is a shorts section.
- _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr);
-
- baseAddress = _shortsSegment->getStart();
- PSP_DEBUG_PRINT("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n",
- _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset());
-
- }
-
- // Set bss segment to 0 if necessary (assumes bss is at the end)
- if (phdr->p_memsz > phdr->p_filesz) {
- PSP_DEBUG_PRINT("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz);
- memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
- }
- // Read the segment into memory
- if (lseek(fd, phdr->p_offset, SEEK_SET) < 0 ||
- read(fd, baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
- PSP_ERROR("Segment load failed.");
- return false;
- }
-
- return true;
-}
-
-
-Elf32_Shdr * DLObject::loadSectionHeaders(int fd, Elf32_Ehdr *ehdr) {
- DEBUG_ENTER_FUNC();
-
- Elf32_Shdr *shdr = NULL;
-
- // Allocate memory for section headers
- if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) {
- PSP_ERROR("Out of memory.");
- return NULL;
- }
-
- // Read from file into section headers
- if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0 ||
- read(fd, shdr, ehdr->e_shnum * sizeof(*shdr)) !=
- (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) {
- PSP_ERROR("Section headers load failed.");
- return NULL;
- }
-
- return shdr;
-}
-
-int DLObject::loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- // Loop over sections, looking for symbol table linked to a string table
- for (int i = 0; i < ehdr->e_shnum; i++) {
- PSP_DEBUG_PRINT("Section %d: type = %x, size = %x, entsize = %x, link = %x\n",
- i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link);
-
- if (shdr[i].sh_type == SHT_SYMTAB &&
- shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
- shdr[i].sh_link < ehdr->e_shnum &&
- shdr[shdr[i].sh_link].sh_type == SHT_STRTAB &&
- _symtab_sect < 0) {
- _symtab_sect = i;
- }
- }
-
- // Check for no symbol table
- if (_symtab_sect < 0) {
- PSP_ERROR("No symbol table.");
- return -1;
- }
-
- PSP_DEBUG_PRINT("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size);
-
- // Allocate memory for symbol table
- if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) {
- PSP_ERROR("Out of memory.");
- return -1;
- }
-
- // Read symbol table into memory
- if (lseek(fd, shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 ||
- read(fd, _symtab, shdr[_symtab_sect].sh_size) !=
- (ssize_t)shdr[_symtab_sect].sh_size) {
- PSP_ERROR("Symbol table load failed.");
- return -1;
- }
-
- // Set number of symbols
- _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym);
- PSP_DEBUG_PRINT("Loaded %d symbols.\n", _symbol_cnt);
-
- return _symtab_sect;
-
-}
-
-bool DLObject::loadStringTable(int fd, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- int string_sect = shdr[_symtab_sect].sh_link;
-
- // Allocate memory for string table
- if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) {
- PSP_ERROR("Out of memory.");
- return false;
- }
-
- // Read string table into memory
- if (lseek(fd, shdr[string_sect].sh_offset, SEEK_SET) < 0 ||
- read(fd, _strtab, shdr[string_sect].sh_size) !=
- (ssize_t)shdr[string_sect].sh_size) {
- PSP_ERROR("Symbol table strings load failed.");
- return false;
- }
- return true;
-}
-
-void DLObject::relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset) {
- DEBUG_ENTER_FUNC();
-
- int shortsCount = 0, othersCount = 0;
- PSP_DEBUG_PRINT("Relocating symbols by %x. Shorts offset=%x\n", offset, shortsOffset);
-
- // Loop over symbols, add relocation offset
- Elf32_Sym *s = (Elf32_Sym *)_symtab;
- for (int c = _symbol_cnt; c--; s++) {
- // Make sure we don't relocate special valued symbols
- if (s->st_shndx < SHN_LOPROC) {
- if (!ShortsMan.inGeneralSegment((char *)s->st_value)) {
- othersCount++;
- s->st_value += offset;
- if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize)
- PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value);
- } else { // shorts section
- shortsCount++;
- s->st_value += shortsOffset;
- if (!_shortsSegment->inSegment((char *)s->st_value))
- PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value);
- }
-
- }
-
- }
-
- PSP_DEBUG_PRINT("Relocated %d short symbols, %d others.\n", shortsCount, othersCount);
-}
-
-bool DLObject::relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- // Loop over sections, finding relocation sections
- for (int i = 0; i < ehdr->e_shnum; i++) {
-
- Elf32_Shdr *curShdr = &(shdr[i]);
- //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]);
-
- if (curShdr->sh_type == SHT_REL && // Check for a relocation section
- curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
- (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
- curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
- (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
- if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment
- if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, _segment)) {
- return false;
- }
- } else { // In Shorts segment
- if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) {
- return false;
- }
- }
-
- }
- }
-
- return true;
-}
-
-
-bool DLObject::load(int fd) {
- DEBUG_ENTER_FUNC();
-
- Elf32_Ehdr ehdr; // ELF header
- Elf32_Phdr phdr; // Program header
- Elf32_Shdr *shdr; // Section header
- bool ret = true;
-
- if (readElfHeader(fd, &ehdr) == false) {
- return false;
- }
-
- for (int i = 0; i < ehdr.e_phnum; i++) { // Load our 2 segments
- PSP_DEBUG_PRINT("Loading segment %d\n", i);
-
- if (readProgramHeaders(fd, &ehdr, &phdr, i) == false)
- return false;
-
- if (!loadSegment(fd, &phdr))
- return false;
- }
-
- if ((shdr = loadSectionHeaders(fd, &ehdr)) == NULL)
- ret = false;
-
- if (ret && ((_symtab_sect = loadSymbolTable(fd, &ehdr, shdr)) < 0))
- ret = false;
-
- if (ret && (loadStringTable(fd, shdr) == false))
- ret = false;
-
- if (ret)
- relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address
-
- if (ret && (relocateRels(fd, &ehdr, shdr) == false))
- ret = false;
-
- free(shdr);
-
- return ret;
-}
-
-bool DLObject::open(const char *path) {
- DEBUG_ENTER_FUNC();
- int fd;
- void *ctors_start, *ctors_end;
-
- PSP_DEBUG_PRINT("open(\"%s\")\n", path);
-
- // Get the address of the global pointer
- _gpVal = (unsigned int) & _gp;
- PSP_DEBUG_PRINT("_gpVal is %x\n", _gpVal);
-
- PowerMan.beginCriticalSection();
-
- if ((fd = ::open(path, O_RDONLY)) < 0) {
- PSP_ERROR("%s not found.", path);
- return false;
- }
-
- // Try to load and relocate
- if (!load(fd)) {
- ::close(fd);
- unload();
- return false;
- }
-
- ::close(fd);
-
- PowerMan.endCriticalSection();
-
- // flush data cache
- sceKernelDcacheWritebackAll();
-
- // Get the symbols for the global constructors and destructors
- ctors_start = symbol("___plugin_ctors");
- ctors_end = symbol("___plugin_ctors_end");
- _dtors_start = symbol("___plugin_dtors");
- _dtors_end = symbol("___plugin_dtors_end");
-
- if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL ||
- _dtors_end == NULL) {
- PSP_ERROR("Missing ctors/dtors.");
- _dtors_start = _dtors_end = NULL;
- unload();
- return false;
- }
-
- PSP_DEBUG_PRINT("Calling constructors.\n");
- for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
- (**f)();
-
- PSP_DEBUG_PRINT("%s opened ok.\n", path);
- return true;
-}
-
-bool DLObject::close() {
- DEBUG_ENTER_FUNC();
- if (_dtors_start != NULL && _dtors_end != NULL)
- for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++)
- (**f)();
- _dtors_start = _dtors_end = NULL;
- unload();
- return true;
-}
-
-void *DLObject::symbol(const char *name) {
- DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("symbol(\"%s\")\n", name);
-
- if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) {
- PSP_ERROR("No symbol table loaded.");
- return NULL;
- }
-
- Elf32_Sym *s = (Elf32_Sym *)_symtab;
- for (int c = _symbol_cnt; c--; s++) {
-
- // We can only import symbols that are global or weak in the plugin
- if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) &&
- /*_strtab[s->st_name] == '_' && */ // Try to make this more efficient
- !strcmp(name, _strtab + s->st_name)) {
-
- // We found the symbol
- PSP_DEBUG_PRINT("=> %p\n", (void*)s->st_value);
- return (void*)s->st_value;
- }
- }
-
- PSP_ERROR("Symbol \"%s\" not found.", name);
- return NULL;
-}
-
-
-
-ShortSegmentManager::ShortSegmentManager() {
- DEBUG_ENTER_FUNC();
- _shortsStart = &__plugin_hole_start ;
- _shortsEnd = &__plugin_hole_end;
-}
-
-ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) {
- DEBUG_ENTER_FUNC();
- char *lastAddress = origAddr;
- Common::List<Segment *>::iterator i;
-
- // Find a block that fits, starting from the beginning
- for (i = _list.begin(); i != _list.end(); ++i) {
- char *currAddress = (*i)->getStart();
-
- if ((int)(currAddress - lastAddress) >= size) break;
-
- lastAddress = (*i)->getEnd();
- }
-
- if ((Elf32_Addr)lastAddress & 3)
- lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4
-
- if (lastAddress + size > _shortsEnd) {
- PSP_ERROR("No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n",
- size, lastAddress, _shortsEnd);
- return NULL;
- }
-
- Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment
-
- if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum
-
- _list.insert(i, seg);
-
- PSP_DEBUG_PRINT("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n",
- size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress);
-
- return seg;
-}
-
-void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) {
- DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd());
- _list.remove(seg);
- delete seg;
-}
-
-static char dlerr[MAXDLERRLEN];
-
-void *dlopen(const char *filename, int flags) {
- DLObject *obj = new DLObject(dlerr);
- if (obj->open(filename))
- return (void *)obj;
- delete obj;
- return NULL;
-}
-
-int dlclose(void *handle) {
- DLObject *obj = (DLObject *)handle;
- if (obj == NULL) {
- strcpy(dlerr, "Handle is NULL.");
- return -1;
- }
- if (obj->close()) {
- delete obj;
- return 0;
- }
- return -1;
-}
-
-void *dlsym(void *handle, const char *symbol) {
- if (handle == NULL) {
- strcpy(dlerr, "Handle is NULL.");
- return NULL;
- }
- return ((DLObject *)handle)->symbol(symbol);
-}
-
-const char *dlerror() {
- return dlerr;
-}
-
-void dlforgetsyms(void *handle) {
- if (handle != NULL)
- ((DLObject *)handle)->discard_symtab();
-}
-
-
-#endif /* DYNAMIC_MODULES && __PSP__ */
diff --git a/backends/platform/psp/psploader.h b/backends/platform/psp/psploader.h
deleted file mode 100644
index 13dcf6ef98..0000000000
--- a/backends/platform/psp/psploader.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef PSPLOADER_H
-#define PSPLOADER_H
-
-#include "elf32.h"
-#include "common/list.h"
-#include "common/singleton.h"
-
-#define MAXDLERRLEN 80
-
-#define ShortsMan ShortSegmentManager::instance()
-
-class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> {
-private:
- char *_shortsStart;
- char *_shortsEnd;
-
-public:
- char *getShortsStart() {
- return _shortsStart;
- }
- bool inGeneralSegment(char *addr) {
- return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd);
- }
-
- class Segment {
- private:
- friend class ShortSegmentManager;
- Segment(char *start, int size, char *origAddr) : _startAddress(start), _size(size), _origAddress(origAddr) {}
- ~Segment() {}
- char *_startAddress; // Start of shorts segment in memory
- int _size; // Size of shorts segment
- char *_origAddress; // Original address this segment was supposed to be at
- public:
- char *getStart() {
- return _startAddress;
- }
- char *getEnd() {
- return (_startAddress + _size);
- }
- Elf32_Addr getOffset() {
- return (Elf32_Addr)(_startAddress - _origAddress);
- }
- bool inSegment(char *addr) {
- return ((char *)addr >= _startAddress && (char *)addr <= _startAddress + _size);
- }
- };
-
- Segment *newSegment(int size, char *origAddr);
- void deleteSegment(Segment *);
-
-private:
- ShortSegmentManager();
- friend class Common::Singleton<ShortSegmentManager>;
- Common::List<Segment *> _list;
- char *_highestAddress;
-};
-
-
-
-
-class DLObject {
-protected:
- char *_errbuf; /* For error messages, at least MAXDLERRLEN in size */
-
- ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges
- void *_segment, *_symtab;
- char *_strtab;
- int _symbol_cnt;
- int _symtab_sect;
- void *_dtors_start, *_dtors_end;
-
- unsigned int _gpVal; // Value of Global Pointer
- int _segmentSize;
-
- void seterror(const char *fmt, ...);
- void unload();
- bool relocate(int fd, unsigned long offset, unsigned long size, void *);
- bool load(int fd);
-
- bool readElfHeader(int fd, Elf32_Ehdr *ehdr);
- bool readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num);
- bool loadSegment(int fd, Elf32_Phdr *phdr);
- Elf32_Shdr *loadSectionHeaders(int fd, Elf32_Ehdr *ehdr);
- int loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
- bool loadStringTable(int fd, Elf32_Shdr *shdr);
- void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset);
- bool relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
-
-public:
- bool open(const char *path);
- bool close();
- void *symbol(const char *name);
- void discard_symtab();
-
- DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL),
- _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) ,
- _segmentSize(0) {}
-};
-
-
-
-#define RTLD_LAZY 0
-
-extern "C" {
- void *dlopen(const char *filename, int flags);
- int dlclose(void *handle);
- void *dlsym(void *handle, const char *symbol);
- const char *dlerror();
- void dlforgetsyms(void *handle);
-}
-
-#endif /* PSPLOADER_H */
diff --git a/backends/events/samsungtvsdl/samsungtvsdl-events.cpp b/backends/platform/samsungtv/events.cpp
index d1c35d3a5a..af39e67fe5 100644
--- a/backends/events/samsungtvsdl/samsungtvsdl-events.cpp
+++ b/backends/platform/samsungtv/events.cpp
@@ -23,17 +23,13 @@
*
*/
-#ifdef SAMSUNGTV
+#include "backends/platform/samsungtv/samsungtv.h"
+#include "common/util.h"
+#include "common/events.h"
-#include "backends/events/samsungtvsdl/samsungtvsdl-events.h"
+#if defined(SAMSUNGTV)
-SamsungTVSdlEventManager::SamsungTVSdlEventManager(Common::EventSource *boss)
- :
- SdlEventManager(boss) {
-
-}
-
-bool SamsungTVSdlEventManager::remapKey(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL_SamsungTV::remapKey(SDL_Event &ev, Common::Event &event) {
switch (ev.type) {
case SDL_KEYDOWN:{
if (ev.key.keysym.sym == SDLK_POWER) {
@@ -71,8 +67,7 @@ bool SamsungTVSdlEventManager::remapKey(SDL_Event &ev, Common::Event &event) {
}
}
- // Invoke parent implementation of this method
- return SdlEventManager::remapKey(ev, event);
+ return false;
}
#endif
diff --git a/backends/platform/samsungtv/main.cpp b/backends/platform/samsungtv/main.cpp
index f3d868641b..2c025b750c 100644
--- a/backends/platform/samsungtv/main.cpp
+++ b/backends/platform/samsungtv/main.cpp
@@ -34,23 +34,16 @@
extern "C" int Game_Main(char *path, char *) {
chdir(path);
- // Create OSystem instance
g_system = new OSystem_SDL_SamsungTV();
assert(g_system);
- // Pre initialize the backend
- ((OSystem_SDL_SamsungTV *)g_system)->init();
-
#ifdef DYNAMIC_MODULES
PluginManager::instance().addPluginProvider(new SDLPluginProvider());
#endif
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(0, 0);
-
- // Free OSystem
- delete (OSystem_SDL_SamsungTV *)g_system;
-
+ ((OSystem_SDL *)g_system)->deinit();
return res;
}
diff --git a/backends/platform/samsungtv/module.mk b/backends/platform/samsungtv/module.mk
index 36ad75da6d..d7ebe75080 100644
--- a/backends/platform/samsungtv/module.mk
+++ b/backends/platform/samsungtv/module.mk
@@ -1,6 +1,7 @@
MODULE := backends/platform/samsungtv
MODULE_OBJS := \
+ events.o \
main.o \
samsungtv.o
diff --git a/backends/platform/samsungtv/samsungtv.cpp b/backends/platform/samsungtv/samsungtv.cpp
index 1e316aa840..aa79b92558 100644
--- a/backends/platform/samsungtv/samsungtv.cpp
+++ b/backends/platform/samsungtv/samsungtv.cpp
@@ -24,32 +24,19 @@
*/
#include "backends/platform/samsungtv/samsungtv.h"
-#include "backends/events/samsungtvsdl/samsungtvsdl-events.h"
-OSystem_SDL_SamsungTV::OSystem_SDL_SamsungTV()
- :
- OSystem_POSIX("/dtv/usb/sda1/.scummvmrc") {
-}
+#if defined(SAMSUNGTV)
bool OSystem_SDL_SamsungTV::hasFeature(Feature f) {
return
- (f == OSystem::kFeatureAspectRatioCorrection) ||
- (f == OSystem::kFeatureCursorHasPalette);
-}
-
-void OSystem_SDL_SamsungTV::initBackend() {
- // Create the events manager
- if (_eventManager == 0)
- _eventManager = new SamsungTVSdlEventManager(this);
-
- // Call parent implementation of this method
- OSystem_SDL::initBackend();
+ (f == kFeatureAspectRatioCorrection) ||
+ (f == kFeatureCursorHasPalette);
}
void OSystem_SDL_SamsungTV::setFeatureState(Feature f, bool enable) {
switch (f) {
- case OSystem::kFeatureAspectRatioCorrection:
- _graphicsManager->setFeatureState(f, enable);
+ case kFeatureAspectRatioCorrection:
+ setAspectRatioCorrection(enable);
break;
default:
break;
@@ -57,14 +44,14 @@ void OSystem_SDL_SamsungTV::setFeatureState(Feature f, bool enable) {
}
bool OSystem_SDL_SamsungTV::getFeatureState(Feature f) {
+ assert (_transactionMode == kTransactionNone);
+
switch (f) {
- case OSystem::kFeatureAspectRatioCorrection:
- return _graphicsManager->getFeatureState(f);
+ case kFeatureAspectRatioCorrection:
+ return _videoMode.aspectRatioCorrection;
default:
return false;
}
}
-void OSystem_SDL_SamsungTV::quit() {
- deinit();
-}
+#endif
diff --git a/backends/platform/samsungtv/samsungtv.h b/backends/platform/samsungtv/samsungtv.h
index 49460a9ddc..b3344385aa 100644
--- a/backends/platform/samsungtv/samsungtv.h
+++ b/backends/platform/samsungtv/samsungtv.h
@@ -23,22 +23,31 @@
*
*/
-#ifndef PLATFORM_SDL_SAMSUNGTV_H
-#define PLATFORM_SDL_SAMSUNGTV_H
+#ifndef SDL_SAMSUNGTV_COMMON_H
+#define SDL_SAMSUNGTV_COMMON_H
-#include "backends/platform/sdl/posix/posix.h"
+#include <SDL.h>
-class OSystem_SDL_SamsungTV : public OSystem_POSIX {
-public:
- OSystem_SDL_SamsungTV();
+#include "backends/base-backend.h"
+#include "backends/platform/sdl/sdl.h"
+
+#if defined(SAMSUNGTV)
- virtual void initBackend();
+namespace Audio {
+ class MixerImpl;
+}
+class OSystem_SDL_SamsungTV : public OSystem_SDL {
+public:
virtual bool hasFeature(Feature f);
virtual void setFeatureState(Feature f, bool enable);
virtual bool getFeatureState(Feature f);
- virtual void quit();
+protected:
+
+ virtual bool remapKey(SDL_Event &ev, Common::Event &event);
};
#endif
+
+#endif
diff --git a/backends/platform/sdl/amigaos/amigaos-main.cpp b/backends/platform/sdl/amigaos/amigaos-main.cpp
deleted file mode 100644
index db4598e879..0000000000
--- a/backends/platform/sdl/amigaos/amigaos-main.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(__amigaos4__)
-
-#include "backends/platform/sdl/amigaos/amigaos.h"
-#include "backends/plugins/sdl/sdl-provider.h"
-#include "base/main.h"
-
-int main(int argc, char *argv[]) {
-
- // Create our OSystem instance
- g_system = new OSystem_AmigaOS();
- assert(g_system);
-
- // Pre initialize the backend
- ((OSystem_AmigaOS *)g_system)->init();
-
-#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new SDLPluginProvider());
-#endif
-
- // Invoke the actual ScummVM main entry point:
- int res = scummvm_main(argc, argv);
-
- // Free OSystem
- delete (OSystem_AmigaOS *)g_system;
-
- return res;
-}
-
-#endif
diff --git a/backends/events/sdl/sdl-events.cpp b/backends/platform/sdl/events.cpp
index deea8d35ca..1c1d82730f 100644
--- a/backends/events/sdl/sdl-events.cpp
+++ b/backends/platform/sdl/events.cpp
@@ -23,11 +23,10 @@
*
*/
-#if defined(SDL_BACKEND)
-
-#include "backends/events/sdl/sdl-events.h"
#include "backends/platform/sdl/sdl.h"
-#include "common/config-manager.h"
+#include "common/util.h"
+#include "common/events.h"
+#include "graphics/scaler/aspect.h" // for aspect2Real
// FIXME move joystick defines out and replace with confile file options
// we should really allow users to map any key to a joystick button
@@ -48,32 +47,10 @@
#define JOY_BUT_SPACE 4
#define JOY_BUT_F5 5
-SdlEventSource::SdlEventSource()
- : _scrollLock(false), _joystick(0), _lastScreenID(0), EventSource() {
- // Reset mouse state
- memset(&_km, 0, sizeof(_km));
-
- int joystick_num = ConfMan.getInt("joystick_num");
- if (joystick_num > -1) {
- // Initialize SDL joystick subsystem
- if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) {
- error("Could not initialize SDL: %s", SDL_GetError());
- }
- // Enable joystick
- if (SDL_NumJoysticks() > 0) {
- printf("Using joystick: %s\n", SDL_JoystickName(0));
- _joystick = SDL_JoystickOpen(joystick_num);
- }
- }
-}
-SdlEventSource::~SdlEventSource() {
- if (_joystick)
- SDL_JoystickClose(_joystick);
-}
-int SdlEventSource::mapKey(SDLKey key, SDLMod mod, Uint16 unicode) {
+static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) {
if (key >= SDLK_F1 && key <= SDLK_F9) {
return key - SDLK_F1 + Common::ASCII_F1;
} else if (key >= SDLK_KP0 && key <= SDLK_KP9) {
@@ -90,17 +67,25 @@ int SdlEventSource::mapKey(SDLKey key, SDLMod mod, Uint16 unicode) {
return key;
}
-void SdlEventSource::fillMouseEvent(Common::Event &event, int x, int y) {
+void OSystem_SDL::fillMouseEvent(Common::Event &event, int x, int y) {
event.mouse.x = x;
event.mouse.y = y;
// Update the "keyboard mouse" coords
_km.x = x;
_km.y = y;
+
+ // Adjust for the screen scaling
+ if (!_overlayVisible) {
+ event.mouse.x /= _videoMode.scaleFactor;
+ event.mouse.y /= _videoMode.scaleFactor;
+ if (_videoMode.aspectRatioCorrection)
+ event.mouse.y = aspect2Real(event.mouse.y);
+ }
}
-void SdlEventSource::handleKbdMouse() {
- uint32 curTime = g_system->getMillis();
+void OSystem_SDL::handleKbdMouse() {
+ uint32 curTime = getMillis();
if (curTime >= _km.last_time + _km.delay_time) {
_km.last_time = curTime;
if (_km.x_down_count == 1) {
@@ -168,7 +153,7 @@ void SdlEventSource::handleKbdMouse() {
}
}
-void SdlEventSource::SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event) {
+static void SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event) {
event.kbd.flags = 0;
@@ -193,19 +178,19 @@ void SdlEventSource::SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event) {
event.kbd.flags |= Common::KBD_CAPS;
}
-bool SdlEventSource::pollEvent(Common::Event &event) {
+bool OSystem_SDL::pollEvent(Common::Event &event) {
+ SDL_Event ev;
+ ev.type = SDL_NOEVENT;
+
handleKbdMouse();
- // If the screen changed, send an Common::EVENT_SCREEN_CHANGED
- int screenID = ((OSystem_SDL *)g_system)->getGraphicsManager()->getScreenChangeID();
- if (screenID != _lastScreenID) {
- _lastScreenID = screenID;
+ // If the screen mode changed, send an Common::EVENT_SCREEN_CHANGED
+ if (_modeChanged) {
+ _modeChanged = false;
event.type = Common::EVENT_SCREEN_CHANGED;
return true;
}
- SDL_Event ev;
- ev.type = SDL_NOEVENT;
while (SDL_PollEvent(&ev)) {
preprocessEvents(&ev);
if (dispatchSDLEvent(ev, event))
@@ -214,7 +199,7 @@ bool SdlEventSource::pollEvent(Common::Event &event) {
return false;
}
-bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
switch (ev.type) {
case SDL_KEYDOWN:
return handleKeyDown(ev, event);
@@ -234,16 +219,8 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
return handleJoyAxisMotion(ev, event);
case SDL_VIDEOEXPOSE:
- // HACK: Send a fake event, handled by SdlGraphicsManager
- event.type = (Common::EventType)OSystem_SDL::kSdlEventExpose;
- return true;
-
- case SDL_VIDEORESIZE:
- // HACK: Send a fake event, handled by OpenGLSdlGraphicsManager
- event.type = (Common::EventType)OSystem_SDL::kSdlEventResize;
- event.mouse.x = ev.resize.w;
- event.mouse.y = ev.resize.h;
- return true;
+ _forceFull = true;
+ break;
case SDL_QUIT:
event.type = Common::EVENT_QUIT;
@@ -255,7 +232,7 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
}
-bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::handleKeyDown(SDL_Event &ev, Common::Event &event) {
SDLModToOSystemKeyFlags(SDL_GetModState(), event);
@@ -266,6 +243,41 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
if (_scrollLock)
event.kbd.flags |= Common::KBD_SCRL;
+ // Alt-Return and Alt-Enter toggle full screen mode
+ if (event.kbd.hasFlags(Common::KBD_ALT) && (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_KP_ENTER)) {
+ beginGFXTransaction();
+ setFullscreenMode(!_videoMode.fullscreen);
+ endGFXTransaction();
+#ifdef USE_OSD
+ if (_videoMode.fullscreen)
+ displayMessageOnOSD("Fullscreen mode");
+ else
+ displayMessageOnOSD("Windowed mode");
+#endif
+
+ return false;
+ }
+
+ // Alt-S: Create a screenshot
+ if (event.kbd.hasFlags(Common::KBD_ALT) && ev.key.keysym.sym == 's') {
+ char filename[20];
+
+ for (int n = 0;; n++) {
+ SDL_RWops *file;
+
+ sprintf(filename, "scummvm%05d.bmp", n);
+ file = SDL_RWFromFile(filename, "r");
+ if (!file)
+ break;
+ SDL_RWclose(file);
+ }
+ if (saveScreenshot(filename))
+ printf("Saved '%s'\n", filename);
+ else
+ printf("Could not save screenshot!\n");
+ return false;
+ }
+
// Ctrl-m toggles mouse capture
if (event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'm') {
toggleMouseGrab();
@@ -297,6 +309,12 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
return true;
}
+ // Ctrl-Alt-<key> will change the GFX mode
+ if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) {
+ if (handleScalerHotkeys(ev.key))
+ return false;
+ }
+
if (remapKey(ev, event))
return true;
@@ -307,7 +325,7 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
return true;
}
-bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::handleKeyUp(SDL_Event &ev, Common::Event &event) {
if (remapKey(ev, event))
return true;
@@ -322,17 +340,22 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
if (_scrollLock)
event.kbd.flags |= Common::KBD_SCRL;
+ if (isScalerHotkey(event))
+ // Swallow these key up events
+ return false;
+
return true;
}
-bool SdlEventSource::handleMouseMotion(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::handleMouseMotion(SDL_Event &ev, Common::Event &event) {
event.type = Common::EVENT_MOUSEMOVE;
fillMouseEvent(event, ev.motion.x, ev.motion.y);
+ setMousePos(event.mouse.x, event.mouse.y);
return true;
}
-bool SdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
if (ev.button.button == SDL_BUTTON_LEFT)
event.type = Common::EVENT_LBUTTONDOWN;
else if (ev.button.button == SDL_BUTTON_RIGHT)
@@ -355,7 +378,7 @@ bool SdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event)
return true;
}
-bool SdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
if (ev.button.button == SDL_BUTTON_LEFT)
event.type = Common::EVENT_LBUTTONUP;
else if (ev.button.button == SDL_BUTTON_RIGHT)
@@ -371,7 +394,7 @@ bool SdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
return true;
}
-bool SdlEventSource::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
if (ev.jbutton.button == JOY_BUT_LMOUSE) {
event.type = Common::EVENT_LBUTTONDOWN;
fillMouseEvent(event, _km.x, _km.y);
@@ -402,7 +425,7 @@ bool SdlEventSource::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
return true;
}
-bool SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
if (ev.jbutton.button == JOY_BUT_LMOUSE) {
event.type = Common::EVENT_LBUTTONUP;
fillMouseEvent(event, _km.x, _km.y);
@@ -433,7 +456,7 @@ bool SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
return true;
}
-bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
int axis = ev.jaxis.value;
if ( axis > JOY_DEADZONE) {
axis -= JOY_DEADZONE;
@@ -446,7 +469,7 @@ bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
if ( ev.jaxis.axis == JOY_XAXIS) {
#ifdef JOY_ANALOG
- _km.x_vel = axis / 2000;
+ _km.x_vel = axis/2000;
_km.x_down_count = 0;
#else
if (axis != 0) {
@@ -481,7 +504,7 @@ bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
return true;
}
-bool SdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
+bool OSystem_SDL::remapKey(SDL_Event &ev, Common::Event &event) {
#ifdef LINUPY
// On Yopy map the End button to quit
if ((ev.key.keysym.sym == 293)) {
@@ -548,19 +571,3 @@ bool SdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
#endif
return false;
}
-
-void SdlEventSource::toggleMouseGrab() {
- if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF)
- SDL_WM_GrabInput(SDL_GRAB_ON);
- else
- SDL_WM_GrabInput(SDL_GRAB_OFF);
-}
-
-void SdlEventSource::resetKeyboadEmulation(int16 x_max, int16 y_max) {
- _km.x_max = x_max;
- _km.y_max = y_max;
- _km.delay_time = 25;
- _km.last_time = 0;
-}
-
-#endif
diff --git a/backends/graphics/sdl/sdl-graphics.cpp b/backends/platform/sdl/graphics.cpp
index 151795a9d8..df63c3a7d6 100644
--- a/backends/graphics/sdl/sdl-graphics.cpp
+++ b/backends/platform/sdl/graphics.cpp
@@ -23,12 +23,7 @@
*
*/
-#if defined(SDL_BACKEND)
-
-#include "backends/graphics/sdl/sdl-graphics.h"
-#include "backends/events/sdl/sdl-events.h"
#include "backends/platform/sdl/sdl.h"
-#include "common/config-manager.h"
#include "common/mutex.h"
#include "common/translation.h"
#include "common/util.h"
@@ -92,176 +87,15 @@ static const int s_gfxModeSwitchTable[][4] = {
static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY);
#endif
-AspectRatio::AspectRatio(int w, int h) {
- // TODO : Validation and so on...
- // Currently, we just ensure the program don't instantiate non-supported aspect ratios
- _kw = w;
- _kh = h;
-}
-
-#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && defined(USE_SCALERS)
-static AspectRatio getDesiredAspectRatio() {
- const size_t AR_COUNT = 4;
- const char *desiredAspectRatioAsStrings[AR_COUNT] = { "auto", "4/3", "16/9", "16/10" };
- const AspectRatio desiredAspectRatios[AR_COUNT] = { AspectRatio(0, 0), AspectRatio(4,3), AspectRatio(16,9), AspectRatio(16,10) };
-
- //TODO : We could parse an arbitrary string, if we code enough proper validation
- Common::String desiredAspectRatio = ConfMan.get("desired_screen_aspect_ratio");
-
- for (size_t i = 0; i < AR_COUNT; i++) {
- assert(desiredAspectRatioAsStrings[i] != NULL);
-
- if (!scumm_stricmp(desiredAspectRatio.c_str(), desiredAspectRatioAsStrings[i])) {
- return desiredAspectRatios[i];
- }
- }
- // TODO : Report a warning
- return AspectRatio(0, 0);
-}
-#endif
-
-SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *sdlEventSource)
- :
- _sdlEventSource(sdlEventSource),
-#ifdef USE_OSD
- _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0),
-#endif
- _hwscreen(0), _screen(0), _tmpscreen(0),
-#ifdef USE_RGB_COLOR
- _screenFormat(Graphics::PixelFormat::createFormatCLUT8()),
- _cursorFormat(Graphics::PixelFormat::createFormatCLUT8()),
-#endif
- _overlayVisible(false),
- _overlayscreen(0), _tmpscreen2(0),
- _scalerProc(0), _screenChangeCount(0),
- _mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0),
- _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true),
- _currentShakePos(0), _newShakePos(0),
- _paletteDirtyStart(0), _paletteDirtyEnd(0),
- _screenIsLocked(false),
- _graphicsMutex(0), _transactionMode(kTransactionNone) {
-
- if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
- error("Could not initialize SDL: %s", SDL_GetError());
- }
-
- // allocate palette storage
- _currentPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
- _cursorPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
-
- _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
-
- memset(&_mouseCurState, 0, sizeof(_mouseCurState));
-
- _graphicsMutex = g_system->createMutex();
-
-#ifdef _WIN32_WCE
- if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) {
- SDL_VideoInit("windib", 0);
- sdlFlags ^= SDL_INIT_VIDEO;
- }
-#endif
-
- SDL_ShowCursor(SDL_DISABLE);
-
- memset(&_oldVideoMode, 0, sizeof(_oldVideoMode));
- memset(&_videoMode, 0, sizeof(_videoMode));
- memset(&_transactionDetails, 0, sizeof(_transactionDetails));
-
-#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && defined(USE_SCALERS)
- _videoMode.mode = GFX_DOUBLESIZE;
- _videoMode.scaleFactor = 2;
- _videoMode.aspectRatioCorrection = ConfMan.getBool("aspect_ratio");
- _videoMode.desiredAspectRatio = getDesiredAspectRatio();
- _scalerProc = Normal2x;
-#else // for small screen platforms
- _videoMode.mode = GFX_NORMAL;
- _videoMode.scaleFactor = 1;
- _videoMode.aspectRatioCorrection = false;
- _scalerProc = Normal1x;
-#endif
- _scalerType = 0;
-
-#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
- _videoMode.fullscreen = ConfMan.getBool("fullscreen");
-#else
- _videoMode.fullscreen = true;
-#endif
-}
-
-SdlGraphicsManager::~SdlGraphicsManager() {
- // Unregister the event observer
- if (g_system->getEventManager()->getEventDispatcher() != NULL)
- g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
-
- unloadGFXMode();
- g_system->deleteMutex(_graphicsMutex);
-
- free(_currentPalette);
- free(_cursorPalette);
- free(_mouseData);
-}
-
-void SdlGraphicsManager::initEventObserver() {
- // Register the graphics manager as a event observer
- g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
-}
-
-bool SdlGraphicsManager::hasFeature(OSystem::Feature f) {
- return
- (f == OSystem::kFeatureFullscreenMode) ||
- (f == OSystem::kFeatureAspectRatioCorrection) ||
- (f == OSystem::kFeatureCursorHasPalette) ||
- (f == OSystem::kFeatureIconifyWindow);
-}
-
-void SdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
- switch (f) {
- case OSystem::kFeatureFullscreenMode:
- setFullscreenMode(enable);
- break;
- case OSystem::kFeatureAspectRatioCorrection:
- setAspectRatioCorrection(enable);
- break;
- case OSystem::kFeatureIconifyWindow:
- if (enable)
- SDL_WM_IconifyWindow();
- break;
- default:
- break;
- }
-}
-
-bool SdlGraphicsManager::getFeatureState(OSystem::Feature f) {
- assert (_transactionMode == kTransactionNone);
-
- switch (f) {
- case OSystem::kFeatureFullscreenMode:
- return _videoMode.fullscreen;
- case OSystem::kFeatureAspectRatioCorrection:
- return _videoMode.aspectRatioCorrection;
- default:
- return false;
- }
-}
-
-const OSystem::GraphicsMode *SdlGraphicsManager::supportedGraphicsModes() {
+const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const {
return s_supportedGraphicsModes;
}
-const OSystem::GraphicsMode *SdlGraphicsManager::getSupportedGraphicsModes() const {
- return s_supportedGraphicsModes;
-}
-
-int SdlGraphicsManager::getDefaultGraphicsMode() const {
+int OSystem_SDL::getDefaultGraphicsMode() const {
return GFX_DOUBLESIZE;
}
-void SdlGraphicsManager::resetGraphicsScale() {
- setGraphicsMode(s_gfxModeSwitchTable[_scalerType][0]);
-}
-
-void SdlGraphicsManager::beginGFXTransaction() {
+void OSystem_SDL::beginGFXTransaction() {
assert(_transactionMode == kTransactionNone);
_transactionMode = kTransactionActive;
@@ -279,34 +113,34 @@ void SdlGraphicsManager::beginGFXTransaction() {
_oldVideoMode = _videoMode;
}
-OSystem::TransactionError SdlGraphicsManager::endGFXTransaction() {
- int errors = OSystem::kTransactionSuccess;
+OSystem::TransactionError OSystem_SDL::endGFXTransaction() {
+ int errors = kTransactionSuccess;
assert(_transactionMode != kTransactionNone);
if (_transactionMode == kTransactionRollback) {
if (_videoMode.fullscreen != _oldVideoMode.fullscreen) {
- errors |= OSystem::kTransactionFullscreenFailed;
+ errors |= kTransactionFullscreenFailed;
_videoMode.fullscreen = _oldVideoMode.fullscreen;
} else if (_videoMode.aspectRatioCorrection != _oldVideoMode.aspectRatioCorrection) {
- errors |= OSystem::kTransactionAspectRatioFailed;
+ errors |= kTransactionAspectRatioFailed;
_videoMode.aspectRatioCorrection = _oldVideoMode.aspectRatioCorrection;
} else if (_videoMode.mode != _oldVideoMode.mode) {
- errors |= OSystem::kTransactionModeSwitchFailed;
+ errors |= kTransactionModeSwitchFailed;
_videoMode.mode = _oldVideoMode.mode;
_videoMode.scaleFactor = _oldVideoMode.scaleFactor;
#ifdef USE_RGB_COLOR
} else if (_videoMode.format != _oldVideoMode.format) {
- errors |= OSystem::kTransactionFormatNotSupported;
+ errors |= kTransactionFormatNotSupported;
_videoMode.format = _oldVideoMode.format;
_screenFormat = _videoMode.format;
#endif
} else if (_videoMode.screenWidth != _oldVideoMode.screenWidth || _videoMode.screenHeight != _oldVideoMode.screenHeight) {
- errors |= OSystem::kTransactionSizeChangeFailed;
+ errors |= kTransactionSizeChangeFailed;
_videoMode.screenWidth = _oldVideoMode.screenWidth;
_videoMode.screenHeight = _oldVideoMode.screenHeight;
@@ -318,7 +152,7 @@ OSystem::TransactionError SdlGraphicsManager::endGFXTransaction() {
_videoMode.aspectRatioCorrection == _oldVideoMode.aspectRatioCorrection &&
_videoMode.mode == _oldVideoMode.mode &&
_videoMode.screenWidth == _oldVideoMode.screenWidth &&
- _videoMode.screenHeight == _oldVideoMode.screenHeight) {
+ _videoMode.screenHeight == _oldVideoMode.screenHeight) {
// Our new video mode would now be exactly the same as the
// old one. Since we still can not assume SDL_SetVideoMode
@@ -344,6 +178,7 @@ OSystem::TransactionError SdlGraphicsManager::endGFXTransaction() {
clearOverlay();
_videoMode.setup = true;
+ _modeChanged = true;
// OSystem_SDL::pollEvent used to update the screen change count,
// but actually it gives problems when a video mode was changed
// but OSystem_SDL::pollEvent was not called. This for example
@@ -360,6 +195,7 @@ OSystem::TransactionError SdlGraphicsManager::endGFXTransaction() {
}
} else {
_videoMode.setup = true;
+ _modeChanged = true;
// OSystem_SDL::pollEvent used to update the screen change count,
// but actually it gives problems when a video mode was changed
// but OSystem_SDL::pollEvent was not called. This for example
@@ -376,16 +212,17 @@ OSystem::TransactionError SdlGraphicsManager::endGFXTransaction() {
}
_transactionMode = kTransactionNone;
- return (OSystem::TransactionError)errors;
+ return (TransactionError)errors;
}
#ifdef USE_RGB_COLOR
-Common::List<Graphics::PixelFormat> SdlGraphicsManager::getSupportedFormats() const {
+
+Common::List<Graphics::PixelFormat> OSystem_SDL::getSupportedFormats() const {
assert(!_supportedFormats.empty());
return _supportedFormats;
}
-void SdlGraphicsManager::detectSupportedFormats() {
+void OSystem_SDL::detectSupportedFormats() {
// Clear old list
_supportedFormats.clear();
@@ -467,9 +304,10 @@ void SdlGraphicsManager::detectSupportedFormats() {
// Finally, we always supposed 8 bit palette graphics
_supportedFormats.push_back(Graphics::PixelFormat::createFormatCLUT8());
}
+
#endif
-bool SdlGraphicsManager::setGraphicsMode(int mode) {
+bool OSystem_SDL::setGraphicsMode(int mode) {
Common::StackLock lock(_graphicsMutex);
assert(_transactionMode == kTransactionActive);
@@ -539,7 +377,7 @@ bool SdlGraphicsManager::setGraphicsMode(int mode) {
return true;
}
-void SdlGraphicsManager::setGraphicsModeIntern() {
+void OSystem_SDL::setGraphicsModeIntern() {
Common::StackLock lock(_graphicsMutex);
ScalerProc *newScalerProc = 0;
@@ -612,12 +450,12 @@ void SdlGraphicsManager::setGraphicsModeIntern() {
blitCursor();
}
-int SdlGraphicsManager::getGraphicsMode() const {
+int OSystem_SDL::getGraphicsMode() const {
assert (_transactionMode == kTransactionNone);
return _videoMode.mode;
}
-void SdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *format) {
+void OSystem_SDL::initSize(uint w, uint h, const Graphics::PixelFormat *format) {
assert(_transactionMode == kTransactionActive);
#ifdef USE_RGB_COLOR
@@ -647,7 +485,7 @@ void SdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *f
_transactionDetails.sizeChanged = true;
}
-int SdlGraphicsManager::effectiveScreenHeight() const {
+int OSystem_SDL::effectiveScreenHeight() const {
return _videoMode.scaleFactor *
(_videoMode.aspectRatioCorrection
? real2Aspect(_videoMode.screenHeight)
@@ -678,6 +516,7 @@ static void fixupResolutionForAspectRatio(AspectRatio desiredAspectRatio, int &w
continue;
if (mode->h * kw != mode->w * kh)
continue;
+ //printf("%d %d\n", mode->w, mode->h);
uint metric = mode->w * mode->h - w * h;
if (metric > bestMetric)
@@ -691,14 +530,16 @@ static void fixupResolutionForAspectRatio(AspectRatio desiredAspectRatio, int &w
warning("Unable to enforce the desired aspect ratio");
return;
}
+ //printf("%d %d\n", bestMode->w, bestMode->h);
width = bestMode->w;
height = bestMode->h;
}
-bool SdlGraphicsManager::loadGFXMode() {
+bool OSystem_SDL::loadGFXMode() {
+ assert(_inited);
_forceFull = true;
-#if !defined(__MAEMO__) && !defined(GP2XWIZ) && !defined(LINUXMOTO) && !defined(DINGUX)
+#if !defined(__MAEMO__) && !defined(DINGUX) && !defined(GPH_DEVICE) && !defined(LINUXMOTO) && !defined(OPENPANDORA)
_videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
_videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
@@ -755,7 +596,7 @@ bool SdlGraphicsManager::loadGFXMode() {
if (!_oldVideoMode.setup) {
warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
- g_system->quit();
+ quit();
} else {
return false;
}
@@ -822,9 +663,11 @@ bool SdlGraphicsManager::loadGFXMode() {
SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey);
#endif
- _sdlEventSource->resetKeyboadEmulation(
- _videoMode.screenWidth * _videoMode.scaleFactor - 1,
- effectiveScreenHeight() - 1);
+ // keyboard cursor control, some other better place for it?
+ _km.x_max = _videoMode.screenWidth * _videoMode.scaleFactor - 1;
+ _km.y_max = effectiveScreenHeight() - 1;
+ _km.delay_time = 25;
+ _km.last_time = 0;
// Distinguish 555 and 565 mode
if (_hwscreen->format->Rmask == 0x7C00)
@@ -835,7 +678,7 @@ bool SdlGraphicsManager::loadGFXMode() {
return true;
}
-void SdlGraphicsManager::unloadGFXMode() {
+void OSystem_SDL::unloadGFXMode() {
if (_screen) {
SDL_FreeSurface(_screen);
_screen = NULL;
@@ -870,7 +713,7 @@ void SdlGraphicsManager::unloadGFXMode() {
DestroyScalers();
}
-bool SdlGraphicsManager::hotswapGFXMode() {
+bool OSystem_SDL::hotswapGFXMode() {
if (!_screen)
return false;
@@ -922,7 +765,7 @@ bool SdlGraphicsManager::hotswapGFXMode() {
return true;
}
-void SdlGraphicsManager::updateScreen() {
+void OSystem_SDL::updateScreen() {
assert (_transactionMode == kTransactionNone);
Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
@@ -930,14 +773,13 @@ void SdlGraphicsManager::updateScreen() {
internUpdateScreen();
}
-void SdlGraphicsManager::internUpdateScreen() {
+void OSystem_SDL::internUpdateScreen() {
SDL_Surface *srcSurf, *origSurf;
int height, width;
ScalerProc *scalerProc;
int scale1;
- // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
-#if defined (DEBUG) && !defined(WIN32) && !defined(_WIN32_WCE)
+#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
assert(_hwscreen != NULL);
assert(_hwscreen->map->sw_data != NULL);
#endif
@@ -1061,7 +903,7 @@ void SdlGraphicsManager::internUpdateScreen() {
assert(scalerProc != NULL);
scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
- (byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h);
+ (byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h);
}
r->x = rx1;
@@ -1100,14 +942,14 @@ void SdlGraphicsManager::internUpdateScreen() {
_mouseNeedsRedraw = false;
}
-bool SdlGraphicsManager::saveScreenshot(const char *filename) {
+bool OSystem_SDL::saveScreenshot(const char *filename) {
assert(_hwscreen != NULL);
Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
return SDL_SaveBMP(_hwscreen, filename) == 0;
}
-void SdlGraphicsManager::setFullscreenMode(bool enable) {
+void OSystem_SDL::setFullscreenMode(bool enable) {
Common::StackLock lock(_graphicsMutex);
if (_oldVideoMode.setup && _oldVideoMode.fullscreen == enable)
@@ -1119,7 +961,7 @@ void SdlGraphicsManager::setFullscreenMode(bool enable) {
}
}
-void SdlGraphicsManager::setAspectRatioCorrection(bool enable) {
+void OSystem_SDL::setAspectRatioCorrection(bool enable) {
Common::StackLock lock(_graphicsMutex);
if (_oldVideoMode.setup && _oldVideoMode.aspectRatioCorrection == enable)
@@ -1131,12 +973,12 @@ void SdlGraphicsManager::setAspectRatioCorrection(bool enable) {
}
}
-void SdlGraphicsManager::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
+void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
assert (_transactionMode == kTransactionNone);
assert(src);
if (_screen == NULL) {
- warning("SdlGraphicsManager::copyRectToScreen: _screen == NULL");
+ warning("OSystem_SDL::copyRectToScreen: _screen == NULL");
return;
}
@@ -1181,11 +1023,11 @@ void SdlGraphicsManager::copyRectToScreen(const byte *src, int pitch, int x, int
SDL_UnlockSurface(_screen);
}
-Graphics::Surface *SdlGraphicsManager::lockScreen() {
+Graphics::Surface *OSystem_SDL::lockScreen() {
assert (_transactionMode == kTransactionNone);
// Lock the graphics mutex
- g_system->lockMutex(_graphicsMutex);
+ lockMutex(_graphicsMutex);
// paranoia check
assert(!_screenIsLocked);
@@ -1208,7 +1050,7 @@ Graphics::Surface *SdlGraphicsManager::lockScreen() {
return &_framebuffer;
}
-void SdlGraphicsManager::unlockScreen() {
+void OSystem_SDL::unlockScreen() {
assert (_transactionMode == kTransactionNone);
// paranoia check
@@ -1222,17 +1064,10 @@ void SdlGraphicsManager::unlockScreen() {
_forceFull = true;
// Finally unlock the graphics mutex
- g_system->unlockMutex(_graphicsMutex);
-}
-
-void SdlGraphicsManager::fillScreen(uint32 col) {
- Graphics::Surface *screen = lockScreen();
- if (screen && screen->pixels)
- memset(screen->pixels, col, screen->h * screen->pitch);
- unlockScreen();
+ unlockMutex(_graphicsMutex);
}
-void SdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) {
+void OSystem_SDL::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) {
if (_forceFull)
return;
@@ -1300,15 +1135,15 @@ void SdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool realCoord
}
}
-int16 SdlGraphicsManager::getHeight() {
+int16 OSystem_SDL::getHeight() {
return _videoMode.screenHeight;
}
-int16 SdlGraphicsManager::getWidth() {
+int16 OSystem_SDL::getWidth() {
return _videoMode.screenWidth;
}
-void SdlGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
+void OSystem_SDL::setPalette(const byte *colors, uint start, uint num) {
assert(colors);
#ifdef USE_RGB_COLOR
@@ -1320,7 +1155,7 @@ void SdlGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
// But it could indicate a programming error, so let's warn about it.
if (!_screen)
- warning("SdlGraphicsManager::setPalette: _screen == NULL");
+ warning("OSystem_SDL::setPalette: _screen == NULL");
const byte *b = colors;
uint i;
@@ -1343,7 +1178,7 @@ void SdlGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
blitCursor();
}
-void SdlGraphicsManager::grabPalette(byte *colors, uint start, uint num) {
+void OSystem_SDL::grabPalette(byte *colors, uint start, uint num) {
assert(colors);
#ifdef USE_RGB_COLOR
@@ -1360,7 +1195,7 @@ void SdlGraphicsManager::grabPalette(byte *colors, uint start, uint num) {
}
}
-void SdlGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) {
+void OSystem_SDL::setCursorPalette(const byte *colors, uint start, uint num) {
assert(colors);
const byte *b = colors;
uint i;
@@ -1376,12 +1211,8 @@ void SdlGraphicsManager::setCursorPalette(const byte *colors, uint start, uint n
blitCursor();
}
-void SdlGraphicsManager::disableCursorPalette(bool disable) {
- _cursorPaletteDisabled = disable;
- blitCursor();
-}
-void SdlGraphicsManager::setShakePos(int shake_pos) {
+void OSystem_SDL::setShakePos(int shake_pos) {
assert (_transactionMode == kTransactionNone);
_newShakePos = shake_pos;
@@ -1392,7 +1223,7 @@ void SdlGraphicsManager::setShakePos(int shake_pos) {
#pragma mark --- Overlays ---
#pragma mark -
-void SdlGraphicsManager::showOverlay() {
+void OSystem_SDL::showOverlay() {
assert (_transactionMode == kTransactionNone);
int x, y;
@@ -1415,7 +1246,7 @@ void SdlGraphicsManager::showOverlay() {
clearOverlay();
}
-void SdlGraphicsManager::hideOverlay() {
+void OSystem_SDL::hideOverlay() {
assert (_transactionMode == kTransactionNone);
if (!_overlayVisible)
@@ -1439,7 +1270,7 @@ void SdlGraphicsManager::hideOverlay() {
_forceFull = true;
}
-void SdlGraphicsManager::clearOverlay() {
+void OSystem_SDL::clearOverlay() {
//assert (_transactionMode == kTransactionNone);
Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
@@ -1472,7 +1303,7 @@ void SdlGraphicsManager::clearOverlay() {
_forceFull = true;
}
-void SdlGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) {
+void OSystem_SDL::grabOverlay(OverlayColor *buf, int pitch) {
assert (_transactionMode == kTransactionNone);
if (_overlayscreen == NULL)
@@ -1492,7 +1323,7 @@ void SdlGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) {
SDL_UnlockSurface(_overlayscreen);
}
-void SdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
+void OSystem_SDL::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
assert (_transactionMode == kTransactionNone);
if (_overlayscreen == NULL)
@@ -1542,7 +1373,7 @@ void SdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, i
#pragma mark --- Mouse ---
#pragma mark -
-bool SdlGraphicsManager::showMouse(bool visible) {
+bool OSystem_SDL::showMouse(bool visible) {
if (_mouseVisible == visible)
return visible;
@@ -1553,7 +1384,7 @@ bool SdlGraphicsManager::showMouse(bool visible) {
return last;
}
-void SdlGraphicsManager::setMousePos(int x, int y) {
+void OSystem_SDL::setMousePos(int x, int y) {
if (x != _mouseCurState.x || y != _mouseCurState.y) {
_mouseNeedsRedraw = true;
_mouseCurState.x = x;
@@ -1561,7 +1392,7 @@ void SdlGraphicsManager::setMousePos(int x, int y) {
}
}
-void SdlGraphicsManager::warpMouse(int x, int y) {
+void OSystem_SDL::warpMouse(int x, int y) {
int y1 = y;
// Don't change actual mouse position, when mouse is outside of our window (in case of windowed mode)
@@ -1590,7 +1421,7 @@ void SdlGraphicsManager::warpMouse(int x, int y) {
}
}
-void SdlGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
+void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
#ifdef USE_RGB_COLOR
if (!format)
_cursorFormat = Graphics::PixelFormat::createFormatCLUT8();
@@ -1647,7 +1478,7 @@ void SdlGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int hot
blitCursor();
}
-void SdlGraphicsManager::blitCursor() {
+void OSystem_SDL::blitCursor() {
byte *dstPtr;
const byte *srcPtr = _mouseData;
#ifdef USE_RGB_COLOR
@@ -1838,7 +1669,14 @@ static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height
}
#endif
-void SdlGraphicsManager::undrawMouse() {
+void OSystem_SDL::toggleMouseGrab() {
+ if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF)
+ SDL_WM_GrabInput(SDL_GRAB_ON);
+ else
+ SDL_WM_GrabInput(SDL_GRAB_OFF);
+}
+
+void OSystem_SDL::undrawMouse() {
const int x = _mouseBackup.x;
const int y = _mouseBackup.y;
@@ -1851,7 +1689,7 @@ void SdlGraphicsManager::undrawMouse() {
addDirtyRect(x, y - _currentShakePos, _mouseBackup.w, _mouseBackup.h);
}
-void SdlGraphicsManager::drawMouse() {
+void OSystem_SDL::drawMouse() {
if (!_mouseVisible || !_mouseSurface) {
_mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
return;
@@ -1859,7 +1697,6 @@ void SdlGraphicsManager::drawMouse() {
SDL_Rect dst;
int scale;
- int width, height;
int hotX, hotY;
dst.x = _mouseCurState.x;
@@ -1867,16 +1704,12 @@ void SdlGraphicsManager::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
- width = _videoMode.screenWidth;
- height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
- width = _videoMode.overlayWidth;
- height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
@@ -1923,7 +1756,7 @@ void SdlGraphicsManager::drawMouse() {
#pragma mark -
#ifdef USE_OSD
-void SdlGraphicsManager::displayMessageOnOSD(const char *msg) {
+void OSystem_SDL::displayMessageOnOSD(const char *msg) {
assert (_transactionMode == kTransactionNone);
assert(msg);
@@ -1997,7 +1830,7 @@ void SdlGraphicsManager::displayMessageOnOSD(const char *msg) {
SDL_UnlockSurface(_osdSurface);
// Init the OSD display parameters, and the fade out
- _osdAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
+ _osdAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
_osdFadeStartTime = SDL_GetTicks() + kOSDFadeOutDelay;
SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha);
@@ -2006,12 +1839,16 @@ void SdlGraphicsManager::displayMessageOnOSD(const char *msg) {
}
#endif
-bool SdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
+#pragma mark -
+#pragma mark --- Misc ---
+#pragma mark -
+
+bool OSystem_SDL::handleScalerHotkeys(const SDL_KeyboardEvent &key) {
// Ctrl-Alt-a toggles aspect ratio correction
- if (key == 'a') {
+ if (key.keysym.sym == 'a') {
beginGFXTransaction();
- setFeatureState(OSystem::kFeatureAspectRatioCorrection, !_videoMode.aspectRatioCorrection);
+ setFeatureState(kFeatureAspectRatioCorrection, !_videoMode.aspectRatioCorrection);
endGFXTransaction();
#ifdef USE_OSD
char buffer[128];
@@ -2033,21 +1870,20 @@ bool SdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
int newMode = -1;
int factor = _videoMode.scaleFactor - 1;
- SDLKey sdlKey = (SDLKey)key;
// Increase/decrease the scale factor
- if (sdlKey == SDLK_EQUALS || sdlKey == SDLK_PLUS || sdlKey == SDLK_MINUS ||
- sdlKey == SDLK_KP_PLUS || sdlKey == SDLK_KP_MINUS) {
- factor += (sdlKey == SDLK_MINUS || sdlKey == SDLK_KP_MINUS) ? -1 : +1;
+ if (key.keysym.sym == SDLK_EQUALS || key.keysym.sym == SDLK_PLUS || key.keysym.sym == SDLK_MINUS ||
+ key.keysym.sym == SDLK_KP_PLUS || key.keysym.sym == SDLK_KP_MINUS) {
+ factor += (key.keysym.sym == SDLK_MINUS || key.keysym.sym == SDLK_KP_MINUS) ? -1 : +1;
if (0 <= factor && factor <= 3) {
newMode = s_gfxModeSwitchTable[_scalerType][factor];
}
}
- const bool isNormalNumber = (SDLK_1 <= sdlKey && sdlKey <= SDLK_9);
- const bool isKeypadNumber = (SDLK_KP1 <= sdlKey && sdlKey <= SDLK_KP9);
+ const bool isNormalNumber = (SDLK_1 <= key.keysym.sym && key.keysym.sym <= SDLK_9);
+ const bool isKeypadNumber = (SDLK_KP1 <= key.keysym.sym && key.keysym.sym <= SDLK_KP9);
if (isNormalNumber || isKeypadNumber) {
- _scalerType = sdlKey - (isNormalNumber ? SDLK_1 : SDLK_KP1);
+ _scalerType = key.keysym.sym - (isNormalNumber ? SDLK_1 : SDLK_KP1);
if (_scalerType >= ARRAYSIZE(s_gfxModeSwitchTable))
return false;
@@ -2065,7 +1901,7 @@ bool SdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
#ifdef USE_OSD
if (_osdSurface) {
const char *newScalerName = 0;
- const OSystem::GraphicsMode *g = getSupportedGraphicsModes();
+ const GraphicsMode *g = getSupportedGraphicsModes();
while (g->name) {
if (g->id == _videoMode.mode) {
newScalerName = g->description;
@@ -2092,7 +1928,7 @@ bool SdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
}
}
-bool SdlGraphicsManager::isScalerHotkey(const Common::Event &event) {
+bool OSystem_SDL::isScalerHotkey(const Common::Event &event) {
if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) {
const bool isNormalNumber = (Common::KEYCODE_1 <= event.kbd.keycode && event.kbd.keycode <= Common::KEYCODE_9);
const bool isKeypadNumber = (Common::KEYCODE_KP1 <= event.kbd.keycode && event.kbd.keycode <= Common::KEYCODE_KP9);
@@ -2108,94 +1944,3 @@ bool SdlGraphicsManager::isScalerHotkey(const Common::Event &event) {
}
return false;
}
-
-void SdlGraphicsManager::adjustMouseEvent(const Common::Event &event) {
- if (!event.synthetic) {
- Common::Event newEvent(event);
- newEvent.synthetic = true;
- if (!_overlayVisible) {
- newEvent.mouse.x /= _videoMode.scaleFactor;
- newEvent.mouse.y /= _videoMode.scaleFactor;
- if (_videoMode.aspectRatioCorrection)
- newEvent.mouse.y = aspect2Real(newEvent.mouse.y);
- }
- g_system->getEventManager()->pushEvent(newEvent);
- }
-}
-
-void SdlGraphicsManager::toggleFullScreen() {
- beginGFXTransaction();
- setFullscreenMode(!_videoMode.fullscreen);
- endGFXTransaction();
-#ifdef USE_OSD
- if (_videoMode.fullscreen)
- displayMessageOnOSD("Fullscreen mode");
- else
- displayMessageOnOSD("Windowed mode");
-#endif
-}
-
-bool SdlGraphicsManager::notifyEvent(const Common::Event &event) {
- switch ((int)event.type) {
- case Common::EVENT_KEYDOWN:
- // Alt-Return and Alt-Enter toggle full screen mode
- if (event.kbd.hasFlags(Common::KBD_ALT) &&
- (event.kbd.keycode == Common::KEYCODE_RETURN ||
- event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER)) {
- toggleFullScreen();
- return true;
- }
-
- // Alt-S: Create a screenshot
- if (event.kbd.hasFlags(Common::KBD_ALT) && event.kbd.keycode == 's') {
- char filename[20];
-
- for (int n = 0;; n++) {
- SDL_RWops *file;
-
- sprintf(filename, "scummvm%05d.bmp", n);
- file = SDL_RWFromFile(filename, "r");
- if (!file)
- break;
- SDL_RWclose(file);
- }
- if (saveScreenshot(filename))
- printf("Saved '%s'\n", filename);
- else
- printf("Could not save screenshot!\n");
- return true;
- }
-
- // Ctrl-Alt-<key> will change the GFX mode
- if (event.kbd.hasFlags(Common::KBD_CTRL|Common::KBD_ALT)) {
- if (handleScalerHotkeys(event.kbd.keycode))
- return true;
- }
- case Common::EVENT_KEYUP:
- return isScalerHotkey(event);
- case Common::EVENT_MOUSEMOVE:
- if (event.synthetic)
- setMousePos(event.mouse.x, event.mouse.y);
- case Common::EVENT_LBUTTONDOWN:
- case Common::EVENT_RBUTTONDOWN:
- case Common::EVENT_WHEELUP:
- case Common::EVENT_WHEELDOWN:
- case Common::EVENT_MBUTTONDOWN:
- case Common::EVENT_LBUTTONUP:
- case Common::EVENT_RBUTTONUP:
- case Common::EVENT_MBUTTONUP:
- adjustMouseEvent(event);
- return !event.synthetic;
-
- // HACK: Handle special SDL event
- case OSystem_SDL::kSdlEventExpose:
- _forceFull = true;
- return false;
- default:
- break;
- }
-
- return false;
-}
-
-#endif
diff --git a/backends/platform/sdl/macosx/macosx-main.cpp b/backends/platform/sdl/macosx/macosx-main.cpp
deleted file mode 100644
index 023860b19f..0000000000
--- a/backends/platform/sdl/macosx/macosx-main.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef MACOSX
-
-#include "backends/platform/sdl/macosx/macosx.h"
-#include "backends/plugins/sdl/sdl-provider.h"
-#include "base/main.h"
-
-int main(int argc, char *argv[]) {
-
- // Create our OSystem instance
- g_system = new OSystem_MacOSX();
- assert(g_system);
-
- // Pre initialize the backend
- ((OSystem_MacOSX *)g_system)->init();
-
-#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new SDLPluginProvider());
-#endif
-
- // Invoke the actual ScummVM main entry point:
- int res = scummvm_main(argc, argv);
-
- // Free OSystem
- delete (OSystem_MacOSX *)g_system;
-
- return res;
-}
-
-#endif
diff --git a/backends/platform/sdl/macosx/macosx.cpp b/backends/platform/sdl/macosx/macosx.cpp
deleted file mode 100644
index a36769b417..0000000000
--- a/backends/platform/sdl/macosx/macosx.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef MACOSX
-
-#include "backends/platform/sdl/macosx/macosx.h"
-#include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h"
-
-#include "common/archive.h"
-#include "common/fs.h"
-
-#include "CoreFoundation/CoreFoundation.h"
-
-OSystem_MacOSX::OSystem_MacOSX()
- :
- OSystem_POSIX("Library/Preferences/ScummVM Preferences") {
-}
-
-void OSystem_MacOSX::initBackend() {
- // Create the mixer manager
- if (_mixer == 0) {
- _mixerManager = new DoubleBufferSDLMixerManager();
-
- // Setup and start mixer
- _mixerManager->init();
- }
-
- // Invoke parent implementation of this method
- OSystem_POSIX::initBackend();
-}
-
-void OSystem_MacOSX::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
- // Invoke parent implementation of this method
- OSystem_POSIX::addSysArchivesToSearchSet(s, priority);
-
- // Get URL of the Resource directory of the .app bundle
- CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
- if (fileUrl) {
- // Try to convert the URL to an absolute path
- UInt8 buf[MAXPATHLEN];
- if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) {
- // Success: Add it to the search path
- Common::String bundlePath((const char *)buf);
- s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority);
- }
- CFRelease(fileUrl);
- }
-}
-
-void OSystem_MacOSX::setupIcon() {
- // Don't set icon on OS X, as we use a nicer external icon there.
-}
-
-#endif
diff --git a/backends/platform/sdl/main.cpp b/backends/platform/sdl/main.cpp
index 00ec0b8185..a9e1f5cf4b 100644
--- a/backends/platform/sdl/main.cpp
+++ b/backends/platform/sdl/main.cpp
@@ -23,33 +23,50 @@
*
*/
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+// Fix for bug #2895217 "MSVC compilation broken with r47595":
+// We need to keep this on top of the "common/scummsys.h" include,
+// otherwise we will get errors about the windows headers redefining
+// "ARRAYSIZE" for example.
+#if defined(WIN32) && !defined(__SYMBIAN32__)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+// winnt.h defines ARRAYSIZE, but we want our own one...
+#undef ARRAYSIZE
+#endif
+
+#include "common/scummsys.h"
+
// Several SDL based ports use a custom main, and hence do not want to compile
// of this file. The following "#if" ensures that.
-#if !defined(UNIX) && !defined(WIN32) && !defined(__MAEMO__) && !defined(__SYMBIAN32__) && !defined(__amigaos4__) && !defined(DINGUX) && !defined(CAANOO) && !defined(OPENPANDORA)
+#if !defined(__MAEMO__) && !defined(__SYMBIAN32__) && !defined(_WIN32_WCE) && !defined(DINGUX) && !defined(GPH_DEVICE) && !defined(LINUXMOTO) && !defined(OPENPANDORA)
+
#include "backends/platform/sdl/sdl.h"
#include "backends/plugins/sdl/sdl-provider.h"
#include "base/main.h"
+#ifdef WIN32
+int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*iShowCmd*/) {
+ SDL_SetModuleHandle(GetModuleHandle(NULL));
+ return main(__argc, __argv);
+}
+#endif
+
int main(int argc, char *argv[]) {
// Create our OSystem instance
g_system = new OSystem_SDL();
assert(g_system);
- // Pre initialize the backend
- ((OSystem_SDL *)g_system)->init();
-
#ifdef DYNAMIC_MODULES
PluginManager::instance().addPluginProvider(new SDLPluginProvider());
#endif
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
-
- // Free OSystem
- delete (OSystem_SDL *)g_system;
-
+ ((OSystem_SDL *)g_system)->deinit();
return res;
}
diff --git a/backends/platform/sdl/module.mk b/backends/platform/sdl/module.mk
index b00bb64718..43751a57b2 100644
--- a/backends/platform/sdl/module.mk
+++ b/backends/platform/sdl/module.mk
@@ -1,31 +1,13 @@
MODULE := backends/platform/sdl
MODULE_OBJS := \
- posix/posix-main.o \
- posix/posix.o \
+ events.o \
+ graphics.o \
hardwarekeys.o \
main.o \
sdl.o
-ifdef MACOSX
-MODULE_OBJS += \
- macosx/macosx-main.o \
- macosx/macosx.o
-endif
-
-ifdef WIN32
-MODULE_OBJS += \
- win32/win32-main.o \
- win32/win32.o
-endif
-
-ifdef AMIGAOS
-MODULE_OBJS += \
- amigaos/amigaos-main.o \
- amigaos/amigaos.o
-endif
-
-# We don't use the rules.mk here on purpose
+# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
OBJS := $(MODULE_OBJS) $(OBJS)
-MODULE_DIRS += $(sort $(dir $(MODULE_OBJS))) \ No newline at end of file
+MODULE_DIRS += $(sort $(dir $(MODULE_OBJS)))
diff --git a/backends/platform/sdl/posix/posix-main.cpp b/backends/platform/sdl/posix/posix-main.cpp
deleted file mode 100644
index de9eb2b7ef..0000000000
--- a/backends/platform/sdl/posix/posix-main.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(UNIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(LINUXMOTO) && !defined(GP2XWIZ) && !defined(GP2X) && !defined(DINGUX)
-
-#include "backends/platform/sdl/posix/posix.h"
-#include "backends/plugins/sdl/sdl-provider.h"
-#include "base/main.h"
-
-int main(int argc, char *argv[]) {
-
- // Create our OSystem instance
- g_system = new OSystem_POSIX();
- assert(g_system);
-
- // Pre initialize the backend
- ((OSystem_POSIX *)g_system)->init();
-
-#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new SDLPluginProvider());
-#endif
-
- // Invoke the actual ScummVM main entry point:
- int res = scummvm_main(argc, argv);
-
- // Free OSystem
- delete (OSystem_POSIX *)g_system;
-
- return res;
-}
-
-#endif
diff --git a/backends/platform/sdl/posix/posix.cpp b/backends/platform/sdl/posix/posix.cpp
deleted file mode 100644
index c9c7304c0f..0000000000
--- a/backends/platform/sdl/posix/posix.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef UNIX
-
-#include "backends/platform/sdl/posix/posix.h"
-#include "backends/saves/posix/posix-saves.h"
-#include "backends/fs/posix/posix-fs-factory.h"
-
-OSystem_POSIX::OSystem_POSIX(Common::String baseConfigName)
- :
- _baseConfigName(baseConfigName) {
-}
-
-void OSystem_POSIX::init() {
- // Initialze File System Factory
- _fsFactory = new POSIXFilesystemFactory();
-
- // Invoke parent implementation of this method
- OSystem_SDL::init();
-}
-
-void OSystem_POSIX::initBackend() {
- // Create the savefile manager
- if (_savefileManager == 0)
- _savefileManager = new POSIXSaveFileManager();
-
- // Invoke parent implementation of this method
- OSystem_SDL::initBackend();
-}
-
-Common::String OSystem_POSIX::getDefaultConfigFileName() {
- char configFile[MAXPATHLEN];
-
- // On UNIX type systems, by default we store the config file inside
- // to the HOME directory of the user.
- const char *home = getenv("HOME");
- if (home != NULL && strlen(home) < MAXPATHLEN)
- snprintf(configFile, MAXPATHLEN, "%s/%s", home, _baseConfigName.c_str());
- else
- strcpy(configFile, _baseConfigName.c_str());
-
- return configFile;
-}
-
-#endif
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index fbfb83fa1d..2e3819f6f5 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -23,149 +23,346 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#if defined(WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+// winnt.h defines ARRAYSIZE, but we want our own one... - this is needed before including util.h
+#undef ARRAYSIZE
+#endif
+
#include "backends/platform/sdl/sdl.h"
+#include "common/archive.h"
#include "common/config-manager.h"
+#include "common/debug.h"
#include "common/EventRecorder.h"
+#include "common/util.h"
-#include "backends/saves/default/default-saves.h"
-#include "backends/audiocd/sdl/sdl-audiocd.h"
-#include "backends/events/sdl/sdl-events.h"
-#include "backends/mutex/sdl/sdl-mutex.h"
-#include "backends/timer/sdl/sdl-timer.h"
-#include "backends/graphics/sdl/sdl-graphics.h"
-#ifdef USE_OPENGL
-#include "backends/graphics/openglsdl/openglsdl-graphics.h"
+#ifdef UNIX
+ #include "backends/saves/posix/posix-saves.h"
+#else
+ #include "backends/saves/default/default-saves.h"
#endif
+#include "backends/audiocd/sdl/sdl-audiocd.h"
+#include "backends/timer/default/default-timer.h"
+#include "sound/mixer_intern.h"
#include "icons/scummvm.xpm"
-#include <time.h>
+#include <time.h> // for getTimeAndDate()
-OSystem_SDL::OSystem_SDL()
- :
-#ifdef USE_OPENGL
- _graphicsModes(0),
- _graphicsMode(0),
- _sdlModesCount(0),
- _glModesCount(0),
+//#define SAMPLES_PER_SEC 11025
+#define SAMPLES_PER_SEC 22050
+//#define SAMPLES_PER_SEC 44100
+
+
+/*
+ * Include header files needed for the getFilesystemFactory() method.
+ */
+#if defined(__amigaos4__)
+ #include "backends/fs/amigaos4/amigaos4-fs-factory.h"
+#elif defined(UNIX)
+ #include "backends/fs/posix/posix-fs-factory.h"
+#elif defined(WIN32)
+ #include "backends/fs/windows/windows-fs-factory.h"
+#endif
+
+
+#if defined(UNIX)
+#ifdef MACOSX
+#define DEFAULT_CONFIG_FILE "Library/Preferences/ScummVM Preferences"
+#elif defined(SAMSUNGTV)
+#define DEFAULT_CONFIG_FILE "/dtv/usb/sda1/.scummvmrc"
+#else
+#define DEFAULT_CONFIG_FILE ".scummvmrc"
+#endif
+#else
+#define DEFAULT_CONFIG_FILE "scummvm.ini"
+#endif
+
+#if defined(MACOSX) || defined(IPHONE)
+#include <CoreFoundation/CoreFoundation.h>
#endif
- _inited(false),
- _initedSDL(false),
- _mixerManager(0),
- _eventSource(0) {
+
+static Uint32 timer_handler(Uint32 interval, void *param) {
+ ((DefaultTimerManager *)param)->handler();
+ return interval;
}
-OSystem_SDL::~OSystem_SDL() {
- deinit();
+AspectRatio::AspectRatio(int w, int h) {
+ // TODO : Validation and so on...
+ // Currently, we just ensure the program don't instantiate non-supported aspect ratios
+ _kw = w;
+ _kh = h;
}
-void OSystem_SDL::init() {
- // Initialize SDL
- initSDL();
+#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && defined(USE_SCALERS)
+static AspectRatio getDesiredAspectRatio() {
+ const size_t AR_COUNT = 4;
+ const char* desiredAspectRatioAsStrings[AR_COUNT] = { "auto", "4/3", "16/9", "16/10" };
+ const AspectRatio desiredAspectRatios[AR_COUNT] = { AspectRatio(0, 0), AspectRatio(4,3), AspectRatio(16,9), AspectRatio(16,10) };
- // Creates the early needed managers, if they don't exist yet
- // (we check for this to allow subclasses to provide their own).
- if (_mutexManager == 0)
- _mutexManager = new SdlMutexManager();
+ //TODO : We could parse an arbitrary string, if we code enough proper validation
+ Common::String desiredAspectRatio = ConfMan.get("desired_screen_aspect_ratio");
- if (_timerManager == 0)
- _timerManager = new SdlTimerManager();
+ for (size_t i = 0; i < AR_COUNT; i++) {
+ assert(desiredAspectRatioAsStrings[i] != NULL);
- #ifdef USE_OPENGL
- // Setup a list with both SDL and OpenGL graphics modes
- setupGraphicsModes();
- #endif
+ if (!scumm_stricmp(desiredAspectRatio.c_str(), desiredAspectRatioAsStrings[i])) {
+ return desiredAspectRatios[i];
+ }
+ }
+ // TODO : Report a warning
+ return AspectRatio(0, 0);
}
+#endif
+
+#if defined(WIN32)
+ struct SdlConsoleHidingWin32 {
+ DWORD myPid;
+ DWORD myTid;
+ HWND consoleHandle;
+ };
+
+ // console hiding for win32
+ static BOOL CALLBACK initBackendFindConsoleWin32Proc(HWND hWnd, LPARAM lParam) {
+ DWORD pid, tid;
+ SdlConsoleHidingWin32 *variables = (SdlConsoleHidingWin32 *)lParam;
+ tid = GetWindowThreadProcessId(hWnd, &pid);
+ if ((tid == variables->myTid) && (pid == variables->myPid)) {
+ variables->consoleHandle = hWnd;
+ return FALSE;
+ }
+ return TRUE;
+ }
+#endif
void OSystem_SDL::initBackend() {
- // Check if backend has not been initialized
assert(!_inited);
- // Create the default event source, in case a custom backend
- // manager didn't provide one yet.
- if (_eventSource == 0)
- _eventSource = new SdlEventSource();
-
- int graphicsManagerType = 0;
+ int joystick_num = ConfMan.getInt("joystick_num");
+ uint32 sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
- if (_graphicsManager == 0) {
-#ifdef USE_OPENGL
- if (ConfMan.hasKey("gfx_mode")) {
- Common::String gfxMode(ConfMan.get("gfx_mode"));
- bool use_opengl = false;
- const OSystem::GraphicsMode *mode = OpenGLSdlGraphicsManager::supportedGraphicsModes();
- while (mode->name) {
- if (scumm_stricmp(mode->name, gfxMode.c_str()) == 0)
- use_opengl = true;
+ if (ConfMan.hasKey("disable_sdl_parachute"))
+ sdlFlags |= SDL_INIT_NOPARACHUTE;
- mode++;
- }
+#ifdef _WIN32_WCE
+ if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) {
+ SDL_VideoInit("windib", 0);
+ sdlFlags ^= SDL_INIT_VIDEO;
+ }
+#endif
- // If the gfx_mode is from OpenGL, create the OpenGL graphics manager
- if (use_opengl) {
- _graphicsManager = new OpenGLSdlGraphicsManager();
- graphicsManagerType = 1;
- }
+ if (joystick_num > -1)
+ sdlFlags |= SDL_INIT_JOYSTICK;
+
+#if 0
+ // NEW CODE TO HIDE CONSOLE FOR WIN32
+#if defined(WIN32)
+ // console hiding for win32
+ SdlConsoleHidingWin32 consoleHidingWin32;
+ consoleHidingWin32.consoleHandle = 0;
+ consoleHidingWin32.myPid = GetCurrentProcessId();
+ consoleHidingWin32.myTid = GetCurrentThreadId();
+ EnumWindows (initBackendFindConsoleWin32Proc, (LPARAM)&consoleHidingWin32);
+
+ if (!ConfMan.getBool("show_console")) {
+ if (consoleHidingWin32.consoleHandle) {
+ // We won't find a window with our TID/PID in case we were started from command-line
+ ShowWindow(consoleHidingWin32.consoleHandle, SW_HIDE);
}
+ }
#endif
- if (_graphicsManager == 0) {
- _graphicsManager = new SdlGraphicsManager(_eventSource);
- graphicsManagerType = 0;
- }
+#endif
+
+ if (SDL_Init(sdlFlags) == -1) {
+ error("Could not initialize SDL: %s", SDL_GetError());
}
- // Creates the backend managers, if they don't exist yet (we check
- // for this to allow subclasses to provide their own).
- if (_eventManager == 0)
- _eventManager = new DefaultEventManager(_eventSource);
-
- // We have to initialize the graphics manager before the event manager
- // so the virtual keyboard can be initialized, but we have to add the
- // graphics manager as an event observer after initializing the event
- // manager.
- if (graphicsManagerType == 0)
- ((SdlGraphicsManager *)_graphicsManager)->initEventObserver();
-#ifdef USE_OPENGL
- else if (graphicsManagerType == 1)
- ((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver();
-#endif
+ _graphicsMutex = createMutex();
- if (_savefileManager == 0)
- _savefileManager = new DefaultSaveFileManager();
+ SDL_ShowCursor(SDL_DISABLE);
- if (_mixerManager == 0) {
- _mixerManager = new SdlMixerManager();
+ // Enable unicode support if possible
+ SDL_EnableUNICODE(1);
- // Setup and start mixer
- _mixerManager->init();
- }
+ memset(&_oldVideoMode, 0, sizeof(_oldVideoMode));
+ memset(&_videoMode, 0, sizeof(_videoMode));
+ memset(&_transactionDetails, 0, sizeof(_transactionDetails));
- if (_audiocdManager == 0)
- _audiocdManager = new SdlAudioCDManager();
+#if !defined(_WIN32_WCE) && !defined(DINGUX) && !defined(__SYMBIAN32__) && defined(USE_SCALERS)
+ _videoMode.mode = GFX_DOUBLESIZE;
+ _videoMode.scaleFactor = 2;
+ _videoMode.aspectRatioCorrection = ConfMan.getBool("aspect_ratio");
+ _videoMode.desiredAspectRatio = getDesiredAspectRatio();
+ _scalerProc = Normal2x;
+#else // for small screen platforms
+ _videoMode.mode = GFX_NORMAL;
+ _videoMode.scaleFactor = 1;
+ _videoMode.aspectRatioCorrection = false;
+ _scalerProc = Normal1x;
+#endif
+ _scalerType = 0;
+#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
+ _videoMode.fullscreen = ConfMan.getBool("fullscreen");
+#else
+ _videoMode.fullscreen = true;
+#endif
+
+#if !defined(MACOSX) && !defined(__SYMBIAN32__)
// Setup a custom program icon.
+ // Don't set icon on OS X, as we use a nicer external icon there.
+ // Don't for Symbian: it uses the EScummVM.aif file for the icon.
setupIcon();
+#endif
+
+ // enable joystick
+ if (joystick_num > -1 && SDL_NumJoysticks() > 0) {
+ printf("Using joystick: %s\n", SDL_JoystickName(0));
+ _joystick = SDL_JoystickOpen(joystick_num);
+ }
+
+
+ // Create the savefile manager, if none exists yet (we check for this to
+ // allow subclasses to provide their own).
+ if (_savefile == 0) {
+#ifdef UNIX
+ _savefile = new POSIXSaveFileManager();
+#else
+ _savefile = new DefaultSaveFileManager();
+#endif
+ }
+
+ // Create and hook up the mixer, if none exists yet (we check for this to
+ // allow subclasses to provide their own).
+ if (_mixer == 0) {
+ setupMixer();
+ }
+
+ // Create and hook up the timer manager, if none exists yet (we check for
+ // this to allow subclasses to provide their own).
+ if (_timer == 0) {
+ // Note: We could implement a custom SDLTimerManager by using
+ // SDL_AddTimer. That might yield better timer resolution, but it would
+ // also change the semantics of a timer: Right now, ScummVM timers
+ // *never* run in parallel, due to the way they are implemented. If we
+ // switched to SDL_AddTimer, each timer might run in a separate thread.
+ // However, not all our code is prepared for that, so we can't just
+ // switch. Still, it's a potential future change to keep in mind.
+ _timer = new DefaultTimerManager();
+ _timerID = SDL_AddTimer(10, &timer_handler, _timer);
+ }
+
+ // Invoke parent implementation of this method
+ OSystem::initBackend();
_inited = true;
}
-void OSystem_SDL::initSDL() {
- // Check if SDL has not been initialized
- if (!_initedSDL) {
- uint32 sdlFlags = 0;
- if (ConfMan.hasKey("disable_sdl_parachute"))
- sdlFlags |= SDL_INIT_NOPARACHUTE;
+OSystem_SDL::OSystem_SDL()
+ :
+#ifdef USE_OSD
+ _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0),
+#endif
+ _hwscreen(0), _screen(0), _tmpscreen(0),
+#ifdef USE_RGB_COLOR
+ _screenFormat(Graphics::PixelFormat::createFormatCLUT8()),
+ _cursorFormat(Graphics::PixelFormat::createFormatCLUT8()),
+#endif
+ _overlayVisible(false),
+ _overlayscreen(0), _tmpscreen2(0),
+ _cdrom(0), _scalerProc(0), _modeChanged(false), _screenChangeCount(0),
+ _scrollLock(false),
+ _mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0),
+ _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true),
+ _joystick(0),
+ _currentShakePos(0), _newShakePos(0),
+ _paletteDirtyStart(0), _paletteDirtyEnd(0),
+#if MIXER_DOUBLE_BUFFERING
+ _soundMutex(0), _soundCond(0), _soundThread(0),
+ _soundThreadIsRunning(false), _soundThreadShouldQuit(false),
+#endif
+ _fsFactory(0),
+ _savefile(0),
+ _mixer(0),
+ _timer(0),
+ _screenIsLocked(false),
+ _graphicsMutex(0), _transactionMode(kTransactionNone) {
+
+ // clear palette storage
+ memset(_currentPalette, 0, sizeof(_currentPalette));
+ memset(_cursorPalette, 0, sizeof(_cursorPalette));
+
+ _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
+
+ // reset mouse state
+ memset(&_km, 0, sizeof(_km));
+ memset(&_mouseCurState, 0, sizeof(_mouseCurState));
+
+ _inited = false;
+
+
+ #if defined(__amigaos4__)
+ _fsFactory = new AmigaOSFilesystemFactory();
+ #elif defined(UNIX)
+ _fsFactory = new POSIXFilesystemFactory();
+ #elif defined(WIN32)
+ _fsFactory = new WindowsFilesystemFactory();
+ #elif defined(__SYMBIAN32__)
+ // Do nothing since its handled by the Symbian SDL inheritance
+ #else
+ #error Unknown and unsupported FS backend
+ #endif
+}
+
+OSystem_SDL::~OSystem_SDL() {
+ SDL_RemoveTimer(_timerID);
+ closeMixer();
- // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers)
- if (SDL_Init(sdlFlags) == -1)
- error("Could not initialize SDL: %s", SDL_GetError());
+ free(_mouseData);
- // Enable unicode support if possible
- SDL_EnableUNICODE(1);
+ delete _savefile;
+ delete _timer;
+}
- _initedSDL = true;
- }
+uint32 OSystem_SDL::getMillis() {
+ uint32 millis = SDL_GetTicks();
+ g_eventRec.processMillis(millis);
+ return millis;
+}
+
+void OSystem_SDL::delayMillis(uint msecs) {
+ SDL_Delay(msecs);
+}
+
+void OSystem_SDL::getTimeAndDate(TimeDate &td) const {
+ time_t curTime = time(0);
+ struct tm t = *localtime(&curTime);
+ td.tm_sec = t.tm_sec;
+ td.tm_min = t.tm_min;
+ td.tm_hour = t.tm_hour;
+ td.tm_mday = t.tm_mday;
+ td.tm_mon = t.tm_mon;
+ td.tm_year = t.tm_year;
+}
+
+Common::TimerManager *OSystem_SDL::getTimerManager() {
+ assert(_timer);
+ return _timer;
+}
+
+Common::SaveFileManager *OSystem_SDL::getSavefileManager() {
+ assert(_savefile);
+ return _savefile;
+}
+
+FilesystemFactory *OSystem_SDL::getFilesystemFactory() {
+ assert(_fsFactory);
+ return _fsFactory;
}
void OSystem_SDL::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
@@ -179,10 +376,88 @@ void OSystem_SDL::addSysArchivesToSearchSet(Common::SearchSet &s, int priority)
}
#endif
+#ifdef MACOSX
+ // Get URL of the Resource directory of the .app bundle
+ CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
+ if (fileUrl) {
+ // Try to convert the URL to an absolute path
+ UInt8 buf[MAXPATHLEN];
+ if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) {
+ // Success: Add it to the search path
+ Common::String bundlePath((const char *)buf);
+ s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority);
+ }
+ CFRelease(fileUrl);
+ }
+
+#endif
+
}
-Common::String OSystem_SDL::getDefaultConfigFileName() {
- return "scummvm.ini";
+
+static Common::String getDefaultConfigFileName() {
+ char configFile[MAXPATHLEN];
+#if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
+ OSVERSIONINFO win32OsVersion;
+ ZeroMemory(&win32OsVersion, sizeof(OSVERSIONINFO));
+ win32OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&win32OsVersion);
+ // Check for non-9X version of Windows.
+ if (win32OsVersion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
+ // Use the Application Data directory of the user profile.
+ if (win32OsVersion.dwMajorVersion >= 5) {
+ if (!GetEnvironmentVariable("APPDATA", configFile, sizeof(configFile)))
+ error("Unable to access application data directory");
+ } else {
+ if (!GetEnvironmentVariable("USERPROFILE", configFile, sizeof(configFile)))
+ error("Unable to access user profile directory");
+
+ strcat(configFile, "\\Application Data");
+ CreateDirectory(configFile, NULL);
+ }
+
+ strcat(configFile, "\\ScummVM");
+ CreateDirectory(configFile, NULL);
+ strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
+
+ FILE *tmp = NULL;
+ if ((tmp = fopen(configFile, "r")) == NULL) {
+ // Check windows directory
+ char oldConfigFile[MAXPATHLEN];
+ GetWindowsDirectory(oldConfigFile, MAXPATHLEN);
+ strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE);
+ if ((tmp = fopen(oldConfigFile, "r"))) {
+ strcpy(configFile, oldConfigFile);
+
+ fclose(tmp);
+ }
+ } else {
+ fclose(tmp);
+ }
+ } else {
+ // Check windows directory
+ GetWindowsDirectory(configFile, MAXPATHLEN);
+ strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
+ }
+#elif defined(UNIX)
+ // On UNIX type systems, by default we store the config file inside
+ // to the HOME directory of the user.
+ //
+ // GP2X is Linux based but Home dir can be read only so do not use
+ // it and put the config in the executable dir.
+ //
+ // On the iPhone, the home dir of the user when you launch the app
+ // from the Springboard, is /. Which we don't want.
+ const char *home = getenv("HOME");
+ if (home != NULL && strlen(home) < MAXPATHLEN)
+ snprintf(configFile, MAXPATHLEN, "%s/%s", home, DEFAULT_CONFIG_FILE);
+ else
+ strcpy(configFile, DEFAULT_CONFIG_FILE);
+#else
+ strcpy(configFile, DEFAULT_CONFIG_FILE);
+#endif
+
+ return configFile;
}
Common::SeekableReadStream *OSystem_SDL::createConfigReadStream() {
@@ -213,36 +488,78 @@ void OSystem_SDL::setWindowCaption(const char *caption) {
SDL_WM_SetCaption(cap.c_str(), cap.c_str());
}
+bool OSystem_SDL::hasFeature(Feature f) {
+ return
+ (f == kFeatureFullscreenMode) ||
+ (f == kFeatureAspectRatioCorrection) ||
+ (f == kFeatureCursorHasPalette) ||
+ (f == kFeatureIconifyWindow);
+}
+
+void OSystem_SDL::setFeatureState(Feature f, bool enable) {
+ switch (f) {
+ case kFeatureFullscreenMode:
+ setFullscreenMode(enable);
+ break;
+ case kFeatureAspectRatioCorrection:
+ setAspectRatioCorrection(enable);
+ break;
+ case kFeatureIconifyWindow:
+ if (enable)
+ SDL_WM_IconifyWindow();
+ break;
+ default:
+ break;
+ }
+}
+
+bool OSystem_SDL::getFeatureState(Feature f) {
+ assert (_transactionMode == kTransactionNone);
+
+ switch (f) {
+ case kFeatureFullscreenMode:
+ return _videoMode.fullscreen;
+ case kFeatureAspectRatioCorrection:
+ return _videoMode.aspectRatioCorrection;
+ default:
+ return false;
+ }
+}
+
void OSystem_SDL::deinit() {
+ if (_cdrom) {
+ SDL_CDStop(_cdrom);
+ SDL_CDClose(_cdrom);
+ }
+ unloadGFXMode();
+ deleteMutex(_graphicsMutex);
+
+ if (_joystick)
+ SDL_JoystickClose(_joystick);
+
SDL_ShowCursor(SDL_ENABLE);
- delete _savefileManager;
- _savefileManager = 0;
- delete _graphicsManager;
- _graphicsManager = 0;
- delete _eventManager;
- _eventManager = 0;
- delete _eventSource;
- _eventSource = 0;
- delete _audiocdManager;
- _audiocdManager = 0;
- delete _mixerManager;
- _mixerManager = 0;
- delete _timerManager;
- _timerManager = 0;
- delete _mutexManager;
- _mutexManager = 0;
-
-#ifdef USE_OPENGL
- delete[] _graphicsModes;
-#endif
+ SDL_RemoveTimer(_timerID);
+ closeMixer();
+
+ free(_mouseData);
+
+ delete _timer;
SDL_Quit();
+
+ // Event Manager requires save manager for storing
+ // recorded events
+ delete getEventManager();
+ delete _savefile;
}
void OSystem_SDL::quit() {
deinit();
+
+#if !defined(SAMSUNGTV)
exit(0);
+#endif
}
void OSystem_SDL::setupIcon() {
@@ -297,128 +614,209 @@ void OSystem_SDL::setupIcon() {
free(icon);
}
-uint32 OSystem_SDL::getMillis() {
- uint32 millis = SDL_GetTicks();
- g_eventRec.processMillis(millis);
- return millis;
+OSystem::MutexRef OSystem_SDL::createMutex() {
+ return (MutexRef) SDL_CreateMutex();
}
-void OSystem_SDL::delayMillis(uint msecs) {
- SDL_Delay(msecs);
+void OSystem_SDL::lockMutex(MutexRef mutex) {
+ SDL_mutexP((SDL_mutex *) mutex);
}
-void OSystem_SDL::getTimeAndDate(TimeDate &td) const {
- time_t curTime = time(0);
- struct tm t = *localtime(&curTime);
- td.tm_sec = t.tm_sec;
- td.tm_min = t.tm_min;
- td.tm_hour = t.tm_hour;
- td.tm_mday = t.tm_mday;
- td.tm_mon = t.tm_mon;
- td.tm_year = t.tm_year;
+void OSystem_SDL::unlockMutex(MutexRef mutex) {
+ SDL_mutexV((SDL_mutex *) mutex);
}
-Audio::Mixer *OSystem_SDL::getMixer() {
- assert(_mixerManager);
- return _mixerManager->getMixer();
+void OSystem_SDL::deleteMutex(MutexRef mutex) {
+ SDL_DestroyMutex((SDL_mutex *) mutex);
}
-SdlMixerManager *OSystem_SDL::getMixerManager() {
- assert(_mixerManager);
- return _mixerManager;
-}
+#pragma mark -
+#pragma mark --- Audio ---
+#pragma mark -
-#ifdef USE_OPENGL
+#if MIXER_DOUBLE_BUFFERING
-const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const {
- return _graphicsModes;
-}
+void OSystem_SDL::mixerProducerThread() {
+ byte nextSoundBuffer;
-int OSystem_SDL::getDefaultGraphicsMode() const {
- // Return the default graphics mode from the current graphics manager
- if (_graphicsMode < _sdlModesCount)
- return _graphicsManager->getDefaultGraphicsMode();
- else
- return _graphicsManager->getDefaultGraphicsMode() + _sdlModesCount;
-}
+ SDL_LockMutex(_soundMutex);
+ while (true) {
+ // Wait till we are allowed to produce data
+ SDL_CondWait(_soundCond, _soundMutex);
-bool OSystem_SDL::setGraphicsMode(int mode) {
- const OSystem::GraphicsMode *srcMode;
- int i;
- // Check if mode is from SDL or OpenGL
- if (mode < _sdlModesCount) {
- srcMode = SdlGraphicsManager::supportedGraphicsModes();
- i = 0;
- } else {
- srcMode = OpenGLSdlGraphicsManager::supportedGraphicsModes();
- i = _sdlModesCount;
- }
- // Loop through modes
- while (srcMode->name) {
- if (i == mode) {
- // If the new mode and the current mode are not from the same graphics
- // manager, delete and create the new mode graphics manager
- if (_graphicsMode >= _sdlModesCount && mode < _sdlModesCount) {
- delete _graphicsManager;
- _graphicsManager = new SdlGraphicsManager(_eventSource);
- ((SdlGraphicsManager *)_graphicsManager)->initEventObserver();
- _graphicsManager->beginGFXTransaction();
- } else if (_graphicsMode < _sdlModesCount && mode >= _sdlModesCount) {
- delete _graphicsManager;
- _graphicsManager = new OpenGLSdlGraphicsManager();
- ((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver();
- _graphicsManager->beginGFXTransaction();
- }
- _graphicsMode = mode;
- return _graphicsManager->setGraphicsMode(srcMode->id);
- }
- i++;
- srcMode++;
+ if (_soundThreadShouldQuit)
+ break;
+
+ // Generate samples and put them into the next buffer
+ nextSoundBuffer = _activeSoundBuf ^ 1;
+ _mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize);
+
+ // Swap buffers
+ _activeSoundBuf = nextSoundBuffer;
}
- return false;
+ SDL_UnlockMutex(_soundMutex);
}
-int OSystem_SDL::getGraphicsMode() const {
- return _graphicsMode;
+int SDLCALL OSystem_SDL::mixerProducerThreadEntry(void *arg) {
+ OSystem_SDL *this_ = (OSystem_SDL *)arg;
+ assert(this_);
+ this_->mixerProducerThread();
+ return 0;
}
-void OSystem_SDL::setupGraphicsModes() {
- const OSystem::GraphicsMode *sdlGraphicsModes = SdlGraphicsManager::supportedGraphicsModes();
- const OSystem::GraphicsMode *openglGraphicsModes = OpenGLSdlGraphicsManager::supportedGraphicsModes();
- _sdlModesCount = 0;
- _glModesCount = 0;
- // Count the number of graphics modes
- const OSystem::GraphicsMode *srcMode = sdlGraphicsModes;
- while (srcMode->name) {
- _sdlModesCount++;
- srcMode++;
- }
- srcMode = openglGraphicsModes;
- while (srcMode->name) {
- _glModesCount++;
- srcMode++;
+void OSystem_SDL::initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize) {
+ _soundThreadIsRunning = false;
+ _soundThreadShouldQuit = false;
+
+ // Create mutex and condition variable
+ _soundMutex = SDL_CreateMutex();
+ _soundCond = SDL_CreateCond();
+
+ // Create two sound buffers
+ _activeSoundBuf = 0;
+ _soundBufSize = bufSize;
+ _soundBuffers[0] = (byte *)calloc(1, bufSize);
+ _soundBuffers[1] = (byte *)calloc(1, bufSize);
+
+ _soundThreadIsRunning = true;
+
+ // Finally start the thread
+ _soundThread = SDL_CreateThread(mixerProducerThreadEntry, this);
+}
+
+void OSystem_SDL::deinitThreadedMixer() {
+ // Kill thread?? _soundThread
+
+ if (_soundThreadIsRunning) {
+ // Signal the producer thread to end, and wait for it to actually finish.
+ _soundThreadShouldQuit = true;
+ SDL_CondBroadcast(_soundCond);
+ SDL_WaitThread(_soundThread, NULL);
+
+ // Kill the mutex & cond variables.
+ // Attention: AT this point, the mixer callback must not be running
+ // anymore, else we will crash!
+ SDL_DestroyMutex(_soundMutex);
+ SDL_DestroyCond(_soundCond);
+
+ _soundThreadIsRunning = false;
+
+ free(_soundBuffers[0]);
+ free(_soundBuffers[1]);
}
+}
+
- // Allocate enough space for merged array of modes
- _graphicsModes = new OSystem::GraphicsMode[_glModesCount + _sdlModesCount + 1];
+void OSystem_SDL::mixCallback(void *arg, byte *samples, int len) {
+ OSystem_SDL *this_ = (OSystem_SDL *)arg;
+ assert(this_);
+ assert(this_->_mixer);
- // Copy SDL graphics modes
- memcpy((void *)_graphicsModes, sdlGraphicsModes, _sdlModesCount * sizeof(OSystem::GraphicsMode));
+ assert((int)this_->_soundBufSize == len);
- // Copy OpenGL graphics modes
- memcpy((void *)(_graphicsModes + _sdlModesCount), openglGraphicsModes, _glModesCount * sizeof(OSystem::GraphicsMode));
+ // Lock mutex, to ensure our data is not overwritten by the producer thread
+ SDL_LockMutex(this_->_soundMutex);
- // Set a null mode at the end
- memset((void *)(_graphicsModes + _sdlModesCount + _glModesCount), 0, sizeof(OSystem::GraphicsMode));
+ // Copy data from the current sound buffer
+ memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len);
- // Set new internal ids for all modes
- int i = 0;
- OSystem::GraphicsMode *mode = _graphicsModes;
- while (mode->name) {
- mode->id = i++;
- mode++;
+ // Unlock mutex and wake up the produced thread
+ SDL_UnlockMutex(this_->_soundMutex);
+ SDL_CondSignal(this_->_soundCond);
+}
+
+#else
+
+void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) {
+ OSystem_SDL *this_ = (OSystem_SDL *)sys;
+ assert(this_);
+ assert(this_->_mixer);
+
+ this_->_mixer->mixCallback(samples, len);
+}
+
+#endif
+
+void OSystem_SDL::setupMixer() {
+ SDL_AudioSpec desired;
+
+ // Determine the desired output sampling frequency.
+ uint32 samplesPerSec = 0;
+ if (ConfMan.hasKey("output_rate"))
+ samplesPerSec = ConfMan.getInt("output_rate");
+ if (samplesPerSec <= 0)
+ samplesPerSec = SAMPLES_PER_SEC;
+
+ // Determine the sample buffer size. We want it to store enough data for
+ // at least 1/16th of a second (though at most 8192 samples). Note
+ // that it must be a power of two. So e.g. at 22050 Hz, we request a
+ // sample buffer size of 2048.
+ uint32 samples = 8192;
+ while (samples * 16 > samplesPerSec * 2)
+ samples >>= 1;
+
+ memset(&desired, 0, sizeof(desired));
+ desired.freq = samplesPerSec;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ desired.samples = (uint16)samples;
+ desired.callback = mixCallback;
+ desired.userdata = this;
+
+ assert(!_mixer);
+ if (SDL_OpenAudio(&desired, &_obtainedRate) != 0) {
+ warning("Could not open audio device: %s", SDL_GetError());
+ _mixer = new Audio::MixerImpl(this, samplesPerSec);
+ assert(_mixer);
+ _mixer->setReady(false);
+ } else {
+ // Note: This should be the obtained output rate, but it seems that at
+ // least on some platforms SDL will lie and claim it did get the rate
+ // even if it didn't. Probably only happens for "weird" rates, though.
+ samplesPerSec = _obtainedRate.freq;
+ debug(1, "Output sample rate: %d Hz", samplesPerSec);
+
+ // Create the mixer instance and start the sound processing
+ _mixer = new Audio::MixerImpl(this, samplesPerSec);
+ assert(_mixer);
+ _mixer->setReady(true);
+
+#if MIXER_DOUBLE_BUFFERING
+ initThreadedMixer(_mixer, _obtainedRate.samples * 4);
+#endif
+
+ // start the sound system
+ SDL_PauseAudio(0);
}
}
+void OSystem_SDL::closeMixer() {
+ if (_mixer)
+ _mixer->setReady(false);
+
+ SDL_CloseAudio();
+
+ delete _mixer;
+ _mixer = 0;
+
+#if MIXER_DOUBLE_BUFFERING
+ deinitThreadedMixer();
#endif
+
+}
+
+Audio::Mixer *OSystem_SDL::getMixer() {
+ assert(_mixer);
+ return _mixer;
+}
+
+#pragma mark -
+#pragma mark --- CD Audio ---
+#pragma mark -
+
+AudioCDManager *OSystem_SDL::getAudioCDManager() {
+ if (!_audiocdManager)
+ _audiocdManager = new SdlAudioCDManager();
+ return _audiocdManager;
+}
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 5b1ce8f803..b701824517 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -23,8 +23,8 @@
*
*/
-#ifndef PLATFORM_SDL_H
-#define PLATFORM_SDL_H
+#ifndef SDL_COMMON_H
+#define SDL_COMMON_H
#if defined(__SYMBIAN32__)
#include <esdl\SDL.h>
@@ -32,99 +32,451 @@
#include <SDL.h>
#endif
-#include "backends/modular-backend.h"
-#include "backends/mixer/sdl/sdl-mixer.h"
-#include "backends/events/sdl/sdl-events.h"
+#include "backends/base-backend.h"
+#include "graphics/scaler.h"
-/**
- * Base OSystem class for all SDL ports.
- */
-class OSystem_SDL : public ModularBackend {
+
+namespace Audio {
+ class MixerImpl;
+}
+
+#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
+// Uncomment this to enable the 'on screen display' code.
+#define USE_OSD 1
+#endif
+
+#if defined(MACOSX)
+// On Mac OS X, we need to double buffer the audio buffer, else anything
+// which produces sampled data with high latency (like the MT-32 emulator)
+// will sound terribly.
+// This could be enabled for more / most ports in the future, but needs some
+// testing.
+#define MIXER_DOUBLE_BUFFERING 1
+#endif
+
+
+enum {
+ GFX_NORMAL = 0,
+ GFX_DOUBLESIZE = 1,
+ GFX_TRIPLESIZE = 2,
+ GFX_2XSAI = 3,
+ GFX_SUPER2XSAI = 4,
+ GFX_SUPEREAGLE = 5,
+ GFX_ADVMAME2X = 6,
+ GFX_ADVMAME3X = 7,
+ GFX_HQ2X = 8,
+ GFX_HQ3X = 9,
+ GFX_TV2X = 10,
+ GFX_DOTMATRIX = 11
+};
+
+class AspectRatio {
+ int _kw, _kh;
+public:
+ AspectRatio() { _kw = _kh = 0; }
+ AspectRatio(int w, int h);
+
+ bool isAuto() const { return (_kw | _kh) == 0; }
+
+ int kw() const { return _kw; }
+ int kh() const { return _kh; }
+};
+
+
+class OSystem_SDL : public BaseBackend {
public:
OSystem_SDL();
virtual ~OSystem_SDL();
- /**
- * Pre-initialize backend. It should be called after
- * instantiating the backend. Early needed managers are
- * created here.
- */
- virtual void init();
+ virtual void initBackend();
- /**
- * Get the Mixer Manager instance. Not to confuse with getMixer(),
- * that returns Audio::Mixer. The Mixer Manager is a SDL wrapper class
- * for the Audio::Mixer. Used by other managers.
- */
- virtual SdlMixerManager *getMixerManager();
+ void beginGFXTransaction();
+ TransactionError endGFXTransaction();
- // Override functions from ModularBackend and OSystem
- virtual void initBackend();
+#ifdef USE_RGB_COLOR
+ // Game screen
+ virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; }
+
+ // Highest supported
+ virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
+#endif
+
+ // Set the size and format of the video bitmap.
+ // Typically, 320x200 CLUT8
+ virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format); // overloaded by CE backend
+
+ virtual int getScreenChangeID() const { return _screenChangeCount; }
+
+ // Set colors of the palette
+ void setPalette(const byte *colors, uint start, uint num);
+
+ // Get colors of the palette
+ void grabPalette(byte *colors, uint start, uint num);
+
+ // Draw a bitmap to screen.
+ // The screen will not be updated to reflect the new bitmap
+ virtual void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME)
+
+ virtual Graphics::Surface *lockScreen();
+ virtual void unlockScreen();
+
+ // Update the dirty areas of the screen
+ void updateScreen();
+
+ // Either show or hide the mouse cursor
+ bool showMouse(bool visible);
+
+ // Warp the mouse cursor. Where set_mouse_pos() only informs the
+ // backend of the mouse cursor's current position, this function
+ // actually moves the cursor to the specified position.
+ virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME)
+
+ // Set the bitmap that's used when drawing the cursor.
+ virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); // overloaded by CE backend (FIXME)
+
+ // Set colors of cursor palette
+ void setCursorPalette(const byte *colors, uint start, uint num);
+
+ // Disables or enables cursor palette
+ void disableCursorPalette(bool disable) {
+ _cursorPaletteDisabled = disable;
+ blitCursor();
+ }
+
+ // Shaking is used in SCUMM. Set current shake position.
+ void setShakePos(int shake_pos);
+
+ // Get the number of milliseconds since the program was started.
+ uint32 getMillis();
+
+ // Delay for a specified amount of milliseconds
+ void delayMillis(uint msecs);
+
+ // Get the next event.
+ // Returns true if an event was retrieved.
+ virtual bool pollEvent(Common::Event &event); // overloaded by CE backend
+
+protected:
+ virtual bool dispatchSDLEvent(SDL_Event &ev, Common::Event &event);
+
+ // Handlers for specific SDL events, called by pollEvent.
+ // This way, if a backend inherits fromt the SDL backend, it can
+ // change the behavior of only a single event, without having to override all
+ // of pollEvent.
+ virtual bool handleKeyDown(SDL_Event &ev, Common::Event &event);
+ virtual bool handleKeyUp(SDL_Event &ev, Common::Event &event);
+ virtual bool handleMouseMotion(SDL_Event &ev, Common::Event &event);
+ virtual bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event);
+ virtual bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event);
+ virtual bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event);
+ virtual bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event);
+ virtual bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event);
+
+public:
+
+
+ // Define all hardware keys for keymapper
virtual Common::HardwareKeySet *getHardwareKeySet();
- virtual void quit();
- virtual void deinit();
+
+ // Set function that generates samples
+ virtual void setupMixer();
+ static void mixCallback(void *s, byte *samples, int len);
+
+ virtual void closeMixer();
+
+ virtual Audio::Mixer *getMixer();
+
+ virtual AudioCDManager *getAudioCDManager();
+
+ // Quit
+ virtual void quit(); // overloaded by CE backend
+
+ void deinit();
+
+ virtual void getTimeAndDate(TimeDate &t) const;
+ virtual Common::TimerManager *getTimerManager();
+
+ // Mutex handling
+ MutexRef createMutex();
+ void lockMutex(MutexRef mutex);
+ void unlockMutex(MutexRef mutex);
+ void deleteMutex(MutexRef mutex);
+
+ // Overlay
+ virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; }
+
+ virtual void showOverlay();
+ virtual void hideOverlay();
+ virtual void clearOverlay();
+ virtual void grabOverlay(OverlayColor *buf, int pitch);
+ virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
+ virtual int16 getHeight();
+ virtual int16 getWidth();
+ virtual int16 getOverlayHeight() { return _videoMode.overlayHeight; }
+ virtual int16 getOverlayWidth() { return _videoMode.overlayWidth; }
+
+ virtual const GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+
virtual void setWindowCaption(const char *caption);
+
+ virtual bool hasFeature(Feature f);
+ virtual void setFeatureState(Feature f, bool enable);
+ virtual bool getFeatureState(Feature f);
+ virtual void preprocessEvents(SDL_Event *event) {}
+
+#ifdef USE_OSD
+ void displayMessageOnOSD(const char *msg);
+#endif
+
+ virtual Common::SaveFileManager *getSavefileManager();
+ virtual FilesystemFactory *getFilesystemFactory();
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
+
virtual Common::SeekableReadStream *createConfigReadStream();
virtual Common::WriteStream *createConfigWriteStream();
- virtual uint32 getMillis();
- virtual void delayMillis(uint msecs);
- virtual void getTimeAndDate(TimeDate &td) const;
- virtual Audio::Mixer *getMixer();
-
- // HACK: Special SDL events types
- enum SdlEvent {
- kSdlEventExpose = 100,
- kSdlEventResize = 101
- };
protected:
bool _inited;
- bool _initedSDL;
+ SDL_AudioSpec _obtainedRate;
- /**
- * Mixer manager that configures and setups SDL for
- * the wrapped Audio::Mixer, the true mixer.
- */
- SdlMixerManager *_mixerManager;
+#ifdef USE_OSD
+ SDL_Surface *_osdSurface;
+ Uint8 _osdAlpha; // Transparency level of the OSD
+ uint32 _osdFadeStartTime; // When to start the fade out
+ enum {
+ kOSDFadeOutDelay = 2 * 1000, // Delay before the OSD is faded out (in milliseconds)
+ kOSDFadeOutDuration = 500, // Duration of the OSD fade out (in milliseconds)
+ kOSDColorKey = 1,
+ kOSDInitialAlpha = 80 // Initial alpha level, in percent
+ };
+#endif
- /**
- * The event source we use for obtaining SDL events.
- */
- SdlEventSource *_eventSource;
+ // hardware screen
+ SDL_Surface *_hwscreen;
- /**
- * Initialze the SDL library.
- */
- virtual void initSDL();
+ // unseen game screen
+ SDL_Surface *_screen;
+#ifdef USE_RGB_COLOR
+ Graphics::PixelFormat _screenFormat;
+ Graphics::PixelFormat _cursorFormat;
+ Common::List<Graphics::PixelFormat> _supportedFormats;
/**
- * Setup the window icon.
+ * Update the list of supported pixel formats.
+ * This method is invoked by loadGFXMode().
*/
- virtual void setupIcon();
+ void detectSupportedFormats();
+#endif
- /**
- * Get the file path where the user configuration
- * of ScummVM will be saved.
- */
- virtual Common::String getDefaultConfigFileName();
+ // temporary screen (for scalers)
+ SDL_Surface *_tmpscreen;
+ SDL_Surface *_tmpscreen2;
+
+ // overlay
+ SDL_Surface *_overlayscreen;
+ bool _overlayVisible;
+ Graphics::PixelFormat _overlayFormat;
+
+ // CD Audio
+ SDL_CD *_cdrom;
+ int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration;
+ uint32 _cdEndTime, _cdStopTime;
+
+ enum {
+ kTransactionNone = 0,
+ kTransactionActive = 1,
+ kTransactionRollback = 2
+ };
+
+ struct TransactionDetails {
+ bool sizeChanged;
+ bool needHotswap;
+ bool needUpdatescreen;
+ bool normal1xScaler;
+#ifdef USE_RGB_COLOR
+ bool formatChanged;
+#endif
+ };
+ TransactionDetails _transactionDetails;
+
+ struct VideoState {
+ bool setup;
+
+ bool fullscreen;
+ bool aspectRatioCorrection;
+ AspectRatio desiredAspectRatio;
+
+ int mode;
+ int scaleFactor;
+
+ int screenWidth, screenHeight;
+ int overlayWidth, overlayHeight;
+ int hardwareWidth, hardwareHeight;
+#ifdef USE_RGB_COLOR
+ Graphics::PixelFormat format;
+#endif
+ };
+ VideoState _videoMode, _oldVideoMode;
+
+ virtual void setGraphicsModeIntern(); // overloaded by CE backend
+
+ /** Force full redraw on next updateScreen */
+ bool _forceFull;
+ ScalerProc *_scalerProc;
+ int _scalerType;
+ int _transactionMode;
+
+ bool _screenIsLocked;
+ Graphics::Surface _framebuffer;
+
+ /** Current video mode flags (see DF_* constants) */
+ bool _modeChanged;
+ int _screenChangeCount;
+
+ enum {
+ NUM_DIRTY_RECT = 100,
+ MAX_SCALING = 3
+ };
+
+ // Dirty rect management
+ SDL_Rect _dirtyRectList[NUM_DIRTY_RECT];
+ int _numDirtyRects;
+
+ // Keyboard mouse emulation. Disabled by fingolfin 2004-12-18.
+ // I am keeping the rest of the code in for now, since the joystick
+ // code (or rather, "hack") uses it, too.
+ struct KbdMouse {
+ int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count;
+ uint32 last_time, delay_time, x_down_time, y_down_time;
+ };
+
+ struct MousePos {
+ // The mouse position, using either virtual (game) or real
+ // (overlay) coordinates.
+ int16 x, y;
+
+ // The size and hotspot of the original cursor image.
+ int16 w, h;
+ int16 hotX, hotY;
-#ifdef USE_OPENGL
- OSystem::GraphicsMode *_graphicsModes;
- int _graphicsMode;
- int _sdlModesCount;
- int _glModesCount;
+ // The size and hotspot of the pre-scaled cursor image, in real
+ // coordinates.
+ int16 rW, rH;
+ int16 rHotX, rHotY;
+
+ // The size and hotspot of the pre-scaled cursor image, in game
+ // coordinates.
+ int16 vW, vH;
+ int16 vHotX, vHotY;
+
+ MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0),
+ rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0),
+ vHotX(0), vHotY(0)
+ { }
+ };
+
+ // mouse
+ KbdMouse _km;
+ bool _mouseVisible;
+ bool _mouseNeedsRedraw;
+ byte *_mouseData;
+ SDL_Rect _mouseBackup;
+ MousePos _mouseCurState;
+#ifdef USE_RGB_COLOR
+ uint32 _mouseKeyColor;
+#else
+ byte _mouseKeyColor;
+#endif
+ int _cursorTargetScale;
+ bool _cursorPaletteDisabled;
+ SDL_Surface *_mouseOrigSurface;
+ SDL_Surface *_mouseSurface;
+ enum {
+ kMouseColorKey = 1
+ };
+
+ // Scroll lock state - since SDL doesn't track it
+ bool _scrollLock;
+
+ // joystick
+ SDL_Joystick *_joystick;
+
+ // Shake mode
+ int _currentShakePos;
+ int _newShakePos;
+
+ // Palette data
+ SDL_Color _currentPalette[256];
+ uint _paletteDirtyStart, _paletteDirtyEnd;
+
+ // Cursor palette data
+ SDL_Color _cursorPalette[256];
/**
- * Creates the merged graphics modes list
+ * Mutex which prevents multiple threads from interfering with each other
+ * when accessing the screen.
*/
- virtual void setupGraphicsModes();
+ MutexRef _graphicsMutex;
- virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- virtual bool setGraphicsMode(int mode);
- virtual int getGraphicsMode() const;
+#ifdef MIXER_DOUBLE_BUFFERING
+ SDL_mutex *_soundMutex;
+ SDL_cond *_soundCond;
+ SDL_Thread *_soundThread;
+ bool _soundThreadIsRunning;
+ bool _soundThreadShouldQuit;
+
+ byte _activeSoundBuf;
+ uint _soundBufSize;
+ byte *_soundBuffers[2];
+
+ void mixerProducerThread();
+ static int SDLCALL mixerProducerThreadEntry(void *arg);
+ void initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize);
+ void deinitThreadedMixer();
#endif
+
+ FilesystemFactory *_fsFactory;
+ Common::SaveFileManager *_savefile;
+ Audio::MixerImpl *_mixer;
+
+ SDL_TimerID _timerID;
+ Common::TimerManager *_timer;
+
+protected:
+ virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false); // overloaded by CE backend
+
+ virtual void drawMouse(); // overloaded by CE backend
+ virtual void undrawMouse(); // overloaded by CE backend (FIXME)
+ virtual void blitCursor(); // overloaded by CE backend (FIXME)
+
+ /** Set the position of the virtual mouse cursor. */
+ void setMousePos(int x, int y);
+ virtual void fillMouseEvent(Common::Event &event, int x, int y); // overloaded by CE backend
+ void toggleMouseGrab();
+
+ virtual void internUpdateScreen(); // overloaded by CE backend
+
+ virtual bool loadGFXMode(); // overloaded by CE backend
+ virtual void unloadGFXMode(); // overloaded by CE backend
+ virtual bool hotswapGFXMode(); // overloaded by CE backend
+
+ void setFullscreenMode(bool enable);
+ void setAspectRatioCorrection(bool enable);
+
+ virtual bool saveScreenshot(const char *filename); // overloaded by CE backend
+
+ int effectiveScreenHeight() const;
+
+ void setupIcon();
+ void handleKbdMouse();
+
+ virtual bool remapKey(SDL_Event &ev, Common::Event &event);
+
+ bool handleScalerHotkeys(const SDL_KeyboardEvent &key);
+ bool isScalerHotkey(const Common::Event &event);
};
#endif
diff --git a/backends/platform/sdl/win32/win32-main.cpp b/backends/platform/sdl/win32/win32-main.cpp
deleted file mode 100644
index 25f208ddac..0000000000
--- a/backends/platform/sdl/win32/win32-main.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef WIN32
-
-// Fix for bug #2895217 "MSVC compilation broken with r47595":
-// We need to keep this on top of the "common/scummsys.h"(base/main.h) include,
-// otherwise we will get errors about the windows headers redefining
-// "ARRAYSIZE" for example.
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one...
-
-#include "backends/platform/sdl/win32/win32.h"
-#include "backends/plugins/sdl/sdl-provider.h"
-#include "base/main.h"
-
-int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*iShowCmd*/) {
- SDL_SetModuleHandle(GetModuleHandle(NULL));
- return main(__argc, __argv);
-}
-
-int main(int argc, char *argv[]) {
- // Create our OSystem instance
- g_system = new OSystem_Win32();
- assert(g_system);
-
- // Pre initialize the backend
- ((OSystem_Win32 *)g_system)->init();
-
-#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new SDLPluginProvider());
-#endif
-
- // Invoke the actual ScummVM main entry point:
- int res = scummvm_main(argc, argv);
-
- // Free OSystem
- delete (OSystem_Win32 *)g_system;
-
- return res;
-}
-
-#endif
diff --git a/backends/platform/sdl/win32/win32.cpp b/backends/platform/sdl/win32/win32.cpp
deleted file mode 100644
index 05005dee6f..0000000000
--- a/backends/platform/sdl/win32/win32.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef WIN32
-
-#include <windows.h>
-#define WIN32_LEAN_AND_MEAN
-#undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one...
-
-#include "backends/platform/sdl/win32/win32.h"
-#include "backends/fs/windows/windows-fs-factory.h"
-
-#define DEFAULT_CONFIG_FILE "scummvm.ini"
-
-void OSystem_Win32::init() {
- // Initialze File System Factory
- _fsFactory = new WindowsFilesystemFactory();
-
- // Invoke parent implementation of this method
- OSystem_SDL::init();
-}
-
-Common::String OSystem_Win32::getDefaultConfigFileName() {
- char configFile[MAXPATHLEN];
-
- OSVERSIONINFO win32OsVersion;
- ZeroMemory(&win32OsVersion, sizeof(OSVERSIONINFO));
- win32OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&win32OsVersion);
- // Check for non-9X version of Windows.
- if (win32OsVersion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
- // Use the Application Data directory of the user profile.
- if (win32OsVersion.dwMajorVersion >= 5) {
- if (!GetEnvironmentVariable("APPDATA", configFile, sizeof(configFile)))
- error("Unable to access application data directory");
- } else {
- if (!GetEnvironmentVariable("USERPROFILE", configFile, sizeof(configFile)))
- error("Unable to access user profile directory");
-
- strcat(configFile, "\\Application Data");
- CreateDirectory(configFile, NULL);
- }
-
- strcat(configFile, "\\ScummVM");
- CreateDirectory(configFile, NULL);
- strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
-
- FILE *tmp = NULL;
- if ((tmp = fopen(configFile, "r")) == NULL) {
- // Check windows directory
- char oldConfigFile[MAXPATHLEN];
- GetWindowsDirectory(oldConfigFile, MAXPATHLEN);
- strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE);
- if ((tmp = fopen(oldConfigFile, "r"))) {
- strcpy(configFile, oldConfigFile);
-
- fclose(tmp);
- }
- } else {
- fclose(tmp);
- }
- } else {
- // Check windows directory
- GetWindowsDirectory(configFile, MAXPATHLEN);
- strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
- }
-
- return configFile;
-}
-
-#endif
diff --git a/backends/platform/symbian/AdaptAllMMPs.pl b/backends/platform/symbian/AdaptAllMMPs.pl
index 8e97f469f9..8786ecff32 100644
--- a/backends/platform/symbian/AdaptAllMMPs.pl
+++ b/backends/platform/symbian/AdaptAllMMPs.pl
@@ -34,6 +34,7 @@ chdir("../../../");
"mmp/scummvm_teenagent.mmp",
"mmp/scummvm_mohawk.mmp",
"mmp/scummvm_hugo.mmp",
+ "mmp/scummvm_toon.mmp",
# Target Platform Project Files
"S60/ScummVM_S60.mmp",
"S60v3/ScummVM_S60v3.mmp",
@@ -92,6 +93,9 @@ my @excludes_graphics = (
"iff.cpp"
);
+my @excludes_gui = (
+);
+
# the USE_ARM_* defines not parsed correctly, exclude manually:
my @excludes_scumm = (
".*ARM.*", # the *ARM.s files are added in .mpp files based on WINS/ARM build!
@@ -104,7 +108,7 @@ my @excludes_scumm = (
#arseModule(mmpStr, dirStr, ifdefArray, [exclusionsArray])
ParseModule("_base", "base", \@section_empty); # now in ./TRG/ScummVM_TRG.mmp, these never change anyways...
ParseModule("_base", "common", \@section_empty);
-ParseModule("_base", "gui", \@section_empty);
+ParseModule("_base", "gui", \@section_empty, \@excludes_gui);
ParseModule("_base", "graphics", \@section_empty, \@excludes_graphics);
ParseModule("_base", "sound", \@section_empty, \@excludes_snd);
@@ -135,6 +139,7 @@ ParseModule("_draci", "draci", \@section_empty);
ParseModule("_teenagent","teenagent", \@section_empty);
ParseModule("_mohawk" ,"mohawk", \@section_empty);
ParseModule("_hugo" ,"hugo", \@section_empty);
+ParseModule("_toon" ,"toon", \@section_empty);
print "
=======================================================================================
Done. Enjoy :P
diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
index a0ec338ca0..bf80c36a0e 100644
--- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
+++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
@@ -4,7 +4,7 @@
@WorkingEngines = qw(
scumm agos sky queen gob groovie saga drascula
kyra lure agi touche parallaction cine
- cruise made m4 tinsel tucker sword1 sword2 draci sci teenagent mohawk hugo
+ cruise made m4 tinsel tucker sword1 sword2 draci sci teenagent mohawk hugo toon
);
@WorkingEngines_1st = qw(
@@ -16,7 +16,7 @@
@WorkingEngines_2nd = qw(
agos sky gob
kyra lure agi tinsel
- sword1 sword2 draci sci teenagent hugo
+ sword1 sword2 draci sci teenagent hugo toon
);
@TestingEngines = qw(
@@ -302,8 +302,8 @@
# the first one includes all SDKs & release-ready engines
$VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines";
- $VariationSets{'ALL'}{'1St'} = "$DefaultFeatures @WorkingEngines_1st @EnablableSubEngines";
- $VariationSets{'ALL'}{'2nd'} = "$DefaultFeatures @WorkingEngines_2nd @EnablableSubEngines";
+# $VariationSets{'ALL'}{'1St'} = "$DefaultFeatures @WorkingEngines_1st @EnablableSubEngines";
+# $VariationSets{'ALL'}{'2nd'} = "$DefaultFeatures @WorkingEngines_2nd @EnablableSubEngines";
# now one for each ready-for-release engine
if (0)
{
diff --git a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
index 12193a8781..d044b33bb0 100644
--- a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
+++ b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
@@ -115,13 +115,14 @@ SOURCEPATH ..\..\..\..\base
SOURCEPATH ..\..\..\..
// backend EPOC/SDL/ESDL specific includes
+SOURCE backends\platform\sdl\events.cpp
+SOURCE backends\platform\sdl\graphics.cpp
SOURCE backends\platform\sdl\hardwarekeys.cpp
SOURCE backends\platform\sdl\sdl.cpp
SOURCE backends\fs\symbian\symbian-fs-factory.cpp
SOURCE backends\platform\symbian\src\SymbianOS.cpp
SOURCE backends\platform\symbian\src\SymbianActions.cpp
SOURCE backends\platform\symbian\src\ScummApp.cpp
-SOURCE backends\platform\symbian\src\SymbianMain.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
diff --git a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
index 31c98b90f1..bcc00017ab 100644
--- a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
+++ b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
@@ -115,13 +115,14 @@ SOURCEPATH ..\..\..\..\base
SOURCEPATH ..\..\..\..
// backend EPOC/SDL/ESDL specific includes
+SOURCE backends\platform\sdl\events.cpp
+SOURCE backends\platform\sdl\graphics.cpp
SOURCE backends\platform\sdl\hardwarekeys.cpp
SOURCE backends\platform\sdl\sdl.cpp
SOURCE backends\fs\symbian\symbian-fs-factory.cpp
SOURCE backends\platform\symbian\src\SymbianOS.cpp
SOURCE backends\platform\symbian\src\SymbianActions.cpp
SOURCE backends\platform\symbian\src\ScummApp.cpp
-SOURCE backends\platform\symbian\src\SymbianMain.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
diff --git a/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in
index 2e50c12cc3..83ce9bc599 100644
--- a/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in
+++ b/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in
@@ -36,6 +36,7 @@
TARGET ScummVM_A0000658.exe
TARGETPATH sys\bin
TARGETTYPE exe
+
OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char
UID 0x100039ce 0xA0000658
@@ -112,14 +113,14 @@ SOURCEPATH ..\..\..\..\base
SOURCEPATH ..\..\..\..
// backend EPOC/SDL/ESDL specific includes
-SOURCE backends\platform\sdl\hardwarekeys.cpp
+SOURCE backends\platform\sdl\events.cpp
+SOURCE backends\platform\sdl\graphics.cpp
SOURCE backends\platform\sdl\hardwarekeys.cpp
SOURCE backends\platform\sdl\sdl.cpp
SOURCE backends\fs\symbian\symbian-fs-factory.cpp
SOURCE backends\platform\symbian\src\SymbianOS.cpp
SOURCE backends\platform\symbian\src\SymbianActions.cpp
SOURCE backends\platform\symbian\src\ScummApp.cpp
-SOURCE backends\platform\symbian\src\SymbianMain.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
diff --git a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
index b00c848667..3c8e41784a 100644
--- a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
+++ b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
@@ -113,14 +113,14 @@ SOURCEPATH ..\..\..\..\base
SOURCEPATH ..\..\..\..
// backend EPOC/SDL/ESDL specific includes
-SOURCE backends\platform\sdl\hardwarekeys.cpp
+SOURCE backends\platform\sdl\events.cpp
+SOURCE backends\platform\sdl\graphics.cpp
SOURCE backends\platform\sdl\hardwarekeys.cpp
SOURCE backends\platform\sdl\sdl.cpp
SOURCE backends\fs\symbian\symbian-fs-factory.cpp
SOURCE backends\platform\symbian\src\SymbianOS.cpp
SOURCE backends\platform\symbian\src\SymbianActions.cpp
SOURCE backends\platform\symbian\src\ScummApp.cpp
-SOURCE backends\platform\symbian\src\SymbianMain.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
diff --git a/backends/platform/symbian/mmp/scummvm_base.mmp.in b/backends/platform/symbian/mmp/scummvm_base.mmp.in
index e799975385..8f51e3c7b5 100644
--- a/backends/platform/symbian/mmp/scummvm_base.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_base.mmp.in
@@ -125,24 +125,12 @@ SOURCE engines\game.cpp
SOURCE engines\advanceddetector.cpp
SOURCE engines\savestate.cpp
// backend specific includes
-SOURCE backends\modular-backend.cpp
-SOURCE backends\audiocd\default\default-audiocd.cpp
-SOURCE backends\audiocd\sdl\sdl-audiocd.cpp
-SOURCE backends\events\sdl\sdl-events.cpp
-SOURCE backends\events\symbiansdl\symbiansdl-events.cpp
SOURCE backends\fs\abstract-fs.cpp
SOURCE backends\fs\symbian\symbianstream.cpp
-SOURCE backends\graphics\sdl\sdl-graphics.cpp
-SOURCE backends\graphics\symbiansdl\symbiansdl-graphics.cpp
SOURCE backends\keymapper\action.cpp
SOURCE backends\keymapper\keymap.cpp
SOURCE backends\keymapper\keymapper.cpp
SOURCE backends\keymapper\remap-dialog.cpp
-SOURCE backends\mixer\sdl\sdl-mixer.cpp
-SOURCE backends\mixer\symbiansdl\symbiansdl-mixer.cpp
-SOURCE backends\mutex\sdl\sdl-mutex.cpp
-SOURCE backends\timer\sdl\sdl-timer.cpp
-
// Source files for virtual keyboard
SOURCE backends\vkeybd\image-map.cpp
SOURCE backends\vkeybd\polygon.cpp
diff --git a/backends/platform/symbian/mmp/scummvm_toon.mmp.in b/backends/platform/symbian/mmp/scummvm_toon.mmp.in
new file mode 100644
index 0000000000..7b907fd92f
--- /dev/null
+++ b/backends/platform/symbian/mmp/scummvm_toon.mmp.in
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ * Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
+ * Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
+ * Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
+ * Copyright (C) 2005-2010 The ScummVM project
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+//
+// EPOC MMP makefile project for ScummVM
+//
+
+// *** Definitions
+
+TARGET scummvm_toon.lib
+TARGETTYPE lib
+OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp
+OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings
+OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char
+ALWAYS_BUILD_AS_ARM
+
+//START_AUTO_MACROS_SLAVE//
+
+ // empty base file, will be updated by Perl build scripts
+
+//STOP_AUTO_MACROS_SLAVE//
+
+// *** SOURCE files
+
+SOURCEPATH ..\..\..\..\engines\toon
+
+//START_AUTO_OBJECTS_TOON_//
+
+ // empty base file, will be updated by Perl build scripts
+
+//STOP_AUTO_OBJECTS_TOON_//
+
+// *** Include paths
+
+USERINCLUDE ..\..\..\..\engines
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
+SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp
index d86adbf354..50ab7e00b1 100644
--- a/backends/platform/symbian/src/SymbianOS.cpp
+++ b/backends/platform/symbian/src/SymbianOS.cpp
@@ -26,17 +26,26 @@
#include <sdlapp.h> // for CSDLApp::GetExecutablePathCStr() @ Symbian::GetExecutablePath()
#include <bautils.h>
+#include "backends/fs/symbian/symbian-fs-factory.h"
#include "backends/platform/symbian/src/SymbianOS.h"
#include "backends/platform/symbian/src/SymbianActions.h"
+#include "backends/saves/default/default-saves.h"
+
+#include "base/main.h"
+
#include "common/config-manager.h"
#include "common/scummsys.h"
+#include "common/translation.h"
+
#include "gui/message.h"
-#include "backends/fs/symbian/symbian-fs-factory.h"
-#include "backends/saves/default/default-saves.h"
-#include "backends/events/symbiansdl/symbiansdl-events.h"
-#include "backends/graphics/symbiansdl/symbiansdl-graphics.h"
-#include "backends/mixer/symbiansdl/symbiansdl-mixer.h"
+#include "sound/mixer_intern.h"
+
+#ifdef SAMPLES_PER_SEC_8000 // the GreanSymbianMMP format cannot handle values for defines :(
+ #define SAMPLES_PER_SEC 8000
+#else
+ #define SAMPLES_PER_SEC 16000
+#endif
#define DEFAULT_CONFIG_FILE "scummvm.ini"
#define DEFAULT_SAVE_PATH "Savegames"
@@ -49,7 +58,8 @@ void FatalError(const char *msg) {
TPtrC8 msgPtr((const TUint8 *)msg);
TBuf<512> msg16Bit;
msg16Bit.Copy(msgPtr);
-#ifndef S60
+#ifdef S60
+#else
CEikonEnv::Static()->InfoWinL(_L("ScummVM Fatal Error"), msg16Bit);
#endif
if (g_system)
@@ -57,7 +67,7 @@ void FatalError(const char *msg) {
}
// make this easily available everywhere
-char *GetExecutablePath() {
+char* GetExecutablePath() {
return CSDLApp::GetExecutablePathCStr();
}
@@ -65,13 +75,66 @@ char *GetExecutablePath() {
////////// OSystem_SDL_Symbian //////////////////////////////////////////
-OSystem_SDL_Symbian::OSystem_SDL_Symbian()
- :
- _RFs(0) {
-
+static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+ {"1x", "Fullscreen", GFX_NORMAL},
+ {0, 0, 0}
+};
+
+bool OSystem_SDL_Symbian::hasFeature(Feature f) {
+ switch (f) {
+ case kFeatureFullscreenMode:
+ case kFeatureAspectRatioCorrection:
+ case kFeatureCursorHasPalette:
+#ifdef USE_VIBRA_SE_PXXX
+ case kFeatureVibration:
+#endif
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+void OSystem_SDL_Symbian::setFeatureState(Feature f, bool enable) {
+ switch (f) {
+ case kFeatureVirtualKeyboard:
+ if (enable) {
+ }
+ else {
+
+ }
+ break;
+ case kFeatureDisableKeyFiltering:
+ GUI::Actions::Instance()->beginMapping(enable);
+ break;
+ default:
+ OSystem_SDL::setFeatureState(f, enable);
+ }
}
-void OSystem_SDL_Symbian::init() {
+static Common::String getDefaultConfigFileName() {
+ char configFile[MAXPATHLEN];
+ strcpy(configFile, Symbian::GetExecutablePath());
+ strcat(configFile, DEFAULT_CONFIG_FILE);
+ return configFile;
+}
+
+Common::SeekableReadStream *OSystem_SDL_Symbian::createConfigReadStream() {
+ Common::FSNode file(getDefaultConfigFileName());
+ return file.createReadStream();
+}
+
+Common::WriteStream *OSystem_SDL_Symbian::createConfigWriteStream() {
+ Common::FSNode file(getDefaultConfigFileName());
+ return file.createWriteStream();
+}
+
+OSystem_SDL_Symbian::zoneDesc OSystem_SDL_Symbian::_zones[TOTAL_ZONES] = {
+ { 0, 0, 320, 145 },
+ { 0, 145, 150, 55 },
+ { 150, 145, 170, 55 }
+};
+OSystem_SDL_Symbian::OSystem_SDL_Symbian() :_channels(0),_stereo_mix_buffer(0) {
_RFs = &CEikonEnv::Static()->FsSession();
_fsFactory = new SymbianFilesystemFactory();
}
@@ -81,19 +144,20 @@ void OSystem_SDL_Symbian::initBackend() {
Common::String savePath;
savePath = Symbian::GetExecutablePath();
savePath += DEFAULT_SAVE_PATH "\\";
- _savefileManager = new DefaultSaveFileManager(savePath);
+ _savefile = new DefaultSaveFileManager(savePath);
// If savepath has not already been set then set it
if (!ConfMan.hasKey("savepath")) {
ConfMan.set("savepath", savePath);
+
}
// Ensure that the current set path (might have been altered by the user) exists
Common::String currentPath = ConfMan.get("savepath");
TFileName fname;
- TPtrC8 ptr((const unsigned char*)currentPath.c_str(), currentPath.size());
+ TPtrC8 ptr((const unsigned char*)currentPath.c_str(),currentPath.size());
fname.Copy(ptr);
- BaflUtils::EnsurePathExistsL(static_cast<OSystem_SDL_Symbian *>(g_system)->FsSession(), fname);
+ BaflUtils::EnsurePathExistsL(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), fname);
ConfMan.setBool("FM_high_quality", false);
#if !defined(S60) || defined(S60V3) // S60 has low quality as default
@@ -101,26 +165,11 @@ void OSystem_SDL_Symbian::initBackend() {
#else
ConfMan.setBool("FM_medium_quality", false);
#endif
- // Symbian OS should have joystick_num set to 0 in the ini file,
- // but uiq devices might refuse opening the joystick
- ConfMan.setInt("joystick_num", 0);
+ ConfMan.setInt("joystick_num", 0); // Symbian OS should have joystick_num set to 0 in the ini file , but uiq devices might refuse opening the joystick
ConfMan.flushToDisk();
GUI::Actions::init();
- // Creates the backend managers
- if (_eventManager == 0)
- _eventManager = new SymbianSdlEventManager(this);
- if (_mixerManager == 0) {
- _mixerManager = new SymbianSdlMixerManager();
-
- // Setup and start mixer
- _mixerManager->init();
- }
- if (_graphicsManager == 0)
- _graphicsManager = new SymbianSdlGraphicsManager();
-
- // Call parent implementation of this method
OSystem_SDL::initBackend();
// Initialize global key mapping for Smartphones
@@ -128,6 +177,7 @@ void OSystem_SDL_Symbian::initBackend() {
actions->initInstanceMain(this);
actions->loadMapping();
+ initZones();
}
void OSystem_SDL_Symbian::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
@@ -137,23 +187,286 @@ void OSystem_SDL_Symbian::addSysArchivesToSearchSet(Common::SearchSet &s, int pr
}
}
+OSystem_SDL_Symbian::~OSystem_SDL_Symbian() {
+ delete[] _stereo_mix_buffer;
+}
+
+int OSystem_SDL_Symbian::getDefaultGraphicsMode() const {
+ return GFX_NORMAL;
+}
+
+const OSystem::GraphicsMode *OSystem_SDL_Symbian::getSupportedGraphicsModes() const {
+ return s_supportedGraphicsModes;
+}
+
+// make sure we always go to normal, even if the string might be set wrong!
+bool OSystem_SDL_Symbian::setGraphicsMode(const char * /*name*/) {
+ // let parent OSystem_SDL handle it
+ return OSystem_SDL::setGraphicsMode(getDefaultGraphicsMode());
+}
+
void OSystem_SDL_Symbian::quitWithErrorMsg(const char * /*aMsg*/) {
+
CEikonEnv::Static()->AlertWin(_L("quitWithErrorMsg()")) ;
if (g_system)
g_system->quit();
}
+// Overloaded from SDL_Commmon
void OSystem_SDL_Symbian::quit() {
delete GUI_Actions::Instance();
-
- // Call parent implementation of this method
OSystem_SDL::quit();
}
+void OSystem_SDL_Symbian::setupMixer() {
+
+ SDL_AudioSpec desired;
+ SDL_AudioSpec obtained;
+
+ // Determine the desired output sampling frequency.
+ uint32 samplesPerSec = 0;
+ if (ConfMan.hasKey("output_rate"))
+ samplesPerSec = ConfMan.getInt("output_rate");
+ if (samplesPerSec <= 0)
+ samplesPerSec = SAMPLES_PER_SEC;
+
+ // Determine the sample buffer size. We want it to store enough data for
+ // at least 1/16th of a second (though at most 8192 samples). Note
+ // that it must be a power of two. So e.g. at 22050 Hz, we request a
+ // sample buffer size of 2048.
+ uint32 samples = 8192;
+ while (samples * 16 > samplesPerSec * 2)
+ samples >>= 1;
+
+ memset(&desired, 0, sizeof(desired));
+ desired.freq = samplesPerSec;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ desired.samples = (uint16)samples;
+ desired.callback = symbianMixCallback;
+ desired.userdata = this;
+
+ assert(!_mixer);
+ if (SDL_OpenAudio(&desired, &obtained) != 0) {
+ warning("Could not open audio device: %s", SDL_GetError());
+ _mixer = new Audio::MixerImpl(this, samplesPerSec);
+ assert(_mixer);
+ _mixer->setReady(false);
+ } else {
+ // Note: This should be the obtained output rate, but it seems that at
+ // least on some platforms SDL will lie and claim it did get the rate
+ // even if it didn't. Probably only happens for "weird" rates, though.
+ samplesPerSec = obtained.freq;
+ _channels = obtained.channels;
+
+ // Need to create mixbuffer for stereo mix to downmix
+ if (_channels != 2) {
+ _stereo_mix_buffer = new byte [obtained.size*2];//*2 for stereo values
+ }
+
+ // Create the mixer instance and start the sound processing
+ _mixer = new Audio::MixerImpl(this, samplesPerSec);
+ assert(_mixer);
+ _mixer->setReady(true);
+ SDL_PauseAudio(0);
+ }
+}
+
+/**
+ * The mixer callback function.
+ */
+void OSystem_SDL_Symbian::symbianMixCallback(void *sys, byte *samples, int len) {
+ OSystem_SDL_Symbian *this_ = (OSystem_SDL_Symbian *)sys;
+ assert(this_);
+
+ if (!this_->_mixer)
+ return;
+
+#if defined (S60) && !defined(S60V3)
+ // If not stereo then we need to downmix
+ if (this_->_mixer->_channels != 2) {
+ this_->_mixer->mixCallback(_stereo_mix_buffer, len * 2);
+
+ int16 *bitmixDst = (int16 *)samples;
+ int16 *bitmixSrc = (int16 *)_stereo_mix_buffer;
+
+ for (int loop = len / 2; loop >= 0; loop --) {
+ *bitmixDst = (*bitmixSrc + *(bitmixSrc + 1)) >> 1;
+ bitmixDst++;
+ bitmixSrc += 2;
+ }
+ } else
+#else
+ this_->_mixer->mixCallback(samples, len);
+#endif
+}
+
+
+/**
+ * This is an implementation by the remapKey function
+ * @param SDL_Event to remap
+ * @param ScumVM event to modify if special result is requested
+ * @return true if Common::Event has a valid return status
+ */
+bool OSystem_SDL_Symbian::remapKey(SDL_Event &ev, Common::Event &event) {
+ if (GUI::Actions::Instance()->mappingActive() || ev.key.keysym.sym <= SDLK_UNKNOWN)
+ return false;
+
+ for (TInt loop = 0; loop < GUI::ACTION_LAST; loop++) {
+ if (GUI::Actions::Instance()->getMapping(loop) == ev.key.keysym.sym &&
+ GUI::Actions::Instance()->isEnabled(loop)) {
+ // Create proper event instead
+ switch (loop) {
+ case GUI::ACTION_UP:
+ if (ev.type == SDL_KEYDOWN) {
+ _km.y_vel = -1;
+ _km.y_down_count = 1;
+ } else {
+ _km.y_vel = 0;
+ _km.y_down_count = 0;
+ }
+ event.type = Common::EVENT_MOUSEMOVE;
+ fillMouseEvent(event, _km.x, _km.y);
+
+ return true;
+
+ case GUI::ACTION_DOWN:
+ if (ev.type == SDL_KEYDOWN) {
+ _km.y_vel = 1;
+ _km.y_down_count = 1;
+ } else {
+ _km.y_vel = 0;
+ _km.y_down_count = 0;
+ }
+ event.type = Common::EVENT_MOUSEMOVE;
+ fillMouseEvent(event, _km.x, _km.y);
+
+ return true;
+
+ case GUI::ACTION_LEFT:
+ if (ev.type == SDL_KEYDOWN) {
+ _km.x_vel = -1;
+ _km.x_down_count = 1;
+ } else {
+ _km.x_vel = 0;
+ _km.x_down_count = 0;
+ }
+ event.type = Common::EVENT_MOUSEMOVE;
+ fillMouseEvent(event, _km.x, _km.y);
+
+ return true;
+
+ case GUI::ACTION_RIGHT:
+ if (ev.type == SDL_KEYDOWN) {
+ _km.x_vel = 1;
+ _km.x_down_count = 1;
+ } else {
+ _km.x_vel = 0;
+ _km.x_down_count = 0;
+ }
+ event.type = Common::EVENT_MOUSEMOVE;
+ fillMouseEvent(event, _km.x, _km.y);
+
+ return true;
+
+ case GUI::ACTION_LEFTCLICK:
+ event.type = (ev.type == SDL_KEYDOWN ? Common::EVENT_LBUTTONDOWN : Common::EVENT_LBUTTONUP);
+ fillMouseEvent(event, _km.x, _km.y);
+
+ return true;
+
+ case GUI::ACTION_RIGHTCLICK:
+ event.type = (ev.type == SDL_KEYDOWN ? Common::EVENT_RBUTTONDOWN : Common::EVENT_RBUTTONUP);
+ fillMouseEvent(event, _km.x, _km.y);
+
+ return true;
+
+ case GUI::ACTION_ZONE:
+ if (ev.type == SDL_KEYDOWN) {
+ int i;
+
+ for (i=0; i < TOTAL_ZONES; i++)
+ if (_km.x >= _zones[i].x && _km.y >= _zones[i].y &&
+ _km.x <= _zones[i].x + _zones[i].width && _km.y <= _zones[i].y + _zones[i].height
+ ) {
+ _mouseXZone[i] = _km.x;
+ _mouseYZone[i] = _km.y;
+ break;
+ }
+ _currentZone++;
+ if (_currentZone >= TOTAL_ZONES)
+ _currentZone = 0;
+ event.type = Common::EVENT_MOUSEMOVE;
+ fillMouseEvent(event, _mouseXZone[_currentZone], _mouseYZone[_currentZone]);
+ SDL_WarpMouse(event.mouse.x, event.mouse.y);
+ }
+
+ return true;
+ case GUI::ACTION_MULTI: {
+ GUI::Key &key = GUI::Actions::Instance()->getKeyAction(loop);
+ // if key code is pause, then change event to interactive or just fall through
+ if (key.keycode() == SDLK_PAUSE) {
+ event.type = Common::EVENT_PREDICTIVE_DIALOG;
+ return true;
+ }
+ }
+ case GUI::ACTION_SAVE:
+ case GUI::ACTION_SKIP:
+ case GUI::ACTION_SKIP_TEXT:
+ case GUI::ACTION_PAUSE:
+ case GUI::ACTION_SWAPCHAR:
+ case GUI::ACTION_FASTMODE:
+ case GUI::ACTION_DEBUGGER:
+ case GUI::ACTION_MAINMENU:
+ case GUI::ACTION_VKB:
+ case GUI::ACTION_KEYMAPPER:{
+ GUI::Key &key = GUI::Actions::Instance()->getKeyAction(loop);
+ ev.key.keysym.sym = (SDLKey) key.keycode();
+ ev.key.keysym.scancode = 0;
+ ev.key.keysym.mod = (SDLMod) key.flags();
+
+ // Translate from SDL keymod event to Scummvm Key Mod Common::Event.
+ // This codes is also present in GP32 backend and in SDL backend as a static function
+ // Perhaps it should be shared.
+ if (key.flags() != 0) {
+ event.kbd.flags = 0;
+
+ if (ev.key.keysym.mod & KMOD_SHIFT)
+ event.kbd.flags |= Common::KBD_SHIFT;
+
+ if (ev.key.keysym.mod & KMOD_ALT)
+ event.kbd.flags |= Common::KBD_ALT;
+
+ if (ev.key.keysym.mod & KMOD_CTRL)
+ event.kbd.flags |= Common::KBD_CTRL;
+ }
+
+ return false;
+ }
+
+ case GUI::ACTION_QUIT:
+ {
+ GUI::MessageDialog alert(_("Do you want to quit ?"), _("Yes"), _("No"));
+ if (alert.runModal() == GUI::kMessageOK)
+ quit();
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void OSystem_SDL_Symbian::setWindowCaption(const char *caption) {
+ OSystem_SDL::setWindowCaption(caption);
+}
+
void OSystem_SDL_Symbian::engineInit() {
// Check mappings for the engine just started
- checkMappings();
+ check_mappings();
}
void OSystem_SDL_Symbian::engineDone() {
@@ -161,26 +474,22 @@ void OSystem_SDL_Symbian::engineDone() {
GUI::Actions::Instance()->initInstanceMain(this);
}
-void OSystem_SDL_Symbian::checkMappings() {
+void OSystem_SDL_Symbian::check_mappings() {
if (ConfMan.get("gameid").empty() || GUI::Actions::Instance()->initialized())
return;
GUI::Actions::Instance()->initInstanceGame();
}
-bool OSystem_SDL_Symbian::setGraphicsMode(const char * /*name*/) {
- return _graphicsManager->setGraphicsMode(0);
-}
+void OSystem_SDL_Symbian::initZones() {
+ int i;
-Common::String OSystem_SDL_Symbian::getDefaultConfigFileName() {
- char configFile[MAXPATHLEN];
- strcpy(configFile, Symbian::GetExecutablePath());
- strcat(configFile, DEFAULT_CONFIG_FILE);
- return configFile;
-}
+ _currentZone = 0;
-void OSystem_SDL_Symbian::setupIcon() {
- // Don't for Symbian: it uses the EScummVM.aif file for the icon.
+ for (i = 0; i < TOTAL_ZONES; i++) {
+ _mouseXZone[i] = (_zones[i].x + (_zones[i].width / 2));
+ _mouseYZone[i] = (_zones[i].y + (_zones[i].height / 2));
+ }
}
RFs& OSystem_SDL_Symbian::FsSession() {
@@ -206,3 +515,67 @@ void* scumm_bsearch(const void *key, const void *base, size_t nmemb, size_t size
return NULL;
}
+
+extern "C"
+{
+// Include the snprintf and vsnprintf implementations as 'C' code
+#include "vsnprintf.h"
+}
+
+// Symbian SDL_Main implementation
+// Redirects standard io, creates Symbian specific SDL backend (inherited from main SDL)
+int main(int argc, char *argv[]) {
+ //
+ // Set up redirects for stdout/stderr under Symbian.
+ // Code copied from SDL_main.
+ //
+
+ // Symbian does not like any output to the console through any *print* function
+ char STDOUT_FILE[256], STDERR_FILE[256]; // shhh, don't tell anybody :)
+ strcpy(STDOUT_FILE, Symbian::GetExecutablePath());
+ strcpy(STDERR_FILE, Symbian::GetExecutablePath());
+ strcat(STDOUT_FILE, "scummvm.stdout.txt");
+ strcat(STDERR_FILE, "scummvm.stderr.txt");
+
+ /* Flush the output in case anything is queued */
+ fclose(stdout);
+ fclose(stderr);
+
+ /* Redirect standard input and standard output */
+ FILE *newfp = freopen(STDOUT_FILE, "w", stdout);
+ if (newfp == NULL) { /* This happens on NT */
+#if !defined(stdout)
+ stdout = fopen(STDOUT_FILE, "w");
+#else
+ newfp = fopen(STDOUT_FILE, "w");
+ if (newfp) {
+ *stdout = *newfp;
+ }
+#endif
+ }
+ newfp = freopen(STDERR_FILE, "w", stderr);
+ if (newfp == NULL) { /* This happens on NT */
+#if !defined(stderr)
+ stderr = fopen(STDERR_FILE, "w");
+#else
+ newfp = fopen(STDERR_FILE, "w");
+ if (newfp) {
+ *stderr = *newfp;
+ }
+#endif
+ }
+ setbuf(stderr, NULL); /* No buffering */
+
+ // Create our OSystem instance
+ g_system = new OSystem_SDL_Symbian();
+ assert(g_system);
+
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new SDLPluginProvider());
+#endif
+
+ // Invoke the actual ScummVM main entry point:
+ int res = scummvm_main(argc, argv);
+ g_system->quit(); // TODO: Consider removing / replacing this!
+ return res;
+}
diff --git a/backends/platform/symbian/src/SymbianOS.h b/backends/platform/symbian/src/SymbianOS.h
index 0142054492..85b5e131da 100644
--- a/backends/platform/symbian/src/SymbianOS.h
+++ b/backends/platform/symbian/src/SymbianOS.h
@@ -22,52 +22,73 @@
* $Id$
*/
-#ifndef PLATFORM_SDL_SYMBIAN_H
-#define PLATFORM_SDL_SYMBIAN_H
+#ifndef SDLSYMBIAN_H
+#define SDLSYMBIAN_H
#include "backends/platform/sdl/sdl.h"
+#define TOTAL_ZONES 3
class RFs;
class OSystem_SDL_Symbian : public OSystem_SDL {
public:
OSystem_SDL_Symbian();
+ virtual ~OSystem_SDL_Symbian();
- // Override from OSystem_SDL
- virtual void init();
- virtual void initBackend();
- virtual void quit();
- virtual void engineInit();
- virtual void engineDone();
- virtual bool setGraphicsMode(const char *name);
- virtual Common::String getDefaultConfigFileName();
- virtual void setupIcon();
-
+public:
/**
- * Returns reference to File session
+ * The following method is called once, from main.cpp, after all
+ * config data (including command line params etc.) are fully loaded.
*/
- RFs& FsSession();
+ virtual void initBackend();
+ int getDefaultGraphicsMode() const;
+ const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
+ bool setGraphicsMode(const char *name);
void quitWithErrorMsg(const char *msg);
+ virtual bool hasFeature(Feature f);
+ void setFeatureState(Feature f, bool enable);
+
+ // Set function that generates samples
+ //
+ // This function is overridden by the symbian port in order to provide MONO audio
+ // downmix is done by supplying our own audiocallback
+ //
+ virtual void setupMixer(); // overloaded by CE backend
+
+ // Overloaded from SDL_Commmon
+ void quit();
+
+ // Returns reference to File session
+ RFs& FsSession();
void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
+protected:
+ //
+ // The mixer callback function.
+ //
+ static void symbianMixCallback(void *s, byte *samples, int len);
+
- // Vibration support
+ virtual Common::SeekableReadStream *createConfigReadStream();
+ virtual Common::WriteStream *createConfigWriteStream();
+public:
+ // vibration support
#ifdef USE_VIBRA_SE_PXXX
- /**
- * Intialize the vibration api used if present and supported
- */
+ //
+ // Intialize the vibration api used if present and supported
+ //
void initializeVibration();
- /**
- * Turn vibration on, repeat no time
- * @param vibraLength number of repetitions
- */
+ //
+ // Turn vibration on, repeat no time
+ // @param vibraLength number of repetitions
+ //
void vibrationOn(int vibraLength);
- /**
- * Turns the vibration off
- */
+ //
+ // Turns the vibration off
+ //
void vibrationOff();
protected:
@@ -75,11 +96,54 @@ protected:
#endif // USE_VIBRA_SE_PXXX
protected:
+
+ //
+ // This is an implementation by the remapKey function
+ // @param SDL_Event to remap
+ // @param ScumVM event to modify if special result is requested
+ // @return true if Common::Event has a valid return status
+ //
+ bool remapKey(SDL_Event &ev, Common::Event &event);
+
+ void setWindowCaption(const char *caption);
+
/**
- * Used to intialized special game mappings
+ * Allows the backend to perform engine specific init.
+ * Called just before the engine is run.
*/
- void checkMappings();
+ virtual void engineInit();
+
+ /**
+ * Allows the backend to perform engine specific de-init.
+ * Called after the engine finishes.
+ */
+ virtual void engineDone();
+
+ //
+ // Used to intialized special game mappings
+ //
+ void check_mappings();
+
+ void initZones();
+
+ // Audio
+ int _channels;
+
+ byte *_stereo_mix_buffer;
+
+ // Used to handle joystick navi zones
+ int _mouseXZone[TOTAL_ZONES];
+ int _mouseYZone[TOTAL_ZONES];
+ int _currentZone;
+
+ struct zoneDesc {
+ int x;
+ int y;
+ int width;
+ int height;
+ };
+ static zoneDesc _zones[TOTAL_ZONES];
RFs* _RFs;
};
diff --git a/backends/platform/symbian/src/Symbianmain.cpp b/backends/platform/symbian/src/Symbianmain.cpp
deleted file mode 100644
index 4aaa05926f..0000000000
--- a/backends/platform/symbian/src/Symbianmain.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "base/main.h"
-#include "backends/platform/symbian/src/SymbianOS.h"
-#include "backends/platform/symbian/src/portdefs.h"
-
-extern "C"
-{
-// Include the snprintf and vsnprintf implementations as 'C' code
-#include "vsnprintf.h"
-}
-
-// Symbian SDL_Main implementation
-// Redirects standard io, creates Symbian specific SDL backend (inherited from main SDL)
-int main(int argc, char *argv[]) {
- //
- // Set up redirects for stdout/stderr under Symbian.
- // Code copied from SDL_main.
- //
-
- // Symbian does not like any output to the console through any *print* function
- char STDOUT_FILE[256], STDERR_FILE[256]; // shhh, don't tell anybody :)
- strcpy(STDOUT_FILE, Symbian::GetExecutablePath());
- strcpy(STDERR_FILE, Symbian::GetExecutablePath());
- strcat(STDOUT_FILE, "scummvm.stdout.txt");
- strcat(STDERR_FILE, "scummvm.stderr.txt");
-
- /* Flush the output in case anything is queued */
- fclose(stdout);
- fclose(stderr);
-
- /* Redirect standard input and standard output */
- FILE *newfp = freopen(STDOUT_FILE, "w", stdout);
- if (newfp == NULL) { /* This happens on NT */
-#if !defined(stdout)
- stdout = fopen(STDOUT_FILE, "w");
-#else
- newfp = fopen(STDOUT_FILE, "w");
- if (newfp) {
- *stdout = *newfp;
- }
-#endif
- }
- newfp = freopen(STDERR_FILE, "w", stderr);
- if (newfp == NULL) { /* This happens on NT */
-#if !defined(stderr)
- stderr = fopen(STDERR_FILE, "w");
-#else
- newfp = fopen(STDERR_FILE, "w");
- if (newfp) {
- *stderr = *newfp;
- }
-#endif
- }
- setbuf(stderr, NULL); /* No buffering */
-
- // Create our OSystem instance
- g_system = new OSystem_SDL_Symbian();
- assert(g_system);
-
- // Pre initialize the backend
- ((OSystem_SDL_Symbian *)g_system)->init();
-
-#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new SDLPluginProvider());
-#endif
-
- // Invoke the actual ScummVM main entry point:
- int res = scummvm_main(argc, argv);
-
- // Free OSystem
- delete (OSystem_SDL_Symbian *)g_system;
-
- return res;
-}
-
diff --git a/backends/platform/symbian/src/portdefs.h b/backends/platform/symbian/src/portdefs.h
index 2a26771a0a..6868faaa89 100644
--- a/backends/platform/symbian/src/portdefs.h
+++ b/backends/platform/symbian/src/portdefs.h
@@ -45,6 +45,13 @@
// and we _really_ don't wanna link with any other windows LIBC library!
#if defined(__GCC32__)
+ FIXME: If the following macros are ever used, then this will lead
+ to serious errors, e.g. an almost guaranteed buffer overflow
+ in Common::String::format(). Do *NOT* re-#define vsnprintf to
+ vsprintf, it will lead to disaster!
+ This shouldn't be necessary anyway, since we have
+ backends/platform/symbian/src/vsnprintf.h
+
#define snprintf(buf,len,args...) sprintf(buf,args)
#define vsnprintf(buf,len,format,valist) vsprintf(buf,format,valist)
diff --git a/backends/platform/wii/main.cpp b/backends/platform/wii/main.cpp
index 7f141f2339..aa688534fc 100644
--- a/backends/platform/wii/main.cpp
+++ b/backends/platform/wii/main.cpp
@@ -25,6 +25,7 @@
#include <unistd.h>
#include "osystem.h"
+#include "backends/plugins/wii/wii-provider.h"
#include <ogc/machine/processor.h>
#include <fat.h>
@@ -210,6 +211,10 @@ int main(int argc, char *argv[]) {
g_system = new OSystem_Wii();
assert(g_system);
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new WiiPluginProvider());
+#endif
+
res = scummvm_main(argc, argv);
g_system->quit();
diff --git a/backends/platform/wii/options.cpp b/backends/platform/wii/options.cpp
index 2a47958e3b..ffabc5ae97 100644
--- a/backends/platform/wii/options.cpp
+++ b/backends/platform/wii/options.cpp
@@ -183,7 +183,7 @@ void WiiOptionsDialog::handleTickle() {
break;
default:
- label = String::printf(_("Network not initialised (%d)"), status);
+ label = String::format(_("Network not initialised (%d)"), status);
break;
}
diff --git a/backends/platform/wii/wii.mk b/backends/platform/wii/wii.mk
index c1512551d7..28066df8d4 100644
--- a/backends/platform/wii/wii.mk
+++ b/backends/platform/wii/wii.mk
@@ -32,6 +32,10 @@ else
$(CP) $(srcdir)/dists/wii/icon.png wiidist/scummvm/
sed "s/@REVISION@/$(VER_SVNREV)/;s/@TIMESTAMP@/`date +%Y%m%d%H%M%S`/" < $(srcdir)/dists/wii/meta.xml > wiidist/scummvm/meta.xml
endif
+ifeq ($(DYNAMIC_MODULES),1)
+ $(MKDIR) wiidist/scummvm/plugins
+ for i in $(PLUGINS); do $(STRIP) --strip-debug $$i -o wiidist/scummvm/plugins/`basename $$i`; done
+endif
sed 's/$$/\r/' < $(srcdir)/dists/wii/READMII > wiidist/scummvm/READMII.txt
for i in $(DIST_FILES_DOCS); do sed 's/$$/\r/' < $$i > wiidist/scummvm/`basename $$i`.txt; done
$(CP) $(DIST_FILES_THEMES) wiidist/scummvm/
diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp
index 64abd0be3e..99d0be2bdc 100644
--- a/backends/platform/wince/CEActionsPocket.cpp
+++ b/backends/platform/wince/CEActionsPocket.cpp
@@ -23,21 +23,25 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "backends/platform/wince/wince-sdl.h"
#include "CEActionsPocket.h"
#include "EventsBuffer.h"
#include "gui/message.h"
-#include "scumm/scumm.h"
#include "common/config-manager.h"
#include "gui/KeysDialog.h"
#include "common/translation.h"
+
#ifdef _WIN32_WCE
#define KEY_ALL_SKIP 3457
#endif
-const String pocketActionNames[] = {
+const Common::String pocketActionNames[] = {
_s("Pause"),
_s("Save"),
_s("Quit"),
@@ -64,7 +68,7 @@ void CEActionsPocket::init() {
}
-String CEActionsPocket::actionName(GUI::ActionType action) {
+Common::String CEActionsPocket::actionName(GUI::ActionType action) {
return _(pocketActionNames[action]);
}
@@ -72,7 +76,7 @@ int CEActionsPocket::size() {
return POCKET_ACTION_LAST;
}
-String CEActionsPocket::domain() {
+Common::String CEActionsPocket::domain() {
return ConfMan.kApplicationDomain;
}
@@ -81,8 +85,7 @@ int CEActionsPocket::version() {
}
CEActionsPocket::CEActionsPocket(const Common::String &gameid) :
-GUI::Actions()
-{
+GUI::Actions() {
int i;
_right_click_needed = false;
@@ -114,7 +117,7 @@ void CEActionsPocket::initInstanceMain(OSystem *mainSystem) {
}
void CEActionsPocket::initInstanceGame() {
- String gameid(ConfMan.get("gameid"));
+ Common::String gameid(ConfMan.get("gameid"));
bool is_simon = (strncmp(gameid.c_str(), "simon", 5) == 0);
bool is_sword1 = (gameid == "sword1");
bool is_sword2 = (strcmp(gameid.c_str(), "sword2") == 0);
diff --git a/backends/platform/wince/CEActionsPocket.h b/backends/platform/wince/CEActionsPocket.h
index 0fe29a9e86..72a2064fbf 100644
--- a/backends/platform/wince/CEActionsPocket.h
+++ b/backends/platform/wince/CEActionsPocket.h
@@ -28,7 +28,7 @@
#include "common/scummsys.h"
#include "common/system.h"
-#include "wince-sdl.h"
+#include "common/str.h"
#include "gui/Key.h"
#include "gui/Actions.h"
@@ -58,33 +58,35 @@ enum pocketActionType {
POCKET_ACTION_LAST
};
+class OSystem_WINCE3;
+
class CEActionsPocket : public GUI::Actions {
- public:
- // Actions
- bool perform(GUI::ActionType action, bool pushed = true);
- String actionName(GUI::ActionType action);
- int size();
+public:
+ // Actions
+ bool perform(GUI::ActionType action, bool pushed = true);
+ Common::String actionName(GUI::ActionType action);
+ int size();
- static void init();
- void initInstanceMain(OSystem *mainSystem);
- void initInstanceGame();
+ static void init();
+ void initInstanceMain(OSystem *mainSystem);
+ void initInstanceGame();
- // Action domain
- String domain();
- int version();
+ // Action domain
+ Common::String domain();
+ int version();
- // Utility
- bool needsRightClickMapping();
- bool needsHideToolbarMapping();
- bool needsZoomMapping();
+ // Utility
+ bool needsRightClickMapping();
+ bool needsHideToolbarMapping();
+ bool needsZoomMapping();
- ~CEActionsPocket();
- private:
- CEActionsPocket(const Common::String &gameid);
- bool _right_click_needed;
- bool _hide_toolbar_needed;
- bool _zoom_needed;
- OSystem_WINCE3 *_CESystem;
- };
+ ~CEActionsPocket();
+private:
+ CEActionsPocket(const Common::String &gameid);
+ bool _right_click_needed;
+ bool _hide_toolbar_needed;
+ bool _zoom_needed;
+ OSystem_WINCE3 *_CESystem;
+};
#endif
diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp
index af80bd2908..5c7feb4950 100644
--- a/backends/platform/wince/CEActionsSmartphone.cpp
+++ b/backends/platform/wince/CEActionsSmartphone.cpp
@@ -23,10 +23,14 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "backends/platform/wince/wince-sdl.h"
+
#include "CEActionsSmartphone.h"
#include "EventsBuffer.h"
#include "gui/message.h"
-#include "scumm/scumm.h"
#include "common/config-manager.h"
#include "gui/KeysDialog.h"
diff --git a/backends/platform/wince/CEActionsSmartphone.h b/backends/platform/wince/CEActionsSmartphone.h
index 36797cd2c8..29156bb152 100644
--- a/backends/platform/wince/CEActionsSmartphone.h
+++ b/backends/platform/wince/CEActionsSmartphone.h
@@ -28,7 +28,7 @@
#include "common/scummsys.h"
#include "common/system.h"
-#include "wince-sdl.h"
+#include "common/str.h"
#include "gui/Key.h"
#include "gui/Actions.h"
@@ -55,24 +55,24 @@ enum smartphoneActionType {
class CEActionsSmartphone : public GUI::Actions {
- public:
- // Actions
- bool perform(GUI::ActionType action, bool pushed = true);
- String actionName(GUI::ActionType action);
- int size();
- static void init();
- void initInstanceMain(OSystem *mainSystem);
- void initInstanceGame();
+public:
+ // Actions
+ bool perform(GUI::ActionType action, bool pushed = true);
+ Common::String actionName(GUI::ActionType action);
+ int size();
+ static void init();
+ void initInstanceMain(OSystem *mainSystem);
+ void initInstanceGame();
- // Action domain
- String domain();
- int version();
+ // Action domain
+ Common::String domain();
+ int version();
- ~CEActionsSmartphone();
- private:
- CEActionsSmartphone();
- bool _right_click_needed;
- OSystem_WINCE3 *_CESystem;
- };
+ ~CEActionsSmartphone();
+private:
+ CEActionsSmartphone();
+ bool _right_click_needed;
+ OSystem_WINCE3 *_CESystem;
+};
#endif
diff --git a/backends/platform/wince/CEDevice.cpp b/backends/platform/wince/CEDevice.cpp
index 98a8fb95f6..08acbbbfcd 100644
--- a/backends/platform/wince/CEDevice.cpp
+++ b/backends/platform/wince/CEDevice.cpp
@@ -23,11 +23,14 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "CEDevice.h"
#include <SDL.h>
-#include "wince-sdl.h"
+#include "backends/platform/wince/wince-sdl.h"
static void (WINAPI* _SHIdleTimerReset)(void) = NULL;
static HANDLE (WINAPI* _SetPowerRequirement)(PVOID,int,ULONG,PVOID,ULONG) = NULL;
diff --git a/backends/platform/wince/CEDevice.h b/backends/platform/wince/CEDevice.h
index ca2f908c6d..b2b20d05ce 100644
--- a/backends/platform/wince/CEDevice.h
+++ b/backends/platform/wince/CEDevice.h
@@ -31,20 +31,20 @@
#include "common/str.h"
class CEDevice {
- public:
- static void init();
- static void end();
- static void wakeUp();
- static bool hasPocketPCResolution();
- static bool hasSquareQVGAResolution();
- static bool hasDesktopResolution();
- static bool hasWideResolution();
- static bool hasSmartphoneResolution();
- static bool isSmartphone();
+public:
+ static void init();
+ static void end();
+ static void wakeUp();
+ static bool hasPocketPCResolution();
+ static bool hasSquareQVGAResolution();
+ static bool hasDesktopResolution();
+ static bool hasWideResolution();
+ static bool hasSmartphoneResolution();
+ static bool isSmartphone();
- private:
- static DWORD reg_access(TCHAR *key, TCHAR *val, DWORD data);
- static void backlight_xchg();
+private:
+ static DWORD reg_access(TCHAR *key, TCHAR *val, DWORD data);
+ static void backlight_xchg();
};
#endif
diff --git a/backends/platform/wince/CELauncherDialog.cpp b/backends/platform/wince/CELauncherDialog.cpp
index 11e4900c2d..66a691f51b 100644
--- a/backends/platform/wince/CELauncherDialog.cpp
+++ b/backends/platform/wince/CELauncherDialog.cpp
@@ -23,8 +23,10 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
-#include "wince-sdl.h"
+#include "backends/platform/wince/wince-sdl.h"
#include "CELauncherDialog.h"
diff --git a/backends/platform/wince/CEScaler.cpp b/backends/platform/wince/CEScaler.cpp
index fd47635e05..182a7e0c94 100644
--- a/backends/platform/wince/CEScaler.cpp
+++ b/backends/platform/wince/CEScaler.cpp
@@ -22,6 +22,7 @@
* $Id$
*
*/
+
#include "graphics/scaler/intern.h"
#include "CEScaler.h"
diff --git a/backends/platform/wince/CEgui/GUIElement.cpp b/backends/platform/wince/CEgui/GUIElement.cpp
index 23e7843de1..7689837e3d 100644
--- a/backends/platform/wince/CEgui/GUIElement.cpp
+++ b/backends/platform/wince/CEgui/GUIElement.cpp
@@ -23,104 +23,108 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include <SDL.h>
+
#include "Toolbar.h"
#include "SDL_ImageResource.h"
namespace CEGUI {
- GUIElement::GUIElement(int x, int y, int width, int height) :
- _background(0), _drawn(false), _visible(true), _x(x), _y(y), _width(width), _height(height)
- {
- }
+GUIElement::GUIElement(int x, int y, int width, int height) :
+_background(0), _drawn(false), _visible(true), _x(x), _y(y), _width(width), _height(height) {
+}
- bool GUIElement::setBackground(WORD backgroundReference) {
- _background = new SDL_ImageResource();
- if (!_background->load(backgroundReference)) {
- delete _background;
- _background = NULL;
- return false;
- }
- if (!_height && !_width) {
- _height = _background->height();
- _width = _background->width();
- }
- else
- if (_background->height() != _height || _background->width() != _width) {
- delete _background;
- _background = NULL;
- return false;
- }
- return true;
+bool GUIElement::setBackground(WORD backgroundReference) {
+ _background = new SDL_ImageResource();
+ if (!_background->load(backgroundReference)) {
+ delete _background;
+ _background = NULL;
+ return false;
}
-
- void GUIElement::move(int x, int y) {
- _x = x;
- _y = y;
+ if (!_height && !_width) {
+ _height = _background->height();
+ _width = _background->width();
}
+ else
+ if (_background->height() != _height || _background->width() != _width) {
+ delete _background;
+ _background = NULL;
+ return false;
+ }
+ return true;
+}
- bool GUIElement::draw(SDL_Surface *surface) {
- if (_background && !_drawn && _visible) {
- SDL_Rect rect;
-
- rect.x = _x;
- rect.y = _y;
- rect.w = _width;
- rect.h = _height;
+void GUIElement::move(int x, int y) {
+ _x = x;
+ _y = y;
+}
- SDL_BlitSurface(_background->get(), NULL, surface, &rect);
+bool GUIElement::draw(SDL_Surface *surface) {
+ if (_background && !_drawn && _visible) {
+ SDL_Rect rect;
- _drawn = true;
+ rect.x = _x;
+ rect.y = _y;
+ rect.w = _width;
+ rect.h = _height;
- return true;
- }
- else
- return false;
- }
+ SDL_BlitSurface(_background->get(), NULL, surface, &rect);
- bool GUIElement::checkInside(int x, int y) {
- if (x >= _x && x <= _x + _width && y >= _y && y <= _y + _height)
- return true;
- else
- return false;
- }
+ _drawn = true;
- void GUIElement::setVisible(bool visibility) {
- if (visibility && !_visible)
- _drawn = false;
- _visible = visibility;
+ return true;
}
+ else
+ return false;
+}
- bool GUIElement::visible() {
- return _visible;
- }
+bool GUIElement::checkInside(int x, int y) {
+ if (x >= _x && x <= _x + _width && y >= _y && y <= _y + _height)
+ return true;
+ else
+ return false;
+}
- void GUIElement::forceRedraw() {
+void GUIElement::setVisible(bool visibility) {
+ if (visibility && !_visible)
_drawn = false;
- }
+ _visible = visibility;
+}
- bool GUIElement::drawn() {
- return _drawn;
- }
+bool GUIElement::visible() {
+ return _visible;
+}
- int GUIElement::x() {
- return _x;
- }
+void GUIElement::forceRedraw() {
+ _drawn = false;
+}
- int GUIElement::y() {
- return _y;
- }
+bool GUIElement::drawn() {
+ return _drawn;
+}
- int GUIElement::width() {
- return _width;
- }
+int GUIElement::x() {
+ return _x;
+}
- int GUIElement::height() {
- return _height;
- }
+int GUIElement::y() {
+ return _y;
+}
- GUIElement::~GUIElement() {
- delete _background;
- }
+int GUIElement::width() {
+ return _width;
+}
+
+int GUIElement::height() {
+ return _height;
+}
+GUIElement::~GUIElement() {
+ delete _background;
}
+
+} // End of namespace CEGUI
diff --git a/backends/platform/wince/CEgui/GUIElement.h b/backends/platform/wince/CEgui/GUIElement.h
index 7e4572d377..c599ebe9b5 100644
--- a/backends/platform/wince/CEgui/GUIElement.h
+++ b/backends/platform/wince/CEgui/GUIElement.h
@@ -29,39 +29,40 @@
#include "common/scummsys.h"
#include "common/system.h"
-#include "SDL.h"
-
-#include "SDL_ImageResource.h"
+struct SDL_Surface;
namespace CEGUI {
- class GUIElement {
- public:
- bool setBackground(WORD backgroundReference);
- void setVisible(bool visibility);
- virtual void forceRedraw();
- virtual bool draw(SDL_Surface *surface);
- virtual ~GUIElement();
- void move(int x, int y);
- int width();
- int height();
- int x();
- int y();
- virtual bool action(int x, int y, bool pushed) = 0;
- bool visible();
- bool drawn();
- protected:
- GUIElement(int x = 0, int y = 0, int width = 0, int height = 0);
- bool checkInside(int x, int y);
- bool _visible;
- SDL_ImageResource *_background;
- int _x;
- int _y;
- bool _drawn;
- private:
- int _width;
- int _height;
- };
-}
+class SDL_ImageResource;
+
+class GUIElement {
+public:
+ bool setBackground(WORD backgroundReference);
+ void setVisible(bool visibility);
+ virtual void forceRedraw();
+ virtual bool draw(SDL_Surface *surface);
+ virtual ~GUIElement();
+ void move(int x, int y);
+ int width();
+ int height();
+ int x();
+ int y();
+ virtual bool action(int x, int y, bool pushed) = 0;
+ bool visible();
+ bool drawn();
+protected:
+ GUIElement(int x = 0, int y = 0, int width = 0, int height = 0);
+ bool checkInside(int x, int y);
+ bool _visible;
+ SDL_ImageResource *_background;
+ int _x;
+ int _y;
+ bool _drawn;
+private:
+ int _width;
+ int _height;
+};
+
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEgui/ItemAction.cpp b/backends/platform/wince/CEgui/ItemAction.cpp
index 3808622b2e..55805744e6 100644
--- a/backends/platform/wince/CEgui/ItemAction.cpp
+++ b/backends/platform/wince/CEgui/ItemAction.cpp
@@ -27,25 +27,25 @@
namespace CEGUI {
- ItemAction::ItemAction(WORD reference, GUI::ActionType action) :
- PanelItem(reference) {
- _action = action;
- if (!GUI::Actions::Instance()->isEnabled(_action))
- _visible = false;
- }
-
-
- ItemAction::~ItemAction() {
- }
-
- bool ItemAction::action(int x, int y, bool pushed) {
-
- if (checkInside(x, y) && _visible && pushed) {
- GUI::Actions::Instance()->perform(_action, true);
- GUI::Actions::Instance()->perform(_action, false);
- return true;
- }
- else
- return false;
- }
+ItemAction::ItemAction(WORD reference, GUI::ActionType action) :
+PanelItem(reference) {
+ _action = action;
+ if (!GUI::Actions::Instance()->isEnabled(_action))
+ _visible = false;
}
+
+
+ItemAction::~ItemAction() {
+}
+
+bool ItemAction::action(int x, int y, bool pushed) {
+
+ if (checkInside(x, y) && _visible && pushed) {
+ GUI::Actions::Instance()->perform(_action, true);
+ GUI::Actions::Instance()->perform(_action, false);
+ return true;
+ } else
+ return false;
+}
+
+} // End of namespace CEGUI
diff --git a/backends/platform/wince/CEgui/ItemAction.h b/backends/platform/wince/CEgui/ItemAction.h
index 74ed6bec4d..4f35b3090d 100644
--- a/backends/platform/wince/CEgui/ItemAction.h
+++ b/backends/platform/wince/CEgui/ItemAction.h
@@ -31,16 +31,18 @@
#include "gui/Actions.h"
#include "CEgui/PanelItem.h"
+
namespace CEGUI {
- class ItemAction : public PanelItem {
- public:
- ItemAction(WORD reference, GUI::ActionType action);
- virtual ~ItemAction();
- virtual bool action(int x, int y, bool pushed);
- private:
- GUI::ActionType _action;
- };
-}
+class ItemAction : public PanelItem {
+public:
+ ItemAction(WORD reference, GUI::ActionType action);
+ virtual ~ItemAction();
+ virtual bool action(int x, int y, bool pushed);
+private:
+ GUI::ActionType _action;
+};
+
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEgui/ItemSwitch.cpp b/backends/platform/wince/CEgui/ItemSwitch.cpp
index 8e0121f7c4..d4648f7556 100644
--- a/backends/platform/wince/CEgui/ItemSwitch.cpp
+++ b/backends/platform/wince/CEgui/ItemSwitch.cpp
@@ -24,71 +24,73 @@
*/
#include "ItemSwitch.h"
+#include "SDL_ImageResource.h"
namespace CEGUI {
- void ItemSwitch::init(WORD referenceTrue, WORD referenceFalse) {
- _backgroundTrue = _background;
- _backgroundFalse = new SDL_ImageResource();
- if (!_backgroundFalse->load(referenceFalse)) {
- delete _backgroundFalse;
- delete _background;
- _background = NULL;
- _backgroundFalse = NULL;
- }
+void ItemSwitch::init(WORD referenceTrue, WORD referenceFalse) {
+ _backgroundTrue = _background;
+ _backgroundFalse = new SDL_ImageResource();
+ if (!_backgroundFalse->load(referenceFalse)) {
+ delete _backgroundFalse;
+ delete _background;
+ _background = NULL;
+ _backgroundFalse = NULL;
}
+}
- ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item) :
- PanelItem(referenceTrue) {
- init(referenceTrue, referenceFalse);
- _item = item;
- _itemmax = -1;
- if (!*_item)
- _background = _backgroundFalse;
- }
+ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item) :
+PanelItem(referenceTrue) {
+ init(referenceTrue, referenceFalse);
+ _item = item;
+ _itemmax = -1;
+ if (!*_item)
+ _background = _backgroundFalse;
+}
- ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max) :
- PanelItem(referenceTrue) {
- init(referenceTrue, referenceFalse);
- _itemmultiple = item;
- _itemmax = max;
- if (!*item)
- _background = _backgroundFalse;
- }
+ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max) :
+PanelItem(referenceTrue) {
+ init(referenceTrue, referenceFalse);
+ _itemmultiple = item;
+ _itemmax = max;
+ if (!*item)
+ _background = _backgroundFalse;
+}
- ItemSwitch::~ItemSwitch() {
- delete _backgroundFalse;
- }
+ItemSwitch::~ItemSwitch() {
+ delete _backgroundFalse;
+}
- bool ItemSwitch::action(int x, int y, bool pushed) {
+bool ItemSwitch::action(int x, int y, bool pushed) {
- if (checkInside(x, y) && _visible && pushed) {
- if (_itemmax <= 0) {
- *_item = !*_item;
- if (*_item)
- _background = _backgroundTrue;
- else
- _background = _backgroundFalse;
+ if (checkInside(x, y) && _visible && pushed) {
+ if (_itemmax <= 0) {
+ *_item = !*_item;
+ if (*_item)
+ _background = _backgroundTrue;
+ else
+ _background = _backgroundFalse;
- if (_panel)
- _panel->forceRedraw();
+ if (_panel)
+ _panel->forceRedraw();
- return true;
- } else {
- *_itemmultiple = *_itemmultiple + 1;
- if (*_itemmultiple > _itemmax)
- *_itemmultiple = 0;
- if (*_itemmultiple)
- _background = _backgroundTrue;
- else
- _background = _backgroundFalse;
+ return true;
+ } else {
+ *_itemmultiple = *_itemmultiple + 1;
+ if (*_itemmultiple > _itemmax)
+ *_itemmultiple = 0;
+ if (*_itemmultiple)
+ _background = _backgroundTrue;
+ else
+ _background = _backgroundFalse;
- if (_panel)
- _panel->forceRedraw();
+ if (_panel)
+ _panel->forceRedraw();
- return true;
- }
- } else
- return false;
- }
+ return true;
+ }
+ } else
+ return false;
}
+
+} // End of namespace CEGUI
diff --git a/backends/platform/wince/CEgui/ItemSwitch.h b/backends/platform/wince/CEgui/ItemSwitch.h
index 8d03ee77cb..1ca6f3c288 100644
--- a/backends/platform/wince/CEgui/ItemSwitch.h
+++ b/backends/platform/wince/CEgui/ItemSwitch.h
@@ -36,20 +36,23 @@ using GUI::Key;
namespace CEGUI {
- class ItemSwitch : public PanelItem {
- public:
- ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item);
- ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max);
- virtual ~ItemSwitch();
- virtual bool action(int x, int y, bool pushed);
- private:
- void init(WORD referenceTrue, WORD referenceFalse);
- bool *_item;
- static bool _itemdummy;
- int *_itemmultiple, _itemmax;
- SDL_ImageResource *_backgroundTrue;
- SDL_ImageResource *_backgroundFalse;
- };
-}
+class SDL_ImageResource;
+
+class ItemSwitch : public PanelItem {
+public:
+ ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item);
+ ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max);
+ virtual ~ItemSwitch();
+ virtual bool action(int x, int y, bool pushed);
+private:
+ void init(WORD referenceTrue, WORD referenceFalse);
+ bool *_item;
+ static bool _itemdummy;
+ int *_itemmultiple, _itemmax;
+ SDL_ImageResource *_backgroundTrue;
+ SDL_ImageResource *_backgroundFalse;
+};
+
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEgui/Panel.cpp b/backends/platform/wince/CEgui/Panel.cpp
index a2d965ca78..dfdd6526be 100644
--- a/backends/platform/wince/CEgui/Panel.cpp
+++ b/backends/platform/wince/CEgui/Panel.cpp
@@ -27,59 +27,58 @@
namespace CEGUI {
- Panel::Panel(int interleave_first, int interleave) : Toolbar()
- {
- _interleave = interleave;
- _currentItem = interleave_first;
- }
+Panel::Panel(int interleave_first, int interleave) : Toolbar() {
+ _interleave = interleave;
+ _currentItem = interleave_first;
+}
- bool Panel::add(const String &name, const PanelItem *item) {
- _itemsMap[name] = (PanelItem*)item;
- _itemsMap[name]->move(_currentItem, _y + 10);
- _itemsMap[name]->setPanel(this);
- _currentItem += _interleave;
+bool Panel::add(const String &name, const PanelItem *item) {
+ _itemsMap[name] = (PanelItem*)item;
+ _itemsMap[name]->move(_currentItem, _y + 10);
+ _itemsMap[name]->setPanel(this);
+ _currentItem += _interleave;
- return true;
- }
+ return true;
+}
- bool Panel::draw(SDL_Surface *surface) {
- ItemMap::const_iterator iterator;
- if (!_drawn && _visible) {
- GUIElement::draw(surface);
- for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) {
- ((GUIElement*)(iterator->_value))->draw(surface);
- }
- return true;
+bool Panel::draw(SDL_Surface *surface) {
+ ItemMap::const_iterator iterator;
+ if (!_drawn && _visible) {
+ GUIElement::draw(surface);
+ for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) {
+ ((GUIElement*)(iterator->_value))->draw(surface);
}
- else
- return false;
+ return true;
}
+ else
+ return false;
+}
- void Panel::forceRedraw() {
- ItemMap::const_iterator iterator;
- GUIElement::forceRedraw();
- for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator)
- ((GUIElement*)(iterator->_value))->forceRedraw();
- }
+void Panel::forceRedraw() {
+ ItemMap::const_iterator iterator;
+ GUIElement::forceRedraw();
+ for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator)
+ ((GUIElement*)(iterator->_value))->forceRedraw();
+}
- bool Panel::action(int x, int y, bool pushed) {
- ItemMap::const_iterator iterator;
- bool result = false;
- if (!_visible || !checkInside(x, y))
- return false;
+bool Panel::action(int x, int y, bool pushed) {
+ ItemMap::const_iterator iterator;
+ bool result = false;
+ if (!_visible || !checkInside(x, y))
+ return false;
- for (iterator = _itemsMap.begin(); !result && iterator != _itemsMap.end(); ++iterator)
- result = ((GUIElement*)(iterator->_value))->action(x, y, pushed);
- return result;
- }
+ for (iterator = _itemsMap.begin(); !result && iterator != _itemsMap.end(); ++iterator)
+ result = ((GUIElement*)(iterator->_value))->action(x, y, pushed);
+ return result;
+}
- void Panel::clear() {
- _itemsMap.clear();
- }
+void Panel::clear() {
+ _itemsMap.clear();
+}
- Panel::~Panel() {
- _itemsMap.clear();
- }
+Panel::~Panel() {
+ _itemsMap.clear();
}
+} // End of namespace CEGUI
diff --git a/backends/platform/wince/CEgui/Panel.h b/backends/platform/wince/CEgui/Panel.h
index 6626e41866..e6b693360d 100644
--- a/backends/platform/wince/CEgui/Panel.h
+++ b/backends/platform/wince/CEgui/Panel.h
@@ -40,23 +40,24 @@ using Common::HashMap;
namespace CEGUI {
- class Panel : public Toolbar {
- public:
- Panel(int interleave_first, int interleave);
- virtual bool draw(SDL_Surface *surface);
- virtual ~Panel();
- bool add(const String &name, const PanelItem *item);
- void clear();
- virtual void forceRedraw();
- virtual bool action(int x, int y, bool pushed);
- private:
-
- typedef HashMap<String, PanelItem*, Common::IgnoreCase_Hash , Common::IgnoreCase_EqualTo> ItemMap;
-
- ItemMap _itemsMap;
- int _interleave;
- int _currentItem;
- };
-}
+class Panel : public Toolbar {
+public:
+ Panel(int interleave_first, int interleave);
+ virtual bool draw(SDL_Surface *surface);
+ virtual ~Panel();
+ bool add(const String &name, const PanelItem *item);
+ void clear();
+ virtual void forceRedraw();
+ virtual bool action(int x, int y, bool pushed);
+private:
+
+ typedef HashMap<String, PanelItem*, Common::IgnoreCase_Hash , Common::IgnoreCase_EqualTo> ItemMap;
+
+ ItemMap _itemsMap;
+ int _interleave;
+ int _currentItem;
+};
+
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEgui/PanelItem.cpp b/backends/platform/wince/CEgui/PanelItem.cpp
index 0898839c5d..8c68c79784 100644
--- a/backends/platform/wince/CEgui/PanelItem.cpp
+++ b/backends/platform/wince/CEgui/PanelItem.cpp
@@ -27,21 +27,21 @@
namespace CEGUI {
- PanelItem::PanelItem(WORD reference) : GUIElement() {
- setBackground(reference);
- _panel = NULL;
- }
+PanelItem::PanelItem(WORD reference) : GUIElement() {
+ setBackground(reference);
+ _panel = NULL;
+}
- PanelItem::~PanelItem() {
- }
+PanelItem::~PanelItem() {
+}
- bool PanelItem::action(int x, int y, bool pushed) {
- return false;
- }
+bool PanelItem::action(int x, int y, bool pushed) {
+ return false;
+}
- void PanelItem::setPanel(Panel *panel) {
- _panel = panel;
- }
+void PanelItem::setPanel(Panel *panel) {
+ _panel = panel;
}
+} // End of namespace CEGUI
diff --git a/backends/platform/wince/CEgui/PanelItem.h b/backends/platform/wince/CEgui/PanelItem.h
index 55920c304a..14b62f0f20 100644
--- a/backends/platform/wince/CEgui/PanelItem.h
+++ b/backends/platform/wince/CEgui/PanelItem.h
@@ -33,18 +33,19 @@
namespace CEGUI {
- class Panel;
-
- class PanelItem : public GUIElement {
- friend class Panel;
- public:
- PanelItem(WORD reference);
- virtual ~PanelItem();
- virtual bool action(int x, int y, bool pushed);
- protected:
- void setPanel(Panel *panel);
- Panel *_panel;
- };
-}
+class Panel;
+
+class PanelItem : public GUIElement {
+friend class Panel;
+public:
+ PanelItem(WORD reference);
+ virtual ~PanelItem();
+ virtual bool action(int x, int y, bool pushed);
+protected:
+ void setPanel(Panel *panel);
+ Panel *_panel;
+};
+
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEgui/PanelKeyboard.cpp b/backends/platform/wince/CEgui/PanelKeyboard.cpp
index 369a75cae1..1b2a478746 100644
--- a/backends/platform/wince/CEgui/PanelKeyboard.cpp
+++ b/backends/platform/wince/CEgui/PanelKeyboard.cpp
@@ -23,77 +23,81 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include <SDL.h>
+
#include "PanelKeyboard.h"
namespace CEGUI {
- const char KEYBOARD_MAPPING_ALPHA[][14] = { {"abcdefghijklm"}, {"nopqrstuvwxyz"} };
- const char KEYBOARD_MAPPING_NUMERIC[][6] = { {"12345"}, {"67890"} };
- const int KEYBOARD_MAPPING_SPECIAL[][3][2] = { { {1,SDLK_ESCAPE}, {224,SDLK_UP}, {32,SDLK_SPACE} },
- { {224,SDLK_LEFT}, {224,SDLK_DOWN}, {224,SDLK_RIGHT} } };
+const char KEYBOARD_MAPPING_ALPHA[][14] = { {"abcdefghijklm"}, {"nopqrstuvwxyz"} };
+const char KEYBOARD_MAPPING_NUMERIC[][6] = { {"12345"}, {"67890"} };
+const int KEYBOARD_MAPPING_SPECIAL[][3][2] = { { {1,SDLK_ESCAPE}, {224,SDLK_UP}, {32,SDLK_SPACE} },
+ { {224,SDLK_LEFT}, {224,SDLK_DOWN}, {224,SDLK_RIGHT} } };
- PanelKeyboard::PanelKeyboard(WORD reference) : Toolbar() {
- setBackground(reference);
- _state = false;
- _lastKey.setKey(0);
- }
-
-
- PanelKeyboard::~PanelKeyboard() {
- }
-
- bool PanelKeyboard::action(int x, int y, bool pushed) {
- Key key;
-
- if (checkInside(x, y)) {
- int keyAscii = 0;
- int keyCode = 0;
- if (x < 185) {
- // Alpha selection
- keyCode = keyAscii = KEYBOARD_MAPPING_ALPHA[y >= _y+20][((x + 10) / 14) - 1];
- } else if (x >= 186 && x <= 255) {
- // Numeric selection
- keyCode = keyAscii = KEYBOARD_MAPPING_NUMERIC[y >= _y+20][((x - 187 + 10) / 14) - 1];
- } else if (x >= 258 && x <= 300) {
- // Special keys
- keyAscii = KEYBOARD_MAPPING_SPECIAL[y >= _y+20][((x - 259 + 10) / 14) - 1][0];
- keyCode = KEYBOARD_MAPPING_SPECIAL[y >= _y+20][((x - 259 + 10) / 14) - 1][1];
- } else if (x >= 302 && x <= 316) {
- if (y < _y +20) {
- // Backspace
- keyAscii = VK_BACK; keyCode = keyAscii;
- } else {
- // Enter
- keyAscii = 13; keyCode = 13;
- }
- }
+PanelKeyboard::PanelKeyboard(WORD reference) : Toolbar() {
+ setBackground(reference);
+ _state = false;
+ _lastKey.setKey(0);
+}
+
+
+PanelKeyboard::~PanelKeyboard() {
+}
- if (keyAscii != 0) {
- if (_state && pushed && keyCode != _lastKey.keycode()) // if cursor is still down and off the current key
- return false;
- else if (_state && !pushed && keyCode != _lastKey.keycode()) { // cursor is up but off the current key
- keyAscii = _lastKey.ascii();
- keyCode = _lastKey.keycode();
- }
- _state = pushed;
- _lastKey.setKey(keyAscii, tolower(keyCode));
-
- key.setKey(keyAscii, tolower(keyCode));
- return EventsBuffer::simulateKey(&key, pushed);
+bool PanelKeyboard::action(int x, int y, bool pushed) {
+ Key key;
+
+ if (checkInside(x, y)) {
+ int keyAscii = 0;
+ int keyCode = 0;
+ if (x < 185) {
+ // Alpha selection
+ keyCode = keyAscii = KEYBOARD_MAPPING_ALPHA[y >= _y+20][((x + 10) / 14) - 1];
+ } else if (x >= 186 && x <= 255) {
+ // Numeric selection
+ keyCode = keyAscii = KEYBOARD_MAPPING_NUMERIC[y >= _y+20][((x - 187 + 10) / 14) - 1];
+ } else if (x >= 258 && x <= 300) {
+ // Special keys
+ keyAscii = KEYBOARD_MAPPING_SPECIAL[y >= _y+20][((x - 259 + 10) / 14) - 1][0];
+ keyCode = KEYBOARD_MAPPING_SPECIAL[y >= _y+20][((x - 259 + 10) / 14) - 1][1];
+ } else if (x >= 302 && x <= 316) {
+ if (y < _y +20) {
+ // Backspace
+ keyAscii = VK_BACK; keyCode = keyAscii;
+ } else {
+ // Enter
+ keyAscii = 13; keyCode = 13;
}
- else if (_state && !pushed) { // cursor is in some forbidden region and is up
- _state = false;
- key = _lastKey;
- return EventsBuffer::simulateKey(&key, false);
- } else
- return false;
}
- else if (_state && !pushed) { // cursor left the keyboard area and is up
+
+ if (keyAscii != 0) {
+ if (_state && pushed && keyCode != _lastKey.keycode()) // if cursor is still down and off the current key
+ return false;
+ else if (_state && !pushed && keyCode != _lastKey.keycode()) { // cursor is up but off the current key
+ keyAscii = _lastKey.ascii();
+ keyCode = _lastKey.keycode();
+ }
+ _state = pushed;
+ _lastKey.setKey(keyAscii, tolower(keyCode));
+
+ key.setKey(keyAscii, tolower(keyCode));
+ return EventsBuffer::simulateKey(&key, pushed);
+ } else if (_state && !pushed) { // cursor is in some forbidden region and is up
_state = false;
key = _lastKey;
return EventsBuffer::simulateKey(&key, false);
} else
return false;
- }
+ } else if (_state && !pushed) { // cursor left the keyboard area and is up
+ _state = false;
+ key = _lastKey;
+ return EventsBuffer::simulateKey(&key, false);
+ } else
+ return false;
}
+} // End of namespace CEGUI
+
diff --git a/backends/platform/wince/CEgui/PanelKeyboard.h b/backends/platform/wince/CEgui/PanelKeyboard.h
index f441e14771..b98e6ff3a8 100644
--- a/backends/platform/wince/CEgui/PanelKeyboard.h
+++ b/backends/platform/wince/CEgui/PanelKeyboard.h
@@ -37,15 +37,16 @@ using CEKEYS::EventsBuffer;
namespace CEGUI {
- class PanelKeyboard : public Toolbar {
- public:
- PanelKeyboard(WORD reference);
- virtual ~PanelKeyboard();
- virtual bool action(int x, int y, bool pushed);
- private:
- bool _state;
- Key _lastKey;
- };
-}
+class PanelKeyboard : public Toolbar {
+public:
+ PanelKeyboard(WORD reference);
+ virtual ~PanelKeyboard();
+ virtual bool action(int x, int y, bool pushed);
+private:
+ bool _state;
+ Key _lastKey;
+};
+
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.cpp b/backends/platform/wince/CEgui/SDL_ImageResource.cpp
index ce6ebd6382..567013b5ff 100644
--- a/backends/platform/wince/CEgui/SDL_ImageResource.cpp
+++ b/backends/platform/wince/CEgui/SDL_ImageResource.cpp
@@ -23,63 +23,67 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "SDL.h"
#include "SDL_ImageResource.h"
namespace CEGUI {
- SDL_ImageResource::SDL_ImageResource() :
- _surface(0)
- {
- }
+SDL_ImageResource::SDL_ImageResource() :
+ _surface(0) {
+}
- SDL_Surface* SDL_ImageResource::load(WORD resourceID) {
- HRSRC resource;
- HGLOBAL resourceGlobal;
- LPVOID resourcePointer;
- DWORD resourceSize;
- SDL_RWops *surfaceData;
- HMODULE moduleHandle;
+SDL_Surface* SDL_ImageResource::load(WORD resourceID) {
+ HRSRC resource;
+ HGLOBAL resourceGlobal;
+ LPVOID resourcePointer;
+ DWORD resourceSize;
+ SDL_RWops *surfaceData;
+ HMODULE moduleHandle;
- moduleHandle = GetModuleHandle(NULL);
- resource = FindResource(moduleHandle, MAKEINTRESOURCE(resourceID), TEXT("BINARY"));
- if (!resource)
- return NULL;
- resourceSize = SizeofResource(moduleHandle, resource);
- if (!resourceSize)
- return NULL;
- resourceGlobal = LoadResource(moduleHandle, resource);
- if (!resourceGlobal)
- return NULL;
- resourcePointer = LockResource(resourceGlobal);
- if (!resourcePointer)
- return NULL;
+ moduleHandle = GetModuleHandle(NULL);
+ resource = FindResource(moduleHandle, MAKEINTRESOURCE(resourceID), TEXT("BINARY"));
+ if (!resource)
+ return NULL;
+ resourceSize = SizeofResource(moduleHandle, resource);
+ if (!resourceSize)
+ return NULL;
+ resourceGlobal = LoadResource(moduleHandle, resource);
+ if (!resourceGlobal)
+ return NULL;
+ resourcePointer = LockResource(resourceGlobal);
+ if (!resourcePointer)
+ return NULL;
- surfaceData = SDL_RWFromMem(resourcePointer, resourceSize);
- if (!surfaceData)
- return NULL;
- _surface = SDL_LoadBMP_RW(surfaceData, 1);
+ surfaceData = SDL_RWFromMem(resourcePointer, resourceSize);
+ if (!surfaceData)
+ return NULL;
+ _surface = SDL_LoadBMP_RW(surfaceData, 1);
- return _surface;
- }
+ return _surface;
+}
- SDL_Surface* SDL_ImageResource::get() {
- return _surface;
- }
+SDL_Surface* SDL_ImageResource::get() {
+ return _surface;
+}
- int SDL_ImageResource::height() {
- if (_surface)
- return _surface->h;
- return 0;
- }
+int SDL_ImageResource::height() {
+ if (_surface)
+ return _surface->h;
+ return 0;
+}
- int SDL_ImageResource::width() {
- if (_surface)
- return _surface->w;
- return 0;
- }
+int SDL_ImageResource::width() {
+ if (_surface)
+ return _surface->w;
+ return 0;
+}
- SDL_ImageResource::~SDL_ImageResource() {
- if (_surface)
- SDL_FreeSurface(_surface);
- }
+SDL_ImageResource::~SDL_ImageResource() {
+ if (_surface)
+ SDL_FreeSurface(_surface);
}
+
+} // End of namespace CEGUI
diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.h b/backends/platform/wince/CEgui/SDL_ImageResource.h
index 454237dd15..5affd5c33c 100644
--- a/backends/platform/wince/CEgui/SDL_ImageResource.h
+++ b/backends/platform/wince/CEgui/SDL_ImageResource.h
@@ -29,20 +29,22 @@
#include "common/scummsys.h"
#include "common/system.h"
-#include "SDL.h"
+struct SDL_Surface;
namespace CEGUI {
- class SDL_ImageResource {
- public:
- SDL_ImageResource();
- SDL_Surface* load(WORD resourceID);
- SDL_Surface* get();
- int height();
- int width();
- virtual ~SDL_ImageResource();
- private:
- SDL_Surface *_surface;
- };
-}
+
+class SDL_ImageResource {
+public:
+ SDL_ImageResource();
+ SDL_Surface* load(WORD resourceID);
+ SDL_Surface* get();
+ int height();
+ int width();
+ virtual ~SDL_ImageResource();
+private:
+ SDL_Surface *_surface;
+};
+
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEgui/Toolbar.cpp b/backends/platform/wince/CEgui/Toolbar.cpp
index 0501249de9..c41a30cb43 100644
--- a/backends/platform/wince/CEgui/Toolbar.cpp
+++ b/backends/platform/wince/CEgui/Toolbar.cpp
@@ -27,12 +27,12 @@
namespace CEGUI {
- // Not to be drawn on game screen !
- Toolbar::Toolbar() : GUIElement(0, 0, 320, 40)
- {
- }
+// Not to be drawn on game screen !
+Toolbar::Toolbar() : GUIElement(0, 0, 320, 40) {
+}
- Toolbar::~Toolbar() {
- }
+Toolbar::~Toolbar() {
}
+
+} // End of namespace CEGUI
diff --git a/backends/platform/wince/CEgui/Toolbar.h b/backends/platform/wince/CEgui/Toolbar.h
index 3c48e6188a..9fdf05ab3f 100644
--- a/backends/platform/wince/CEgui/Toolbar.h
+++ b/backends/platform/wince/CEgui/Toolbar.h
@@ -27,25 +27,20 @@
#define CEGUI_TOOLBAR_H
#include "common/scummsys.h"
-#include "common/system.h"
-
-//#include "common/map.h"
-#include "common/str.h"
#include "GUIElement.h"
-
-
namespace CEGUI {
- class Toolbar : public GUIElement {
- public:
- virtual ~Toolbar();
- virtual bool action(int x, int y, bool pushed) = 0;
- protected:
- Toolbar();
+class Toolbar : public GUIElement {
+public:
+ virtual ~Toolbar();
+ virtual bool action(int x, int y, bool pushed) = 0;
+protected:
+ Toolbar();
+
+};
- };
-}
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEgui/ToolbarHandler.cpp b/backends/platform/wince/CEgui/ToolbarHandler.cpp
index 3f93a4720d..f74d24ad25 100644
--- a/backends/platform/wince/CEgui/ToolbarHandler.cpp
+++ b/backends/platform/wince/CEgui/ToolbarHandler.cpp
@@ -23,106 +23,111 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include <SDL.h>
+
#include "ToolbarHandler.h"
namespace CEGUI {
- ToolbarHandler::ToolbarHandler():
- _current(""), _active(NULL) {
- }
-
+ToolbarHandler::ToolbarHandler():
+_current(""), _active(NULL) {
+}
- bool ToolbarHandler::add(const String &name, const Toolbar &toolbar) {
- _toolbarMap[name] = (Toolbar*)&toolbar;
- if (!_active) {
- _active = &((Toolbar&)toolbar);
- _current = name;
- }
+bool ToolbarHandler::add(const String &name, const Toolbar &toolbar) {
+ _toolbarMap[name] = (Toolbar*)&toolbar;
- return true;
+ if (!_active) {
+ _active = &((Toolbar&)toolbar);
+ _current = name;
}
- String ToolbarHandler::activeName() {
- return _current;
- }
+ return true;
+}
- bool ToolbarHandler::setActive(const String &name) {
- if (!_toolbarMap.contains(name))
- return false;
- if (_current == name)
- return true;
- _active->action(0, 0, false); // make sure any items are unpushed when changing toolbars (e.g. forced VK->main panel)
- _current = name;
- _active = _toolbarMap[name];
- _active->forceRedraw();
+String ToolbarHandler::activeName() {
+ return _current;
+}
+
+bool ToolbarHandler::setActive(const String &name) {
+ if (!_toolbarMap.contains(name))
+ return false;
+ if (_current == name)
return true;
- }
+ _active->action(0, 0, false); // make sure any items are unpushed when changing toolbars (e.g. forced VK->main panel)
+ _current = name;
+ _active = _toolbarMap[name];
+ _active->forceRedraw();
+ return true;
+}
- bool ToolbarHandler::action(int x, int y, bool pushed) {
- if (_active && _active->visible()) {
- // FIXME !
- if (_offset > 240)
- return _active->action(x / 2, (y - _offset) / 2, pushed);
- else
- return _active->action(x, y - _offset, pushed);
- }
+bool ToolbarHandler::action(int x, int y, bool pushed) {
+ if (_active && _active->visible()) {
+ // FIXME !
+ if (_offset > 240)
+ return _active->action(x / 2, (y - _offset) / 2, pushed);
else
- return false;
+ return _active->action(x, y - _offset, pushed);
}
+ else
+ return false;
+}
- void ToolbarHandler::setVisible(bool visible) {
- if (_active)
- _active->setVisible(visible);
- }
+void ToolbarHandler::setVisible(bool visible) {
+ if (_active)
+ _active->setVisible(visible);
+}
- bool ToolbarHandler::visible() {
- if (_active)
- return _active->visible();
- else
- return false;
- }
+bool ToolbarHandler::visible() {
+ if (_active)
+ return _active->visible();
+ else
+ return false;
+}
- void ToolbarHandler::forceRedraw() {
- if (_active)
- _active->forceRedraw();
- }
+void ToolbarHandler::forceRedraw() {
+ if (_active)
+ _active->forceRedraw();
+}
- bool ToolbarHandler::drawn() {
- if (_active)
- return _active->drawn();
- else
- return false;
- }
+bool ToolbarHandler::drawn() {
+ if (_active)
+ return _active->drawn();
+ else
+ return false;
+}
- bool ToolbarHandler::draw(SDL_Surface *surface, SDL_Rect *rect) {
- if (_active) {
- bool result = _active->draw(surface);
- if (result) {
- rect->x = _active->x();
- rect->y = _active->y();
- rect->w = _active->width();
- rect->h = _active->height();
- }
- return result;
+bool ToolbarHandler::draw(SDL_Surface *surface, SDL_Rect *rect) {
+ if (_active) {
+ bool result = _active->draw(surface);
+ if (result) {
+ rect->x = _active->x();
+ rect->y = _active->y();
+ rect->w = _active->width();
+ rect->h = _active->height();
}
- else
- return false;
- }
+ return result;
+ } else
+ return false;
+}
- void ToolbarHandler::setOffset(int offset) {
- _offset = offset;
- }
+void ToolbarHandler::setOffset(int offset) {
+ _offset = offset;
+}
- int ToolbarHandler::getOffset() {
- return _offset;
- }
+int ToolbarHandler::getOffset() {
+ return _offset;
+}
- Toolbar* ToolbarHandler::active() {
- return _active;
- }
+Toolbar* ToolbarHandler::active() {
+ return _active;
+}
- ToolbarHandler::~ToolbarHandler() {
- _toolbarMap.clear();
- }
+ToolbarHandler::~ToolbarHandler() {
+ _toolbarMap.clear();
}
+
+} // End of namespace CEGUI
diff --git a/backends/platform/wince/CEgui/ToolbarHandler.h b/backends/platform/wince/CEgui/ToolbarHandler.h
index 4a79ed1609..e3bf590768 100644
--- a/backends/platform/wince/CEgui/ToolbarHandler.h
+++ b/backends/platform/wince/CEgui/ToolbarHandler.h
@@ -39,29 +39,30 @@ using Common::HashMap;
namespace CEGUI {
- class ToolbarHandler {
- public:
- ToolbarHandler();
- bool add(const String &name, const Toolbar &toolbar);
- bool setActive(const String &name);
- bool action(int x, int y, bool pushed);
- void setVisible(bool visible);
- bool visible();
- String activeName();
- void forceRedraw();
- void setOffset(int offset);
- int getOffset();
- bool draw(SDL_Surface *surface, SDL_Rect *rect);
- bool drawn();
- Toolbar *active();
- virtual ~ToolbarHandler();
- private:
+class ToolbarHandler {
+public:
+ ToolbarHandler();
+ bool add(const String &name, const Toolbar &toolbar);
+ bool setActive(const String &name);
+ bool action(int x, int y, bool pushed);
+ void setVisible(bool visible);
+ bool visible();
+ String activeName();
+ void forceRedraw();
+ void setOffset(int offset);
+ int getOffset();
+ bool draw(SDL_Surface *surface, SDL_Rect *rect);
+ bool drawn();
+ Toolbar *active();
+ virtual ~ToolbarHandler();
+private:
- HashMap<String, Toolbar*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _toolbarMap;
- String _current;
- Toolbar *_active;
- int _offset;
- };
-}
+ HashMap<String, Toolbar*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _toolbarMap;
+ String _current;
+ Toolbar *_active;
+ int _offset;
+};
+
+} // End of namespace CEGUI
#endif
diff --git a/backends/platform/wince/CEkeys/EventsBuffer.cpp b/backends/platform/wince/CEkeys/EventsBuffer.cpp
index f31a77570f..3cdcb44173 100644
--- a/backends/platform/wince/CEkeys/EventsBuffer.cpp
+++ b/backends/platform/wince/CEkeys/EventsBuffer.cpp
@@ -23,6 +23,11 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include <SDL.h>
+
#include "EventsBuffer.h"
namespace CEKEYS {
diff --git a/backends/platform/wince/CEkeys/EventsBuffer.h b/backends/platform/wince/CEkeys/EventsBuffer.h
index 44e1c66e47..22590db03c 100644
--- a/backends/platform/wince/CEkeys/EventsBuffer.h
+++ b/backends/platform/wince/CEkeys/EventsBuffer.h
@@ -30,8 +30,6 @@
#include "common/system.h"
#include "common/list.h"
-#include <SDL.h>
-
#include "gui/Key.h"
namespace CEKEYS {
diff --git a/backends/platform/wince/missing/assert.h b/backends/platform/wince/missing/assert.h
index 0a9dc23bb8..734b8f9482 100644
--- a/backends/platform/wince/missing/assert.h
+++ b/backends/platform/wince/missing/assert.h
@@ -3,7 +3,7 @@
// defined in common/util.h
void CDECL _declspec(noreturn) error(const char *s, ...);
-#define assert(e) ((e) ? 0 : (::error("Assertion failed " #e " (%s, %d)", __FILE__, __LINE__)))
+#define assert(e) ((e) ? 0 : (::error("Assertion failed %s (%s, %d)", #e, __FILE__, __LINE__)))
#define abort() ::error("Abort (%s, %d)", __FILE__, __LINE__)
diff --git a/backends/platform/wince/missing/conio.h b/backends/platform/wince/missing/conio.h
deleted file mode 100644
index 0cb5c297ea..0000000000
--- a/backends/platform/wince/missing/conio.h
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Header is not present in Windows CE SDK */
-
diff --git a/backends/platform/wince/missing/dir.h b/backends/platform/wince/missing/dir.h
deleted file mode 100644
index 7ee9f5e5ba..0000000000
--- a/backends/platform/wince/missing/dir.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Header is not present in Windows CE SDK */
diff --git a/backends/platform/wince/missing/direct.h b/backends/platform/wince/missing/direct.h
deleted file mode 100644
index 7ee9f5e5ba..0000000000
--- a/backends/platform/wince/missing/direct.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Header is not present in Windows CE SDK */
diff --git a/backends/platform/wince/missing/dirent.h b/backends/platform/wince/missing/dirent.h
deleted file mode 100644
index 07e54bbb9d..0000000000
--- a/backends/platform/wince/missing/dirent.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Header is not present in Windows CE SDK */
-/* It would not be a bad idea to take this thing from gcc distro and port
- it properly. For now only required part is ported. */
-
-struct dirent
-{
- long d_ino; /* Always zero. */
- unsigned short d_reclen; /* Always zero. */
- unsigned short d_namlen; /* Length of name in d_name. */
- char* d_name; /* File name. */
- /* NOTE: The name in the dirent structure points to the name in the
- * finddata_t structure in the DIR. */
-};
-
-/*
- * This is an internal data structure. Good programmers will not use it
- * except as an argument to one of the functions below.
- */
-typedef struct
-{
- /* disk transfer area for this dir */
-/* struct _finddata_t dd_dta; */
-
- /* dirent struct to return from dir (NOTE: this makes this thread
- * safe as long as only one thread uses a particular DIR struct at
- * a time) */
- struct dirent dd_dir;
-
- /* _findnext handle */
- long dd_handle;
-
- /*
- * Status of search:
- * 0 = not started yet (next entry to read is first entry)
- * -1 = off the end
- * positive = 0 based index of next entry
- */
- short dd_stat;
-
- /* given path for dir with search pattern (struct is extended) */
- char dd_name[1];
-} DIR;
-
-
-DIR* opendir (const char*);
-struct dirent* readdir (DIR*);
-int closedir (DIR*);
-/*
-void rewinddir (DIR*);
-long telldir (DIR*);
-void seekdir (DIR*, long);
-*/
diff --git a/backends/platform/wince/missing/fcntl.h b/backends/platform/wince/missing/fcntl.h
deleted file mode 100644
index 7ee9f5e5ba..0000000000
--- a/backends/platform/wince/missing/fcntl.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Header is not present in Windows CE SDK */
diff --git a/backends/platform/wince/missing/gcc/assert.h b/backends/platform/wince/missing/gcc/assert.h
deleted file mode 100644
index 06742532ac..0000000000
--- a/backends/platform/wince/missing/gcc/assert.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* Header is not present in Windows CE SDK */
-
-// defined in common/util.h
-void CDECL _declspec(noreturn) error(const char *s, ...);
-
-#define assert(e) ((e) ? (void) 0 : (::error("Assertion failed " #e " (%s, %d)", __FILE__, __LINE__)))
-
-#define abort() ::error("Abort (%s, %d)", __FILE__, __LINE__)
-
diff --git a/backends/platform/wince/missing/gcc/direct.h b/backends/platform/wince/missing/gcc/direct.h
deleted file mode 100644
index 7ee9f5e5ba..0000000000
--- a/backends/platform/wince/missing/gcc/direct.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Header is not present in Windows CE SDK */
diff --git a/backends/platform/wince/missing/gcc/errno.h b/backends/platform/wince/missing/gcc/errno.h
deleted file mode 100644
index 7ee9f5e5ba..0000000000
--- a/backends/platform/wince/missing/gcc/errno.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Header is not present in Windows CE SDK */
diff --git a/backends/platform/wince/missing/gcc/sys/stat.h b/backends/platform/wince/missing/gcc/sys/stat.h
deleted file mode 100644
index d9eef1318d..0000000000
--- a/backends/platform/wince/missing/gcc/sys/stat.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Header is not present in Windows CE SDK */
-
-#include <sys/types.h>
-
-struct stat {
- _dev_t st_dev;
- _ino_t st_ino;
- unsigned short st_mode;
- short st_nlink;
- short st_uid;
- short st_gid;
- _dev_t st_rdev;
- _off_t st_size;
- time_t st_atime;
- time_t st_mtime;
- time_t st_ctime;
-};
-
-
-#define _S_IFDIR 0040000 /* directory */
-#define S_IFDIR _S_IFDIR
-
-int stat(const char *, struct stat *);
diff --git a/backends/platform/wince/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp
index 532f1d2e89..92af3e6961 100644
--- a/backends/platform/wince/missing/missing.cpp
+++ b/backends/platform/wince/missing/missing.cpp
@@ -29,19 +29,14 @@
* by Vasyl Tsvirkunov
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include <windows.h>
#include <tchar.h>
#include <string.h>
#include <stdlib.h>
-#include "sys/stat.h"
-#ifndef __GNUC__
-#include "sys/time.h"
-#else
#include <stdio.h>
-#endif
-#include "time.h"
-#include "dirent.h"
#include "common/debug.h"
char *strdup(const char *strSource);
@@ -74,44 +69,8 @@ void *bsearch(const void *key, const void *base, size_t nmemb,
return NULL;
}
-static WIN32_FIND_DATA wfd;
-
-int stat(const char *fname, struct stat *ss) {
- TCHAR fnameUnc[MAX_PATH+1];
- HANDLE handle;
- int len;
-
- if (fname == NULL || ss == NULL)
- return -1;
-
- /* Special case (dummy on WinCE) */
- len = strlen(fname);
- if (len >= 2 && fname[len-1] == '.' && fname[len-2] == '.' &&
- (len == 2 || fname[len-3] == '\\')) {
- /* That's everything implemented so far */
- memset(ss, 0, sizeof(struct stat));
- ss->st_size = 1024;
- ss->st_mode |= S_IFDIR;
- return 0;
- }
-
- MultiByteToWideChar(CP_ACP, 0, fname, -1, fnameUnc, MAX_PATH);
- handle = FindFirstFile(fnameUnc, &wfd);
- FindClose(handle);
- if (handle == INVALID_HANDLE_VALUE)
- return -1;
- else
- {
- /* That's everything implemented so far */
- memset(ss, 0, sizeof(struct stat));
- ss->st_size = wfd.nFileSizeLow;
- if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- ss->st_mode |= S_IFDIR;
- }
- return 0;
-}
+static char cwd[MAX_PATH+1] = "";
-char cwd[MAX_PATH+1] = "";
EXT_C char *getcwd(char *buffer, int maxlen) {
TCHAR fileUnc[MAX_PATH+1];
char* plast;
@@ -226,112 +185,6 @@ int _access(const char *path, int mode) {
// evc only functions follow
#ifndef __GNUC__
-/* Limited dirent implementation. Used by UI.C and DEVICES.C */
-DIR* opendir(const char* fname) {
- DIR* pdir;
- char fnameMask[MAX_PATH+1];
- TCHAR fnameUnc[MAX_PATH+1];
- char nameFound[MAX_PATH+1];
-
- if (fname == NULL)
- return NULL;
-
- strcpy(fnameMask, fname);
- if (!strlen(fnameMask) || fnameMask[strlen(fnameMask)-1] != '\\')
- strncat(fnameMask, "\\", MAX_PATH-strlen(fnameMask)-1);
- strncat(fnameMask, "*.*", MAX_PATH-strlen(fnameMask)-4);
-
- pdir = (DIR*)malloc(sizeof(DIR)+strlen(fname));
- pdir->dd_dir.d_ino = 0;
- pdir->dd_dir.d_reclen = 0;
- pdir->dd_dir.d_name = 0;
- pdir->dd_dir.d_namlen = 0;
-
- pdir->dd_handle = 0;
- pdir->dd_stat = 0;
- strcpy(pdir->dd_name, fname); /* it has exactly enough space for fname and nul char */
-
- MultiByteToWideChar(CP_ACP, 0, fnameMask, -1, fnameUnc, MAX_PATH);
- if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE) {
- free(pdir);
- return NULL;
- } else {
- WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL);
-
- pdir->dd_dir.d_name = strdup(nameFound);
- pdir->dd_dir.d_namlen = strlen(nameFound);
- }
- return pdir;
-}
-
-struct dirent* readdir(DIR* dir) {
- char nameFound[MAX_PATH+1];
- static struct dirent dummy;
-
- if (dir->dd_stat == 0) {
- dummy.d_name = ".";
- dummy.d_namlen = 1;
- dir->dd_stat ++;
- return &dummy;
- } else if (dir->dd_stat == 1) {
- dummy.d_name = "..";
- dummy.d_namlen = 2;
- dir->dd_stat ++;
- return &dummy;
- } else if (dir->dd_stat == 2) {
- dir->dd_stat++;
- return &dir->dd_dir;
- } else {
- if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0) {
- dir->dd_stat = -1;
- return NULL;
- }
- WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL);
-
- free(dir->dd_dir.d_name);
-
- dir->dd_dir.d_name = strdup(nameFound);
- dir->dd_dir.d_namlen = strlen(nameFound);
-
- dir->dd_stat ++;
-
- return &dir->dd_dir;
- }
-}
-
-int closedir(DIR* dir) {
- if (dir == NULL)
- return 0;
-
- if (dir->dd_handle)
- FindClose((HANDLE)dir->dd_handle);
-
- free(dir->dd_dir.d_name);
- free(dir);
- return 1;
-}
-
-/* Make directory, Unix style */
-void mkdir(char* dirname, int mode) {
- char path[MAX_PATH+1];
- TCHAR pathUnc[MAX_PATH+1];
- char *ptr;
- strncpy(path, dirname, MAX_PATH);
- if (*path == '/')
- *path = '\\';
- /* Run through the string and attempt creating all subdirs on the path */
- for (ptr = path+1; *ptr; ptr ++) {
- if (*ptr == '\\' || *ptr == '/') {
- *ptr = 0;
- MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
- CreateDirectory(pathUnc, 0);
- *ptr = '\\';
- }
- }
- MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
- CreateDirectory(pathUnc, 0);
-}
-
char *strdup(const char *strSource) {
char *buffer;
size_z len = strlen(strSource) + 1;
diff --git a/backends/platform/wince/missing/signal.h b/backends/platform/wince/missing/signal.h
deleted file mode 100644
index 128d6bf1db..0000000000
--- a/backends/platform/wince/missing/signal.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* Header is not present in Windows CE SDK */
-/* Functionality is not critical -- Pocket PC devices do not have Ctrl+C */
-#define signal(a,b)
diff --git a/backends/platform/wince/missing/sys/stat.h b/backends/platform/wince/missing/sys/stat.h
deleted file mode 100644
index 8f5bda59e1..0000000000
--- a/backends/platform/wince/missing/sys/stat.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Header is not present in Windows CE SDK */
-
-#include <sys/types.h>
-
-#ifndef __MINGW32CE__
-struct stat {
- _dev_t st_dev;
- _ino_t st_ino;
- unsigned short st_mode;
- short st_nlink;
- short st_uid;
- short st_gid;
- _dev_t st_rdev;
- _off_t st_size;
- time_t st_atime;
- time_t st_mtime;
- time_t st_ctime;
-};
-
-int stat(const char *, struct stat *);
-
-#endif
-
-#define _S_IFDIR 0040000 /* directory */
-#define S_IFDIR _S_IFDIR
diff --git a/backends/platform/wince/missing/sys/time.h b/backends/platform/wince/missing/sys/time.h
deleted file mode 100644
index ded29bb009..0000000000
--- a/backends/platform/wince/missing/sys/time.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* Header is not present in Windows CE SDK */
-
-struct timeval
-{
- int tv_sec;
- int tv_usec;
-};
-
-void gettimeofday(struct timeval* tp, void* dummy);
-void usleep(long usec);
diff --git a/backends/platform/wince/missing/sys/types.h b/backends/platform/wince/missing/sys/types.h
deleted file mode 100644
index b6c05e3958..0000000000
--- a/backends/platform/wince/missing/sys/types.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/* Header is not present in Windows CE SDK */
-
-typedef unsigned short _ino_t;
-typedef unsigned int _dev_t;
-typedef long _off_t;
diff --git a/backends/platform/wince/missing/unistd.h b/backends/platform/wince/missing/unistd.h
deleted file mode 100644
index 7ee9f5e5ba..0000000000
--- a/backends/platform/wince/missing/unistd.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Header is not present in Windows CE SDK */
diff --git a/backends/platform/wince/portdefs.h b/backends/platform/wince/portdefs.h
index 4b9c53e707..cbf2006be2 100644
--- a/backends/platform/wince/portdefs.h
+++ b/backends/platform/wince/portdefs.h
@@ -69,14 +69,10 @@ char *strpbrk(const char *s, const char *accept);
#include <string.h>
#include <io.h>
#include <stdarg.h>
-#include <fcntl.h>
-#include <conio.h>
-#include <malloc.h>
#include <assert.h>
#include <mmsystem.h>
#include <ctype.h>
//#include <direct.h>
-#include <time.h>
#ifdef __MINGW32CE__
void *bsearch(const void *, const void *, size_t, size_t, int (*x) (const void *, const void *));
diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp
index ac9be5df48..3f64cb7d5d 100644
--- a/backends/platform/wince/wince-sdl.cpp
+++ b/backends/platform/wince/wince-sdl.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/platform/wince/wince-sdl.h"
#include "common/config-manager.h"
@@ -970,8 +973,9 @@ bool OSystem_WINCE3::getFeatureState(Feature f) {
return false;
case kFeatureVirtualKeyboard:
return (_panelStateForced);
+ default:
+ return OSystem_SDL::getFeatureState(f);
}
- return OSystem_SDL::getFeatureState(f);
}
void OSystem_WINCE3::check_mappings() {
@@ -2053,7 +2057,7 @@ void OSystem_WINCE3::undrawMouse() {
if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
error("SDL_LockSurface failed: %s", SDL_GetError());
- int x, y;
+ int y;
if (!_overlayVisible) {
byte *dst, *bak = _mouseBackupOld;
@@ -2242,14 +2246,15 @@ static int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter) {
if (unfilter) {
switch (key) {
- case SDLK_ESCAPE:
- return SDLK_BACKSPACE;
- case SDLK_F8:
- return SDLK_ASTERISK;
- case SDLK_F9:
- return SDLK_HASH;
+ case SDLK_ESCAPE:
+ return SDLK_BACKSPACE;
+ case SDLK_F8:
+ return SDLK_ASTERISK;
+ case SDLK_F9:
+ return SDLK_HASH;
+ default:
+ return key;
}
- return key;
}
if (key >= SDLK_KP0 && key <= SDLK_KP9) {
@@ -2265,7 +2270,6 @@ static int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter) {
bool OSystem_WINCE3::pollEvent(Common::Event &event) {
SDL_Event ev;
ev.type = SDL_NOEVENT;
- byte b = 0;
DWORD currentTime;
bool keyEvent = false;
int deltaX, deltaY;
diff --git a/backends/mixer/symbiansdl/symbiansdl-mixer.h b/backends/plugins/ds/ds-provider.cpp
index 6a0d281b1a..832fd1312c 100644
--- a/backends/mixer/symbiansdl/symbiansdl-mixer.h
+++ b/backends/plugins/ds/ds-provider.cpp
@@ -23,27 +23,25 @@
*
*/
-#ifndef BACKENDS_MIXER_SYMBIAN_SDL_H
-#define BACKENDS_MIXER_SYMBIAN_SDL_H
+#if defined(DYNAMIC_MODULES) && defined(__DS__)
-#include "backends/mixer/sdl/sdl-mixer.h"
+#include <malloc.h>
+#include <nds.h>
-/**
- * SDL mixer manager for Symbian
- */
-class SymbianSdlMixerManager : public SdlMixerManager {
-public:
- SymbianSdlMixerManager();
- virtual ~SymbianSdlMixerManager();
-
- virtual void init();
+#include "backends/plugins/ds/ds-provider.h"
+#include "backends/plugins/elf/arm-loader.h"
+class DSDLObject : public ARMDLObject {
protected:
- int _channels;
- byte *_stereo_mix_buffer;
-
- virtual void callbackHandler(byte *samples, int len);
+ virtual void flushDataCache(void *ptr, uint32 len) const {
+ DC_FlushRange(ptr, len);
+ IC_InvalidateRange(ptr, len);
+ }
};
-#endif
+Plugin *DSPluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new TemplatedELFPlugin<DSDLObject>(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(__DS__)
diff --git a/backends/plugins/ds/ds-provider.h b/backends/plugins/ds/ds-provider.h
new file mode 100644
index 0000000000..dcb93c085f
--- /dev/null
+++ b/backends/plugins/ds/ds-provider.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__DS__)
+
+#ifndef BACKENDS_PLUGINS_DS_PROVIDER_H
+#define BACKENDS_PLUGINS_DS_PROVIDER_H
+
+#include "backends/plugins/elf/elf-provider.h"
+
+class DSPluginProvider : public ELFPluginProvider {
+public:
+ Plugin *createPlugin(const Common::FSNode &node) const;
+};
+
+#endif // BACKENDS_PLUGINS_DS_PROVIDER_H
+
+#endif // defined(DYNAMIC_MODULES) && defined(__DS__)
+
diff --git a/backends/plugins/ds/plugin.ld b/backends/plugins/ds/plugin.ld
new file mode 100644
index 0000000000..04035b0169
--- /dev/null
+++ b/backends/plugins/ds/plugin.ld
@@ -0,0 +1,217 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */
+PHDRS {
+ plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */
+}
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0;
+ .interp : { *(.interp) } : plugin
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rel_iplt_start = .);
+ *(.rel.iplt)
+ PROVIDE_HIDDEN (__rel_iplt_end = .);
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rel_iplt_start = .);
+ PROVIDE_HIDDEN (__rel_iplt_end = .);
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .rel.plt :
+ {
+ *(.rel.plt)
+ }
+ .rela.plt :
+ {
+ *(.rela.plt)
+ }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0
+ .plt : { *(.plt) }
+ .iplt : { *(.iplt) }
+ .text :
+ {
+ *(.text.unlikely .text.*_unlikely)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ } =0
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+ __exidx_start = .;
+ .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+ __exidx_end = .;
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1));
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ }
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ .ctors :
+ {
+ ___plugin_ctors = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ ___plugin_ctors_end = .;
+ }
+ .dtors :
+ {
+ ___plugin_dtors = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ ___plugin_dtors_end = .;
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
+ .data :
+ {
+ __data_start = . ;
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .; PROVIDE (edata = .);
+ __bss_start = .;
+ __bss_start__ = .;
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 32 / 8 : 1);
+ }
+ _bss_end__ = . ; __bss_end__ = . ;
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ __end__ = . ;
+ _end = .; PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ .stack 0x80000 :
+ {
+ _stack = .;
+ *(.stack)
+ }
+ .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
+ .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/backends/plugins/elf/arm-loader.cpp b/backends/plugins/elf/arm-loader.cpp
new file mode 100644
index 0000000000..93d3c60f84
--- /dev/null
+++ b/backends/plugins/elf/arm-loader.cpp
@@ -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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ARM_TARGET)
+
+#include "backends/plugins/elf/arm-loader.h"
+
+#include "common/debug.h"
+
+bool ARMDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) {
+ Elf32_Rel *rel = 0; //relocation entry
+
+ // Allocate memory for relocation table
+ if (!(rel = (Elf32_Rel *)malloc(size))) {
+ warning("elfloader: Out of memory.");
+ return false;
+ }
+
+ // Read in our relocation table
+ if (!_file->seek(offset, SEEK_SET) || _file->read(rel, size) != size) {
+ warning("elfloader: Relocation table load failed.");
+ free(rel);
+ return false;
+ }
+
+ // Treat each relocation entry. Loop over all of them
+ uint32 cnt = size / sizeof(*rel);
+
+ debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", cnt, relSegment);
+
+ int32 a = 0;
+ uint32 relocation = 0;
+
+ // Loop over relocation entries
+ for (uint32 i = 0; i < cnt; i++) {
+ // Get the symbol this relocation entry is referring to
+ Elf32_Sym *sym = _symtab + (REL_INDEX(rel[i].r_info));
+
+ // Get the target instruction in the code. TODO: repect _segmentVMA
+ uint32 *target = (uint32 *)((byte *)relSegment + rel[i].r_offset);
+
+ uint32 origTarget = *target; //Save for debugging
+
+ // Act differently based on the type of relocation
+ switch (REL_TYPE(rel[i].r_info)) {
+ case R_ARM_ABS32:
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+ relocation = a + Elf32_Addr(_segment); // Shift by main offset
+
+ *target = relocation;
+
+ debug(8, "elfloader: R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x", i, a, origTarget, *target);
+ }
+ break;
+
+ case R_ARM_THM_CALL:
+ debug(8, "elfloader: R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.");
+ break;
+
+ case R_ARM_CALL:
+ debug(8, "elfloader: R_ARM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.");
+ break;
+
+ case R_ARM_JUMP24:
+ debug(8, "elfloader: R_ARM_JUMP24: PC-relative jump, ld takes care of all relocation work for us.");
+ break;
+
+ case R_ARM_V4BX:
+ debug(8, "elfloader: R_ARM_V4BX: No relocation calculation necessary.");
+ break;
+
+ default:
+ warning("elfloader: Unknown relocation type %d.", REL_TYPE(rel[i].r_info));
+ free(rel);
+ return false;
+ }
+ }
+
+ free(rel);
+ return true;
+}
+
+bool ARMDLObject::relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+ // Loop over sections, finding relocation sections
+ for (uint32 i = 0; i < ehdr->e_shnum; i++) {
+ Elf32_Shdr *curShdr = &(shdr[i]);
+
+ if ((curShdr->sh_type == SHT_REL || curShdr->sh_type == SHT_RELA) && // Check for a relocation section
+ curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
+ int32(curShdr->sh_link) == _symtab_sect && // Check that the sh_link connects to our symbol table
+ curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
+
+ if (curShdr->sh_type == SHT_RELA) {
+ warning("elfloader: RELA entries not supported yet!");
+ return false;
+ }
+
+ if (!relocate(curShdr->sh_offset, curShdr->sh_size, _segment))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ARM_TARGET) */
+
diff --git a/backends/events/samsungtvsdl/samsungtvsdl-events.h b/backends/plugins/elf/arm-loader.h
index 10e1eb84bb..cb4230c1ee 100644
--- a/backends/events/samsungtvsdl/samsungtvsdl-events.h
+++ b/backends/plugins/elf/arm-loader.h
@@ -23,20 +23,22 @@
*
*/
-#if !defined(BACKEND_EVENTS_SDL_SAMSUNGTV_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
-#define BACKEND_EVENTS_SDL_SAMSUNGTV_H
+#ifndef BACKENDS_PLUGINS_ARM_LOADER_H
+#define BACKENDS_PLUGINS_ARM_LOADER_H
-#include "backends/events/sdl/sdl-events.h"
+#include "common/scummsys.h"
-/**
- * SDL events manager for Samsung TV
- */
-class SamsungTVSdlEventManager : public SdlEventManager {
-public:
- SamsungTVSdlEventManager(Common::EventSource *boss);
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ARM_TARGET)
+
+#include "backends/plugins/elf/elf-loader.h"
+class ARMDLObject : public DLObject {
protected:
- virtual bool remapKey(SDL_Event &ev, Common::Event &event);
+ virtual bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment);
+ virtual bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
};
-#endif
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ARM_TARGET) */
+
+#endif /* BACKENDS_PLUGINS_ARM_LOADER_H */
+
diff --git a/backends/plugins/elf/elf-loader.cpp b/backends/plugins/elf/elf-loader.cpp
new file mode 100644
index 0000000000..f7b151ecee
--- /dev/null
+++ b/backends/plugins/elf/elf-loader.cpp
@@ -0,0 +1,440 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
+
+#include "backends/plugins/elf/elf-loader.h"
+
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/fs.h"
+#include "common/ptr.h"
+
+#include <malloc.h> // for memalign()
+
+DLObject::DLObject() :
+ _file(0),
+ _segment(0),
+ _symtab(0),
+ _strtab(0),
+ _segmentSize(0),
+ _segmentOffset(0),
+ _segmentVMA(0),
+ _symbol_cnt(0),
+ _symtab_sect(-1),
+ _dtors_start(0),
+ _dtors_end(0) {
+}
+
+DLObject::~DLObject() {
+ discardSymtab();
+ free(_segment);
+ _segment = 0;
+}
+
+// Expel the symbol table from memory
+void DLObject::discardSymtab() {
+ free(_symtab);
+ _symtab = 0;
+
+ free(_strtab);
+ _strtab = 0;
+
+ _symbol_cnt = 0;
+}
+
+// Unload all objects from memory
+void DLObject::unload() {
+ discardSymtab();
+
+ free(_segment);
+
+ _segment = 0;
+ _segmentSize = 0;
+ _segmentOffset = 0;
+ _segmentVMA = 0;
+}
+
+bool DLObject::readElfHeader(Elf32_Ehdr *ehdr) {
+ assert(_file);
+
+ // Start reading the elf header. Check for errors and magic
+ if (_file->read(ehdr, sizeof(*ehdr)) != sizeof(*ehdr) ||
+ memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+ warning("elfloader: No ELF file.");
+ return false;
+ }
+
+ if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
+ warning("elfloader: Wrong ELF file class.");
+ return false;
+ }
+
+ if (ehdr->e_ident[EI_DATA] !=
+#ifdef SCUMM_BIG_ENDIAN
+ ELFDATA2MSB
+#else
+ ELFDATA2LSB
+#endif
+ ) {
+ warning("elfloader: Wrong ELF file endianess.");
+ return false;
+ }
+
+ if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
+ warning("elfloader: Wrong ELF file version.");
+ return false;
+ }
+
+ if (ehdr->e_type != ET_EXEC) {
+ warning("elfloader: No executable ELF file.");
+ return false;
+ }
+
+ if (ehdr->e_machine !=
+#ifdef ARM_TARGET
+ EM_ARM
+#endif
+#ifdef MIPS_TARGET
+ EM_MIPS
+#endif
+#ifdef PPC_TARGET
+ EM_PPC
+#endif
+ ) {
+ warning("elfloader: Wrong ELF file architecture.");
+ return false;
+ }
+
+ if (ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header
+ ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header
+ warning("elfloader: Invalid ELF structure sizes.");
+ return false;
+ }
+
+ debug(2, "elfloader: phoff = %d, phentsz = %d, phnum = %d",
+ ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum);
+
+ return true;
+}
+
+bool DLObject::readProgramHeaders(Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, Elf32_Half num) {
+ assert(_file);
+
+ // Read program header
+ if (!_file->seek(ehdr->e_phoff + sizeof(*phdr) * num, SEEK_SET) ||
+ _file->read(phdr, sizeof(*phdr)) != sizeof(*phdr)) {
+ warning("elfloader: Program header load failed.");
+ return false;
+ }
+
+ // Check program header values
+ if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) {
+ warning("elfloader: Invalid program header.");
+ return false;
+ }
+
+ debug(2, "elfloader: offs = %x, filesz = %x, memsz = %x, align = %x",
+ phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align);
+
+ return true;
+}
+
+bool DLObject::loadSegment(Elf32_Phdr *phdr) {
+ _segment = (byte *)memalign(phdr->p_align, phdr->p_memsz);
+
+ if (!_segment) {
+ warning("elfloader: Out of memory.");
+ return false;
+ }
+
+ debug(2, "elfloader: Allocated segment @ %p", _segment);
+
+ // Get offset to load segment into
+ _segmentSize = phdr->p_memsz;
+ _segmentVMA = phdr->p_vaddr;
+
+ // Set .bss segment to 0 if necessary
+ if (phdr->p_memsz > phdr->p_filesz) {
+ debug(2, "elfloader: Setting %p to %p to 0 for bss",
+ _segment + phdr->p_filesz, _segment + phdr->p_memsz);
+ memset(_segment + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+ }
+
+ debug(2, "elfloader: Reading the segment into memory");
+
+ // Read the segment into memory
+ if (!_file->seek(phdr->p_offset, SEEK_SET) ||
+ _file->read(_segment, phdr->p_filesz) != phdr->p_filesz) {
+ warning("elfloader: Segment load failed.");
+ return false;
+ }
+
+ debug(2, "elfloader: Segment has been read into memory");
+
+ return true;
+}
+
+Elf32_Shdr * DLObject::loadSectionHeaders(Elf32_Ehdr *ehdr) {
+ assert(_file);
+
+ Elf32_Shdr *shdr = 0;
+
+ // Allocate memory for section headers
+ if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) {
+ warning("elfloader: Out of memory.");
+ return 0;
+ }
+
+ // Read from file into section headers
+ if (!_file->seek(ehdr->e_shoff, SEEK_SET) ||
+ _file->read(shdr, ehdr->e_shnum * sizeof(*shdr)) !=
+ ehdr->e_shnum * sizeof(*shdr)) {
+ warning("elfloader: Section headers load failed.");
+ free(shdr);
+ return 0;
+ }
+
+ return shdr;
+}
+
+int DLObject::loadSymbolTable(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+ assert(_file);
+
+ // Loop over sections, looking for symbol table linked to a string table
+ for (uint32 i = 0; i < ehdr->e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB &&
+ shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
+ shdr[i].sh_link < ehdr->e_shnum &&
+ shdr[shdr[i].sh_link].sh_type == SHT_STRTAB &&
+ _symtab_sect < 0) {
+ _symtab_sect = i;
+ }
+ }
+
+ // Check for no symbol table
+ if (_symtab_sect < 0) {
+ warning("elfloader: No symbol table.");
+ return -1;
+ }
+
+ debug(2, "elfloader: Symbol section at section %d, size %x",
+ _symtab_sect, shdr[_symtab_sect].sh_size);
+
+ // Allocate memory for symbol table
+ if (!(_symtab = (Elf32_Sym *)malloc(shdr[_symtab_sect].sh_size))) {
+ warning("elfloader: Out of memory.");
+ return -1;
+ }
+
+ // Read symbol table into memory
+ if (!_file->seek(shdr[_symtab_sect].sh_offset, SEEK_SET) ||
+ _file->read(_symtab, shdr[_symtab_sect].sh_size) !=
+ shdr[_symtab_sect].sh_size) {
+ warning("elfloader: Symbol table load failed.");
+ free(_symtab);
+ _symtab = 0;
+ return -1;
+ }
+
+ // Set number of symbols
+ _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym);
+ debug(2, "elfloader: Loaded %d symbols.", _symbol_cnt);
+
+ return _symtab_sect;
+}
+
+bool DLObject::loadStringTable(Elf32_Shdr *shdr) {
+ assert(_file);
+
+ uint32 string_sect = shdr[_symtab_sect].sh_link;
+
+ // Allocate memory for string table
+ if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) {
+ warning("elfloader: Out of memory.");
+ return false;
+ }
+
+ // Read string table into memory
+ if (!_file->seek(shdr[string_sect].sh_offset, SEEK_SET) ||
+ _file->read(_strtab, shdr[string_sect].sh_size) !=
+ shdr[string_sect].sh_size) {
+ warning("elfloader: Symbol table strings load failed.");
+ free(_strtab);
+ _strtab = 0;
+ return false;
+ }
+
+ return true;
+}
+
+void DLObject::relocateSymbols(ptrdiff_t offset) {
+ // Loop over symbols, add relocation offset
+ Elf32_Sym *s = _symtab;
+
+ for (uint32 c = _symbol_cnt; c--; s++) {
+ // Make sure we don't relocate special valued symbols
+ if (s->st_shndx < SHN_LOPROC) {
+ s->st_value += offset;
+
+ if (s->st_value < Elf32_Addr(_segment) ||
+ s->st_value > Elf32_Addr(_segment) + _segmentSize)
+ warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value);
+ }
+ }
+}
+
+bool DLObject::load() {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+
+ if (readElfHeader(&ehdr) == false)
+ return false;
+
+ for (uint32 i = 0; i < ehdr.e_phnum; i++) { //Load our segments
+ debug(2, "elfloader: Loading segment %d", i);
+
+ if (readProgramHeaders(&ehdr, &phdr, i) == false)
+ return false;
+
+ if (!loadSegment(&phdr))
+ return false;
+ }
+
+ Elf32_Shdr *shdr = loadSectionHeaders(&ehdr);
+ if (!shdr)
+ return false;
+
+ _symtab_sect = loadSymbolTable(&ehdr, shdr);
+ if (_symtab_sect < 0) {
+ free(shdr);
+ return false;
+ }
+
+ if (!loadStringTable(shdr)) {
+ free(shdr);
+ return false;
+ }
+
+ // Offset by our segment allocated address
+ // must use _segmentVMA here for multiple segments (MIPS)
+ _segmentOffset = ptrdiff_t(_segment) - _segmentVMA;
+ relocateSymbols(_segmentOffset);
+
+ if (!relocateRels(&ehdr, shdr)) {
+ free(shdr);
+ return false;
+ }
+
+ return true;
+}
+
+bool DLObject::open(const char *path) {
+ void *ctors_start, *ctors_end;
+
+ debug(2, "elfloader: open(\"%s\")", path);
+
+ _file = Common::FSNode(path).createReadStream();
+
+ if (!_file) {
+ warning("elfloader: File %s not found.", path);
+ return false;
+ }
+
+ debug(2, "elfloader: %s found!", path);
+
+ /*Try to load and relocate*/
+ if (!load()) {
+ unload();
+ return false;
+ }
+
+ debug(2, "elfloader: Loaded!");
+
+ delete _file;
+ _file = 0;
+
+ flushDataCache(_segment, _segmentSize);
+
+ ctors_start = symbol("___plugin_ctors");
+ ctors_end = symbol("___plugin_ctors_end");
+ _dtors_start = symbol("___plugin_dtors");
+ _dtors_end = symbol("___plugin_dtors_end");
+
+ if (!ctors_start || !ctors_end || !_dtors_start || !_dtors_end) {
+ warning("elfloader: Missing ctors/dtors.");
+ _dtors_start = _dtors_end = 0;
+ unload();
+ return false;
+ }
+
+ debug(2, "elfloader: Calling constructors.");
+ for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
+ (**f)();
+
+ debug(2, "elfloader: %s opened ok.", path);
+
+ return true;
+}
+
+bool DLObject::close() {
+ if (_dtors_start && _dtors_end)
+ for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++)
+ (**f)();
+
+ _dtors_start = _dtors_end = 0;
+ unload();
+ return true;
+}
+
+void *DLObject::symbol(const char *name) {
+ debug(2, "elfloader: Symbol(\"%s\")", name);
+
+ if (!_symtab || !_strtab || _symbol_cnt < 1) {
+ warning("elfloader: No symbol table loaded.");
+ return 0;
+ }
+
+ Elf32_Sym *s = _symtab;
+
+ for (uint32 c = _symbol_cnt; c--; s++)
+ // We can only import symbols that are global or weak in the plugin
+ if ((SYM_BIND(s->st_info) == STB_GLOBAL ||
+ SYM_BIND(s->st_info) == STB_WEAK) &&
+ !strcmp(name, _strtab + s->st_name)) {
+ // We found the symbol
+ debug(2, "elfloader: => 0x%08x", s->st_value);
+ return (void*)s->st_value;
+ }
+
+ // We didn't find the symbol
+ warning("elfloader: Symbol \"%s\" not found.", name);
+ return 0;
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) */
+
diff --git a/backends/plugins/elf/elf-loader.h b/backends/plugins/elf/elf-loader.h
new file mode 100644
index 0000000000..2825cc9d8d
--- /dev/null
+++ b/backends/plugins/elf/elf-loader.h
@@ -0,0 +1,102 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_PLUGINS_ELF_LOADER_H
+#define BACKENDS_PLUGINS_ELF_LOADER_H
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
+
+#include <stddef.h>
+
+#include "backends/plugins/elf/elf32.h"
+#include "backends/plugins/dynamic-plugin.h"
+
+#include "common/stream.h"
+
+/**
+ * DLObject
+ *
+ * Class that most directly handles operations on a plugin file
+ * (opening it for reading, loading/unloading it in memory, finding a specific symbol in the file, etc.)
+ * Subclasses have the same functionality, but implementations specific to different processors/platforms.
+ */
+class DLObject {
+protected:
+ Common::SeekableReadStream *_file;
+
+ byte *_segment;
+ Elf32_Sym *_symtab;
+ char *_strtab;
+
+ uint32 _segmentSize;
+ ptrdiff_t _segmentOffset;
+ uint32 _segmentVMA;
+
+ uint32 _symbol_cnt;
+ int32 _symtab_sect;
+ void *_dtors_start, *_dtors_end;
+
+ virtual void unload();
+ bool load();
+
+ bool readElfHeader(Elf32_Ehdr *ehdr);
+ bool readProgramHeaders(Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, Elf32_Half num);
+ virtual bool loadSegment(Elf32_Phdr *phdr);
+ Elf32_Shdr *loadSectionHeaders(Elf32_Ehdr *ehdr);
+ int loadSymbolTable(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+ bool loadStringTable(Elf32_Shdr *shdr);
+ virtual void relocateSymbols(ptrdiff_t offset);
+
+ // architecture specific
+
+ /**
+ * Follow the instruction of a relocation section.
+ *
+ * @param fileOffset Offset into the File
+ * @param size Size of relocation section
+ * @param relSegment Base address of relocated segment in memory (memory offset)
+ */
+ virtual bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) = 0;
+ virtual bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0;
+
+ // platform specific
+ virtual void flushDataCache(void *ptr, uint32 len) const = 0;
+
+public:
+ DLObject();
+ virtual ~DLObject();
+
+ bool open(const char *path);
+ bool close();
+ void *symbol(const char *name);
+ void discardSymtab();
+};
+
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) */
+
+#endif /* BACKENDS_PLUGINS_ELF_LOADER_H */
+
diff --git a/backends/plugins/elf/elf-provider.cpp b/backends/plugins/elf/elf-provider.cpp
new file mode 100644
index 0000000000..b241379934
--- /dev/null
+++ b/backends/plugins/elf/elf-provider.cpp
@@ -0,0 +1,177 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
+
+#ifdef ELF_LOADER_CXA_ATEXIT
+#include <cxxabi.h>
+#endif
+
+#include "backends/plugins/elf/elf-provider.h"
+#include "backends/plugins/dynamic-plugin.h"
+
+#include "common/debug.h"
+#include "common/fs.h"
+
+/* Note about ELF_LOADER_CXA_ATEXIT:
+ *
+ * consider the code:
+ *
+ * class Foobar {
+ * const char *work() {
+ * static String foo = "bar";
+ * return s.c_str();
+ * }
+ * }
+ *
+ * When instantiating Foobar and calling work() for the first time the String
+ * foo will be constructed. GCC automatically registers its destruction via
+ * either atexit() or __cxa_atexit(). Only the latter will add information
+ * about which DSO did the construction (Using &__dso_handle).
+ *
+ * __cxa_atexit allows plugins to reference C++ ABI symbols in the main
+ * executable without code duplication (No need to link the plugin against
+ * libstdc++), since we can distinguish which registered exit functions belong
+ * to a specific DSO. When unloading a plugin, we just use the C++ ABI call
+ * __cxa_finalize(&__dso_handle) to call all destructors of only that DSO.
+ *
+ * Prerequisites:
+ * - The used libc needs to support __cxa_atexit
+ * - -fuse-cxa-atexit in CXXFLAGS
+ * - Every plugin needs its own hidden __dso_handle symbol
+ * This is automatically done via REGISTER_PLUGIN_DYNAMIC, see base/plugins.h
+ *
+ * When __cxa_atexit can not be used, each plugin needs to link against
+ * libstdc++ to embed its own set of C++ ABI symbols. When not doing so,
+ * registered destructors of already unloaded plugins will crash the
+ * application upon returning from main().
+ *
+ * See "3.3.5 DSO Object Destruction API" of the C++ ABI
+ */
+
+DynamicPlugin::VoidFunc ELFPlugin::findSymbol(const char *symbol) {
+ void *func = 0;
+
+ if (_dlHandle)
+ func = _dlHandle->symbol(symbol);
+
+ if (!func) {
+ if (!_dlHandle)
+ warning("elfloader: Failed loading symbol '%s' from plugin '%s' (Handle is NULL)", symbol, _filename.c_str());
+ else
+ warning("elfloader: Failed loading symbol '%s' from plugin '%s'", symbol, _filename.c_str());
+ }
+
+ // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++
+ // standard and POSIX: ISO C++ disallows casting between function pointers
+ // and data pointers, but dlsym always returns a void pointer. For details,
+ // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>.
+ assert(sizeof(VoidFunc) == sizeof(func));
+ VoidFunc tmp;
+ memcpy(&tmp, &func, sizeof(VoidFunc));
+ return tmp;
+}
+
+bool ELFPlugin::loadPlugin() {
+ assert(!_dlHandle);
+
+ DLObject *obj = makeDLObject();
+ if (obj->open(_filename.c_str())) {
+ _dlHandle = obj;
+ } else {
+ delete obj;
+ _dlHandle = 0;
+ }
+
+ if (!_dlHandle) {
+ warning("elfloader: Failed loading plugin '%s'", _filename.c_str());
+ return false;
+ }
+
+ CharFunc buildDateFunc = (CharFunc)findSymbol("PLUGIN_getBuildDate");
+ if (!buildDateFunc) {
+ unloadPlugin();
+ warning("elfloader: plugin '%s' is missing symbols", _filename.c_str());
+ return false;
+ }
+
+ if (strncmp(gScummVMPluginBuildDate, buildDateFunc(), strlen(gScummVMPluginBuildDate))) {
+ unloadPlugin();
+ warning("elfloader: plugin '%s' has a different build date", _filename.c_str());
+ return false;
+ }
+
+ bool ret = DynamicPlugin::loadPlugin();
+
+#ifdef ELF_LOADER_CXA_ATEXIT
+ if (ret) {
+ // FIXME HACK: Reverse HACK of findSymbol() :P
+ VoidFunc tmp;
+ tmp = findSymbol("__dso_handle");
+ memcpy(&_dso_handle, &tmp, sizeof(VoidFunc));
+ debug(2, "elfloader: __dso_handle is %p", _dso_handle);
+ }
+#endif
+
+ _dlHandle->discardSymtab();
+
+ return ret;
+}
+
+void ELFPlugin::unloadPlugin() {
+ DynamicPlugin::unloadPlugin();
+
+ if (_dlHandle) {
+#ifdef ELF_LOADER_CXA_ATEXIT
+ if (_dso_handle) {
+ debug(2, "elfloader: calling __cxa_finalize");
+ __cxxabiv1::__cxa_finalize(_dso_handle);
+ _dso_handle = 0;
+ }
+#endif
+
+ if (!_dlHandle->close())
+ warning("elfloader: Failed unloading plugin '%s'", _filename.c_str());
+
+ delete _dlHandle;
+ _dlHandle = 0;
+ }
+}
+
+bool ELFPluginProvider::isPluginFilename(const Common::FSNode &node) const {
+ // Check the plugin suffix
+ Common::String filename = node.getName();
+
+ if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg") &&
+ !filename.hasSuffix(".PLUGIN") && !filename.hasSuffix(".plugin"))
+ return false;
+
+ return true;
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
+
diff --git a/backends/plugins/elf/elf-provider.h b/backends/plugins/elf/elf-provider.h
new file mode 100644
index 0000000000..4d05c0956b
--- /dev/null
+++ b/backends/plugins/elf/elf-provider.h
@@ -0,0 +1,97 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_PLUGINS_ELF_PROVIDER_H
+#define BACKENDS_PLUGINS_ELF_PROVIDER_H
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
+
+#include "backends/plugins/elf/elf-loader.h"
+
+#include "common/fs.h"
+
+/**
+ * ELFPlugin
+ *
+ * Objects of this class are returned when the PluginManager calls
+ * getPlugins() on an ELFPluginProvider. An intermediary class for
+ * dealing with plugin files, ELFPlugin is responsible for creating/destroying
+ * a DLObject that handles the opening/loading/unloading of the plugin file whose
+ * path in the target backend's file system is "_filename".
+ */
+class ELFPlugin : public DynamicPlugin {
+protected:
+ typedef const char *(*CharFunc)();
+
+ DLObject *_dlHandle;
+ Common::String _filename;
+ void *_dso_handle;
+
+ virtual VoidFunc findSymbol(const char *symbol);
+
+public:
+ ELFPlugin(const Common::String &filename) :
+ _dlHandle(0),
+ _filename(filename),
+ _dso_handle(0) {
+ }
+
+ virtual ~ELFPlugin() {
+ if (_dlHandle)
+ unloadPlugin();
+ }
+
+ virtual DLObject *makeDLObject() = 0;
+
+ bool loadPlugin();
+ void unloadPlugin();
+};
+
+template<class T>
+class TemplatedELFPlugin : public ELFPlugin {
+public:
+ TemplatedELFPlugin(const Common::String &filename) :
+ ELFPlugin(filename) {
+ }
+
+ virtual DLObject *makeDLObject() {
+ return new T();
+ }
+};
+
+
+class ELFPluginProvider : public FilePluginProvider {
+protected:
+ virtual Plugin *createPlugin(const Common::FSNode &node) const = 0;
+
+ bool isPluginFilename(const Common::FSNode &node) const;
+};
+
+#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
+
+#endif /* BACKENDS_PLUGINS_ELF_PROVIDER_H */
+
diff --git a/backends/plugins/elf/elf32.h b/backends/plugins/elf/elf32.h
new file mode 100644
index 0000000000..48ebf2e7b2
--- /dev/null
+++ b/backends/plugins/elf/elf32.h
@@ -0,0 +1,252 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_ELF_H
+#define BACKENDS_ELF_H
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
+
+/**
+ * ELF stuff:
+ * The contents of this file were gathered mainly from the SYSTEM V APPLICATION BINARY INTERFACE.
+ * Processor-specific things were garnered from processor-specific supplements to the abi.
+ */
+
+typedef uint16 Elf32_Half, Elf32_Section;
+typedef uint32 Elf32_Word, Elf32_Addr, Elf32_Off;
+typedef int32 Elf32_Sword;
+typedef Elf32_Half Elf32_Versym;
+
+#define EI_NIDENT (16)
+#define SELFMAG 4
+
+/* ELF File format structures. Look up ELF structure for more details */
+
+// ELF header (contains info about the file)
+typedef struct {
+ byte e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+// Should be in e_ident
+#define ELFMAG "\177ELF" /* ELF Magic number */
+
+#define EI_CLASS 4 /* File class byte index */
+#define ELFCLASS32 1 /* 32-bit objects */
+
+#define EI_DATA 5 /* Data encoding byte index */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+
+#define EI_VERSION 6
+#define EV_CURRENT 1 /* Current version */
+
+// e_type values
+#define ET_NONE 0 /* no file type */
+#define ET_REL 1 /* relocatable */
+#define ET_EXEC 2 /* executable */
+#define ET_DYN 3 /* shared object */
+#define ET_CORE 4 /* core file */
+
+// e_machine values
+#define EM_MIPS 8
+#define EM_PPC 20
+#define EM_ARM 40
+#define EM_SH 42
+
+// Program header (contains info about segment)
+typedef struct {
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+// p_type values
+#define PT_NULL 0 /* ignored */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* dynamic linking info */
+#define PT_INTERP 3 /* info about interpreter */
+#define PT_NOTE 4 /* note segment */
+#define PT_SHLIB 5 /* reserved */
+#define PT_PHDR 6 /* Program header table */
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage info for MIPS */
+#define PT_ARM_ARCHEXT 0x70000000 /* Platform architecture compatibility info for ARM */
+#define PT_ARM_EXIDX 0x70000001 /* Exception unwind tables for ARM */
+
+// p_flags value
+#define PF_X 1 /* execute */
+#define PF_W 2 /* write */
+#define PF_R 4 /* read */
+
+// Section header (contains info about section)
+typedef struct {
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+// sh_type values
+#define SHT_NULL 0 /* Inactive section */
+#define SHT_PROGBITS 1 /* Proprietary */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addend */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Info for dynamic linking */
+#define SHT_NOTE 7 /* Note section */
+#define SHT_NOBITS 8 /* Occupies no space */
+#define SHT_REL 9 /* Relocation entries without addend */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */
+#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs for MIPS*/
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects for MIPS */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table for MIPS*/
+#define SHT_ARM_EXIDX 0x70000001 /* Exception Index table for ARM*/
+#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking pre-emption map for ARM */
+#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility attributes for ARM*/
+
+// sh_flags values
+#define SHF_WRITE 0 /* writable section */
+#define SHF_ALLOC 2 /* section occupies memory */
+#define SHF_EXECINSTR 4 /* machine instructions */
+#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area for MIPS */
+
+// Symbol entry (contain info about a symbol)
+typedef struct {
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ byte st_info; /* Symbol type and binding */
+ byte st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+// Extract from the st_info
+#define SYM_TYPE(x) ((x) & 0xf)
+#define SYM_BIND(x) ((x) >> 4)
+
+// Symbol binding values from st_info
+#define STB_LOCAL 0 /* Symbol not visible outside object */
+#define STB_GLOBAL 1 /* Symbol visible to all object files */
+#define STB_WEAK 2 /* Similar to STB_GLOBAL */
+
+// Symbol type values from st_info
+#define STT_NOTYPE 0 /* Not specified */
+#define STT_OBJECT 1 /* Data object e.g. variable */
+#define STT_FUNC 2 /* Function */
+#define STT_SECTION 3 /* Section */
+#define STT_FILE 4 /* Source file associated with object file */
+
+// Special section header index values from st_shndex
+#define SHN_UNDEF 0
+#define SHN_LOPROC 0xFF00 /* Extended values */
+#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */
+#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */
+#define SHN_HIPROC 0xFF1F
+#define SHN_HIRESERVE 0xFFFF
+
+// Relocation entry with implicit addend (info about how to relocate)
+typedef struct {
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+// Relocation entry with explicit addend (info about how to relocate)
+typedef struct {
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+ Elf32_Sword r_addend; /* Addend */
+} Elf32_Rela;
+
+// Access macros for the relocation info
+#define REL_TYPE(x) ((byte) (x)) /* Extract relocation type */
+#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */
+
+//MIPS relocation types
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+#define R_MIPS_GOTHI16 13
+#define R_MIPS_GOTLO16 14
+#define R_MIPS_CALLHI16 15
+#define R_MIPS_CALLLO16 16
+
+// ARM relocation types
+#define R_ARM_NONE 0
+#define R_ARM_ABS32 2
+#define R_ARM_THM_CALL 10
+#define R_ARM_CALL 28
+#define R_ARM_JUMP24 29
+#define R_ARM_TARGET1 38
+#define R_ARM_V4BX 40
+
+// PPC relocation types
+#define R_PPC_ADDR32 1
+#define R_PPC_ADDR16_LO 4
+#define R_PPC_ADDR16_HI 5
+#define R_PPC_ADDR16_HA 6
+#define R_PPC_REL24 10
+#define R_PPC_REL32 26
+
+#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
+
+#endif /* BACKENDS_ELF_H */
+
diff --git a/backends/plugins/elf/mips-loader.cpp b/backends/plugins/elf/mips-loader.cpp
new file mode 100644
index 0000000000..b25017af98
--- /dev/null
+++ b/backends/plugins/elf/mips-loader.cpp
@@ -0,0 +1,342 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET)
+
+#include "backends/plugins/elf/mips-loader.h"
+
+#include "common/debug.h"
+
+#define DEBUG_NUM 2
+
+bool MIPSDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) {
+ Elf32_Rel *rel = 0; // relocation entry
+
+ // Allocate memory for relocation table
+ if (!(rel = (Elf32_Rel *)malloc(size))) {
+ warning("elfloader: Out of memory.");
+ return false;
+ }
+
+ // Read in our relocation table
+ if (!_file->seek(offset, SEEK_SET) || _file->read(rel, size) != size) {
+ warning("elfloader: Relocation table load failed.");
+ free(rel);
+ return false;
+ }
+
+ // Treat each relocation entry. Loop over all of them
+ uint32 cnt = size / sizeof(*rel);
+
+ debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", cnt, relSegment);
+
+ Elf32_Addr adjustedMainSegment = Elf32_Addr(_segment) - _segmentVMA; // adjust for VMA offset
+
+ bool seenHi16 = false; // For treating HI/LO16 commands
+ int32 firstHi16 = -1; // Mark the point of the first hi16 seen
+ Elf32_Addr ahl = 0; // Calculated addend
+ int32 a = 0; // Addend: taken from the target
+
+ uint32 *lastTarget = 0; // For processing hi16 when lo16 arrives
+ uint32 relocation = 0;
+ uint debugRelocs[10] = { 0 }; // For debugging
+ uint extendedHi16 = 0; // Count extended hi16 treatments
+ Elf32_Addr lastHiSymVal = 0;
+ bool hi16InShorts = false;
+
+ // Loop over relocation entries
+ for (uint32 i = 0; i < cnt; i++) {
+ // Get the symbol this relocation entry is referring to
+ Elf32_Sym *sym = _symtab + (REL_INDEX(rel[i].r_info));
+
+ // Get the target instruction in the code.
+ uint32 *target = (uint32 *)((byte *)relSegment + rel[i].r_offset);
+
+ uint32 origTarget = *target; // Save for debugging
+
+ // Act differently based on the type of relocation
+ switch (REL_TYPE(rel[i].r_info)) {
+ case R_MIPS_HI16: // Absolute addressing.
+ if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index)
+ firstHi16 < 0) { // Only process first in block of HI16s
+ firstHi16 = i; // Keep the first Hi16 we saw
+ seenHi16 = true;
+ ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up
+
+ lastHiSymVal = sym->st_value;
+ hi16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value); // Fix for problem with switching btw segments
+ if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number
+ debug(8, "elfloader: R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x",
+ i, rel[i].r_offset, ahl, *target);
+ }
+ break;
+
+ case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index)
+ if (!seenHi16) { // We MUST have seen HI16 first
+ debug(8, "elfloader: R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!", i);
+ free(rel);
+ return false;
+ }
+
+ // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment)
+ // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section
+ // and will be screened out above
+ bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value);
+
+ // Correct the bug by getting the proper value in ahl (taken from the current symbol)
+ if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) {
+ ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset
+ ahl += (sym->st_value & 0xffff0000);
+ }
+
+ ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s
+ a = *target & 0xffff; // Take lower 16 bits of the target
+ a = (a << 16) >> 16; // Sign extend them
+ ahl += a; // Add lower 16 bits. AHL is now complete
+
+ // Fix: we can have LO16 access to the short segment sometimes
+ if (lo16InShorts)
+ relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset
+ else // It's in the regular segment
+ relocation = ahl + adjustedMainSegment; // Add in the new offset for the segment
+
+ if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now
+ for (uint32 j = firstHi16; j < i; j++) {
+ if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16)
+ continue; // Skip over non-Hi16s
+
+ lastTarget = (uint32 *)((char *)relSegment + rel[j].r_offset); // get hi16 target
+ *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target
+ *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation
+ if (relocation & 0x8000)
+ (*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case
+ }
+
+ firstHi16 = -1; // Reset so we'll know we treated it
+ } else {
+ extendedHi16++;
+ }
+
+ *target &= 0xffff0000; // Clear the lower 16 bits of current target
+ *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation
+
+ if (debugRelocs[1]++ < DEBUG_NUM)
+ debug(8, "elfloader: R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, "
+ "lastTarget = %x, origt = %x, target = %x",
+ i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
+
+ if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM)
+ debug(8, "elfloader: R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, "
+ "lastTarget = %x, origt = %x, target = %x",
+ i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
+ }
+ break;
+
+ case R_MIPS_26: // Absolute addressing (for jumps and branches only)
+ if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment
+ a = *target & 0x03ffffff; // Get 26 bits' worth of the addend
+ a = (a << 6) >> 6; // Sign extend a
+ relocation = ((a << 2) + adjustedMainSegment) >> 2; // a already points to the target. Add our offset
+ *target &= 0xfc000000; // Clean lower 26 target bits
+ *target |= (relocation & 0x03ffffff);
+
+ if (debugRelocs[3]++ < DEBUG_NUM)
+ debug(8, "elfloader: R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, "
+ "a=%x, origTarget=%x, target=%x",
+ i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
+ } else {
+ if (debugRelocs[4]++ < DEBUG_NUM)
+ debug(8, "elfloader: R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, "
+ "a=%x, origTarget=%x, target=%x",
+ i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
+ }
+ break;
+
+ case R_MIPS_GPREL16: // GP Relative addressing
+ if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section
+ ShortsMan.inGeneralSegment((char *) sym->st_value)) { // Only relocate things in the plugin hole
+ a = *target & 0xffff; // Get 16 bits' worth of the addend
+ a = (a << 16) >> 16; // Sign extend it
+
+ relocation = a + _shortsSegment->getOffset();
+
+ *target &= 0xffff0000; // Clear the lower 16 bits of the target
+ *target |= relocation & 0xffff;
+
+ if (debugRelocs[5]++ < DEBUG_NUM)
+ debug(8, "elfloader: R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, "
+ "target=%x, offset=%x",
+ i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset());
+ }
+
+ break;
+
+ case R_MIPS_32: // Absolute addressing
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+
+ if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment
+ relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset
+ else // We're in the main section
+ relocation = a + adjustedMainSegment; // Shift by main offset
+
+ *target = relocation;
+
+ if (debugRelocs[6]++ < DEBUG_NUM)
+ debug(8, "elfloader: R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x",
+ i, a, origTarget, *target);
+ }
+
+ break;
+
+ default:
+ warning("elfloader: Unknown relocation type %x at relocation %d.", REL_TYPE(rel[i].r_info), i);
+ free(rel);
+ return false;
+ }
+ }
+
+ debug(2, "elfloader: Done with relocation. extendedHi16=%d", extendedHi16);
+
+ free(rel);
+ return true;
+}
+
+bool MIPSDLObject::relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+ // Loop over sections, finding relocation sections
+ for (uint32 i = 0; i < ehdr->e_shnum; i++) {
+ Elf32_Shdr *curShdr = &(shdr[i]);
+ //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]);
+
+ if (curShdr->sh_type == SHT_REL && // Check for a relocation section
+ curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
+ int32(curShdr->sh_link) == _symtab_sect && // Check that the sh_link connects to our symbol table
+ curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
+ if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment
+ if (!relocate(curShdr->sh_offset, curShdr->sh_size, _segment - _segmentVMA))
+ return false;
+ } else { // In Shorts segment
+ if (!relocate(curShdr->sh_offset, curShdr->sh_size, (byte *)_shortsSegment->getOffset()))
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void MIPSDLObject::relocateSymbols(ptrdiff_t offset) {
+ // Loop over symbols, add relocation offset
+ Elf32_Sym *s = _symtab;
+
+ for (uint32 c = _symbol_cnt; c--; s++) {
+ // Make sure we don't relocate special valued symbols
+ if (s->st_shndx < SHN_LOPROC) {
+ if (!ShortsMan.inGeneralSegment((char *)s->st_value)) {
+ if (s->st_value < _segmentVMA)
+ s->st_value = _segmentVMA; // deal with symbols referring to sections, which start before the VMA
+
+ s->st_value += offset;
+
+ if (s->st_value < Elf32_Addr(_segment) || s->st_value > Elf32_Addr(_segment) + _segmentSize)
+ warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value);
+ } else { // shorts section
+ s->st_value += _shortsSegment->getOffset();
+ if (!_shortsSegment->inSegment((char *)s->st_value))
+ warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value);
+ }
+ }
+ }
+}
+
+bool MIPSDLObject::loadSegment(Elf32_Phdr *phdr) {
+ byte *baseAddress = 0;
+
+ // We need to take account of non-allocated segment for shorts
+ if (phdr->p_flags & PF_X) { // This is a relocated segment
+ // Attempt to allocate memory for segment
+ _segment = (byte *)memalign(phdr->p_align, phdr->p_memsz);
+
+ if (!_segment) {
+ warning("elfloader: Out of memory.");
+ return false;
+ }
+
+ debug(2, "elfloader: Allocated segment @ %p", _segment);
+
+ // Get offset to load segment into
+ baseAddress = _segment;
+ _segmentSize = phdr->p_memsz;
+ _segmentVMA = phdr->p_vaddr;
+
+ } else { // This is a shorts section.
+ _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr);
+
+ baseAddress = (byte *)_shortsSegment->getStart();
+ debug(2, "elfloader: Shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x",
+ _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr,
+ _shortsSegment->getOffset());
+ }
+
+ // Set .sbss segment to 0 if necessary
+ if (phdr->p_memsz > phdr->p_filesz) {
+ debug(2, "elfloader: Setting %p to %p to 0 for bss", baseAddress + phdr->p_filesz,
+ baseAddress + phdr->p_memsz);
+ memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+ }
+
+ debug(2, "elfloader: Reading the segment into memory");
+
+ // Read the segment into memory
+ if (!_file->seek(phdr->p_offset, SEEK_SET) ||
+ _file->read(baseAddress, phdr->p_filesz) != phdr->p_filesz) {
+ warning("elfloader: Segment load failed.");
+ return false;
+ }
+
+ debug(2, "elfloader: Segment has been read into memory");
+
+ return true;
+}
+
+// Unload all objects from memory
+void MIPSDLObject::unload() {
+ DLObject::unload();
+ freeShortsSegment();
+}
+
+void MIPSDLObject::freeShortsSegment() {
+ if (_shortsSegment) {
+ ShortsMan.deleteSegment(_shortsSegment);
+ _shortsSegment = 0;
+ }
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) */
+
diff --git a/engines/sword25/kernel/bs_stdint.h b/backends/plugins/elf/mips-loader.h
index c1970bff3e..23bd5980c8 100644
--- a/engines/sword25/kernel/bs_stdint.h
+++ b/backends/plugins/elf/mips-loader.h
@@ -1,3 +1,4 @@
+
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
@@ -23,32 +24,41 @@
*
*/
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
+#ifndef BACKENDS_PLUGINS_MIPS_LOADER_H
+#define BACKENDS_PLUGINS_MIPS_LOADER_H
-// TODO: Properly replace all game occurances that use these types with proper ScummVM types, and remove this file
+#include "common/scummsys.h"
-#ifndef SWORD25_STDINT_H
-#define SWORD25_STDINT_H
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET)
-#include "common/scummsys.h"
+#include "backends/plugins/elf/elf-loader.h"
+#include "backends/plugins/elf/shorts-segment-manager.h"
+
+class MIPSDLObject : public DLObject {
+protected:
+ ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges
+ uint32 _gpVal; // Value of Global Pointer
+
+ virtual bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment);
+ virtual bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+ virtual void relocateSymbols(ptrdiff_t offset);
+ virtual bool loadSegment(Elf32_Phdr *phdr);
+ virtual void unload();
+
+ void freeShortsSegment();
+
+public:
+ MIPSDLObject() :
+ DLObject() {
+ _shortsSegment = NULL;
+ _gpVal = 0;
+ }
+ ~MIPSDLObject() {
+ freeShortsSegment();
+ }
+};
-typedef uint8 uint8_t;
-typedef uint16 uint16_t;
-typedef uint32 uint32_t;
-typedef int8 int8_t;
-typedef int16 int16_t;
-typedef int32 int32_t;
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) */
-typedef unsigned long long uint64_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64;
-typedef signed long long int64;
+#endif /* BACKENDS_PLUGINS_MIPS_LOADER_H */
-#endif
diff --git a/backends/platform/psp/plugin.syms b/backends/plugins/elf/plugin.syms
index 24ee1a19dc..70465ae976 100644
--- a/backends/platform/psp/plugin.syms
+++ b/backends/plugins/elf/plugin.syms
@@ -1,3 +1,4 @@
+PLUGIN_getBuildDate
PLUGIN_getVersion
PLUGIN_getType
PLUGIN_getTypeVersion
diff --git a/backends/plugins/elf/ppc-loader.cpp b/backends/plugins/elf/ppc-loader.cpp
new file mode 100644
index 0000000000..ec6d442876
--- /dev/null
+++ b/backends/plugins/elf/ppc-loader.cpp
@@ -0,0 +1,129 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(PPC_TARGET)
+
+#include "backends/plugins/elf/elf-loader.h"
+#include "backends/plugins/elf/ppc-loader.h"
+
+#include "common/debug.h"
+
+bool PPCDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) {
+ Elf32_Rela *rel = NULL;
+
+ if (!(rel = (Elf32_Rela *)malloc(size))) {
+ warning("elfloader: Out of memory.");
+ return false;
+ }
+
+ if (!_file->seek(offset, SEEK_SET) || _file->read(rel, size) != size) {
+ warning("elfloader: Relocation table load failed.");
+ free(rel);
+ return false;
+ }
+
+ uint32 cnt = size / sizeof(*rel);
+
+ debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", cnt, relSegment);
+
+ uint32 *src;
+ uint32 value;
+
+ for (uint32 i = 0; i < cnt; i++) {
+ // Get the symbol this relocation entry is referring to
+ Elf32_Sym *sym = _symtab + (REL_INDEX(rel[i].r_info));
+
+ // Get the target instruction in the code
+ src = (uint32 *)((char *)relSegment + rel[i].r_offset - _segmentVMA);
+ value = sym->st_value + rel[i].r_addend;
+
+ //debug(8, "elfloader: i=%05d %p +0x%04x: (0x%08x) 0x%08x ", i, src, rel[i].r_addend, sym->st_value, *src);
+
+ switch (REL_TYPE(rel[i].r_info)) {
+ case R_PPC_ADDR32:
+ *src = value;
+ debug(8, "elfloader: R_PPC_ADDR32 -> 0x%08x", *src);
+ break;
+ case R_PPC_ADDR16_LO:
+ *(uint16 *)src = value;
+ debug(8, "elfloader: R_PPC_ADDR16_LO -> 0x%08x", *src);
+ break;
+ case R_PPC_ADDR16_HI:
+ *(uint16 *)src = value >> 16;
+ debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x", *src);
+ break;
+ case R_PPC_ADDR16_HA:
+ *(uint16 *)src = (value + 0x8000) >> 16;
+ debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x", *src);
+ break;
+ case R_PPC_REL24:
+ *src = (*src & ~0x03fffffc) | ((value - (uint32)src) & 0x03fffffc);
+ debug(8, "elfloader: R_PPC_REL24 -> 0x%08x", *src);
+ break;
+ case R_PPC_REL32:
+ *src = value - (uint32)src;
+ debug(8, "elfloader: R_PPC_REL32 -> 0x%08x", *src);
+ break;
+ default:
+ warning("elfloader: Unknown relocation type %d", REL_TYPE(rel[i].r_info));
+ free(rel);
+ return false;
+ }
+ }
+
+ free(rel);
+ return true;
+}
+
+bool PPCDLObject::relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+ for (uint32 i = 0; i < ehdr->e_shnum; i++) {
+ Elf32_Shdr *curShdr = &(shdr[i]);
+
+ if ((curShdr->sh_type == SHT_REL) &&
+ curShdr->sh_entsize == sizeof(Elf32_Rel) &&
+ int32(curShdr->sh_link) == _symtab_sect &&
+ curShdr->sh_info < ehdr->e_shnum &&
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) {
+ warning("elfloader: REL entries not supported!");
+ return false;
+ }
+
+ if ((curShdr->sh_type == SHT_RELA) &&
+ curShdr->sh_entsize == sizeof(Elf32_Rela) &&
+ int32(curShdr->sh_link) == _symtab_sect &&
+ curShdr->sh_info < ehdr->e_shnum &&
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) {
+ if (!relocate(curShdr->sh_offset, curShdr->sh_size, _segment))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(PPC_TARGET) */
+
diff --git a/backends/plugins/elf/ppc-loader.h b/backends/plugins/elf/ppc-loader.h
new file mode 100644
index 0000000000..edf2b33965
--- /dev/null
+++ b/backends/plugins/elf/ppc-loader.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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_PLUGINS_PPC_LOADER_H
+#define BACKENDS_PLUGINS_PPC_LOADER_H
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(PPC_TARGET)
+
+#include "backends/plugins/elf/elf-loader.h"
+
+class PPCDLObject : public DLObject {
+protected:
+ virtual bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment);
+ virtual bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+};
+
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(PPC_TARGET) */
+
+#endif /* BACKENDS_PLUGINS_PPC_LOADER_H */
+
diff --git a/backends/plugins/elf/shorts-segment-manager.cpp b/backends/plugins/elf/shorts-segment-manager.cpp
new file mode 100644
index 0000000000..99a765287b
--- /dev/null
+++ b/backends/plugins/elf/shorts-segment-manager.cpp
@@ -0,0 +1,90 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET)
+
+#include "backends/plugins/elf/shorts-segment-manager.h"
+
+#include "common/debug.h"
+#include "common/textconsole.h"
+
+extern char __plugin_hole_start; // Indicates start of hole in program file for shorts
+extern char __plugin_hole_end; // Indicates end of hole in program file
+extern char _gp[]; // Value of gp register
+
+DECLARE_SINGLETON(ShortSegmentManager); // For singleton
+
+ShortSegmentManager::ShortSegmentManager() {
+ _shortsStart = &__plugin_hole_start ; //shorts segment begins at the plugin hole we made when linking
+ _shortsEnd = &__plugin_hole_end; //and ends at the end of that hole.
+}
+
+ShortSegmentManager::Segment *ShortSegmentManager::newSegment(uint32 size, char *origAddr) {
+ char *lastAddress = origAddr;
+ Common::List<Segment *>::iterator i;
+
+ // Find a block that fits, starting from the beginning
+ for (i = _list.begin(); i != _list.end(); ++i) {
+ char *currAddress = (*i)->getStart();
+
+ if (uint32(currAddress) - uint32(lastAddress) >= size)
+ break;
+
+ lastAddress = (*i)->getEnd();
+ }
+
+ if ((Elf32_Addr)lastAddress & 3)
+ lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4
+
+ if (lastAddress + size > _shortsEnd) {
+ warning("elfloader: No space in shorts segment for %x bytes. Last address is %p, max address is %p.",
+ size, lastAddress, _shortsEnd);
+ return 0;
+ }
+
+ Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment
+
+ if (lastAddress + size > _highestAddress)
+ _highestAddress = lastAddress + size; // Keep track of maximum
+
+ _list.insert(i, seg);
+
+ debug(2, "elfloader: Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.",
+ size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress);
+
+ return seg;
+}
+
+void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) {
+ debug(2, "elfloader: Deleting shorts segment from %p to %p.", seg->getStart(), seg->getEnd());
+ _list.remove(seg);
+ delete seg;
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET)
+
+
diff --git a/backends/plugins/elf/shorts-segment-manager.h b/backends/plugins/elf/shorts-segment-manager.h
new file mode 100644
index 0000000000..219648d91d
--- /dev/null
+++ b/backends/plugins/elf/shorts-segment-manager.h
@@ -0,0 +1,117 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SHORTS_SEGMENT_MANAGER_H
+#define SHORTS_SEGMENT_MANAGER_H
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET)
+
+#include "backends/plugins/elf/elf32.h"
+
+#include "common/singleton.h"
+#include "common/list.h"
+
+#define ShortsMan ShortSegmentManager::instance()
+
+/**
+ * ShortSegmentManager
+ *
+ * Since MIPS is limited to 32 bits per instruction, loading data that's further away than 16 bits
+ * takes several instructions. Thus, small global data (which is likely to be accessed a lot from
+ * multiple locations) is often put into a GP-relative area (GP standing for the global pointer register)
+ * in MIPS processors. This class manages these segments of small global data, and is used by the
+ * member functions of MIPSDLObject, which query in information from this manager in order to deal with
+ * this segment during the loading/unloading of plugins.
+ *
+ * Since there's no true dynamic linker to change the GP register between plugins and the main engine,
+ * custom ld linker scripts for both the main executable and the plugins ensure the GP-area is in the
+ * same place for both. The ShortSegmentManager accesses this place via the symbols __plugin_hole_start
+ * and __plugin_hole_end, which are defined in those custom ld linker scripts.
+ */
+class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> {
+private:
+ char *_shortsStart;
+ char *_shortsEnd;
+
+public:
+ char *getShortsStart() {
+ return _shortsStart;
+ }
+
+ // Returns whether or not an absolute address is in the GP-relative section.
+ bool inGeneralSegment(char *addr) {
+ return (addr >= _shortsStart && addr < _shortsEnd);
+ }
+
+ class Segment {
+ private:
+ friend class ShortSegmentManager;
+ Segment(char *start, uint32 size, char *origAddr) :
+ _startAddress(start),
+ _size(size),
+ _origAddress(origAddr) {
+ }
+
+ virtual ~Segment() {
+ }
+
+ char *_startAddress; // Start of shorts segment in memory
+ uint32 _size; // Size of shorts segment
+ char *_origAddress; // Original address this segment was supposed to be at
+
+ public:
+ char *getStart() {
+ return _startAddress;
+ }
+
+ char *getEnd() {
+ return (_startAddress + _size);
+ }
+
+ Elf32_Addr getOffset() {
+ return (Elf32_Addr)(_startAddress - _origAddress);
+ }
+
+ bool inSegment(char *addr) {
+ return (addr >= _startAddress && addr <= _startAddress + _size);
+ }
+ };
+
+ Segment *newSegment(uint32 size, char *origAddr);
+ void deleteSegment(Segment *);
+
+private:
+ ShortSegmentManager();
+ friend class Common::Singleton<ShortSegmentManager>;
+ Common::List<Segment *> _list;
+ char *_highestAddress;
+};
+
+#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET)
+
+#endif /* SHORTS_SEGMENT_MANAGER_H */
+
diff --git a/backends/platform/sdl/win32/win32.h b/backends/plugins/elf/version.cpp
index f18ee6ead1..0277c6ae1c 100644
--- a/backends/platform/sdl/win32/win32.h
+++ b/backends/plugins/elf/version.cpp
@@ -23,17 +23,10 @@
*
*/
-#ifndef PLATFORM_SDL_WIN32_H
-#define PLATFORM_SDL_WIN32_H
-
-#include "backends/platform/sdl/sdl.h"
-
-class OSystem_Win32 : public OSystem_SDL {
-public:
- virtual void init();
-
-protected:
- virtual Common::String getDefaultConfigFileName();
-};
+#include "backends/plugins/elf/version.h"
+#ifdef USE_ELF_LOADER
+const char *gScummVMPluginBuildDate __attribute__((visibility("hidden"))) =
+ __DATE__ " " __TIME__ ;
#endif
+
diff --git a/backends/plugins/elf/version.h b/backends/plugins/elf/version.h
new file mode 100644
index 0000000000..726204aeb7
--- /dev/null
+++ b/backends/plugins/elf/version.h
@@ -0,0 +1,35 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef BACKENDS_PLUGINS_ELF_VERSION_H
+#define BACKENDS_PLUGINS_ELF_VERSION_H
+
+#include "common/scummsys.h"
+
+#ifdef USE_ELF_LOADER
+extern const char *gScummVMPluginBuildDate;
+#endif
+
+#endif
+
diff --git a/backends/plugins/ps2/main_prog.ld b/backends/plugins/ps2/main_prog.ld
new file mode 100644
index 0000000000..9dba69c50e
--- /dev/null
+++ b/backends/plugins/ps2/main_prog.ld
@@ -0,0 +1,99 @@
+ENTRY(_start);
+
+SECTIONS {
+ .text 0x00100000: {
+ _ftext = . ;
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t*)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ QUAD(0)
+ }
+
+ PROVIDE(_etext = .);
+ PROVIDE(etext = .);
+
+ .reginfo : { *(.reginfo) }
+
+ /* Global/static constructors and deconstructors. */
+ .ctors ALIGN(16): {
+ KEEP(*crtbegin*.o(.ctors))
+ KEEP(*(EXCLUDE_FILE(*crtend*.o) .ctors))
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ }
+ .dtors ALIGN(16): {
+ KEEP(*crtbegin*.o(.dtors))
+ KEEP(*(EXCLUDE_FILE(*crtend*.o) .dtors))
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ }
+
+ /* Static data. */
+ .rodata ALIGN(128): {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r*)
+ }
+
+ .data ALIGN(128): {
+ _fdata = . ;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d*)
+ SORT(CONSTRUCTORS)
+ }
+
+ .rdata ALIGN(128): { *(.rdata) }
+ .gcc_except_table ALIGN(128): { *(.gcc_except_table) }
+
+ _gp = ALIGN(128) + 0x7ff0;
+ .lit4 ALIGN(128): { *(.lit4) }
+ .lit8 ALIGN(128): { *(.lit8) }
+
+ .sdata ALIGN(128): {
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s*)
+ }
+
+ _edata = .;
+ PROVIDE(edata = .);
+
+ /* Uninitialized data. */
+ .sbss ALIGN(128) : {
+ _fbss = . ;
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb*)
+ *(.scommon)
+ }
+
+ /*This "plugin hole" is so the plugins can all have global small data
+ in the same place.*/
+ __plugin_hole_start = .;
+ . = _gp + 0x7ff0;
+ __plugin_hole_end = .;
+
+ COMMON :
+ {
+ *(COMMON)
+ }
+ . = ALIGN(128);
+
+ .bss ALIGN(128) : {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b*)
+ }
+ _end_bss = .;
+
+ _end = . ;
+ PROVIDE(end = .);
+
+ /* Symbols needed by crt0.s. */
+ PROVIDE(_heap_size = -1);
+ PROVIDE(_stack = -1);
+ PROVIDE(_stack_size = 128 * 1024);
+}
diff --git a/backends/plugins/ps2/plugin.ld b/backends/plugins/ps2/plugin.ld
new file mode 100644
index 0000000000..45efe4db7a
--- /dev/null
+++ b/backends/plugins/ps2/plugin.ld
@@ -0,0 +1,94 @@
+/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */
+PHDRS {
+ plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */
+ shorts PT_LOAD ; /* Specifies that the shorts segment should be loaded from file */
+}
+
+SECTIONS {
+ .text 0: {
+ _ftext = . ;
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t*)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ QUAD(0)
+ } : plugin /*The ": plugin" tells the linker to assign this and
+ the following sections to the "plugin" segment*/
+ PROVIDE(_etext = .);
+ PROVIDE(etext = .);
+
+ .reginfo : { *(.reginfo) }
+
+ /* Global/static constructors and deconstructors. */
+ .ctors ALIGN(16): {
+ ___plugin_ctors = .;
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ ___plugin_ctors_end = .;
+ }
+ .dtors ALIGN(16): {
+ ___plugin_dtors = .;
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ ___plugin_dtors_end = .;
+ }
+
+ /* Static data. */
+ .rodata ALIGN(128): {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r*)
+ }
+
+ .data ALIGN(128): {
+ _fdata = . ;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d*)
+ SORT(CONSTRUCTORS)
+ }
+
+ .rdata ALIGN(128): { *(.rdata) }
+ .gcc_except_table ALIGN(128): { *(.gcc_except_table) }
+
+ .bss ALIGN(128) : {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b*)
+ *(COMMON)
+ }
+ _end_bss = .;
+
+ _end = . ;
+ PROVIDE(end = .);
+
+ /* Symbols needed by crt0.s. */
+ PROVIDE(_heap_size = -1);
+ PROVIDE(_stack = -1);
+ PROVIDE(_stack_size = 128 * 1024);
+
+ /*We assign the output location counter to the plugin hole made
+ in main_prog.ld, then assign the small data sections to the shorts segment*/
+ . = __plugin_hole_start;
+ .lit4 ALIGN(128): { *(.lit4) } : shorts
+ .lit8 ALIGN(128): { *(.lit8) }
+
+ .sdata ALIGN(128): {
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s*)
+ }
+
+ _edata = .;
+ PROVIDE(edata = .);
+
+ /* Uninitialized data. */
+ .sbss ALIGN(128) : {
+ _fbss = . ;
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb*)
+ *(.scommon)
+ }
+}
diff --git a/backends/timer/sdl/sdl-timer.h b/backends/plugins/ps2/ps2-provider.cpp
index 5995aed4b0..37bdff0525 100644
--- a/backends/timer/sdl/sdl-timer.h
+++ b/backends/plugins/ps2/ps2-provider.cpp
@@ -23,29 +23,23 @@
*
*/
-#ifndef BACKENDS_TIMER_SDL_H
-#define BACKENDS_TIMER_SDL_H
+#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
-#include "backends/timer/default/default-timer.h"
-
-#if defined(__SYMBIAN32__)
-#include <esdl\SDL.h>
-#else
-#include <SDL.h>
-#endif
-
-/**
- * SDL timer manager. Setups the timer callback for
- * DefaultTimerManager.
- */
-class SdlTimerManager : public DefaultTimerManager {
-public:
- SdlTimerManager();
- virtual ~SdlTimerManager();
+#include "backends/plugins/ps2/ps2-provider.h"
+#include "backends/plugins/elf/mips-loader.h"
+class PS2DLObject : public MIPSDLObject {
protected:
- SDL_TimerID _timerID;
+
+ virtual void flushDataCache(void *, uint32) const {
+ FlushCache(0);
+ FlushCache(2);
+ }
};
+Plugin *PS2PluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new TemplatedELFPlugin<PS2DLObject>(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
-#endif
diff --git a/backends/plugins/ps2/ps2-provider.h b/backends/plugins/ps2/ps2-provider.h
new file mode 100644
index 0000000000..3d4b4b0128
--- /dev/null
+++ b/backends/plugins/ps2/ps2-provider.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
+
+#ifndef BACKENDS_PLUGINS_PS2_PROVIDER_H
+#define BACKENDS_PLUGINS_PS2_PROVIDER_H
+
+#include "backends/plugins/elf/elf-provider.h"
+
+class PS2PluginProvider : public ELFPluginProvider {
+public:
+ Plugin *createPlugin(const Common::FSNode &node) const;
+};
+
+#endif // BACKENDS_PLUGINS_PS2_PROVIDER_H
+
+#endif // defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
+
diff --git a/backends/platform/psp/main_prog.ld b/backends/plugins/psp/main_prog.ld
index 4216e7f0ab..4216e7f0ab 100644
--- a/backends/platform/psp/main_prog.ld
+++ b/backends/plugins/psp/main_prog.ld
diff --git a/backends/platform/psp/plugin.ld b/backends/plugins/psp/plugin.ld
index 7534c15290..a4456d199d 100644
--- a/backends/platform/psp/plugin.ld
+++ b/backends/plugins/psp/plugin.ld
@@ -1,11 +1,12 @@
-OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips",
- "elf32-littlemips")
+OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", "elf32-littlemips")
OUTPUT_ARCH(mips:allegrex)
+
PHDRS
{
plugin PT_LOAD ;
shorts PT_LOAD ;
}
+
/* Do we need any of these for elf?
__DYNAMIC = 0; */
SECTIONS
@@ -208,7 +209,7 @@ SECTIONS
.debug_varnames 0 : { *(.debug_varnames) }
/DISCARD/ : { *(.comment) *(.pdr) }
/DISCARD/ : { *(.note.GNU-stack) }
-
+
. = __plugin_hole_start;
.got : { *(.got.plt) *(.got) } : shorts
/* We want the small data sections together, so single-instruction offsets
@@ -234,6 +235,4 @@ SECTIONS
PROVIDE (__sbss_end = .);
PROVIDE (___sbss_end = .);
}
-
-
}
diff --git a/backends/plugins/psp/psp-provider.cpp b/backends/plugins/psp/psp-provider.cpp
index 5760424cbf..87e4428024 100644
--- a/backends/plugins/psp/psp-provider.cpp
+++ b/backends/plugins/psp/psp-provider.cpp
@@ -25,86 +25,23 @@
#if defined(DYNAMIC_MODULES) && defined(__PSP__)
-#include "backends/plugins/psp/psp-provider.h"
-#include "backends/plugins/dynamic-plugin.h"
-#include "common/fs.h"
-
-#include "backends/platform/psp/psploader.h"
-
-#include "backends/platform/psp/trace.h"
+#include <psputils.h>
+#include <psputilsforkernel.h>
+#include "backends/plugins/psp/psp-provider.h"
+#include "backends/plugins/elf/mips-loader.h"
-class PSPPlugin : public DynamicPlugin {
+class PSPDLObject : public MIPSDLObject {
protected:
- void *_dlHandle;
- Common::String _filename;
-
- virtual VoidFunc findSymbol(const char *symbol) {
- void *func = dlsym(_dlHandle, symbol);
- if (!func)
- warning("Failed loading symbol '%s' from plugin '%s' (%s)", symbol, _filename.c_str(), dlerror());
-
- // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++
- // standard and POSIX: ISO C++ disallows casting between function pointers
- // and data pointers, but dlsym always returns a void pointer. For details,
- // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>.
- assert(sizeof(VoidFunc) == sizeof(func));
- VoidFunc tmp;
- memcpy(&tmp, &func, sizeof(VoidFunc));
- return tmp;
- }
-
-public:
- PSPPlugin(const Common::String &filename)
- : _dlHandle(0), _filename(filename) {}
-
- ~PSPPlugin() {
- if (_dlHandle) unloadPlugin();
- }
-
- bool loadPlugin() {
- assert(!_dlHandle);
- _dlHandle = dlopen(_filename.c_str(), RTLD_LAZY);
-
- if (!_dlHandle) {
- warning("Failed loading plugin '%s' (%s)", _filename.c_str(), dlerror());
- return false;
- }
-
- bool ret = DynamicPlugin::loadPlugin();
-
- if (ret)
- dlforgetsyms(_dlHandle);
-
- return ret;
- }
-
- void unloadPlugin() {
- DynamicPlugin::unloadPlugin();
- if (_dlHandle) {
- if (dlclose(_dlHandle) != 0)
- warning("Failed unloading plugin '%s' (%s)", _filename.c_str(), dlerror());
- _dlHandle = 0;
- }
+ virtual void flushDataCache(void *ptr, uint32 len) const {
+ sceKernelDcacheWritebackRange(ptr, len);
+ sceKernelIcacheInvalidateRange(ptr, len);
}
};
-
-Plugin* PSPPluginProvider::createPlugin(const Common::FSNode &node) const {
- return new PSPPlugin(node.getPath());
-}
-
-bool PSPPluginProvider::isPluginFilename(const Common::FSNode &node) const {
- // Check the plugin suffix
- Common::String filename = node.getName();
- PSP_DEBUG_PRINT("Testing name %s", filename.c_str());
- if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg")) {
- PSP_DEBUG_PRINT(" fail.\n");
- return false;
- }
-
- PSP_DEBUG_PRINT(" success!\n");
- return true;
+Plugin *PSPPluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new TemplatedELFPlugin<PSPDLObject>(node.getPath());
}
#endif // defined(DYNAMIC_MODULES) && defined(__PSP__)
+
diff --git a/backends/plugins/psp/psp-provider.h b/backends/plugins/psp/psp-provider.h
index d6c44c5a85..39e0d32caa 100644
--- a/backends/plugins/psp/psp-provider.h
+++ b/backends/plugins/psp/psp-provider.h
@@ -18,26 +18,24 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL$
- * $Id$
+ * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/ds/ds-provider.h $
+ * $Id: ds-provider.h 52112 2010-08-16 08:41:04Z toneman1138 $
*
*/
-#ifndef BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H
-#define BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H
-
-#include "base/plugins.h"
-
#if defined(DYNAMIC_MODULES) && defined(__PSP__)
-class PSPPluginProvider : public FilePluginProvider {
-protected:
- Plugin* createPlugin(const Common::FSNode &node) const;
+#ifndef BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H
+#define BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H
- bool isPluginFilename(const Common::FSNode &node) const;
+#include "backends/plugins/elf/elf-provider.h"
+class PSPPluginProvider : public ELFPluginProvider {
+public:
+ Plugin *createPlugin(const Common::FSNode &node) const;
};
+#endif // BACKENDS_PLUGINS_PSP_PROVIDER_H
+
#endif // defined(DYNAMIC_MODULES) && defined(__PSP__)
-#endif /* BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H */
diff --git a/backends/plugins/sdl/sdl-provider.cpp b/backends/plugins/sdl/sdl-provider.cpp
index be04b5a1eb..6f8ca594f6 100644
--- a/backends/plugins/sdl/sdl-provider.cpp
+++ b/backends/plugins/sdl/sdl-provider.cpp
@@ -25,6 +25,9 @@
#if defined(DYNAMIC_MODULES) && defined(SDL_BACKEND)
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "backends/plugins/sdl/sdl-provider.h"
#include "backends/plugins/dynamic-plugin.h"
#include "common/fs.h"
diff --git a/backends/plugins/wii/plugin.ld b/backends/plugins/wii/plugin.ld
new file mode 100644
index 0000000000..61b90d3394
--- /dev/null
+++ b/backends/plugins/wii/plugin.ld
@@ -0,0 +1,263 @@
+/*
+ * Linkscript for Wii
+ */
+
+OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc");
+OUTPUT_ARCH(powerpc:common);
+
+PHDRS
+{
+ plugin PT_LOAD FLAGS(7);
+}
+
+SECTIONS
+{
+ . = 0x81000000;
+
+ /* Program */
+ .init :
+ {
+ KEEP (*crt0.o(*.init))
+ KEEP (*(.init))
+ } :plugin = 0
+ .plt : { *(.plt) }
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+ .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+ .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+ .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+ .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rela.got1 : { *(.rela.got1) }
+ .rela.got2 : { *(.rela.got2) }
+ .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+ .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+ .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+ .rela.sbss : { *(.rela.sbss .rela.sbss.* .rel.gnu.linkonce.sb.*) }
+ .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+ .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+ .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+ .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+ .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+ .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+
+ .text :
+ {
+ *(.text)
+ *(.text.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.gnu.linkonce.t.*)
+ . = ALIGN(32); /* REQUIRED. LD is flaky without it. */
+ } = 0
+
+ .fini :
+ {
+ KEEP (*(.fini))
+ . = ALIGN(32); /* REQUIRED. LD is flaky without it. */
+ } = 0
+
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ .rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .sdata2 : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) }
+ .sbss2 : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(32 / 8);
+ PROVIDE (__preinit_array_start = .);
+ .preinit_array : { *(.preinit_array) }
+ PROVIDE (__preinit_array_end = .);
+ PROVIDE (__init_array_start = .);
+ .init_array : { *(.init_array) }
+ PROVIDE (__init_array_end = .);
+ PROVIDE (__fini_array_start = .);
+ .fini_array : { *(.fini_array) }
+ PROVIDE (__fini_array_end = .);
+ .data :
+ {
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ . = ALIGN(32); /* REQUIRED. LD is flaky without it. */
+ }
+
+ .data1 : { *(.data1) }
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .eh_frame : { KEEP (*(.eh_frame)) }
+ .gcc_except_table : { *(.gcc_except_table) }
+ .fixup : { *(.fixup) }
+ .got1 : { *(.got1) }
+ .got2 : { *(.got2) }
+ .dynamic : { *(.dynamic) }
+
+ .ctors :
+ {
+ ___plugin_ctors = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ ___plugin_ctors_end = .;
+ . = ALIGN(32); /* REQUIRED. LD is flaky without it. */
+ }
+
+ .dtors :
+ {
+ ___plugin_dtors = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ ___plugin_dtors_end = .;
+ . = ALIGN(32); /* REQUIRED. LD is flaky without it. */
+ }
+
+ .jcr : { KEEP (*(.jcr)) }
+ .got : { *(.got.plt) *(.got) }
+
+
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+
+ .sdata :
+ {
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s.*)
+ . = ALIGN(32); /* REQUIRED. LD is flaky without it. */
+ }
+
+ _edata = .;
+ PROVIDE (edata = .);
+
+ .sbss :
+ {
+ __sbss_start = .;
+ PROVIDE (__sbss_start = .);
+ PROVIDE (___sbss_start = .);
+ *(.dynsbss)
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb.*)
+ *(.scommon)
+ PROVIDE (__sbss_end = .);
+ PROVIDE (___sbss_end = .);
+ . = ALIGN(32); /* REQUIRED. LD is flaky without it. */
+ __sbss_end = .;
+ }
+
+ .bss :
+ {
+ __bss_start = .;
+ PROVIDE (__bss_start = .);
+ *(.dynbss)
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+
+ . = ALIGN(32);
+
+ PROVIDE (__bss_end = .);
+ __bss_end = .;
+ }
+
+ _end = .;
+ PROVIDE(end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* These must appear regardless of . */
+}
+
+__isIPL = 0;
+__stack_addr = (__bss_start + SIZEOF(.bss) + 0x20000 + 7) & (-8);
+__stack_end = (__bss_start + SIZEOF(.bss));
+__intrstack_addr = (__stack_addr + 0x4000);
+__intrstack_end = (__stack_addr);
+__Arena1Lo = (__intrstack_addr + 31) & (-32);
+__Arena1Hi = (0x816ffff0);
+__Arena2Lo = (0x90002000);
+__Arena2Hi = (0x933E0000);
+
+__gxregs = (__Arena1Hi + 31) & (-32);
+__ipcbufferLo = (0x933e0000);
+__ipcbufferHi = (0x93400000);
+
+/* for backward compatibility with old crt0 */
+PROVIDE (__stack = (0x816ffff0));
+
+PROVIDE(__isIPL = __isIPL);
+PROVIDE(__stack_addr = __stack_addr);
+PROVIDE(__stack_end = __stack_end);
+PROVIDE(__intrstack_addr = __intrstack_addr);
+PROVIDE(__intrstack_end = __intrstack_end);
+PROVIDE(__Arena1Lo = __Arena1Lo);
+PROVIDE(__Arena1Hi = __Arena1Hi);
+PROVIDE(__Arena2Lo = __Arena2Lo);
+PROVIDE(__Arena2Hi = __Arena2Hi);
+PROVIDE(__ipcbufferLo = __ipcbufferLo);
+PROVIDE(__ipcbufferHi = __ipcbufferHi);
+PROVIDE(__gxregs = __gxregs);
diff --git a/backends/graphics/gp2xsdl/gp2xsdl-graphics.h b/backends/plugins/wii/wii-provider.cpp
index 776a9b1a0f..b05bc59432 100644
--- a/backends/graphics/gp2xsdl/gp2xsdl-graphics.h
+++ b/backends/plugins/wii/wii-provider.cpp
@@ -23,26 +23,25 @@
*
*/
-#ifndef BACKENDS_GRAPHICS_SDL_GP2X_H
-#define BACKENDS_GRAPHICS_SDL_GP2X_H
+#if defined(DYNAMIC_MODULES) && defined(__WII__)
-#include "backends/graphics/sdl/sdl-graphics.h"
+#include <malloc.h>
+#include <ogc/cache.h>
-class GP2XSdlGraphicsManager : public SdlGraphicsManager {
-public:
-
- virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- virtual void drawMouse();
-
- virtual bool hasFeature(OSystem::Feature f);
- virtual void setFeatureState(OSystem::Feature f, bool enable);
-
- // Toggles zoom adjust on mouse
- void toggleZoomOnMouse();
+#include "backends/plugins/wii/wii-provider.h"
+#include "backends/plugins/elf/ppc-loader.h"
+class WiiDLObject : public PPCDLObject {
protected:
- bool _adjustZoomOnMouse;
+ virtual void flushDataCache(void *ptr, uint32 len) const {
+ DCFlushRange(ptr, len);
+ ICInvalidateRange(ptr, len);
+ }
};
-#endif
+Plugin *WiiPluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new TemplatedELFPlugin<WiiDLObject>(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(__WII__)
+
diff --git a/backends/plugins/wii/wii-provider.h b/backends/plugins/wii/wii-provider.h
new file mode 100644
index 0000000000..4ec771490d
--- /dev/null
+++ b/backends/plugins/wii/wii-provider.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__WII__)
+
+#ifndef BACKENDS_PLUGINS_WII_PROVIDER_H
+#define BACKENDS_PLUGINS_WII_PROVIDER_H
+
+#include "backends/plugins/elf/elf-provider.h"
+
+class WiiPluginProvider : public ELFPluginProvider {
+public:
+ Plugin *createPlugin(const Common::FSNode &node) const;
+};
+
+#endif // BACKENDS_PLUGINS_WII_PROVIDER_H
+
+#endif // defined(DYNAMIC_MODULES) && defined(__WII__)
+
diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp
index 1ab898d2d6..c88f36f5cc 100644
--- a/backends/saves/default/default-saves.cpp
+++ b/backends/saves/default/default-saves.cpp
@@ -34,8 +34,9 @@
#include "common/config-manager.h"
#include "common/zlib.h"
+#ifndef _WIN32_WCE
#include <errno.h> // for removeSavefile()
-
+#endif
DefaultSaveFileManager::DefaultSaveFileManager() {
}
diff --git a/backends/timer/default/default-timer.h b/backends/timer/default/default-timer.h
index 778c69b32d..e7ac3d122f 100644
--- a/backends/timer/default/default-timer.h
+++ b/backends/timer/default/default-timer.h
@@ -40,8 +40,7 @@ private:
public:
DefaultTimerManager();
- virtual ~DefaultTimerManager();
-
+ ~DefaultTimerManager();
bool installTimerProc(TimerProc proc, int32 interval, void *refCon);
void removeTimerProc(TimerProc proc);
diff --git a/backends/timer/sdl/sdl-timer.cpp b/backends/timer/sdl/sdl-timer.cpp
deleted file mode 100644
index 4957b4bc1c..0000000000
--- a/backends/timer/sdl/sdl-timer.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(SDL_BACKEND)
-
-#include "backends/timer/sdl/sdl-timer.h"
-
-static Uint32 timer_handler(Uint32 interval, void *param) {
- ((DefaultTimerManager *)param)->handler();
- return interval;
-}
-
-SdlTimerManager::SdlTimerManager() {
- // Initializes the SDL timer subsystem
- if (SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
- error("Could not initialize SDL: %s", SDL_GetError());
- }
-
- // Creates the timer callback
- _timerID = SDL_AddTimer(10, &timer_handler, this);
-}
-
-SdlTimerManager::~SdlTimerManager() {
- // Removes the timer callback
- SDL_RemoveTimer(_timerID);
-}
-
-#endif
diff --git a/backends/vkeybd/virtual-keyboard-parser.cpp b/backends/vkeybd/virtual-keyboard-parser.cpp
index 6a644e0cdf..dd11866262 100644
--- a/backends/vkeybd/virtual-keyboard-parser.cpp
+++ b/backends/vkeybd/virtual-keyboard-parser.cpp
@@ -270,7 +270,7 @@ bool VirtualKeyboardParser::parserCallback_layout(ParserNode *node) {
int r, g, b;
if (node->values.contains("transparent_color")) {
- if (!parseIntegerKey(node->values["transparent_color"].c_str(), 3, &r, &g, &b))
+ if (!parseIntegerKey(node->values["transparent_color"], 3, &r, &g, &b))
return parserError("Could not parse color value");
} else {
// default to purple
@@ -281,7 +281,7 @@ bool VirtualKeyboardParser::parserCallback_layout(ParserNode *node) {
_mode->transparentColor = format.RGBToColor(r, g, b);
if (node->values.contains("display_font_color")) {
- if (!parseIntegerKey(node->values["display_font_color"].c_str(), 3, &r, &g, &b))
+ if (!parseIntegerKey(node->values["display_font_color"], 3, &r, &g, &b))
return parserError("Could not parse color value");
} else {
r = g = b = 0; // default to black
@@ -336,7 +336,7 @@ byte VirtualKeyboardParser::parseFlags(const String& flags) {
bool VirtualKeyboardParser::parseRect(Rect &rect, const String& coords) {
int x1, y1, x2, y2;
- if (!parseIntegerKey(coords.c_str(), 4, &x1, &y1, &x2, &y2))
+ if (!parseIntegerKey(coords, 4, &x1, &y1, &x2, &y2))
return parserError("Invalid coords for rect area");
rect.left = x1;
rect.top = y1;
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 5a45ed74a1..b1610feb2e 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -157,6 +157,7 @@ void registerDefaults() {
// Graphics
ConfMan.registerDefault("fullscreen", false);
ConfMan.registerDefault("aspect_ratio", false);
+ ConfMan.registerDefault("disable_dithering", false);
ConfMan.registerDefault("gfx_mode", "normal");
ConfMan.registerDefault("render_mode", "default");
ConfMan.registerDefault("desired_screen_aspect_ratio", "auto");
@@ -219,6 +220,14 @@ void registerDefaults() {
ConfMan.registerDefault("record_file_name", "record.bin");
ConfMan.registerDefault("record_temp_file_name", "record.tmp");
ConfMan.registerDefault("record_time_file_name", "record.time");
+
+#if 0
+ // NEW CODE TO HIDE CONSOLE FOR WIN32
+#ifdef WIN32
+ // console hiding for win32
+ ConfMan.registerDefault("show_console", false);
+#endif
+#endif
}
//
@@ -546,6 +555,15 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
END_OPTION
#endif
+#if 0
+ // NEW CODE TO HIDE CONSOLE FOR WIN32
+#ifdef WIN32
+ // console hiding for win32
+ DO_LONG_OPTION_BOOL("show-console")
+ END_OPTION
+#endif
+#endif
+
unknownOption:
// If we get till here, the option is unhandled and hence unknown.
usage("Unrecognized option '%s'", argv[i]);
@@ -596,7 +614,7 @@ static void listTargets() {
description = g.description();
}
- targets.push_back(Common::String::printf("%-20s %s", name.c_str(), description.c_str()));
+ targets.push_back(Common::String::format("%-20s %s", name.c_str(), description.c_str()));
}
Common::sort(targets.begin(), targets.end());
diff --git a/base/internal_version.h b/base/internal_version.h
index 5a049b0bb8..2b00ce60d2 100644
--- a/base/internal_version.h
+++ b/base/internal_version.h
@@ -3,7 +3,7 @@
#endif
#ifndef SCUMMVM_SVN_REVISION
-#define SCUMMVM_SVN_REVISION
+#define SCUMMVM_SVN_REVISION ""
#endif
#ifdef RELEASE_BUILD
diff --git a/base/internal_version.h.in b/base/internal_version.h.in
index adf5f94d21..dacaf72d40 100644
--- a/base/internal_version.h.in
+++ b/base/internal_version.h.in
@@ -3,7 +3,7 @@
#endif
#ifndef SCUMMVM_SVN_REVISION
-#define SCUMMVM_SVN_REVISION
+#define SCUMMVM_SVN_REVISION "@SVN_REVISION@"
#endif
#ifdef RELEASE_BUILD
diff --git a/base/main.cpp b/base/main.cpp
index 7afba3db37..3e4af53065 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -104,7 +104,12 @@ static const EnginePlugin *detectPlugin() {
// Query the plugins and find one that will handle the specified gameid
printf("User picked target '%s' (gameid '%s')...\n", ConfMan.getActiveDomainName().c_str(), gameid.c_str());
printf("%s", " Looking for a plugin supporting this gameid... ");
- GameDescriptor game = EngineMan.findGame(gameid, &plugin);
+
+#if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
+ GameDescriptor game = EngineMan.findGameOnePluginAtATime(gameid, &plugin);
+#else
+ GameDescriptor game = EngineMan.findGame(gameid, &plugin);
+#endif
if (plugin == 0) {
printf("failed\n");
@@ -210,6 +215,11 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const
// Run the engine
Common::Error result = engine->run();
+#if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
+ // do our best to prevent fragmentation by unloading as soon as we can
+ PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
+#endif
+
// Inform backend that the engine finished
system.engineDone();
@@ -309,7 +319,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
Common::StringMap settings;
command = Base::parseCommandLine(settings, argc, argv);
- // Load the config file (possibly overriden via command line):
+ // Load the config file (possibly overridden via command line):
if (settings.contains("config")) {
ConfMan.loadConfigFile(settings["config"]);
settings.erase("config");
@@ -335,8 +345,13 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
settings.erase("debugflags");
}
- // Load the plugins.
- PluginManager::instance().loadPlugins();
+#if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
+ // Only load non-engine plugins and first engine plugin initially in this case.
+ PluginManager::instance().loadNonEnginePluginsAndEnumerate();
+#else
+ // Load the plugins.
+ PluginManager::instance().loadPlugins();
+#endif
// If we received an invalid music parameter via command line we check this here.
// We can't check this before loading the music plugins.
@@ -352,6 +367,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
// config file and the plugins have been loaded.
Common::Error res;
+ // TODO: deal with settings that require plugins to be loaded
if ((res = Base::processSettings(command, settings)) != Common::kArgumentNotProcessed)
return res;
@@ -419,11 +435,11 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
ConfMan.setActiveDomain("");
// PluginManager::instance().unloadPlugins();
+
+#if !defined(ONE_PLUGIN_AT_A_TIME)
PluginManager::instance().loadPlugins();
+#endif
} else {
- // A dialog would be nicer, but we don't have any
- // screen to draw on yet.
- warning("%s", _("Could not find any engine capable of running the selected game"));
GUI::displayErrorDialog(_("Could not find any engine capable of running the selected game"));
}
@@ -433,9 +449,10 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
}
PluginManager::instance().unloadPlugins();
PluginManager::destroy();
+ GUI::GuiManager::destroy();
Common::ConfigManager::destroy();
Common::SearchManager::destroy();
- GUI::GuiManager::destroy();
+ Common::TranslationManager::destroy();
return 0;
}
diff --git a/base/plugins.cpp b/base/plugins.cpp
index e2af9328a7..41e213a53a 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -121,6 +121,9 @@ public:
#if PLUGIN_ENABLED_STATIC(KYRA)
LINK_PLUGIN(KYRA)
#endif
+ #if PLUGIN_ENABLED_STATIC(LASTEXPRESS)
+ LINK_PLUGIN(LASTEXPRESS)
+ #endif
#if PLUGIN_ENABLED_STATIC(LURE)
LINK_PLUGIN(LURE)
#endif
@@ -320,6 +323,62 @@ void PluginManager::addPluginProvider(PluginProvider *pp) {
_providers.push_back(pp);
}
+//
+// This should only be run once
+void PluginManager::loadNonEnginePluginsAndEnumerate() {
+ unloadPlugins();
+ _allEnginePlugins.clear();
+
+ // We need to resize our pluginsInMem list to prevent fragmentation
+ // Otherwise, as soon as we add our 1 engine plugin (which is all we'll have in memory at a time)
+ // We'll get an allocation in memory that will never go away
+ _pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2); // more than we need
+
+ for (ProviderList::iterator pp = _providers.begin();
+ pp != _providers.end();
+ ++pp) {
+ PluginList pl((*pp)->getPlugins());
+ for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) {
+ // To find out which are engine plugins, we have to load them. This is inefficient
+ // Hopefully another way can be found (e.g. if the music plugins are all static,
+ // we can use only the static provider
+ if ((*p)->loadPlugin()) {
+ if ((*p)->getType() == PLUGIN_TYPE_ENGINE) {
+ (*p)->unloadPlugin(); // to prevent fragmentation
+ _allEnginePlugins.push_back(*p);
+ } else { // add non-engine plugins to the 'in-memory' list
+ // these won't ever get unloaded (in this implementation)
+ addToPluginsInMemList(*p);
+ }
+ }
+ }
+ }
+}
+
+void PluginManager::loadFirstPlugin() {
+ unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
+
+ // let's try to find one we can load
+ for (_currentPlugin = _allEnginePlugins.begin(); _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {
+ if ((*_currentPlugin)->loadPlugin()) {
+ addToPluginsInMemList(*_currentPlugin);
+ break;
+ }
+ }
+}
+
+bool PluginManager::loadNextPlugin() {
+ unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
+
+ for (++_currentPlugin; _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {
+ if ((*_currentPlugin)->loadPlugin()) {
+ addToPluginsInMemList(*_currentPlugin);
+ return true;
+ }
+ }
+ return false; // no more in list
+}
+
void PluginManager::loadPlugins() {
for (ProviderList::iterator pp = _providers.begin();
pp != _providers.end();
@@ -327,7 +386,6 @@ void PluginManager::loadPlugins() {
PluginList pl((*pp)->getPlugins());
Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManager::tryLoadPlugin), this));
}
-
}
void PluginManager::unloadPlugins() {
@@ -335,19 +393,20 @@ void PluginManager::unloadPlugins() {
unloadPluginsExcept((PluginType)i, NULL);
}
-void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin) {
+void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, bool deletePlugin /*=true*/) {
Plugin *found = NULL;
- for (PluginList::iterator p = _plugins[type].begin(); p != _plugins[type].end(); ++p) {
+ for (PluginList::iterator p = _pluginsInMem[type].begin(); p != _pluginsInMem[type].end(); ++p) {
if (*p == plugin) {
found = *p;
} else {
(*p)->unloadPlugin();
- delete *p;
+ if (deletePlugin)
+ delete *p;
}
}
- _plugins[type].clear();
+ _pluginsInMem[type].clear();
if (found != NULL) {
- _plugins[type].push_back(found);
+ _pluginsInMem[type].push_back(found);
}
}
@@ -355,27 +414,7 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
assert(plugin);
// Try to load the plugin
if (plugin->loadPlugin()) {
- // The plugin is valid, see if it provides the same module as an
- // already loaded one and should replace it.
- bool found = false;
-
- PluginList::iterator pl = _plugins[plugin->getType()].begin();
- while (!found && pl != _plugins[plugin->getType()].end()) {
- if (!strcmp(plugin->getName(), (*pl)->getName())) {
- // Found a duplicated module. Replace the old one.
- found = true;
- delete *pl;
- *pl = plugin;
- debug(1, "Replaced the duplicated plugin: '%s'", plugin->getName());
- }
- pl++;
- }
-
- if (!found) {
- // If it provides a new module, just add it to the list of known plugins.
- _plugins[plugin->getType()].push_back(plugin);
- }
-
+ addToPluginsInMemList(plugin);
return true;
} else {
// Failed to load the plugin
@@ -384,6 +423,28 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
}
}
+void PluginManager::addToPluginsInMemList(Plugin *plugin) {
+ bool found = false;
+ // The plugin is valid, see if it provides the same module as an
+ // already loaded one and should replace it.
+
+ PluginList::iterator pl = _pluginsInMem[plugin->getType()].begin();
+ while (!found && pl != _pluginsInMem[plugin->getType()].end()) {
+ if (!strcmp(plugin->getName(), (*pl)->getName())) {
+ // Found a duplicated module. Replace the old one.
+ found = true;
+ delete *pl;
+ *pl = plugin;
+ debug(1, "Replaced the duplicated plugin: '%s'", plugin->getName());
+ }
+ pl++;
+ }
+
+ if (!found) {
+ // If it provides a new module, just add it to the list of known plugins in memory.
+ _pluginsInMem[plugin->getType()].push_back(plugin);
+ }
+}
// Engine plugins
@@ -391,6 +452,18 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
DECLARE_SINGLETON(EngineManager)
+GameDescriptor EngineManager::findGameOnePluginAtATime(const Common::String &gameName, const EnginePlugin **plugin) const {
+ GameDescriptor result;
+ PluginManager::instance().loadFirstPlugin();
+ do {
+ result = findGame(gameName, plugin);
+ if (!result.gameid().empty()) {
+ break;
+ }
+ } while (PluginManager::instance().loadNextPlugin());
+ return result;
+}
+
GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const {
// Find the GameDescriptor for this target
const EnginePlugin::List &plugins = getPlugins();
@@ -399,13 +472,14 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Eng
if (plugin)
*plugin = 0;
- EnginePlugin::List::const_iterator iter = plugins.begin();
+ EnginePlugin::List::const_iterator iter;
+
for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
result = (**iter)->findGame(gameName.c_str());
if (!result.gameid().empty()) {
if (plugin)
*plugin = *iter;
- break;
+ return result;
}
}
return result;
@@ -413,16 +487,21 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Eng
GameList EngineManager::detectGames(const Common::FSList &fslist) const {
GameList candidates;
-
- const EnginePlugin::List &plugins = getPlugins();
-
- // Iterate over all known games and for each check if it might be
- // the game in the presented directory.
+ EnginePlugin::List plugins;
EnginePlugin::List::const_iterator iter;
- for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
- candidates.push_back((**iter)->detectGames(fslist));
- }
-
+#if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
+ PluginManager::instance().loadFirstPlugin();
+ do {
+#endif
+ plugins = getPlugins();
+ // Iterate over all known games and for each check if it might be
+ // the game in the presented directory.
+ for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
+ candidates.push_back((**iter)->detectGames(fslist));
+ }
+#if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
+ } while (PluginManager::instance().loadNextPlugin());
+#endif
return candidates;
}
diff --git a/base/plugins.h b/base/plugins.h
index a4c7f114f9..fc8adbf0d4 100644
--- a/base/plugins.h
+++ b/base/plugins.h
@@ -30,6 +30,7 @@
#include "common/error.h"
#include "common/singleton.h"
#include "common/util.h"
+#include "backends/plugins/elf/version.h"
namespace Common {
class FSList;
@@ -90,6 +91,21 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
#define PLUGIN_ENABLED_DYNAMIC(ID) \
(ENABLE_##ID && (ENABLE_##ID == DYNAMIC_PLUGIN) && DYNAMIC_MODULES)
+// see comments in backends/plugins/elf/elf-provider.cpp
+#if defined(USE_ELF_LOADER) && defined(ELF_LOADER_CXA_ATEXIT)
+#define PLUGIN_DYNAMIC_DSO_HANDLE \
+ uint32 __dso_handle __attribute__((visibility("hidden"))) = 0;
+#else
+#define PLUGIN_DYNAMIC_DSO_HANDLE
+#endif
+
+#ifdef USE_ELF_LOADER
+#define PLUGIN_DYNAMIC_BUILD_DATE \
+ PLUGIN_EXPORT const char *PLUGIN_getBuildDate() { return gScummVMPluginBuildDate; }
+#else
+#define PLUGIN_DYNAMIC_BUILD_DATE
+#endif
+
/**
* REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare
* the plugin interface for static plugins. Code (such as game engines)
@@ -119,6 +135,8 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
*/
#define REGISTER_PLUGIN_DYNAMIC(ID,TYPE,PLUGINCLASS) \
extern "C" { \
+ PLUGIN_DYNAMIC_DSO_HANDLE \
+ PLUGIN_DYNAMIC_BUILD_DATE \
PLUGIN_EXPORT int32 PLUGIN_getVersion() { return PLUGIN_VERSION; } \
PLUGIN_EXPORT int32 PLUGIN_getType() { return TYPE; } \
PLUGIN_EXPORT int32 PLUGIN_getTypeVersion() { return TYPE##_VERSION; } \
@@ -212,6 +230,11 @@ public:
* @return a list of Plugin instances
*/
virtual PluginList getPlugins() = 0;
+
+ /**
+ * @return whether or not object is a FilePluginProvider.
+ */
+ virtual bool isFilePluginProvider() { return false; }
};
#ifdef DYNAMIC_MODULES
@@ -234,6 +257,11 @@ public:
*/
virtual PluginList getPlugins();
+ /**
+ * @return whether or not object is a FilePluginProvider.
+ */
+ bool isFilePluginProvider() { return true; }
+
protected:
/**
* Create a Plugin instance from a loadable code module with the specified name.
@@ -273,11 +301,15 @@ protected:
class PluginManager : public Common::Singleton<PluginManager> {
typedef Common::Array<PluginProvider *> ProviderList;
private:
- PluginList _plugins[PLUGIN_TYPE_MAX];
+ PluginList _pluginsInMem[PLUGIN_TYPE_MAX];
ProviderList _providers;
- bool tryLoadPlugin(Plugin *plugin);
+ PluginList _allEnginePlugins;
+ PluginList::iterator _currentPlugin;
+ bool tryLoadPlugin(Plugin *plugin);
+ void addToPluginsInMemList(Plugin *plugin);
+
friend class Common::Singleton<SingletonBaseType>;
PluginManager();
@@ -286,11 +318,15 @@ public:
void addPluginProvider(PluginProvider *pp);
+ void loadNonEnginePluginsAndEnumerate();
+ void loadFirstPlugin();
+ bool loadNextPlugin();
+
void loadPlugins();
void unloadPlugins();
- void unloadPluginsExcept(PluginType type, const Plugin *plugin);
+ void unloadPluginsExcept(PluginType type, const Plugin *plugin, bool deletePlugin = true);
- const PluginList &getPlugins(PluginType t) { return _plugins[t]; }
+ const PluginList &getPlugins(PluginType t) { return _pluginsInMem[t]; }
};
#endif
diff --git a/base/version.cpp b/base/version.cpp
index 2a6d1bb0c0..6967263f5c 100644
--- a/base/version.cpp
+++ b/base/version.cpp
@@ -111,5 +111,9 @@ const char *gScummVMFeatures = ""
#ifdef USE_FLUIDSYNTH
"FluidSynth "
#endif
+
+#ifdef USE_THEORADEC
+ "Theora "
+#endif
;
diff --git a/common/algorithm.h b/common/algorithm.h
index 9d22af4090..b34d6f852d 100644
--- a/common/algorithm.h
+++ b/common/algorithm.h
@@ -242,13 +242,17 @@ void sort(T first, T last) {
*/
template<class T>
T gcd(T a, T b) {
- if (a <= 0) a = -a;
- if (b <= 0) b = -b;
+ if (a <= 0)
+ a = -a;
+ if (b <= 0)
+ b = -b;
+
while (a > 0) {
T tmp = a;
a = b % a;
b = tmp;
}
+
return b;
}
diff --git a/common/config-manager.cpp b/common/config-manager.cpp
index 554a99ea95..ec9fcaee6a 100644
--- a/common/config-manager.cpp
+++ b/common/config-manager.cpp
@@ -69,7 +69,7 @@ void ConfigManager::loadDefaultConfigFile() {
} else {
// No config file -> create new one!
- printf("Default configuration file missing, creating a new one\n");
+ debug("Default configuration file missing, creating a new one");
flushToDisk();
}
@@ -81,9 +81,9 @@ void ConfigManager::loadConfigFile(const String &filename) {
FSNode node(filename);
File cfg_file;
if (!cfg_file.open(node)) {
- printf("Creating configuration file: %s\n", filename.c_str());
+ debug("Creating configuration file: %s\n", filename.c_str());
} else {
- printf("Using configuration file: %s\n", _filename.c_str());
+ debug("Using configuration file: %s\n", _filename.c_str());
loadFromStream(cfg_file);
}
}
@@ -508,9 +508,7 @@ void ConfigManager::set(const String &key, const String &value, const String &do
}
void ConfigManager::setInt(const String &key, int value, const String &domName) {
- char tmp[128];
- snprintf(tmp, sizeof(tmp), "%i", value);
- set(key, String(tmp), domName);
+ set(key, String::format("%i", value), domName);
}
void ConfigManager::setBool(const String &key, bool value, const String &domName) {
@@ -530,9 +528,7 @@ void ConfigManager::registerDefault(const String &key, const char *value) {
}
void ConfigManager::registerDefault(const String &key, int value) {
- char tmp[128];
- snprintf(tmp, sizeof(tmp), "%i", value);
- registerDefault(key, tmp);
+ registerDefault(key, String::format("%i", value));
}
void ConfigManager::registerDefault(const String &key, bool value) {
diff --git a/common/debug.cpp b/common/debug.cpp
index 116c0d0d56..46f8e8b829 100644
--- a/common/debug.cpp
+++ b/common/debug.cpp
@@ -22,6 +22,10 @@
* $Id$
*/
+// Disable symbol overrides so that we can use system headers.
+// FIXME: Necessary for the PS2 port, should get rid of this eventually.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/util.h"
@@ -119,31 +123,15 @@ bool DebugManager::isDebugChannelEnabled(uint32 channel) {
return (gDebugChannelsEnabled & channel) != 0;
}
-
-
-static OutputFormatter s_debugOutputFormatter = 0;
-
-void setDebugOutputFormatter(OutputFormatter f) {
- s_debugOutputFormatter = f;
-}
-
} // End of namespace Common
#ifndef DISABLE_TEXT_CONSOLE
static void debugHelper(const char *s, va_list va, bool caret = true) {
- char in_buf[STRINGBUFLEN];
char buf[STRINGBUFLEN];
- vsnprintf(in_buf, STRINGBUFLEN, s, va);
- // Next, give the active engine (if any) a chance to augment the message,
- // but only if not used from debugN.
- if (caret && Common::s_debugOutputFormatter) {
- (*Common::s_debugOutputFormatter)(buf, in_buf, STRINGBUFLEN);
- } else {
- strncpy(buf, in_buf, STRINGBUFLEN);
- }
+ vsnprintf(buf, STRINGBUFLEN, s, va);
buf[STRINGBUFLEN-1] = '\0';
if (caret) {
@@ -186,6 +174,14 @@ void debug(int level, const char *s, ...) {
}
+void debugN(const char *s, ...) {
+ va_list va;
+
+ va_start(va, s);
+ debugHelper(s, va, false);
+ va_end(va);
+}
+
void debugN(int level, const char *s, ...) {
va_list va;
diff --git a/common/debug.h b/common/debug.h
index 2068a1314a..03de7f4f77 100644
--- a/common/debug.h
+++ b/common/debug.h
@@ -26,23 +26,12 @@
#define COMMON_DEBUG_H
#include "common/scummsys.h"
-#include "common/textconsole.h"
-
-namespace Common {
-
-/**
- * Set the output formatter used by debug() and related functions.
- */
-void setDebugOutputFormatter(OutputFormatter f);
-
-
-} // End of namespace Common
-
#ifdef DISABLE_TEXT_CONSOLE
inline void debug(const char *s, ...) {}
inline void debug(int level, const char *s, ...) {}
+inline void debugN(const char *s, ...) {}
inline void debugN(int level, const char *s, ...) {}
inline void debugC(int level, uint32 engineChannel, const char *s, ...) {}
inline void debugC(uint32 engineChannel, const char *s, ...) {}
@@ -68,6 +57,12 @@ void debug(const char *s, ...) GCC_PRINTF(1, 2);
void debug(int level, const char *s, ...) GCC_PRINTF(2, 3);
/**
+ * Print a debug message to the text console (stdout).
+ * Does not append a newline.
+ */
+void debugN(const char *s, ...) GCC_PRINTF(1, 2);
+
+/**
* Print a debug message to the text console (stdout), but only if
* the gDebugLevel equals at least the specified level.
* As a rule of thumb, the more important the message, the lower the level.
diff --git a/common/forbidden.h b/common/forbidden.h
new file mode 100644
index 0000000000..92e662ccc6
--- /dev/null
+++ b/common/forbidden.h
@@ -0,0 +1,161 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef COMMON_FORBIDDEN_H
+#define COMMON_FORBIDDEN_H
+
+/**
+ * @file
+ * This header file is meant to help ensure that engines and
+ * infrastructure code do not make use of certain "forbidden" APIs, such
+ * as fopen(), setjmp(), etc.
+ * This is achieved by re-#defining various symbols to a "garbage"
+ * string which then trigers a compiler error.
+ *
+ * Backend files may #define FORBIDDEN_SYMBOL_ALLOW_ALL if they
+ * have to access functions like fopen, fread etc.
+ * Regular code, esp. code in engines/, should never do that.
+ */
+
+#ifndef FORBIDDEN_SYMBOL_ALLOW_ALL
+
+/**
+ * The garbage string to use as replacement for forbidden symbols.
+ *
+ * The reason for this particular string is the following:
+ * By including a space and "!" we try to ensure a compiler error.
+ * By using the words "forbidden symbol" we try to make it a bit
+ * clearer what is causing the error.
+ */
+#define FORBIDDEN_SYMBOL_REPLACEMENT FORBIDDEN SYMBOL!
+
+
+/*
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_printf
+#undef printf
+#define printf FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_fprintf
+#undef fprintf
+#define fprintf FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+*/
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_FILE
+#undef FILE
+#define FILE FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_fopen
+#undef fopen
+#define fopen(a,b) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_fclose
+#undef fclose
+#define fclose(a) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_fread
+#undef fread
+#define fread(a,b,c,d) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_fwrite
+#undef fwrite
+#define fwrite(a,b,c,d) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_fseek
+#undef fseek
+#define fseek(a,b,c) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_ftell
+#undef ftell
+#define ftell(a) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_feof
+#undef feof
+#define feof(a) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_fgetc
+#undef fgetc
+#define fgetc(a) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_fputc
+#undef fputc
+#define fputc(a,b) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_setjmp
+#undef setjmp
+#define setjmp(a) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_longjmp
+#undef longjmp
+#define longjmp(a,b) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#ifndef FORBIDDEN_SYMBOL_EXCEPTION_system
+#undef system
+#define system(a) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+
+/*
+time_t
+
+time
+
+difftime
+
+mktime
+
+localtime
+
+clock
+
+gmtime
+
+system
+
+remove
+
+setlocale
+
+setvbuf
+*/
+
+#endif
+
+
+#endif
diff --git a/common/hashmap.cpp b/common/hashmap.cpp
index d8b84f61a5..5fe18f33ee 100644
--- a/common/hashmap.cpp
+++ b/common/hashmap.cpp
@@ -89,7 +89,7 @@ void updateHashCollisionStats(int collisions, int dummyHits, int lookups, int ar
g_max_capacity = MAX(g_max_capacity, arrsize);
g_max_size = MAX(g_max_size, nele);
- fprintf(stdout, "%d hashmaps: colls %.1f; dummies hit %.1f, lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)\n",
+ debug("%d hashmaps: colls %.1f; dummies hit %.1f, lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)",
g_totalHashmaps,
g_collisions / g_totalHashmaps,
g_dummyHits / g_totalHashmaps,
@@ -97,7 +97,7 @@ void updateHashCollisionStats(int collisions, int dummyHits, int lookups, int ar
100 * g_collPerLook / g_totalHashmaps,
g_size / g_totalHashmaps, g_max_size,
g_capacity / g_totalHashmaps, g_max_capacity);
- fprintf(stdout, " %d less than %d; %d less than %d; %d less than %d; %d less than %d\n",
+ debug(" %d less than %d; %d less than %d; %d less than %d; %d less than %d",
g_stats[0], 2*8/3,
g_stats[1],2*16/3,
g_stats[2],2*32/3,
diff --git a/common/hashmap.h b/common/hashmap.h
index 0d4d7663f3..81a136f671 100644
--- a/common/hashmap.h
+++ b/common/hashmap.h
@@ -29,28 +29,46 @@
#ifndef COMMON_HASHMAP_H
#define COMMON_HASHMAP_H
+/**
+ * @def DEBUG_HASH_COLLISIONS
+ * Enable the following #define if you want to check how many collisions the
+ * code produces (many collisions indicate either a bad hash function, or a
+ * hash table that is too small).
+ */
+//#define DEBUG_HASH_COLLISIONS
+
+/**
+ * @def USE_HASHMAP_MEMORY_POOL
+ * Enable the following define to let HashMaps use a memory pool for the
+ nodes they contain. * This increases memory usage, but also can improve
+ speed quite a bit.
+ */
+#define USE_HASHMAP_MEMORY_POOL
+
+
#include "common/func.h"
#include "common/str.h"
#include "common/util.h"
-#define USE_HASHMAP_MEMORY_POOL
+#ifdef DEBUG_HASH_COLLISIONS
+#include "common/debug.h"
+#endif
+
#ifdef USE_HASHMAP_MEMORY_POOL
#include "common/memorypool.h"
#endif
+
+
namespace Common {
// The sgi IRIX MIPSpro Compiler has difficulties with nested templates.
// This and the other __sgi conditionals below work around these problems.
-#if defined(__sgi) && !defined(__GNUC__)
+// The Intel C++ Compiler suffers from the same problems.
+#if (defined(__sgi) && !defined(__GNUC__)) || defined(__INTEL_COMPILER)
template<class T> class IteratorImpl;
#endif
-// Enable the following #define if you want to check how many collisions the
-// code produces (many collisions indicate either a bad hash function, or a
-// hash table that is too small).
-//#define DEBUG_HASH_COLLISIONS
-
/**
* HashMap<Key,Val> maps objects of type Key to objects of type Val.
@@ -138,7 +156,7 @@ private:
template<class NodeType>
class IteratorImpl {
friend class HashMap;
-#if defined(__sgi) && !defined(__GNUC__)
+#if (defined(__sgi) && !defined(__GNUC__)) || defined(__INTEL_COMPILER)
template<class T> friend class Common::IteratorImpl;
#else
template<class T> friend class IteratorImpl;
@@ -459,7 +477,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
#ifdef DEBUG_HASH_COLLISIONS
_lookups++;
- fprintf(stderr, "collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
+ debug("collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d",
_collisions, _dummyHits, _lookups, ((double) _collisions / (double)_lookups),
(const void *)this, _mask+1, _size);
#endif
@@ -497,7 +515,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &
#ifdef DEBUG_HASH_COLLISIONS
_lookups++;
- fprintf(stderr, "collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
+ debug("collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d",
_collisions, _dummyHits, _lookups, ((double) _collisions / (double)_lookups),
(const void *)this, _mask+1, _size);
#endif
diff --git a/common/macresman.cpp b/common/macresman.cpp
index 641702b5ec..22216763b8 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -73,38 +73,36 @@ void MacResManager::close() {
delete _stream; _stream = 0;
}
-bool MacResManager::hasDataFork() {
+bool MacResManager::hasDataFork() const {
return !_baseFileName.empty();
}
-bool MacResManager::hasResFork() {
+bool MacResManager::hasResFork() const {
return !_baseFileName.empty() && _mode != kResForkNone;
}
-uint32 MacResManager::getResForkSize() {
+uint32 MacResManager::getResForkSize() const {
if (!hasResFork())
return 0;
return _resForkSize;
}
-bool MacResManager::getResForkMD5(char *md5str, uint32 length) {
+String MacResManager::computeResForkMD5AsString(uint32 length) const {
if (!hasResFork())
- return false;
+ return String();
- ReadStream *stream = new SeekableSubReadStream(_stream, _resForkOffset, _resForkOffset + _resForkSize);
- bool retVal = md5_file_string(*stream, md5str, MIN<uint32>(length, _resForkSize));
- delete stream;
- return retVal;
+ SeekableSubReadStream resForkStream(_stream, _resForkOffset, _resForkOffset + _resForkSize);
+ return computeStreamMD5AsString(resForkStream, MIN<uint32>(length, _resForkSize));
}
-bool MacResManager::open(Common::String filename) {
+bool MacResManager::open(String filename) {
close();
#ifdef MACOSX
// Check the actual fork on a Mac computer
- Common::String fullPath = ConfMan.get("path") + "/" + filename + "/..namedfork/rsrc";
- Common::SeekableReadStream *macResForkRawStream = StdioStream::makeFromPath(fullPath, false);
+ String fullPath = ConfMan.get("path") + "/" + filename + "/..namedfork/rsrc";
+ SeekableReadStream *macResForkRawStream = StdioStream::makeFromPath(fullPath, false);
if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) {
_baseFileName = filename;
@@ -114,7 +112,7 @@ bool MacResManager::open(Common::String filename) {
delete macResForkRawStream;
#endif
- Common::File *file = new Common::File();
+ File *file = new File();
// First, let's try to see if the Mac converted name exists
if (file->open("._" + filename) && loadFromAppleDouble(*file)) {
@@ -158,13 +156,13 @@ bool MacResManager::open(Common::String filename) {
return false;
}
-bool MacResManager::open(Common::FSNode path, Common::String filename) {
+bool MacResManager::open(FSNode path, String filename) {
close();
#ifdef MACOSX
// Check the actual fork on a Mac computer
- Common::String fullPath = path.getPath() + "/" + filename + "/..namedfork/rsrc";
- Common::SeekableReadStream *macResForkRawStream = StdioStream::makeFromPath(fullPath, false);
+ String fullPath = path.getPath() + "/" + filename + "/..namedfork/rsrc";
+ SeekableReadStream *macResForkRawStream = StdioStream::makeFromPath(fullPath, false);
if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) {
_baseFileName = filename;
@@ -175,7 +173,7 @@ bool MacResManager::open(Common::FSNode path, Common::String filename) {
#endif
// First, let's try to see if the Mac converted name exists
- Common::FSNode fsNode = path.getChild("._" + filename);
+ FSNode fsNode = path.getChild("._" + filename);
if (fsNode.exists() && !fsNode.isDirectory()) {
SeekableReadStream *stream = fsNode.createReadStream();
if (loadFromAppleDouble(*stream)) {
@@ -228,7 +226,7 @@ bool MacResManager::open(Common::FSNode path, Common::String filename) {
return false;
}
-bool MacResManager::loadFromAppleDouble(Common::SeekableReadStream &stream) {
+bool MacResManager::loadFromAppleDouble(SeekableReadStream &stream) {
if (stream.readUint32BE() != 0x00051607) // tag
return false;
@@ -253,7 +251,7 @@ bool MacResManager::loadFromAppleDouble(Common::SeekableReadStream &stream) {
return false;
}
-bool MacResManager::isMacBinary(Common::SeekableReadStream &stream) {
+bool MacResManager::isMacBinary(SeekableReadStream &stream) {
byte infoHeader[MBI_INFOHDR];
int resForkOffset = -1;
@@ -281,7 +279,7 @@ bool MacResManager::isMacBinary(Common::SeekableReadStream &stream) {
return true;
}
-bool MacResManager::loadFromMacBinary(Common::SeekableReadStream &stream) {
+bool MacResManager::loadFromMacBinary(SeekableReadStream &stream) {
byte infoHeader[MBI_INFOHDR];
stream.read(infoHeader, MBI_INFOHDR);
@@ -310,14 +308,14 @@ bool MacResManager::loadFromMacBinary(Common::SeekableReadStream &stream) {
return load(stream);
}
-bool MacResManager::loadFromRawFork(Common::SeekableReadStream &stream) {
+bool MacResManager::loadFromRawFork(SeekableReadStream &stream) {
_mode = kResForkRaw;
_resForkOffset = 0;
_resForkSize = stream.size();
return load(stream);
}
-bool MacResManager::load(Common::SeekableReadStream &stream) {
+bool MacResManager::load(SeekableReadStream &stream) {
if (_mode == kResForkNone)
return false;
@@ -345,7 +343,7 @@ bool MacResManager::load(Common::SeekableReadStream &stream) {
return true;
}
-Common::SeekableReadStream *MacResManager::getDataFork() {
+SeekableReadStream *MacResManager::getDataFork() {
if (!_stream)
return NULL;
@@ -355,7 +353,7 @@ Common::SeekableReadStream *MacResManager::getDataFork() {
return new SeekableSubReadStream(_stream, MBI_INFOHDR, MBI_INFOHDR + dataSize);
}
- Common::File *file = new Common::File();
+ File *file = new File();
if (file->open(_baseFileName))
return file;
delete file;
@@ -398,7 +396,7 @@ MacResTagArray MacResManager::getResTagArray() {
return tagArray;
}
-Common::String MacResManager::getResName(uint32 typeID, uint16 resID) {
+String MacResManager::getResName(uint32 typeID, uint16 resID) const {
int typeNum = -1;
for (int i = 0; i < _resMap.numTypes; i++)
@@ -417,7 +415,7 @@ Common::String MacResManager::getResName(uint32 typeID, uint16 resID) {
return "";
}
-Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 resID) {
+SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 resID) {
int typeNum = -1;
int resNum = -1;
@@ -449,7 +447,7 @@ Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 res
return _stream->readStream(len);
}
-Common::SeekableReadStream *MacResManager::getResource(const Common::String &filename) {
+SeekableReadStream *MacResManager::getResource(const String &filename) {
for (uint32 i = 0; i < _resMap.numTypes; i++) {
for (uint32 j = 0; j < _resTypes[i].items; j++) {
if (_resLists[i][j].nameOffset != -1 && filename.equalsIgnoreCase(_resLists[i][j].name)) {
@@ -468,7 +466,7 @@ Common::SeekableReadStream *MacResManager::getResource(const Common::String &fil
return 0;
}
-Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, const Common::String &filename) {
+SeekableReadStream *MacResManager::getResource(uint32 typeID, const String &filename) {
for (uint32 i = 0; i < _resMap.numTypes; i++) {
if (_resTypes[i].id != typeID)
continue;
@@ -545,7 +543,7 @@ void MacResManager::readMap() {
void MacResManager::convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize) {
- Common::MemoryReadStream dis(data, datasize);
+ MemoryReadStream dis(data, datasize);
int i, b;
byte imageByte;
byte *iconData;
diff --git a/common/macresman.h b/common/macresman.h
index d47b0ca329..f88ba9ceb5 100644
--- a/common/macresman.h
+++ b/common/macresman.h
@@ -33,8 +33,8 @@ namespace Common {
class FSNode;
-typedef Common::Array<uint16> MacResIDArray;
-typedef Common::Array<uint32> MacResTagArray;
+typedef Array<uint16> MacResIDArray;
+typedef Array<uint32> MacResTagArray;
/**
* Class for reading Mac Binary files.
@@ -46,14 +46,14 @@ public:
MacResManager();
~MacResManager();
- bool open(Common::String filename);
- bool open(Common::FSNode path, Common::String filename);
+ bool open(String filename);
+ bool open(FSNode path, String filename);
void close();
- bool hasDataFork();
- bool hasResFork();
+ bool hasDataFork() const;
+ bool hasResFork() const;
- static bool isMacBinary(Common::SeekableReadStream &stream);
+ static bool isMacBinary(SeekableReadStream &stream);
/**
* Read resource from the Mac Binary file
@@ -61,7 +61,7 @@ public:
* @param resID Resource ID to fetch
* @return Pointer to a SeekableReadStream with loaded resource
*/
- Common::SeekableReadStream *getResource(uint32 typeID, uint16 resID);
+ SeekableReadStream *getResource(uint32 typeID, uint16 resID);
/**
* Read resource from the Mac Binary file
@@ -69,7 +69,7 @@ public:
* @param filename filename of the resource
* @return Pointer to a SeekableReadStream with loaded resource
*/
- Common::SeekableReadStream *getResource(const Common::String &filename);
+ SeekableReadStream *getResource(const String &filename);
/**
* Read resource from the Mac Binary file
@@ -77,14 +77,14 @@ public:
* @param filename filename of the resource
* @return Pointer to a SeekableReadStream with loaded resource
*/
- Common::SeekableReadStream *getResource(uint32 typeID, const Common::String &filename);
+ SeekableReadStream *getResource(uint32 typeID, const String &filename);
- Common::SeekableReadStream *getDataFork();
- Common::String getResName(uint32 typeID, uint16 resID);
- uint32 getResForkSize();
- bool getResForkMD5(char *md5str, uint32 length);
+ SeekableReadStream *getDataFork();
+ String getResName(uint32 typeID, uint16 resID) const;
+ uint32 getResForkSize() const;
+ String computeResForkMD5AsString(uint32 length = 0) const;
- Common::String getBaseFileName() { return _baseFileName; }
+ String getBaseFileName() const { return _baseFileName; }
/**
* Convert cursor from crsr format to format suitable for feeding to CursorMan
@@ -117,14 +117,14 @@ public:
MacResTagArray getResTagArray();
private:
- Common::SeekableReadStream *_stream;
- Common::String _baseFileName;
+ SeekableReadStream *_stream;
+ String _baseFileName;
- bool load(Common::SeekableReadStream &stream);
+ bool load(SeekableReadStream &stream);
- bool loadFromRawFork(Common::SeekableReadStream &stream);
- bool loadFromMacBinary(Common::SeekableReadStream &stream);
- bool loadFromAppleDouble(Common::SeekableReadStream &stream);
+ bool loadFromRawFork(SeekableReadStream &stream);
+ bool loadFromMacBinary(SeekableReadStream &stream);
+ bool loadFromAppleDouble(SeekableReadStream &stream);
enum {
kResForkNone = 0,
diff --git a/common/md5.cpp b/common/md5.cpp
index df544ca0f0..e4736e85ca 100644
--- a/common/md5.cpp
+++ b/common/md5.cpp
@@ -246,7 +246,7 @@ void md5_finish(md5_context *ctx, uint8 digest[16]) {
}
-bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length) {
+bool computeStreamMD5(ReadStream &stream, uint8 digest[16], uint32 length) {
#ifdef DISABLE_MD5
memset(digest, 0, 16);
@@ -267,12 +267,14 @@ bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length) {
while ((i = stream.read(buf, readlen)) > 0) {
md5_update(&ctx, buf, i);
- length -= i;
- if (restricted && length == 0)
- break;
+ if (restricted) {
+ length -= i;
+ if (length == 0)
+ break;
- if (restricted && sizeof(buf) > length)
- readlen = length;
+ if (sizeof(buf) > length)
+ readlen = length;
+ }
}
md5_finish(&ctx, digest);
@@ -280,16 +282,16 @@ bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length) {
return true;
}
-bool md5_file_string(ReadStream &stream, char *md5str, uint32 length) {
+String computeStreamMD5AsString(ReadStream &stream, uint32 length) {
+ String md5;
uint8 digest[16];
- if (!md5_file(stream, digest, length))
- return false;
-
- for (int i = 0; i < 16; i++) {
- snprintf(md5str + i*2, 3, "%02x", (int)digest[i]);
+ if (computeStreamMD5(stream, digest, length)) {
+ for (int i = 0; i < 16; i++) {
+ md5 += String::format("%02x", (int)digest[i]);
+ }
}
- return true;
+ return md5;
}
} // End of namespace Common
diff --git a/common/md5.h b/common/md5.h
index 1fb937ae9b..29f3aeeb4c 100644
--- a/common/md5.h
+++ b/common/md5.h
@@ -26,18 +26,35 @@
#define COMMON_MD5_H
#include "common/scummsys.h"
+#include "common/str.h"
namespace Common {
class ReadStream;
-bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length = 0);
-
-// The following method work similar to the above one, but
-// instead of computing the binary MD5 digest, it produces
-// a human readable lowercase hexstring representing the digest.
-// The md5str parameter must point to a buffer of 32+1 chars.
-bool md5_file_string(ReadStream &stream, char *md5str, uint32 length = 0);
+/**
+ * Compute the MD5 checksum of the content of the given ReadStream.
+ * The 128 bit MD5 checksum is returned directly in the array digest.
+ * If length is set to a positive value, then only the first length
+ * bytes of the stream are used to compute the checksum.
+ * @param[in] stream the stream of whose data the MD5 is computed
+ * @param[out] digest the computed MD5 checksum
+ * @param[in] length the number of bytes for which to compute the checksum; 0 means all
+ * @return true on success, false if an error occurred
+ */
+bool computeStreamMD5(ReadStream &stream, uint8 digest[16], uint32 length = 0);
+
+/**
+ * Compute the MD5 checksum of the content of the given ReadStream.
+ * The 128 bit MD5 checksum is converted to a human readable
+ * lowercase hex string of length 32.
+ * If length is set to a positive value, then only the first length
+ * bytes of the stream are used to compute the checksum.
+ * @param[in] stream the stream of whose data the MD5 is computed
+ * @param[in] length the number of bytes for which to compute the checksum; 0 means all
+ * @return the MD5 as a hex string on success, and an empty string if an error occurred
+ */
+String computeStreamMD5AsString(ReadStream &stream, uint32 length = 0);
} // End of namespace Common
diff --git a/common/memorypool.cpp b/common/memorypool.cpp
index c677c45ff4..c4dbb5fbbd 100644
--- a/common/memorypool.cpp
+++ b/common/memorypool.cpp
@@ -161,7 +161,7 @@ void MemoryPool::freeUnusedPages() {
}
}
-// printf("freed %d pages out of %d\n", (int)freedPagesCount, (int)_pages.size());
+// debug("freed %d pages out of %d", (int)freedPagesCount, (int)_pages.size());
// Remove all now unused pages
size_t newSize = 0;
diff --git a/common/memorypool.h b/common/memorypool.h
index 7188e854f9..e19d982913 100644
--- a/common/memorypool.h
+++ b/common/memorypool.h
@@ -66,7 +66,7 @@ public:
* Constructor for a memory pool with the given chunk size.
* @param chunkSize the chunk size of this memory pool
*/
- MemoryPool(size_t chunkSize);
+ explicit MemoryPool(size_t chunkSize);
~MemoryPool();
/**
diff --git a/common/mutex.h b/common/mutex.h
index ba5c45c30e..3addaa6b18 100644
--- a/common/mutex.h
+++ b/common/mutex.h
@@ -49,8 +49,8 @@ class StackLock {
void lock();
void unlock();
public:
- StackLock(MutexRef mutex, const char *mutexName = NULL);
- StackLock(const Mutex &mutex, const char *mutexName = NULL);
+ explicit StackLock(MutexRef mutex, const char *mutexName = NULL);
+ explicit StackLock(const Mutex &mutex, const char *mutexName = NULL);
~StackLock();
};
diff --git a/common/ptr.h b/common/ptr.h
index 7307038936..4d7fff1fc2 100644
--- a/common/ptr.h
+++ b/common/ptr.h
@@ -243,7 +243,7 @@ public:
operator bool() const { return _pointer != 0; }
~ScopedPtr() {
- delete _pointer;
+ delete _pointer;
}
/**
@@ -277,7 +277,6 @@ private:
PointerType _pointer;
};
-
} // End of namespace Common
#endif
diff --git a/common/scummsys.h b/common/scummsys.h
index 71873ee4e6..d168544b18 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -334,13 +334,6 @@
#define SCUMM_BIG_ENDIAN
#define SCUMM_NEED_ALIGNMENT
-#ifdef KEYCODE_LESS
- #undef KEYCODE_LESS
-#endif
-#ifdef KEYCODE_GREATER
- #undef KEYCODE_GREATER
-#endif
-
#elif defined (__DS__)
#define scumm_stricmp stricmp
@@ -444,5 +437,6 @@
typedef uint16 OverlayColor;
#endif
+#include <common/forbidden.h>
#endif
diff --git a/common/str.cpp b/common/str.cpp
index c3c19adfe6..c21e4412db 100644
--- a/common/str.cpp
+++ b/common/str.cpp
@@ -430,7 +430,7 @@ uint String::hash() const {
}
// static
-String String::printf(const char *fmt, ...) {
+String String::format(const char *fmt, ...) {
String output;
assert(output.isStorageIntern());
diff --git a/common/str.h b/common/str.h
index e3dec6cdc2..56feaacf1b 100644
--- a/common/str.h
+++ b/common/str.h
@@ -218,7 +218,7 @@ public:
/**
* Printf-like function. Returns a formatted String.
*/
- static Common::String printf(const char *fmt, ...) GCC_PRINTF(1,2);
+ static Common::String format(const char *fmt, ...) GCC_PRINTF(1,2);
public:
typedef char * iterator;
diff --git a/common/textconsole.cpp b/common/textconsole.cpp
index 0d0b0aead9..246a9a1fe1 100644
--- a/common/textconsole.cpp
+++ b/common/textconsole.cpp
@@ -22,14 +22,13 @@
* $Id$
*/
+// Disable symbol overrides so that we can use system headers.
+// FIXME: Necessary for the PS2 port, should get rid of this eventually.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/textconsole.h"
#include "common/system.h"
-#ifdef _WIN32_WCE
-// This is required for the debugger attachment
-extern bool isSmartphone();
-#endif
-
#ifdef __PLAYSTATION2__
// for those replaced fopen/fread/etc functions
#include "backends/platform/ps2/fileio.h"
diff --git a/common/timer.h b/common/timer.h
index 3a48875842..c87c2b3240 100644
--- a/common/timer.h
+++ b/common/timer.h
@@ -26,7 +26,6 @@
#define COMMON_TIMER_H
#include "common/scummsys.h"
-#include "common/system.h"
#include "common/noncopyable.h"
namespace Common {
diff --git a/common/unzip.cpp b/common/unzip.cpp
index e0ddb8f286..3f084ad861 100644
--- a/common/unzip.cpp
+++ b/common/unzip.cpp
@@ -401,7 +401,7 @@ typedef struct {
/* ===========================================================================
Read a byte from a gz_stream; update next_in and avail_in. Return EOF
for end of file.
- IN assertion: the stream s has been sucessfully opened for reading.
+ IN assertion: the stream s has been successfully opened for reading.
*/
diff --git a/common/util.cpp b/common/util.cpp
index 2fffdca8a6..533795ca9e 100644
--- a/common/util.cpp
+++ b/common/util.cpp
@@ -38,20 +38,20 @@ void hexdump(const byte *data, int len, int bytesPerLine, int startOffset) {
byte c;
int offset = startOffset;
while (len >= bytesPerLine) {
- printf("%06x: ", offset);
+ debugN("%06x: ", offset);
for (i = 0; i < bytesPerLine; i++) {
- printf("%02x ", data[i]);
+ debugN("%02x ", data[i]);
if (i % 4 == 3)
- printf(" ");
+ debugN(" ");
}
- printf(" |");
+ debugN(" |");
for (i = 0; i < bytesPerLine; i++) {
c = data[i];
if (c < 32 || c >= 127)
c = '.';
- printf("%c", c);
+ debugN("%c", c);
}
- printf("|\n");
+ debugN("|\n");
data += bytesPerLine;
len -= bytesPerLine;
offset += bytesPerLine;
@@ -60,25 +60,25 @@ void hexdump(const byte *data, int len, int bytesPerLine, int startOffset) {
if (len <= 0)
return;
- printf("%06x: ", offset);
+ debugN("%06x: ", offset);
for (i = 0; i < bytesPerLine; i++) {
if (i < len)
- printf("%02x ", data[i]);
+ debugN("%02x ", data[i]);
else
- printf(" ");
+ debugN(" ");
if (i % 4 == 3)
- printf(" ");
+ debugN(" ");
}
- printf(" |");
+ debugN(" |");
for (i = 0; i < len; i++) {
c = data[i];
if (c < 32 || c >= 127)
c = '.';
- printf("%c", c);
+ debugN("%c", c);
}
for (; i < bytesPerLine; i++)
- printf(" ");
- printf("|\n");
+ debugN(" ");
+ debugN("|\n");
}
diff --git a/common/util.h b/common/util.h
index 52e4295bbb..699653918a 100644
--- a/common/util.h
+++ b/common/util.h
@@ -63,6 +63,20 @@ template<typename T> inline void SWAP(T &a, T &b) { T tmp = a; a = b; b = tmp; }
#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
+/**
+ * @def SCUMMVM_CURRENT_FUNCTION
+ * This macro evaluates to the current function's name on compilers supporting this.
+ */
+#if defined(__GNUC__)
+# define SCUMMVM_CURRENT_FUNCTION __PRETTY_FUNCTION__
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
+# define SCUMMVM_CURRENT_FUNCTION __func__
+#elif defined(_MSC_VER) && _MSC_VER >= 1300
+# define SCUMMVM_CURRENT_FUNCTION __FUNCTION__
+#else
+# define SCUMMVM_CURRENT_FUNCTION "<unknown>"
+#endif
+
namespace Common {
/**
diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp
index 1c652fa19d..ab56ba3751 100644
--- a/common/xmlparser.cpp
+++ b/common/xmlparser.cpp
@@ -229,6 +229,47 @@ bool XMLParser::parseKeyValue(Common::String keyName) {
return true;
}
+bool XMLParser::parseIntegerKey(const char *key, int count, ...) {
+ bool result;
+ va_list args;
+ va_start(args, count);
+ result = vparseIntegerKey(key, count, args);
+ va_end(args);
+ return result;
+}
+
+bool XMLParser::parseIntegerKey(const Common::String &key, int count, ...) {
+ bool result;
+ va_list args;
+ va_start(args, count);
+ result = vparseIntegerKey(key.c_str(), count, args);
+ va_end(args);
+ return result;
+}
+
+bool XMLParser::vparseIntegerKey(const char *key, int count, va_list args) {
+ char *parseEnd;
+ int *num_ptr;
+
+ while (count--) {
+ while (isspace(*key))
+ key++;
+
+ num_ptr = va_arg(args, int*);
+ *num_ptr = strtol(key, &parseEnd, 10);
+
+ key = parseEnd;
+
+ while (isspace(*key))
+ key++;
+
+ if (count && *key++ != ',')
+ return false;
+ }
+
+ return (*key == 0);
+}
+
bool XMLParser::closeKey() {
bool ignore = false;
bool result = true;
@@ -410,5 +451,61 @@ bool XMLParser::parse() {
return true;
}
+bool XMLParser::skipSpaces() {
+ if (!isspace(_char))
+ return false;
+
+ while (_char && isspace(_char))
+ _char = _stream->readByte();
+
+ return true;
+}
+
+bool XMLParser::skipComments() {
+ if (_char == '<') {
+ _char = _stream->readByte();
+
+ if (_char != '!') {
+ _stream->seek(-1, SEEK_CUR);
+ _char = '<';
+ return false;
+ }
+
+ if (_stream->readByte() != '-' || _stream->readByte() != '-')
+ return parserError("Malformed comment syntax.");
+
+ _char = _stream->readByte();
+
+ while (_char) {
+ if (_char == '-') {
+ if (_stream->readByte() == '-') {
+
+ if (_stream->readByte() != '>')
+ return parserError("Malformed comment (double-hyphen inside comment body).");
+
+ _char = _stream->readByte();
+ return true;
+ }
+ }
+
+ _char = _stream->readByte();
+ }
+
+ return parserError("Comment has no closure.");
+ }
+
+ return false;
+}
+
+bool XMLParser::parseToken() {
+ _token.clear();
+
+ while (isValidNameChar(_char)) {
+ _token += _char;
+ _char = _stream->readByte();
+ }
+
+ return isspace(_char) != 0 || _char == '>' || _char == '=' || _char == '/';
}
+} // End of namespace Common
diff --git a/common/xmlparser.h b/common/xmlparser.h
index 5271917927..c8cc349a6c 100644
--- a/common/xmlparser.h
+++ b/common/xmlparser.h
@@ -293,65 +293,22 @@ protected:
/**
* Prints an error message when parsing fails and stops the parser.
- * Parser error always returns "false" so we can pass the return value directly
- * and break down the parsing.
+ * Parser error always returns "false" so we can pass the return value
+ * directly and break down the parsing.
*/
bool parserError(const char *errorString, ...) GCC_PRINTF(2, 3);
/**
- * Skips spaces/whitelines etc. Returns true if any spaces were skipped.
+ * Skips spaces/whitelines etc.
+ * @return true if any spaces were skipped.
*/
- bool skipSpaces() {
- if (!isspace(_char))
- return false;
-
- while (_char && isspace(_char))
- _char = _stream->readByte();
-
- return true;
- }
+ bool skipSpaces();
/**
* Skips comment blocks and comment lines.
- * Returns true if any comments were skipped.
- * Overload this if you want to disable comments on your XML syntax
- * or to change the commenting syntax.
+ * @return true if any comments were skipped.
*/
- virtual bool skipComments() {
- if (_char == '<') {
- _char = _stream->readByte();
-
- if (_char != '!') {
- _stream->seek(-1, SEEK_CUR);
- _char = '<';
- return false;
- }
-
- if (_stream->readByte() != '-' || _stream->readByte() != '-')
- return parserError("Malformed comment syntax.");
-
- _char = _stream->readByte();
-
- while (_char) {
- if (_char == '-') {
- if (_stream->readByte() == '-') {
-
- if (_stream->readByte() != '>')
- return parserError("Malformed comment (double-hyphen inside comment body).");
-
- _char = _stream->readByte();
- return true;
- }
- }
-
- _char = _stream->readByte();
- }
-
- return parserError("Comment has no closure.");
- }
-
- return false;
- }
+ bool skipComments();
/**
* Check if a given character can be part of a KEY or VALUE name.
@@ -364,18 +321,8 @@ protected:
/**
* Parses a the first textual token found.
- * There's no reason to overload this.
*/
- bool parseToken() {
- _token.clear();
-
- while (isValidNameChar(_char)) {
- _token += _char;
- _char = _stream->readByte();
- }
-
- return isspace(_char) != 0 || _char == '>' || _char == '=' || _char == '/';
- }
+ bool parseToken();
/**
* Parses the values inside an integer key.
@@ -395,32 +342,9 @@ protected:
* by reference.
* @returns True if the parsing succeeded.
*/
- bool parseIntegerKey(const char *key, int count, ...) {
- char *parseEnd;
- int *num_ptr;
-
- va_list args;
- va_start(args, count);
-
- while (count--) {
- while (isspace(*key))
- key++;
-
- num_ptr = va_arg(args, int*);
- *num_ptr = strtol(key, &parseEnd, 10);
-
- key = parseEnd;
-
- while (isspace(*key))
- key++;
-
- if (count && *key++ != ',')
- return false;
- }
-
- va_end(args);
- return (*key == 0);
- }
+ bool parseIntegerKey(const char *key, int count, ...);
+ bool parseIntegerKey(const Common::String &keyStr, int count, ...);
+ bool vparseIntegerKey(const char *key, int count, va_list args);
bool parseXMLHeader(ParserNode *node);
@@ -446,6 +370,6 @@ private:
Common::Stack<ParserNode*> _activeKey; /** Node stack of the parsed keys */
};
-}
+} // End of namespace Common
#endif
diff --git a/configure b/configure
index 27cf9f3592..a3f0d101e5 100755
--- a/configure
+++ b/configure
@@ -91,6 +91,7 @@ add_engine groovie2 "Groovie 2 games" no
add_engine hugo "Hugo Trilogy" no
add_engine kyra "Legend of Kyrandia" yes "lol"
add_engine lol "Lands of Lore" no
+add_engine lastexpress "The Last Express" no
add_engine lure "Lure of the Temptress" yes
add_engine m4 "M4/MADS" no
add_engine made "MADE" yes
@@ -131,7 +132,6 @@ _png=auto
_theoradec=auto
_fluidsynth=auto
_16bit=auto
-_opengl=auto
_readline=auto
# Default option behaviour yes/no
_debug_build=auto
@@ -144,6 +144,7 @@ _indeo3=auto
_enable_prof=no
_unix=no
_global_constructors=no
+_elf_loader=no
# Default vkeybd/keymapper options
_vkeybd=no
_keymapper=no
@@ -676,7 +677,7 @@ Fine tuning of the installation directories:
Special configuration feature:
--host=HOST cross-compile to target HOST (arm-linux, ...)
special targets: android for Android
- caanoo for GP2X Caanoo
+ caanoo for Caanoo
dingux for Dingux
dreamcast for Sega Dreamcast
ds for Nintendo DS
@@ -709,7 +710,6 @@ Optional Features:
--default-dynamic make plugins dynamic by default
--disable-mt32emu don't enable the integrated MT-32 emulator
--disable-16bit don't enable 16bit color support
- --disable-opengl don't enable OpenGL (ES)
--disable-scalers exclude scalers
--disable-hq-scalers exclude HQ2x and HQ3x scalers
--disable-translation don't build support for translated messages
@@ -740,15 +740,12 @@ Optional Libraries:
--with-mpeg2-prefix=DIR Prefix where libmpeg2 is installed (optional)
--enable-mpeg2 enable mpeg2 codec for cutscenes [no]
- --with-opengl-prefix=DIR Prefix where OpenGL (ES) is installed (optional)
- --disable-opengl disable OpenGL (ES) support [autodetect]
-
--disable-indeo3 disable Indeo3 decoder [autodetect]
--with-png-prefix=DIR Prefix where libpng is installed (optional)
--disable-png disable PNG decoder [autodetect]
- --with-theoradec-prefix=DIR Prefix where libtheoraec is installed (optional)
+ --with-theoradec-prefix=DIR Prefix where libtheoradec is installed (optional)
--disable-theoradec disable Theora decoder [autodetect]
--with-fluidsynth-prefix=DIR Prefix where libfluidsynth is
@@ -807,13 +804,11 @@ for ac_option in $@; do
--enable-indeo3) _indeo3=yes ;;
--disable-png) _png=no ;;
--enable-png) _png=yes ;;
- --disable-theoradec) _png=no ;;
- --enable-theoradec) _theoradec=yes ;;
+ --disable-theoradec) _theoradec=no ;;
+ --enable-theoradec) _theoradec=yes ;;
--disable-fluidsynth) _fluidsynth=no ;;
--enable-readline) _readline=yes ;;
--disable-readline) _readline=no ;;
- --enable-opengl) _opengl=yes ;;
- --disable-opengl) _opengl=no ;;
--enable-verbose-build) _verbose_build=yes ;;
--enable-plugins) _dynamic_modules=yes ;;
--default-dynamic) _plugins_default=dynamic ;;
@@ -887,11 +882,6 @@ for ac_option in $@; do
READLINE_CFLAGS="-I$arg/include"
READLINE_LIBS="-L$arg/lib"
;;
- --with-opengl-prefix=*)
- arg=`echo $ac_option | cut -d '=' -f 2`
- OPENGL_CFLAGS="-I$arg/include"
- OPENGL_LIBS="-L$arg/lib"
- ;;
--backend=*)
_backend=`echo $ac_option | cut -d '=' -f 2`
;;
@@ -1188,10 +1178,10 @@ HOSTEXEEXT=$_exeext
# Determine separator used for $PATH
#
case $_host_os in
-os2-emx* )
+os2-emx*)
SEPARATOR=";"
;;
-* )
+*)
SEPARATOR=":"
;;
esac
@@ -1474,7 +1464,6 @@ case $_host_os in
# We have to use 'long' for our 4 byte typedef because AmigaOS already typedefs (u)int32
# as (unsigned) long, and consequently we'd get a compiler error otherwise.
type_4_byte='long'
- add_line_to_config_mk 'AMIGAOS = 1'
;;
android)
CXXFLAGS="$CXXFLAGS -Os -msoft-float -mtune=xscale -march=armv5te -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5TE__"
@@ -1501,7 +1490,6 @@ case $_host_os in
;;
darwin*)
DEFINES="$DEFINES -DMACOSX"
- CXXFLAGS="$CXXFLAGS"
LIBS="$LIBS -framework AudioUnit -framework AudioToolbox -framework Carbon -framework CoreMIDI"
add_line_to_config_mk 'MACOSX = 1'
_unix=yes
@@ -1515,7 +1503,13 @@ case $_host_os in
CXXFLAGS="$CXXFLAGS -isystem $DEVKITPRO/libnds/include -isystem $DEVKITPRO/devkitARM/arm-eabi/include"
CXXFLAGS="$CXXFLAGS -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer -mthumb-interwork"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fno-strict-aliasing"
- LDFLAGS="$LDFLAGS -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt -Wl,--gc-sections"
+ CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
+ LDFLAGS="$LDFLAGS -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt"
+ if test "$_dynamic_modules" = no ; then
+ LDFLAGS="$LDFLAGS -Wl,--gc-sections"
+ else
+ LDFLAGS="$LDFLAGS -Wl,--retain-symbols-file,ds.syms"
+ fi
LDFLAGS="$LDFLAGS -L$DEVKITPRO/libnds/lib"
LIBS="$LIBS -lnds9"
;;
@@ -1527,9 +1521,14 @@ case $_host_os in
gamecube)
CXXFLAGS="$CXXFLAGS -Os -mogc -mcpu=750 -meabi -mhard-float"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
+ CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
# libogc is required to link the cc tests (includes _start())
LDFLAGS="$LDFLAGS -mogc -mcpu=750 -L$DEVKITPRO/libogc/lib/cube -logc"
+ if test "$_dynamic_modules" = "yes" ; then
+ # retarded toolchain patch forces --gc-sections, overwrite it
+ LDFLAGS="$LDFLAGS -Wl,--no-gc-sections"
+ fi
;;
haiku*)
DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
@@ -1557,7 +1556,6 @@ case $_host_os in
DEFINES="$DEFINES -DWIN32 -D__USE_MINGW_ANSI_STDIO=0"
LIBS="$LIBS -lmingw32 -lwinmm"
OBJS="$OBJS scummvmico.o"
- add_line_to_config_mk 'WIN32 = 1'
;;
mint*)
DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
@@ -1589,9 +1587,14 @@ case $_host_os in
wii)
CXXFLAGS="$CXXFLAGS -Os -mrvl -mcpu=750 -meabi -mhard-float"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
+ CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
# libogc is required to link the cc tests (includes _start())
LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -L$DEVKITPRO/libogc/lib/wii -logc"
+ if test "$_dynamic_modules" = "yes" ; then
+ # retarded toolchain patch forces --gc-sections, overwrite it
+ LDFLAGS="$LDFLAGS -Wl,--no-gc-sections"
+ fi
;;
wince)
CXXFLAGS="$CXXFLAGS -O3 -march=armv4 -mtune=xscale"
@@ -1640,9 +1643,9 @@ if test -n "$_host"; then
_need_memalign=yes
;;
caanoo)
+ # This uses the GPH backend.
+ DEFINES="$DEFINES -DGPH_DEVICE"
DEFINES="$DEFINES -DCAANOO -DREDUCE_MEMORY_USAGE"
- # Disable DOSBOX OPL for now.
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
if test "$_debug_build" = yes; then
DEFINES="$DEFINES -DGPH_DEBUG"
else
@@ -1731,9 +1734,9 @@ if test -n "$_host"; then
add_line_to_config_h "#define USE_WII_DI"
;;
gp2x)
+ # This uses the GPH backend.
+ DEFINES="$DEFINES -DGPH_DEVICE"
DEFINES="$DEFINES -DGP2X -DREDUCE_MEMORY_USAGE"
- # Disable DOSBOX OPL for now.
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
if test "$_debug_build" = yes; then
DEFINES="$DEFINES -DGPH_DEBUG"
fi
@@ -1755,9 +1758,9 @@ if test -n "$_host"; then
_port_mk="backends/platform/gp2x/gp2x-bundle.mk"
;;
gp2xwiz)
+ # This uses the GPH backend.
+ DEFINES="$DEFINES -DGPH_DEVICE"
DEFINES="$DEFINES -DGP2XWIZ -DREDUCE_MEMORY_USAGE"
- # Disable DOSBOX OPL for now.
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
if test "$_debug_build" = yes; then
DEFINES="$DEFINES -DGPH_DEBUG"
fi
@@ -1803,6 +1806,8 @@ if test -n "$_host"; then
_ranlib=$_host-ranlib
;;
mips-sgi*)
+ LDFLAGS="$LDFLAGS -static-libgcc"
+ LIBS="$LIBS -laudio"
_endian=big
_need_memalign=yes
;;
@@ -1858,7 +1863,7 @@ if test -n "$_host"; then
_dynamic_modules=no
_plugins_default=static
# Force use of libmad, libtremor and zlib
- _mad=yes
+ _mad=no
_tremor=yes
_zlib=yes
_port_mk="backends/platform/n64/n64.mk"
@@ -1873,8 +1878,6 @@ if test -n "$_host"; then
;;
openpandora)
DEFINES="$DEFINES -DOPENPANDORA -DREDUCE_MEMORY_USAGE"
- # Disable DOSBOX OPL for now.
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
if test "$_release_build" = no; then
DEFINES="$DEFINES -DOP_DEBUG"
else
@@ -2128,6 +2131,13 @@ PRE_OBJS_FLAGS := -Wl,--whole-archive
POST_OBJS_FLAGS := -Wl,--no-whole-archive
'
;;
+ ds)
+ _elf_loader=yes
+ DEFINES="$DEFINES -DARM_TARGET -DELF_LOADER_CXA_ATEXIT -DONE_PLUGIN_AT_A_TIME"
+_mak_plugins='
+PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/ds/plugin.ld -mthumb-interwork -mno-fpu
+'
+ ;;
freebsd*)
_def_plugin='
#define PLUGIN_PREFIX "lib"
@@ -2145,6 +2155,13 @@ PRE_OBJS_FLAGS := -Wl,-export-dynamic -Wl,-whole-archive
POST_OBJS_FLAGS := -Wl,-no-whole-archive
'
;;
+ gamecube | wii)
+ _elf_loader=yes
+ DEFINES="$DEFINES -DPPC_TARGET -DELF_LOADER_CXA_ATEXIT -DONE_PLUGIN_AT_A_TIME"
+_mak_plugins='
+PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/wii/plugin.ld
+'
+ ;;
gph*)
_def_plugin='
#define PLUGIN_PREFIX ""
@@ -2197,21 +2214,20 @@ PRE_OBJS_FLAGS := -Wl,--whole-archive
POST_OBJS_FLAGS := -Wl,--export-all-symbols -Wl,--no-whole-archive -Wl,--out-implib,./libscummvm.a
'
;;
- psp)
-_def_plugin='
-#define PLUGIN_PREFIX ""
-#define PLUGIN_SUFFIX ".plg"
+ ps2)
+ _elf_loader=yes
+ DEFINES="$DEFINES -DMIPS_TARGET"
+_mak_plugins='
+LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T$(srcdir)/backends/plugins/ps2/main_prog.ld
+PLUGIN_LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -Wl,-T$(srcdir)/backends/plugins/ps2/plugin.ld -lstdc++ -lc
'
+ ;;
+ psp)
+ _elf_loader=yes
+ DEFINES="$DEFINES -DMIPS_TARGET"
_mak_plugins='
-DYNAMIC_MODULES := 1
-PLUGIN_PREFIX :=
-PLUGIN_SUFFIX := .plg
-PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
-CXXFLAGS += -DDYNAMIC_MODULES
-LDFLAGS += -Wl,-T$(srcdir)/backends/platform/psp/main_prog.ld
-PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols,$(EXECUTABLE),--retain-symbols-file,$(srcdir)/backends/platform/psp/plugin.syms,-T$(srcdir)/backends/platform/psp/plugin.ld -lstdc++ -lc -lm
-PRE_OBJS_FLAGS := -Wl,--whole-archive
-POST_OBJS_FLAGS := -Wl,--no-whole-archive
+LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/psp/main_prog.ld
+PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/psp/plugin.ld -lstdc++ -lc
'
;;
*)
@@ -2223,6 +2239,27 @@ POST_OBJS_FLAGS := -Wl,--no-whole-archive
echo "$_dynamic_modules"
fi
+#
+# Check whether integrated ELF loader support is requested
+#
+define_in_config_if_yes "$_elf_loader" 'USE_ELF_LOADER'
+
+if test "$_elf_loader" = yes; then
+ CXXFLAGS="$CXXFLAGS -DDYNAMIC_MODULES"
+ _def_plugin='
+#define PLUGIN_PREFIX ""
+#define PLUGIN_SUFFIX ".plg"
+'
+ _mak_plugins='
+DYNAMIC_MODULES := 1
+PLUGIN_PREFIX :=
+PLUGIN_SUFFIX := .plg
+PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
+PLUGIN_LDFLAGS = -nostartfiles backends/plugins/elf/version.o -Wl,-q,--just-symbols,$(EXECUTABLE),--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms
+PRE_OBJS_FLAGS := -Wl,--whole-archive
+POST_OBJS_FLAGS := -Wl,--no-whole-archive
+'"$_mak_plugins"
+fi
#
# Check whether integrated MT-32 emulator support is requested
@@ -2387,16 +2424,21 @@ if test "$_png" = auto ; then
_png=no
cat > $TMPC << EOF
#include <png.h>
-int main(void) { if (PNG_LIBPNG_VER >= 10208) { return 0; } return 1; }
+int main(void) {
+#if PNG_LIBPNG_VER >= 10208
+#else
+ syntax error
+#endif
+ return 0;
+}
EOF
- cc_check_no_clean $PNG_CFLAGS $PNG_LIBS -lpng && $TMPO$HOSTEXEEXT && _png=yes
- cc_check_clean
+ cc_check $PNG_CFLAGS $PNG_LIBS -lpng && _png=yes
fi
if test "$_png" = yes ; then
LIBS="$LIBS $PNG_LIBS -lpng"
INCLUDES="$INCLUDES $PNG_CFLAGS"
fi
-define_in_config_h_if_yes "$_png" 'USE_PNG'
+define_in_config_if_yes "$_png" 'USE_PNG'
echo "$_png"
if test `get_engine_build sword25` = yes && test ! "$_png" = yes ; then
@@ -2425,16 +2467,11 @@ if test "$_theoradec" = yes ; then
LIBS="$LIBS $THEORADEC_LIBS -ltheoradec"
INCLUDES="$INCLUDES $THEORADEC_CFLAGS"
fi
-define_in_config_h_if_yes "$_theoradec" 'USE_THEORADEC'
+define_in_config_if_yes "$_theoradec" 'USE_THEORADEC'
if test ! "$_theoradec" = notsupported ; then
echo "$_theoradec"
fi
-if test `get_engine_build sword25` = yes && test ! "$_theoradec" = yes ; then
- echo "...disabling Broken Sword 2.5 engine. libtheoradec is required"
- engine_disable sword25
-fi
-
#
# Check for SEQ MIDI
#
@@ -2589,51 +2626,6 @@ define_in_config_h_if_yes "$_readline" 'USE_READLINE'
define_in_config_h_if_yes "$_text_console" 'USE_TEXT_CONSOLE'
#
-# Check for OpenGL (ES)
-#
-
-echocheck "OpenGL (ES)"
-if test "$_opengl" = auto ; then
- _opengl=no
- if test "$_backend" = "sdl" ; then
- case $_host_os in
- *darwin*)
- _opengl=yes
- ;;
- *mingw*)
- _opengl=yes
- ;;
- *)
- cat > $TMPC << EOF
-#include <GL/gl.h>
-int main(void) { return GL_VERSION_1_1; }
-EOF
- cc_check $DEFINES $OPENGL_CFLAGS $OPENGL_LIBS -lGL && _opengl=yes
- esac
- fi
-fi
-if test "$_opengl" = yes ; then
- LIBS="$LIBS $OPENGL_LIBS"
- INCLUDES="$INCLUDES $OPENGL_CFLAGS"
- DEFINES="$DEFINES -DUSE_OPENGL"
- case $_host_os in
- *darwin*)
- INCLUDES="$INCLUDES -I/System/Library/Frameworks/OpenGL.framework/Headers"
- LIBS="$LIBS -framework OpenGL"
- ;;
- *mingw*)
- LIBS="$LIBS -lopengl32"
- ;;
- *)
- LIBS="$LIBS -lGL"
- esac
-fi
-
-echo "$_opengl"
-
-add_to_config_mk_if_yes "$_opengl" 'USE_OPENGL=1'
-
-#
# Check for nasm
#
if test "$_have_x86" = yes ; then
@@ -2732,8 +2724,16 @@ test "x$prefix" = xNONE && prefix=/usr/local
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
DEFINES="$DEFINES -DDATA_PATH=\\\"$datadir\\\""
-DEFINES="$DEFINES -DPLUGIN_DIRECTORY=\\\"$libdir/scummvm\\\""
+case $_backend in
+ openpandora)
+ # Add ../plugins as a path so plugins can be found when running from a .PND.
+ DEFINES="$DEFINES -DPLUGIN_DIRECTORY=\\\"../plugins\\\""
+ ;;
+ *)
+ DEFINES="$DEFINES -DPLUGIN_DIRECTORY=\\\"$libdir/scummvm\\\""
+ ;;
+esac
#
# Set variables for profiling.
@@ -2883,12 +2883,14 @@ case $_backend in
# TODO ps2
DEFINES="$DEFINES -D_EE -DFORCE_RTL"
INCLUDES="$INCLUDES -I$PS2SDK/ee/include -I$PS2SDK/common/include -I$PS2SDK/ports/include"
- LDFLAGS="$LDFLAGS -mno-crt0 $PS2SDK/ee/startup/crt0.o -T $PS2SDK/ee/startup/linkfile"
+ if test "$_dynamic_modules" = no ; then
+ LDFLAGS="$LDFLAGS -mno-crt0 $PS2SDK/ee/startup/crt0.o -T $PS2SDK/ee/startup/linkfile"
+ fi
LDFLAGS="$LDFLAGS -L$PS2SDK/ee/lib -L$PS2SDK/ports/lib"
LIBS="$LIBS -lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm -lm -lc -lfileXio -lkernel -lstdc++ "
;;
psp)
- DEFINES="$DEFINES -D__PSP__ -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DDISABLE_DOSBOX_OPL"
+ DEFINES="$DEFINES -D__PSP__ -DDISABLE_COMMAND_LINE -DDISABLE_DOSBOX_OPL"
LIBS="$LIBS -lpng -Wl,-Map,mapfile.txt"
;;
samsungtv)
@@ -3147,4 +3149,3 @@ include \$(srcdir)/Makefile
EOF
fi
-
diff --git a/dists/engine-data/README b/dists/engine-data/README
index 9016e1f808..7ccc52e5c8 100644
--- a/dists/engine-data/README
+++ b/dists/engine-data/README
@@ -1,6 +1,10 @@
engine-data README
-------------------------------------------------------------------------------
+hugo.dat:
+This file contains all the hardcoded logic, strings and fonts used by Hugo
+engine. Those information were stored in the original executables.
+
kyra.dat:
The 'kyra.dat' file is created by extracting hardcoded data, like the
roomtable, inventory names, various strings, tables for shapes and sequence
@@ -15,3 +19,6 @@ mp3/ogg/flac encoded need the datafile.
sky.cpt:
TODO
+
+toon.dat:
+'toon.dat' contains all the strings hardcoded in the original executables. \ No newline at end of file
diff --git a/dists/engine-data/hugo.dat b/dists/engine-data/hugo.dat
index 8fda3fb2f4..465f6cccb4 100644
--- a/dists/engine-data/hugo.dat
+++ b/dists/engine-data/hugo.dat
Binary files differ
diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat
index d8cb28076a..23e866c62e 100644
--- a/dists/engine-data/kyra.dat
+++ b/dists/engine-data/kyra.dat
Binary files differ
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp
index 22212675c7..9be406d714 100644
--- a/engines/advancedDetector.cpp
+++ b/engines/advancedDetector.cpp
@@ -244,18 +244,21 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
if (cleanupPirated(matches))
return detectedGames;
- // Use fallback detector if there were no matches by other means
if (matches.empty()) {
+ // Use fallback detector if there were no matches by other means
const ADGameDescription *fallbackDesc = fallbackDetect(fslist);
if (fallbackDesc != 0) {
GameDescriptor desc(toGameDescriptor(*fallbackDesc, params.list));
updateGameDescriptor(desc, fallbackDesc, params);
detectedGames.push_back(desc);
}
- } else for (uint i = 0; i < matches.size(); i++) { // Otherwise use the found matches
- GameDescriptor desc(toGameDescriptor(*matches[i], params.list));
- updateGameDescriptor(desc, matches[i], params);
- detectedGames.push_back(desc);
+ } else {
+ // Otherwise use the found matches
+ for (uint i = 0; i < matches.size(); i++) {
+ GameDescriptor desc(toGameDescriptor(*matches[i], params.list));
+ updateGameDescriptor(desc, matches[i], params);
+ detectedGames.push_back(desc);
+ }
}
return detectedGames;
@@ -354,7 +357,7 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
struct SizeMD5 {
int size;
- char md5[32+1];
+ Common::String md5;
};
typedef Common::HashMap<Common::String, SizeMD5, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SizeMD5Map;
@@ -371,7 +374,7 @@ static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSiz
printf("of the game you tried to add and its version/language/etc.:\n");
for (SizeMD5Map::const_iterator file = filesSizeMD5.begin(); file != filesSizeMD5.end(); ++file)
- printf(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5, file->_value.size);
+ printf(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5.c_str(), file->_value.size);
printf("\n");
}
@@ -446,34 +449,37 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
Common::String fname = fileDesc->fileName;
SizeMD5 tmp;
+ if (filesSizeMD5.contains(fname))
+ continue;
+
+ // FIXME/TODO: We don't handle the case that a file is listed as a regular
+ // file and as one with resource fork.
+
if (g->flags & ADGF_MACRESFORK) {
Common::MacResManager *macResMan = new Common::MacResManager();
if (macResMan->open(parent, fname)) {
- if (!macResMan->getResForkMD5(tmp.md5, params.md5Bytes))
- tmp.md5[0] = 0;
+ tmp.md5 = macResMan->computeResForkMD5AsString(params.md5Bytes);
tmp.size = macResMan->getResForkSize();
- debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5);
+ debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str());
filesSizeMD5[fname] = tmp;
}
delete macResMan;
} else {
- if (allFiles.contains(fname) && !filesSizeMD5.contains(fname)) {
+ if (allFiles.contains(fname)) {
debug(3, "+ %s", fname.c_str());
Common::File testFile;
if (testFile.open(allFiles[fname])) {
tmp.size = (int32)testFile.size();
- if (!md5_file_string(testFile, tmp.md5, params.md5Bytes))
- tmp.md5[0] = 0;
+ tmp.md5 = Common::computeStreamMD5AsString(testFile, params.md5Bytes);
} else {
tmp.size = -1;
- tmp.md5[0] = 0;
}
- debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5);
+ debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str());
filesSizeMD5[fname] = tmp;
}
}
@@ -502,6 +508,7 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
continue;
bool allFilesPresent = true;
+ int curFilesMatched = 0;
// Try to match all files for this game
for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
@@ -513,8 +520,8 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
break;
}
- if (fileDesc->md5 != NULL && 0 != strcmp(fileDesc->md5, filesSizeMD5[tstr].md5)) {
- debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesSizeMD5[tstr].md5);
+ if (fileDesc->md5 != NULL && fileDesc->md5 != filesSizeMD5[tstr].md5) {
+ debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesSizeMD5[tstr].md5.c_str());
fileMissing = true;
break;
}
@@ -526,12 +533,13 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
}
debug(3, "Matched file: %s", tstr.c_str());
+ curFilesMatched++;
}
// We found at least one entry with all required files present.
// That means that we got new variant of the game.
//
- // Wihtout this check we would have errorneous checksum display
+ // Without this check we would have erroneous checksum display
// where only located files will be enlisted.
//
// Potentially this could rule out variants where some particular file
@@ -544,22 +552,11 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameid, g->extra,
getPlatformDescription(g->platform), getLanguageDescription(g->language), i);
- // Count the number of matching files. Then, only keep those
- // entries which match a maximal amount of files.
- int curFilesMatched = 0;
- for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++)
- curFilesMatched++;
-
if (curFilesMatched > maxFilesMatched) {
debug(2, " ... new best match, removing all previous candidates");
maxFilesMatched = curFilesMatched;
- for (uint j = 0; j < matched.size();) {
- if (matched[j]->flags & ADGF_KEEPMATCH)
- ++j;
- else
- matched.remove_at(j);
- }
+ matched.clear(); // Remove any prior, lower ranked matches.
matched.push_back(g);
} else if (curFilesMatched == maxFilesMatched) {
matched.push_back(g);
@@ -622,7 +619,7 @@ static ADGameDescList detectGameFilebased(const FileMap &allFiles, const ADParam
matchedDesc = agdesc;
maxNumMatchedFiles = numMatchedFiles;
- debug(4, "and overriden");
+ debug(4, "and overridden");
}
}
}
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h
index 0ebb264f74..515127b23d 100644
--- a/engines/advancedDetector.h
+++ b/engines/advancedDetector.h
@@ -49,7 +49,6 @@ enum ADGameFlags {
ADGF_ADDENGLISH = (1 << 24), // always add English as language option
ADGF_MACRESFORK = (1 << 25), // the md5 for this entry will be calculated from the resource fork
ADGF_USEEXTRAASTITLE = (1 << 26), // Extra field value will be used as main game title, not gameid
- ADGF_KEEPMATCH = (1 << 27), // this entry is kept even when there are matched entries with more files
ADGF_DROPLANGUAGE = (1 << 28), // don't add language to gameid
ADGF_CD = (1 << 29), // add "-cd" to gameid
ADGF_DEMO = (1 << 30) // add "-demo" to gameid
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 0646f321d4..cfe921a91e 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -360,12 +360,12 @@ int AgiEngine::agiInit() {
switch (getVersion() >> 12) {
case 2:
- report("Emulating Sierra AGI v%x.%03x\n",
+ debug("Emulating Sierra AGI v%x.%03x\n",
(int)(getVersion() >> 12) & 0xF,
(int)(getVersion()) & 0xFFF);
break;
case 3:
- report("Emulating Sierra AGI v%x.002.%03x\n",
+ debug("Emulating Sierra AGI v%x.002.%03x\n",
(int)(getVersion() >> 12) & 0xF,
(int)(getVersion()) & 0xFFF);
break;
@@ -382,10 +382,10 @@ int AgiEngine::agiInit() {
_game.sbuf = _game.sbuf256c;
if (_game.gameFlags & ID_AMIGA)
- report("Amiga padded game detected.\n");
+ debug(1, "Amiga padded game detected.");
if (_game.gameFlags & ID_AGDS)
- report("AGDS mode enabled.\n");
+ debug(1, "AGDS mode enabled.");
ec = _loader->init(); // load vol files, etc
@@ -459,9 +459,8 @@ int AgiEngine::agiLoadResource(int r, int n) {
if (i == errOK && getGameID() == GID_GOLDRUSH && r == rPICTURE && n == 147 && _game.dirPic[n].len == 1982) {
uint8 *pic = _game.pictures[n].rdata;
Common::MemoryReadStream picStream(pic, _game.dirPic[n].len);
- char md5str[32+1];
- Common::md5_file_string(picStream, md5str, _game.dirPic[n].len);
- if (scumm_stricmp(md5str, "1c685eb048656cedcee4eb6eca2cecea") == 0) {
+ Common::String md5str = Common::computeStreamMD5AsString(picStream, _game.dirPic[n].len);
+ if (md5str == "1c685eb048656cedcee4eb6eca2cecea") {
pic[0x042] = 0x4B; // 0x49 -> 0x4B
pic[0x043] = 0x66; // 0x26 -> 0x66
pic[0x204] = 0x68; // 0x28 -> 0x68
@@ -655,7 +654,7 @@ void AgiEngine::initialize() {
_game.state = STATE_LOADED;
debugC(2, kDebugLevelMain, "game loaded");
} else {
- report("Could not open AGI game");
+ warning("Could not open AGI game");
}
debugC(2, kDebugLevelMain, "Init sound");
@@ -703,7 +702,6 @@ Common::Error AgiBase::init() {
Common::Error AgiEngine::go() {
CursorMan.showMouse(true);
- report(" \nAGI engine %s is ready.\n", gScummVMVersion);
if (_game.state < STATE_LOADED) {
do {
mainCycle();
@@ -716,6 +714,33 @@ Common::Error AgiEngine::go() {
}
void AgiEngine::parseFeatures() {
+
+ /* FIXME: Seems this method doesn't really do anything. It might
+ be a leftover that could be removed, except that some of its
+ intended purpose may still need to be reimplemented.
+
+ [0:29] <Fingolfin> can you tell me what the point behind AgiEngine::parseFeatures() is?
+ [0:30] <_sev> when games are created with WAGI studio
+ [0:31] <_sev> it creates .wag site with game-specific features such as full game title, whether to use AGIMOUSE etc
+ [0:32] <Fingolfin> ... and the "features" config key is created by our detector based on the wag file, I guess?
+ [0:33] <_sev> yes
+ [0:33] <Fingolfin> it's just that I cant seem to find a place we do that
+ [0:33] <_sev> it is used for fallback
+ [0:34] <_sev> ah, perhaps it was not updated
+ [0:34] <Fingolfin> I only see us check the value, but never set it
+ [0:34] <Fingolfin> maybe I am grepping wrong, who knows :)
+ [0:44] <Fingolfin> _sev: so, unless I miss something, it seem that function does nothing right now
+ [0:45] <_sev> Fingolfin: it could be unfinished. It was part of GSoC 3 years ago
+ [0:45] <Fingolfin> well
+ [0:45] <_sev> I just don't remember
+ [0:45] <Fingolfin> but don't we just re-parse the wag when the game is loaded anyway?
+ [0:45] <_sev> but it documents the format
+ [0:45] <Fingolfin> the advanced meta engine would re-run the detector, wouldn't it?
+ [0:45] <_sev> yep
+ [0:47] <Fingolfin> so... shouldn't we at least add a comment to the function explaining what it does and that it's unfinished etc.? maybe add a TODO to the wiki?
+ [0:47] <Fingolfin> otherwise it might stay as it is for another 3 years :)
+ */
+
if (!ConfMan.hasKey("features"))
return;
@@ -747,13 +772,15 @@ void AgiEngine::parseFeatures() {
for (int i = 0; i < numFeatures; i++) {
for (const Flags *flag = flags; flag->name; flag++) {
if (!scumm_stricmp(feature[i], flag->name)) {
- debug(0, "Added feature: %s", flag->name);
+ debug(2, "Added feature: %s", flag->name);
setFeature(flag->flag);
break;
}
}
}
+
+ free(features);
}
} // End of namespace Agi
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 4df8824b0e..8ff7f6c35e 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -52,8 +52,12 @@ namespace Common { class RandomSource; }
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Early Sierra adventure games
+ * - many fan made games
+ * - Mickey's Space Adventure (Pre-AGI)
+ * - Winnie the Pooh in the Hundred Acre Wood (Pre-AGI)
+ * - Troll's Tale (Pre-AGI)
*/
namespace Agi {
@@ -232,8 +236,6 @@ enum AgiMouseButton {
kAgiMouseButtonMiddle // Middle mouse button
};
-#define report printf
-
enum GameId {
GID_AGI = 1
};
@@ -556,8 +558,8 @@ struct AgiGame {
int lineUserInput; /**< line to put user input on */
int lineMinPrint; /**< num lines to print on */
int cursorPos; /**< column where the input cursor is */
- uint8 inputBuffer[40]; /**< buffer for user input */
- uint8 echoBuffer[40]; /**< buffer for echo.line */
+ byte inputBuffer[40]; /**< buffer for user input */
+ byte echoBuffer[40]; /**< buffer for echo.line */
int keypress;
InputMode inputMode; /**< keyboard input mode */
diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp
index e5942455e2..370f48e018 100644
--- a/engines/agi/console.cpp
+++ b/engines/agi/console.cpp
@@ -152,7 +152,7 @@ bool Console::Cmd_Flags(int argc, const char **argv) {
for (j = 0; j < 10; j++, i++) {
DebugPrintf("%c ", _vm->getflag(i) ? 'T' : 'F');
}
- report("\n");
+ DebugPrintf("\n");
}
return true;
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 57bcabb188..86c1b519a9 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -319,12 +319,12 @@ int AgiEngine::playGame() {
// We run AGIMOUSE always as a side effect
if (getFeatures() & GF_AGIMOUSE || true)
- report("Using AGI Mouse 1.0 protocol\n");
+ debug(1, "Using AGI Mouse 1.0 protocol");
if (getFeatures() & GF_AGIPAL)
debug(1, "Running AGIPAL game");
- report("Running AGI script.\n");
+ debug(0, "Running AGI script.\n");
setflag(fEnteredCli, false);
setflag(fSaidAcceptedInput, false);
diff --git a/engines/agi/id.cpp b/engines/agi/id.cpp
index 77c527444b..2e12e45458 100644
--- a/engines/agi/id.cpp
+++ b/engines/agi/id.cpp
@@ -47,7 +47,7 @@ int AgiEngine::setupV2Game(int ver) {
if (getFeatures() & GF_AGDS)
setVersion(ver = 0x2440); // ALL AGDS games built for 2.440
- report("Setting up for version 0x%04X\n", ver);
+ debug(0, "Setting up for version 0x%04X", ver);
// 'quit' takes 0 args for 2.089
if (ver == 0x2089)
@@ -70,7 +70,7 @@ int AgiEngine::setupV2Game(int ver) {
int AgiEngine::setupV3Game(int ver) {
int ec = errOK;
- report("Setting up for version 0x%04X\n", ver);
+ debug(0, "Setting up for version 0x%04X", ver);
// 'unknown176' takes 1 arg for 3.002.086, not 0 args.
// 'unknown173' also takes 1 arg for 3.002.068, not 0 args.
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 62bcd5d8d8..344654128d 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -121,7 +121,6 @@ int AgiEngine::handleController(int key) {
if (_game.controllers[i].keycode == key) {
debugC(3, kDebugLevelInput, "event %d: key press", _game.controllers[i].controller);
_game.controllerOccured[_game.controllers[i].controller] = true;
- report("event AC:%i occurred\n", _game.controllers[i].controller);
return true;
}
}
diff --git a/engines/agi/loader_v2.cpp b/engines/agi/loader_v2.cpp
index de6f8d0653..8780e1dab8 100644
--- a/engines/agi/loader_v2.cpp
+++ b/engines/agi/loader_v2.cpp
@@ -43,7 +43,7 @@ int AgiLoader_v2::loadDir(AgiDir *agid, const char *fname) {
uint32 flen;
uint i;
- report("Loading directory: %s\n", fname);
+ debug(0, "Loading directory: %s", fname);
if (!fp.open(fname)) {
return errBadFileOpen;
@@ -157,8 +157,7 @@ uint8 *AgiLoader_v2::loadVolRes(struct AgiDir *agid) {
exit(1);
}
} else {
- report("Error: bad signature %04x\n", sig);
- // fprintf (stderr, "ACK! BAD RESOURCE!!!\n");
+ warning("AgiLoader_v2::loadVolRes: bad signature %04x", sig);
return 0;
}
fp.close();
diff --git a/engines/agi/loader_v3.cpp b/engines/agi/loader_v3.cpp
index f145140768..18ea4cae7d 100644
--- a/engines/agi/loader_v3.cpp
+++ b/engines/agi/loader_v3.cpp
@@ -121,7 +121,7 @@ int AgiLoader_v3::init() {
}
if (!fp.open(path)) {
- printf("Failed to open \"%s\"\n", path.c_str());
+ warning("Failed to open '%s'", path.c_str());
return errBadFileOpen;
}
// build offset table for v3 directory format
diff --git a/engines/agi/objects.cpp b/engines/agi/objects.cpp
index 5d1866bea4..d942a2b538 100644
--- a/engines/agi/objects.cpp
+++ b/engines/agi/objects.cpp
@@ -46,9 +46,9 @@ int AgiEngine::decodeObjects(uint8 *mem, uint32 flen) {
// if so, its encrypted, else it is not
if (READ_LE_UINT16(mem) > flen) {
- report("Decrypting objects... ");
+ debugN(0, "Decrypting objects... ");
decrypt(mem, flen);
- report("done.\n");
+ debug(0, "done.");
}
// alloc memory for object list
@@ -74,12 +74,11 @@ int AgiEngine::decodeObjects(uint8 *mem, uint32 flen) {
if ((uint) offset < flen) {
(_objects + i)->name = (char *)strdup((const char *)mem + offset);
} else {
- printf("ERROR: object %i name beyond object filesize! "
- "(%04x > %04x)\n", i, offset, flen);
+ warning("object %i name beyond object filesize (%04x > %04x)", i, offset, flen);
(_objects + i)->name = strdup("");
}
}
- report("Reading objects: %d objects read.\n", _game.numObjects);
+ debug(0, "Reading objects: %d objects read.", _game.numObjects);
return errOK;
}
@@ -92,8 +91,7 @@ int AgiEngine::loadObjects(const char *fname) {
_objects = NULL;
_game.numObjects = 0;
- debugC(5, kDebugLevelResources, "(fname = %s)", fname);
- report("Loading objects: %s\n", fname);
+ debugC(5, kDebugLevelResources, "(Loading objects '%s')", fname);
if (!fp.open(fname))
return errBadFileOpen;
@@ -130,7 +128,7 @@ void AgiEngine::unloadObjects() {
void AgiEngine::objectSetLocation(unsigned int n, int i) {
if (n >= _game.numObjects) {
- report("Error: Can't access object %d.\n", n);
+ warning("AgiEngine::objectSetLocation: Can't access object %d.\n", n);
return;
}
_objects[n].location = i;
@@ -138,7 +136,7 @@ void AgiEngine::objectSetLocation(unsigned int n, int i) {
int AgiEngine::objectGetLocation(unsigned int n) {
if (n >= _game.numObjects) {
- report("Error: Can't access object %d.\n", n);
+ warning("AgiEngine::objectGetLocation: Can't access object %d.\n", n);
return 0;
}
return _objects[n].location;
@@ -146,7 +144,7 @@ int AgiEngine::objectGetLocation(unsigned int n) {
const char *AgiEngine::objectName(unsigned int n) {
if (n >= _game.numObjects) {
- report("Error: Can't access object %d.\n", n);
+ warning("AgiEngine::objectName: Can't access object %d.\n", n);
return "";
}
return _objects[n].name;
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 1627f03863..2ea53e57ad 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -492,7 +492,7 @@ void AgiEngine::cmd_init_joy(uint8 *p) { // do nothing
}
void AgiEngine::cmd_script_size(uint8 *p) {
- report("script.size(%d)\n", p0);
+ debug(0, "script.size(%d)", p0);
}
void AgiEngine::cmd_cancel_line(uint8 *p) {
@@ -609,7 +609,7 @@ void AgiEngine::cmd_set_simple(uint8 *p) {
void AgiEngine::cmd_pop_script(uint8 *p) {
if (getVersion() >= 0x2915) {
- report("pop.script\n");
+ debug(0, "pop.script");
}
}
@@ -621,7 +621,7 @@ void AgiEngine::cmd_hold_key(uint8 *p) {
void AgiEngine::cmd_discard_sound(uint8 *p) {
if (getVersion() >= 0x2936) {
- report("discard.sound\n");
+ debug(0, "discard.sound");
}
}
@@ -1101,7 +1101,7 @@ void AgiEngine::cmd_set_game_id(uint8 *p) {
else
_game.id[0] = 0;
- report("Game ID: \"%s\"\n", _game.id);
+ debug(0, "Game ID: \"%s\"", _game.id);
}
void AgiEngine::cmd_pause(uint8 *p) {
@@ -1453,7 +1453,7 @@ void AgiEngine::cmd_clear_text_rect(uint8 *p) {
}
void AgiEngine::cmd_toggle_monitor(uint8 *p) {
- report("toggle.monitor\n");
+ debug(0, "toggle.monitor");
}
void AgiEngine::cmd_echo_line(uint8 *p) {
@@ -1510,7 +1510,7 @@ void AgiEngine::cmd_push_script(uint8 *p) {
_game.vars[29] = _mouse.y;
} else {
if (getVersion() >= 0x2915) {
- report("push.script\n");
+ debug(0, "push.script");
}
}
}
@@ -1518,7 +1518,7 @@ void AgiEngine::cmd_push_script(uint8 *p) {
void AgiEngine::cmd_set_pri_base(uint8 *p) {
int i, x, pri;
- report("Priority base set to %d\n", p0);
+ debug(0, "Priority base set to %d", p0);
// _game.alt_pri = true;
x = (_HEIGHT - p0) * _HEIGHT / 10;
diff --git a/engines/agi/op_dbg.cpp b/engines/agi/op_dbg.cpp
index be10f6ee75..f3b4815790 100644
--- a/engines/agi/op_dbg.cpp
+++ b/engines/agi/op_dbg.cpp
@@ -275,11 +275,11 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
uint8 a, c, z;
if (str) {
- report(" %s\n", str);
+ debug(0, " %s", str);
return;
}
- report("%03d:%04x ", lognum, ip);
+ debugN(0, "%03d:%04x ", lognum, ip);
switch (*(code + ip)) {
case 0xFC:
@@ -289,7 +289,7 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
x = logicNamesIf;
if (_debug.opcodes) {
- report("%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
+ debugN(0, "%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
" ",
(uint8)*(code + (0 + ip)) & 0xFF,
(uint8)*(code + (1 + ip)) & 0xFF,
@@ -301,7 +301,7 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
(uint8)*(code + (7 + ip)) & 0xFF,
(uint8)*(code + (8 + ip)) & 0xFF);
}
- report("%s ", (x + *(code + ip) - 0xFC)->name);
+ debugN(0, "%s ", (x + *(code + ip) - 0xFC)->name);
break;
default:
x = mode == lCOMMAND_MODE ? logicNamesCmd : logicNamesTest;
@@ -309,7 +309,7 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
c = (unsigned char)(x + *(code + ip))->argMask;
if (_debug.opcodes) {
- report("%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
+ debugN(0, "%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
" ",
(uint8)*(code + (0 + ip)) & 0xFF,
(uint8)*(code + (1 + ip)) & 0xFF,
@@ -321,23 +321,23 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
(uint8)*(code + (7 + ip)) & 0xFF,
(uint8)*(code + (8 + ip)) & 0xFF);
}
- report("%s ", (x + *(code + ip))->name);
+ debugN(0, "%s ", (x + *(code + ip))->name);
for (z = 1; a > 0;) {
if (~c & 0x80) {
- report("%d", *(code + (ip + z)));
+ debugN(0, "%d", *(code + (ip + z)));
} else {
- report("v%d[%d]", *(code + (ip + z)), getvar(*(code + (ip + z))));
+ debugN(0, "v%d[%d]", *(code + (ip + z)), getvar(*(code + (ip + z))));
}
c <<= 1;
z++;
if (--a > 0)
- report(",");
+ debugN(0, ",");
}
break;
}
- report("\n");
+ debugN(0, "\n");
}
} // End of namespace Agi
diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp
index ec8a1f4878..ea041a93c7 100644
--- a/engines/agi/preagi_mickey.cpp
+++ b/engines/agi/preagi_mickey.cpp
@@ -302,6 +302,8 @@ void Mickey::getMouseMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow, i
if (y != IDI_MSA_ROW_MENU_1) return;
sel = sel1;
break;
+ default:
+ return;
}
for (iWord = 0; iWord < menu.row[iRow].count; iWord++) {
@@ -1234,7 +1236,7 @@ int Mickey::getPlanet() {
if (!_game.nButtons)
return -1;
- for (int iPlanet = 0; iPlanet < IDI_MSA_MAX_DAT; iPlanet++) {
+ for (int iPlanet = 0; iPlanet < IDI_MSA_MAX_DAT - 1; iPlanet++) {
if (!strcmp(IDS_MSA_ADDR_PLANET[iPlanet], _game.szAddr)) {
return iPlanet;
}
@@ -1313,7 +1315,7 @@ void Mickey::flipSwitch() {
_game.iPlanetXtal[0] = IDI_MSA_PLANET_EARTH;
_game.iPlanetXtal[8] = IDI_MSA_PLANET_URANUS;
- for (int i = 1; i < 9; i++) {
+ for (int i = 1; i < IDI_MSA_MAX_PLANET; i++) {
if (i < 8) {
do {
// Earth (planet 0) and Uranus (planet 8) are excluded
diff --git a/engines/agi/predictive.cpp b/engines/agi/predictive.cpp
index 414477a381..250ac1df22 100644
--- a/engines/agi/predictive.cpp
+++ b/engines/agi/predictive.cpp
@@ -546,7 +546,7 @@ void AgiEngine::loadDict() {
#endif
uint32 time3 = _system->getMillis();
- printf("Time to parse pred.dic: %d, total: %d\n", time3-time2, time3-time1);
+ debug("Time to parse pred.dic: %d, total: %d", time3-time2, time3-time1);
}
bool AgiEngine::matchWord() {
diff --git a/engines/agi/sound_2gs.cpp b/engines/agi/sound_2gs.cpp
index cc1cd0f6d5..2748344b36 100644
--- a/engines/agi/sound_2gs.cpp
+++ b/engines/agi/sound_2gs.cpp
@@ -855,11 +855,10 @@ bool SoundGen2GS::loadInstrumentHeaders(const Common::FSNode &exePath, const IIg
// Check instrument set's md5sum
data->seek(exeInfo.instSetStart);
- char md5str[32+1];
- Common::md5_file_string(*data, md5str, exeInfo.instSet.byteCount);
- if (scumm_stricmp(md5str, exeInfo.instSet.md5)) {
+ Common::String md5str = Common::computeStreamMD5AsString(*data, exeInfo.instSet.byteCount);
+ if (md5str != exeInfo.instSet.md5) {
warning("Unknown Apple IIGS instrument set (md5: %s) in %s, trying to use it nonetheless",
- md5str, exePath.getPath().c_str());
+ md5str.c_str(), exePath.getPath().c_str());
}
// Read in the instrument set one instrument at a time
@@ -898,12 +897,11 @@ bool SoundGen2GS::loadWaveFile(const Common::FSNode &wavePath, const IIgsExeInfo
// Check that we got the whole wave file
if (uint8Wave && uint8Wave->size() == SIERRASTANDARD_SIZE) {
// Check wave file's md5sum
- char md5str[32+1];
- Common::md5_file_string(*uint8Wave, md5str, SIERRASTANDARD_SIZE);
- if (scumm_stricmp(md5str, exeInfo.instSet.waveFileMd5)) {
+ Common::String md5str = Common::computeStreamMD5AsString(*uint8Wave, SIERRASTANDARD_SIZE);
+ if (md5str != exeInfo.instSet.waveFileMd5) {
warning("Unknown Apple IIGS wave file (md5: %s, game: %s).\n" \
"Please report the information on the previous line to the ScummVM team.\n" \
- "Using the wave file as it is - music may sound weird", md5str, exeInfo.exePrefix);
+ "Using the wave file as it is - music may sound weird", md5str.c_str(), exeInfo.exePrefix);
}
uint8Wave->seek(0); // Seek wave to its start
diff --git a/engines/agi/sound_coco3.cpp b/engines/agi/sound_coco3.cpp
index f054be0682..858c1c8515 100644
--- a/engines/agi/sound_coco3.cpp
+++ b/engines/agi/sound_coco3.cpp
@@ -61,9 +61,9 @@ void SoundGenCoCo3::play(int resnum) {
uint32 start_time = _vm->_system->getMillis();
while (_vm->_system->getMillis() < start_time + note.duration) {
- _vm->_system->updateScreen();
+ _vm->_system->updateScreen();
- _vm->_system->delayMillis(10);
+ _vm->_system->delayMillis(10);
}
}
} while (note.freq != 0xff);
diff --git a/engines/agi/sound_midi.cpp b/engines/agi/sound_midi.cpp
index 0c8b3fa36a..f7f38a8d55 100644
--- a/engines/agi/sound_midi.cpp
+++ b/engines/agi/sound_midi.cpp
@@ -294,7 +294,7 @@ static uint32 convertSND2MIDI(byte *snddata, byte **data) {
for (n = 0; n < 3; n++) {
uint16 start, end, pos;
-
+
st.write("MTrk", 4);
lp = st.pos();
st.writeUint32BE(0); /* chunklength */
diff --git a/engines/agi/sound_sarien.cpp b/engines/agi/sound_sarien.cpp
index 08bdd47497..4ede50a749 100644
--- a/engines/agi/sound_sarien.cpp
+++ b/engines/agi/sound_sarien.cpp
@@ -95,13 +95,10 @@ SoundGenSarien::SoundGenSarien(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(v
break;
}
- report("Initializing sound:\n");
-
- report("sound: envelopes ");
if (_env) {
- report("enabled (decay=%d, sustain=%d)\n", ENV_DECAY, ENV_SUSTAIN);
+ debug(0, "Initializing sound: envelopes enabled (decay=%d, sustain=%d)", ENV_DECAY, ENV_SUSTAIN);
} else {
- report("disabled\n");
+ debug(0, "Initializing sound: envelopes disabled");
}
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index 464c218ae8..c48ed90ad8 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -52,10 +52,10 @@ int AgiEngine::loadWords(const char *fname) {
words = NULL;
if (!fp.open(fname)) {
- report("Warning: can't open %s\n", fname);
+ warning("loadWords: can't open %s", fname);
return errOK; // err_BadFileOpen
}
- report("Loading dictionary: %s\n", fname);
+ debug(0, "Loading dictionary: %s", fname);
fp.seek(0, SEEK_END);
flen = fp.pos();
diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp
index 0c8e6dd63c..68fa521178 100644
--- a/engines/agos/agos.cpp
+++ b/engines/agos/agos.cpp
@@ -42,8 +42,6 @@
#include "sound/mididrv.h"
#include "sound/mods/protracker.h"
-using Common::File;
-
namespace AGOS {
static const GameSpecificSettings simon1_settings = {
diff --git a/engines/agos/agos.h b/engines/agos/agos.h
index b12bf09d62..17f476cb50 100644
--- a/engines/agos/agos.h
+++ b/engines/agos/agos.h
@@ -47,8 +47,13 @@
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Elvira: Mistress of the Dark
+ * - Elvira 2: The Jaws of Cerberus
+ * - The Feeble Files
+ * - Simon the Sorcerer
+ * - Simon the Sorcerer 2
+ * - Simon the Sorcerer Puzzle Pack
*/
namespace AGOS {
@@ -2093,6 +2098,8 @@ protected:
void startOverlayAnims();
void startAnOverlayAnim();
+ void printInfoText(const char *itemText);
+
virtual char *genSaveName(int slot);
};
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index af85c50114..4fe8f8e6bc 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -250,7 +250,7 @@ bool MoviePlayerDXA::load() {
}
}
- Common::String videoName = Common::String::printf("%s.dxa", baseName);
+ Common::String videoName = Common::String::format("%s.dxa", baseName);
if (!loadFile(videoName))
error("Failed to load video file %s", videoName.c_str());
@@ -410,7 +410,7 @@ MoviePlayerSMK::MoviePlayerSMK(AGOSEngine_Feeble *vm, const char *name)
}
bool MoviePlayerSMK::load() {
- Common::String videoName = Common::String::printf("%s.smk", baseName);
+ Common::String videoName = Common::String::format("%s.smk", baseName);
if (!loadFile(videoName))
error("Failed to load video file %s", videoName.c_str());
diff --git a/engines/agos/debug.cpp b/engines/agos/debug.cpp
index 519dfc344c..cb11d65218 100644
--- a/engines/agos/debug.cpp
+++ b/engines/agos/debug.cpp
@@ -76,30 +76,30 @@ const byte *AGOSEngine::dumpOpcode(const byte *p) {
while (*st != '|')
st++;
- printf("%s ", st + 1);
+ debugN("%s ", st + 1);
for (;;) {
switch (*s++) {
case 'x':
- printf("\n");
+ debugN("\n");
return NULL;
case '|':
- printf("\n");
+ debugN("\n");
return p;
case 'B':{
byte b = *p++;
if (b == 255)
- printf("[%d] ", *p++);
+ debugN("[%d] ", *p++);
else
- printf("%d ", b);
+ debugN("%d ", b);
break;
}
case 'V':{
byte b = *p++;
if (b == 255)
- printf("[[%d]] ", *p++);
+ debugN("[[%d]] ", *p++);
else
- printf("[%d] ", b);
+ debugN("[%d] ", b);
break;
}
@@ -108,15 +108,15 @@ const byte *AGOSEngine::dumpOpcode(const byte *p) {
p += 2;
if (getGameType() == GType_PP) {
if (n >= 60000 && n < 62048)
- printf("[%d] ", n - 60000);
+ debugN("[%d] ", n - 60000);
else
- printf("%d ", n);
+ debugN("%d ", n);
} else {
if (n >= 30000 && n < 30512)
- printf("[%d] ", n - 30000);
+ debugN("[%d] ", n - 30000);
else
- printf("%d ", n);
+ debugN("%d ", n);
}
break;
}
@@ -124,7 +124,7 @@ const byte *AGOSEngine::dumpOpcode(const byte *p) {
case 'w':{
int n = (int16)READ_BE_UINT16(p);
p += 2;
- printf("%d ", n);
+ debugN("%d ", n);
break;
}
@@ -132,22 +132,22 @@ const byte *AGOSEngine::dumpOpcode(const byte *p) {
int n = (int16)READ_BE_UINT16(p);
p += 2;
if (n == -1)
- printf("SUBJECT_ITEM ");
+ debugN("SUBJECT_ITEM ");
else if (n == -3)
- printf("OBJECT_ITEM ");
+ debugN("OBJECT_ITEM ");
else if (n == -5)
- printf("ME_ITEM ");
+ debugN("ME_ITEM ");
else if (n == -7)
- printf("ACTOR_ITEM ");
+ debugN("ACTOR_ITEM ");
else if (n == -9)
- printf("ITEM_A_PARENT ");
+ debugN("ITEM_A_PARENT ");
else
- printf("<%d> ", n);
+ debugN("<%d> ", n);
break;
}
case 'J':{
- printf("-> ");
+ debugN("-> ");
}
break;
@@ -155,9 +155,9 @@ const byte *AGOSEngine::dumpOpcode(const byte *p) {
uint n = READ_BE_UINT16(p);
p += 2;
if (n != 0xFFFF)
- printf("\"%s\"(%d) ", getStringPtrByID(n), n);
+ debugN("\"%s\"(%d) ", getStringPtrByID(n), n);
else
- printf("NULL_STRING ");
+ debugN("NULL_STRING ");
}
break;
}
@@ -167,11 +167,11 @@ const byte *AGOSEngine::dumpOpcode(const byte *p) {
void AGOSEngine::dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
const byte *p;
- printf("; ****\n");
+ debugN("; ****\n");
p = (byte *)sl + SUBROUTINE_LINE_SMALL_SIZE;
if (sub->id == 0) {
- printf("; verb=%d, noun1=%d, noun2=%d\n", sl->verb, sl->noun1, sl->noun2);
+ debugN("; verb=%d, noun1=%d, noun2=%d\n", sl->verb, sl->noun1, sl->noun2);
p = (byte *)sl + SUBROUTINE_LINE_BIG_SIZE;
}
@@ -185,12 +185,12 @@ void AGOSEngine::dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
void AGOSEngine::dumpSubroutine(Subroutine *sub) {
SubroutineLine *sl;
- printf("\n******************************************\n;Subroutine, ID=%d:\nSUB_%d:\n", sub->id, sub->id);
+ debugN("\n******************************************\n;Subroutine, ID=%d:\nSUB_%d:\n", sub->id, sub->id);
sl = (SubroutineLine *)((byte *)sub + sub->first);
for (; (byte *)sl != (byte *)sub; sl = (SubroutineLine *)((byte *)sub + sl->next)) {
dumpSubroutineLine(sl, sub);
}
- printf("\nEND ******************************************\n");
+ debugN("\nEND ******************************************\n");
}
void AGOSEngine::dumpSubroutines() {
@@ -245,35 +245,35 @@ void AGOSEngine::dumpVideoScript(const byte *src, bool singeOpcode) {
while (*strn != '|')
strn++;
- printf("%.2d: %s ", opcode, strn + 1);
+ debugN("%.2d: %s ", opcode, strn + 1);
int end = (getGameType() == GType_FF || getGameType() == GType_PP) ? 9999 : 999;
for (; *str != '|'; str++) {
switch (*str) {
case 'x':
- printf("\n");
+ debugN("\n");
return;
case 'b':
- printf("%d ", *src++);
+ debugN("%d ", *src++);
break;
case 'd':
- printf("%d ", (int16)readUint16Wrapper(src));
+ debugN("%d ", (int16)readUint16Wrapper(src));
src += 2;
break;
case 'v':
- printf("[%d] ", readUint16Wrapper(src));
+ debugN("[%d] ", readUint16Wrapper(src));
src += 2;
break;
case 'i':
- printf("%d ", (int16)readUint16Wrapper(src));
+ debugN("%d ", (int16)readUint16Wrapper(src));
src += 2;
break;
case 'j':
- printf("-> ");
+ debugN("-> ");
break;
case 'q':
while (readUint16Wrapper(src) != end) {
- printf("(%d,%d) ", readUint16Wrapper(src),
+ debugN("(%d,%d) ", readUint16Wrapper(src),
readUint16Wrapper(src + 2));
src += 4;
}
@@ -284,7 +284,7 @@ void AGOSEngine::dumpVideoScript(const byte *src, bool singeOpcode) {
}
}
- printf("\n");
+ debugN("\n");
} while (!singeOpcode);
}
@@ -293,10 +293,10 @@ void AGOSEngine::dumpVgaScript(const byte *ptr, uint16 res, uint16 id) {
}
void AGOSEngine::dumpVgaScriptAlways(const byte *ptr, uint16 res, uint16 id) {
- printf("; address=%x, vgafile=%d vgasprite=%d\n",
+ debugN("; address=%x, vgafile=%d vgasprite=%d\n",
(unsigned int)(ptr - _vgaBufferPointers[res].vgaFile1), res, id);
dumpVideoScript(ptr, false);
- printf("; end\n");
+ debugN("; end\n");
}
void AGOSEngine::dumpAllVgaImageFiles() {
diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp
index 32c26752a2..2f7fdb6256 100644
--- a/engines/agos/event.cpp
+++ b/engines/agos/event.cpp
@@ -36,6 +36,7 @@
#include "graphics/surface.h"
+
namespace AGOS {
void AGOSEngine::addTimeEvent(uint16 timeout, uint16 subroutine_id) {
diff --git a/engines/agos/menus.cpp b/engines/agos/menus.cpp
index df837a5e16..5629a1dca6 100644
--- a/engines/agos/menus.cpp
+++ b/engines/agos/menus.cpp
@@ -33,8 +33,6 @@
#include "agos/agos.h"
#include "agos/intern.h"
-using Common::File;
-
namespace AGOS {
void AGOSEngine::loadMenuFile() {
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index 858307685c..fe2d1cd25b 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -226,7 +226,7 @@ void MidiPlayer::startTrack(int track) {
parser->setMidiDriver(this);
parser->setTimerRate(_driver->getBaseTempo());
if (!parser->loadMusic(_music.songs[track], _music.song_sizes[track])) {
- printf ("Error reading track!\n");
+ warning("Error reading track %d", track);
delete parser;
parser = 0;
}
@@ -455,7 +455,7 @@ void MidiPlayer::loadSMF(Common::File *in, int song, bool sfx) {
parser->setMidiDriver(this);
parser->setTimerRate(timerRate);
if (!parser->loadMusic(p->data, size)) {
- printf("Error reading track!\n");
+ warning("Error reading track");
delete parser;
parser = 0;
}
@@ -484,7 +484,7 @@ void MidiPlayer::loadMultipleSMF(Common::File *in, bool sfx) {
p->num_songs = in->readByte();
if (p->num_songs > 16) {
- printf ("playMultipleSMF: %d is too many songs to keep track of!\n", (int)p->num_songs);
+ warning("playMultipleSMF: %d is too many songs to keep track of", (int)p->num_songs);
return;
}
@@ -496,7 +496,7 @@ void MidiPlayer::loadMultipleSMF(Common::File *in, bool sfx) {
// Make sure there's a MThd
in->read(buf, 4);
if (memcmp(buf, "MThd", 4)) {
- printf("Expected MThd but found '%c%c%c%c' instead!\n", buf[0], buf[1], buf[2], buf[3]);
+ warning("Expected MThd but found '%c%c%c%c' instead", buf[0], buf[1], buf[2], buf[3]);
return;
}
in->seek(in->readUint32BE(), SEEK_CUR);
diff --git a/engines/agos/res.cpp b/engines/agos/res.cpp
index cb48e5e50b..5775e71a7a 100644
--- a/engines/agos/res.cpp
+++ b/engines/agos/res.cpp
@@ -35,8 +35,6 @@
#include "common/zlib.h"
-using Common::File;
-
namespace AGOS {
#ifdef ENABLE_AGOS2
@@ -67,7 +65,7 @@ uint32 AGOSEngine::readUint32Wrapper(const void *src) {
void AGOSEngine::decompressData(const char *srcName, byte *dst, uint32 offset, uint32 srcSize, uint32 dstSize) {
#ifdef USE_ZLIB
- File in;
+ Common::File in;
in.open(srcName);
if (in.isOpen() == false)
error("decompressData: Can't load %s", srcName);
@@ -548,7 +546,7 @@ uint fileReadItemID(Common::SeekableReadStream *in) {
}
void AGOSEngine::openGameFile() {
- _gameFile = new File();
+ _gameFile = new Common::File();
_gameFile->open(getFileName(GAME_GMEFILE));
if (!_gameFile->isOpen())
@@ -783,7 +781,7 @@ void AGOSEngine::loadVGABeardFile(uint16 id) {
uint32 offs, size;
if (getFeatures() & GF_OLD_BUNDLE) {
- File in;
+ Common::File in;
char filename[15];
if (id == 23)
id = 112;
@@ -824,7 +822,7 @@ void AGOSEngine::loadVGABeardFile(uint16 id) {
}
void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) {
- File in;
+ Common::File in;
char filename[15];
byte *dst;
uint32 file, offs, srcSize, dstSize;
diff --git a/engines/agos/res_snd.cpp b/engines/agos/res_snd.cpp
index c6417962fb..29a4242970 100644
--- a/engines/agos/res_snd.cpp
+++ b/engines/agos/res_snd.cpp
@@ -34,8 +34,6 @@
#include "sound/mididrv.h"
#include "sound/mods/protracker.h"
-using Common::File;
-
namespace AGOS {
void AGOSEngine_Simon1::playSpeech(uint16 speech_id, uint16 vgaSpriteId) {
@@ -174,7 +172,7 @@ static const ModuleOffs amigaWaxworksOffs[20] = {
void AGOSEngine::playModule(uint16 music) {
char filename[15];
- File f;
+ Common::File f;
uint32 offs = 0;
if (getPlatform() == Common::kPlatformAmiga && getGameType() == GType_WW) {
@@ -261,7 +259,7 @@ void AGOSEngine_Simon1::playMusic(uint16 music, uint16 track) {
// TODO: Add support for Desktop Tracker format in Acorn disk version
} else {
char filename[15];
- File f;
+ Common::File f;
sprintf(filename, "MOD%d.MUS", music);
f.open(filename);
if (f.isOpen() == false)
@@ -290,7 +288,7 @@ void AGOSEngine::playMusic(uint16 music, uint16 track) {
_midi.setLoop(true); // Must do this BEFORE loading music.
char filename[15];
- File f;
+ Common::File f;
sprintf(filename, "MOD%d.MUS", music);
f.open(filename);
if (f.isOpen() == false)
@@ -315,7 +313,7 @@ void AGOSEngine::playSting(uint16 soundId) {
char filename[15];
- File mus_file;
+ Common::File mus_file;
uint16 mus_offset;
sprintf(filename, "STINGS%i.MUS", _soundFileId);
@@ -346,7 +344,7 @@ static const byte elvira1_soundTable[100] = {
};
bool AGOSEngine::loadVGASoundFile(uint16 id, uint8 type) {
- File in;
+ Common::File in;
char filename[15];
byte *dst;
uint32 srcSize, dstSize;
@@ -451,7 +449,7 @@ static const char *dimpSoundList[32] = {
void AGOSEngine::loadSoundFile(const char* filename) {
- File in;
+ Common::File in;
in.open(filename);
if (in.isOpen() == false)
@@ -470,7 +468,7 @@ void AGOSEngine::loadSound(uint16 sound, int16 pan, int16 vol, uint16 type) {
byte *dst;
if (getGameId() == GID_DIMP) {
- File in;
+ Common::File in;
char filename[15];
assert(sound >= 1 && sound <= 32);
diff --git a/engines/agos/rooms.cpp b/engines/agos/rooms.cpp
index 91c8a53681..a2eff06fcc 100644
--- a/engines/agos/rooms.cpp
+++ b/engines/agos/rooms.cpp
@@ -30,24 +30,22 @@
#include "agos/agos.h"
#include "agos/intern.h"
-using Common::File;
-
namespace AGOS {
uint16 AGOSEngine::getBackExit(int n) {
switch (n) {
- case 0:
- return 2;
- case 1:
- return 3;
- case 2:
- return 0;
- case 3:
- return 1;
- case 4:
- return 5;
- case 5:
- return 4;
+ case 0:
+ return 2;
+ case 1:
+ return 3;
+ case 2:
+ return 0;
+ case 3:
+ return 1;
+ case 4:
+ return 5;
+ case 5:
+ return 4;
}
return 0;
@@ -205,13 +203,13 @@ void AGOSEngine_Elvira2::moveDirn(Item *i, uint x) {
if (n == 1) {
sr = (SubSuperRoom *)findChildOfType(p, kSuperRoomType);
switch (x) {
- case 0: a = -(sr->roomX); break;
- case 1: a = 1; break;
- case 2: a = sr->roomX; break;
- case 3: a = 0xFFFF; break;
- case 4: a = -(sr->roomX * sr->roomY); break;
- case 5: a = (sr->roomX * sr->roomY); break;
- default: return;
+ case 0: a = -(sr->roomX); break;
+ case 1: a = 1; break;
+ case 2: a = sr->roomX; break;
+ case 3: a = 0xFFFF; break;
+ case 4: a = -(sr->roomX * sr->roomY); break;
+ case 5: a = (sr->roomX * sr->roomY); break;
+ default: return;
}
_superRoomNumber += a;
}
@@ -366,7 +364,7 @@ bool AGOSEngine::loadRoomItems(uint16 room) {
byte *p;
uint i, minNum, maxNum;
char filename[30];
- File in;
+ Common::File in;
Item *item, *itemTmp;
if (_roomsList == NULL)
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp
index ffa95506c5..eefa2460ec 100644
--- a/engines/agos/saveload.cpp
+++ b/engines/agos/saveload.cpp
@@ -154,7 +154,7 @@ void AGOSEngine::quickLoadOrSave() {
Subroutine *sub;
success = loadGame(genSaveName(_saveLoadSlot));
if (!success) {
- buf = Common::String::printf(_("Failed to load game state from file:\n\n%s"), filename);
+ buf = Common::String::format(_("Failed to load game state from file:\n\n%s"), filename);
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
drawIconArray(2, me(), 0, 0);
setBitFlag(97, true);
@@ -189,7 +189,7 @@ void AGOSEngine::quickLoadOrSave() {
} else {
success = saveGame(_saveLoadSlot, _saveLoadName);
if (!success)
- buf = Common::String::printf(_("Failed to save game state to file:\n\n%s"), filename);
+ buf = Common::String::format(_("Failed to save game state to file:\n\n%s"), filename);
}
if (!success) {
@@ -197,7 +197,7 @@ void AGOSEngine::quickLoadOrSave() {
dialog.runModal();
} else if (_saveLoadType == 1) {
- buf = Common::String::printf(_("Successfully saved game state in file:\n\n%s"), filename);
+ buf = Common::String::format(_("Successfully saved game state in file:\n\n%s"), filename);
GUI::TimedMessageDialog dialog(buf, 1500);
dialog.runModal();
diff --git a/engines/agos/script_pn.cpp b/engines/agos/script_pn.cpp
index 0391d67b31..909c051362 100644
--- a/engines/agos/script_pn.cpp
+++ b/engines/agos/script_pn.cpp
@@ -890,7 +890,7 @@ int AGOSEngine_PN::doline(int needsave) {
int myTag = ++_tagOfActiveDoline; // Obtain a unique tag for this doline invocation
_dolineReturnVal = 0;
- if (needsave)
+ if (_stackbase && needsave)
_stackbase->tagOfParentDoline = myTag;
do {
diff --git a/engines/agos/script_pp.cpp b/engines/agos/script_pp.cpp
index 01c467a07e..bded0f69dd 100644
--- a/engines/agos/script_pp.cpp
+++ b/engines/agos/script_pp.cpp
@@ -336,13 +336,12 @@ void AGOSEngine_PuzzlePack::opp_loadMouseImage() {
void AGOSEngine_PuzzlePack::opp_message() {
// 63: show string nl
-
+ const byte *stringPtr = getStringPtrByID(getNextStringID());
if (getBitFlag(105)) {
// Swampy adventures
- getStringPtrByID(getNextStringID());
-// printInfoText(getStringPtrByID(getNextStringID()));
+ printInfoText((const char *)stringPtr);
} else {
- showMessageFormat("%s\n", getStringPtrByID(getNextStringID()));
+ showMessageFormat("%s\n", stringPtr);
}
}
diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp
index 6ec72814fa..8914470370 100644
--- a/engines/agos/sound.cpp
+++ b/engines/agos/sound.cpp
@@ -38,23 +38,21 @@
#include "sound/decoders/vorbis.h"
#include "sound/decoders/wave.h"
-using Common::File;
-
namespace AGOS {
#define SOUND_BIG_ENDIAN true
class BaseSound : Common::NonCopyable {
protected:
- File *_file;
+ Common::File *_file;
uint32 *_offsets;
Audio::Mixer *_mixer;
bool _freeOffsets;
DisposeAfterUse::Flag _disposeFile;
public:
- BaseSound(Audio::Mixer *mixer, File *file, uint32 base, bool bigEndian, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES);
- BaseSound(Audio::Mixer *mixer, File *file, uint32 *offsets, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES);
+ BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 base, bool bigEndian, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES);
+ BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 *offsets, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES);
virtual ~BaseSound();
void playSound(uint sound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, bool loop, int vol = 0) {
@@ -64,7 +62,7 @@ public:
virtual Audio::AudioStream *makeAudioStream(uint sound) = 0;
};
-BaseSound::BaseSound(Audio::Mixer *mixer, File *file, uint32 base, bool bigEndian, DisposeAfterUse::Flag disposeFileAfterUse)
+BaseSound::BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 base, bool bigEndian, DisposeAfterUse::Flag disposeFileAfterUse)
: _mixer(mixer), _file(file), _disposeFile(disposeFileAfterUse) {
uint res = 0;
@@ -98,7 +96,7 @@ BaseSound::BaseSound(Audio::Mixer *mixer, File *file, uint32 base, bool bigEndia
_offsets[res] = _file->size();
}
-BaseSound::BaseSound(Audio::Mixer *mixer, File *file, uint32 *offsets, DisposeAfterUse::Flag disposeFileAfterUse)
+BaseSound::BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 *offsets, DisposeAfterUse::Flag disposeFileAfterUse)
: _mixer(mixer), _file(file), _disposeFile(disposeFileAfterUse) {
_offsets = offsets;
@@ -225,9 +223,9 @@ static void convertPan(int &pan) {
class WavSound : public BaseSound {
public:
- WavSound(Audio::Mixer *mixer, File *file, uint32 base = 0, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES)
+ WavSound(Audio::Mixer *mixer, Common::File *file, uint32 base = 0, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES)
: BaseSound(mixer, file, base, false, disposeFileAfterUse) {}
- WavSound(Audio::Mixer *mixer, File *file, uint32 *offsets) : BaseSound(mixer, file, offsets) {}
+ WavSound(Audio::Mixer *mixer, Common::File *file, uint32 *offsets) : BaseSound(mixer, file, offsets) {}
Audio::AudioStream *makeAudioStream(uint sound);
void playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, bool loop, int vol = 0);
};
@@ -251,7 +249,7 @@ void WavSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType typ
class VocSound : public BaseSound {
const byte _flags;
public:
- VocSound(Audio::Mixer *mixer, File *file, bool isUnsigned, uint32 base = 0, bool bigEndian = false, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES)
+ VocSound(Audio::Mixer *mixer, Common::File *file, bool isUnsigned, uint32 base = 0, bool bigEndian = false, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES)
: BaseSound(mixer, file, base, bigEndian, disposeFileAfterUse), _flags(isUnsigned ? Audio::FLAG_UNSIGNED : 0) {}
Audio::AudioStream *makeAudioStream(uint sound);
void playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, bool loop, int vol = 0);
@@ -275,7 +273,7 @@ void VocSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType typ
class RawSound : public BaseSound {
const byte _flags;
public:
- RawSound(Audio::Mixer *mixer, File *file, bool isUnsigned)
+ RawSound(Audio::Mixer *mixer, Common::File *file, bool isUnsigned)
: BaseSound(mixer, file, 0, SOUND_BIG_ENDIAN), _flags(isUnsigned ? Audio::FLAG_UNSIGNED : 0) {}
Audio::AudioStream *makeAudioStream(uint sound);
void playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, bool loop, int vol = 0);
@@ -305,7 +303,7 @@ void RawSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType typ
class CompressedSound : public BaseSound {
public:
- CompressedSound(Audio::Mixer *mixer, File *file, uint32 base) : BaseSound(mixer, file, base, false) {}
+ CompressedSound(Audio::Mixer *mixer, Common::File *file, uint32 base) : BaseSound(mixer, file, base, false) {}
Common::MemoryReadStream *loadStream(uint sound) const {
if (_offsets == NULL)
@@ -334,7 +332,7 @@ public:
#ifdef USE_MAD
class MP3Sound : public CompressedSound {
public:
- MP3Sound(Audio::Mixer *mixer, File *file, uint32 base = 0) : CompressedSound(mixer, file, base) {}
+ MP3Sound(Audio::Mixer *mixer, Common::File *file, uint32 base = 0) : CompressedSound(mixer, file, base) {}
Audio::AudioStream *makeAudioStream(uint sound) {
Common::MemoryReadStream *tmp = loadStream(sound);
if (!tmp)
@@ -350,7 +348,7 @@ public:
#ifdef USE_VORBIS
class VorbisSound : public CompressedSound {
public:
- VorbisSound(Audio::Mixer *mixer, File *file, uint32 base = 0) : CompressedSound(mixer, file, base) {}
+ VorbisSound(Audio::Mixer *mixer, Common::File *file, uint32 base = 0) : CompressedSound(mixer, file, base) {}
Audio::AudioStream *makeAudioStream(uint sound) {
Common::MemoryReadStream *tmp = loadStream(sound);
if (!tmp)
@@ -366,7 +364,7 @@ public:
#ifdef USE_FLAC
class FLACSound : public CompressedSound {
public:
- FLACSound(Audio::Mixer *mixer, File *file, uint32 base = 0) : CompressedSound(mixer, file, base) {}
+ FLACSound(Audio::Mixer *mixer, Common::File *file, uint32 base = 0) : CompressedSound(mixer, file, base) {}
Audio::AudioStream *makeAudioStream(uint sound) {
Common::MemoryReadStream *tmp = loadStream(sound);
if (!tmp)
@@ -379,7 +377,7 @@ public:
///////////////////////////////////////////////////////////////////////////////
#pragma mark -
-static CompressedSound *makeCompressedSound(Audio::Mixer *mixer, File *file, const Common::String &basename) {
+static CompressedSound *makeCompressedSound(Audio::Mixer *mixer, Common::File *file, const Common::String &basename) {
#ifdef USE_FLAC
file->open(basename + ".fla");
if (file->isOpen()) {
@@ -451,7 +449,7 @@ void Sound::loadVoiceFile(const GameSpecificSettings *gss) {
char filename[16];
- File *file = new File();
+ Common::File *file = new Common::File();
if (!_hasVoiceFile) {
_voice = makeCompressedSound(_mixer, file, gss->speech_filename);
@@ -506,7 +504,7 @@ void Sound::loadVoiceFile(const GameSpecificSettings *gss) {
void Sound::loadSfxFile(const GameSpecificSettings *gss) {
char filename[16];
- File *file = new File();
+ Common::File *file = new Common::File();
if (!_hasEffectsFile) {
_effects = makeCompressedSound(_mixer, file, gss->effects_filename);
@@ -540,7 +538,7 @@ void Sound::readSfxFile(const Common::String &filename) {
_mixer->stopHandle(_effectsHandle);
- File *file = new File();
+ Common::File *file = new Common::File();
file->open(filename);
if (file->isOpen() == false) {
@@ -557,7 +555,7 @@ void Sound::readSfxFile(const Common::String &filename) {
}
// This method is only used by Simon2
-void Sound::loadSfxTable(File *gameFile, uint32 base) {
+void Sound::loadSfxTable(Common::File *gameFile, uint32 base) {
stopAll();
delete _effects;
@@ -572,7 +570,7 @@ void Sound::loadSfxTable(File *gameFile, uint32 base) {
void Sound::readVoiceFile(const Common::String &filename) {
_mixer->stopHandle(_voiceHandle);
- File *file = new File();
+ Common::File *file = new Common::File();
file->open(filename);
if (file->isOpen() == false)
@@ -592,7 +590,7 @@ void Sound::playVoice(uint sound) {
char filename[16];
_lastVoiceFile = _filenums[sound];
sprintf(filename, "voices%d.dat", _filenums[sound]);
- File *file = new File();
+ Common::File *file = new Common::File();
file->open(filename);
if (file->isOpen() == false)
error("playVoice: Can't load voice file %s", filename);
@@ -801,7 +799,7 @@ void Sound::switchVoiceFile(const GameSpecificSettings *gss, uint disc) {
_lastVoiceFile = disc;
char filename[16];
- File *file = new File();
+ Common::File *file = new Common::File();
if (!_hasVoiceFile) {
sprintf(filename, "%s%d", gss->speech_filename, disc);
diff --git a/engines/agos/string.cpp b/engines/agos/string.cpp
index 40506e4874..ed56cbd266 100644
--- a/engines/agos/string.cpp
+++ b/engines/agos/string.cpp
@@ -27,11 +27,12 @@
#include "common/file.h"
+#include "gui/about.h"
+#include "gui/message.h"
+
#include "agos/agos.h"
#include "agos/intern.h"
-using Common::File;
-
namespace AGOS {
void AGOSEngine::uncompressText(byte *ptr) {
@@ -265,7 +266,7 @@ uint AGOSEngine::loadTextFile(const char *filename, byte *dst) {
}
uint AGOSEngine::loadTextFile_simon1(const char *filename, byte *dst) {
- File fo;
+ Common::File fo;
fo.open(filename);
uint32 size;
@@ -561,6 +562,162 @@ void AGOSEngine::printScreenText(uint vgaSpriteId, uint color, const char *strin
}
#ifdef ENABLE_AGOS2
+// Swampy Adventures specific
+void AGOSEngine_PuzzlePack::printInfoText(const char *itemText) {
+ const char *itemName = NULL;
+ int flag = (_mouse.y / 32) * 20 + (_mouse.x / 32) + 1300;
+
+ switch (_variableArray[999]) {
+ case 80:
+ if (_variableArray[flag]) {
+ if (_variableArray[flag] == 201)
+ itemName = " Bridge: ";
+ if (_variableArray[flag] == 231 || _variableArray[flag] == 241)
+ itemName = " Log: ";
+ if (_variableArray[flag] == 281)
+ itemName = " Rubble: ";
+ if (_variableArray[flag] == 291)
+ itemName = " Boulder: ";
+ if (_variableArray[flag] == 311)
+ itemName = " Key: ";
+ if (_variableArray[flag] == 312)
+ itemName = " Spanner: ";
+ if (_variableArray[flag] == 321)
+ itemName = " Gate: ";
+ if (_variableArray[flag] == 331)
+ itemName = " Crate: ";
+ } else {
+ flag -= 300;
+ if (_variableArray[flag] == 2)
+ itemName = " Water: ";
+ if (_variableArray[flag] == 5)
+ itemName = " Exit: ";
+ if ((_variableArray[flag] == 5) && (_variableArray[81] == 10))
+ itemName = " Gem: ";
+ if (_variableArray[flag] == 236 || _variableArray[flag] == 246)
+ itemName = " Floating Log: ";
+ if (_variableArray[flag] == 400)
+ itemName = " Valve: ";
+ }
+ break;
+
+ case 81:
+ if (_variableArray[flag]) {
+ if (_variableArray[flag] == 281)
+ itemName = " Cracked Block: ";
+ if (_variableArray[flag] == 291)
+ itemName = " Boulder: ";
+ if (_variableArray[flag] == 331)
+ itemName = " Block: ";
+ if (_variableArray[flag] == 341)
+ itemName = " Switch: ";
+ if (_variableArray[flag] == 343)
+ itemName = " Button: ";
+ if ((_variableArray[flag] > 430) && (_variableArray[flag] < 480))
+ itemName = " Mosaic Block: ";
+ } else {
+ flag -= 300;
+ if (_variableArray[flag] == 5)
+ itemName = " Exit: ";
+ if ((_variableArray[flag] == 5) && (_variableArray[82] == 10))
+ itemName = " Gem: ";
+ }
+ break;
+
+ case 82:
+ if (_variableArray[flag]) {
+ if (_variableArray[flag] == 201 || _variableArray[flag] == 211)
+ itemName = " Unstable Track: ";
+ if (_variableArray[flag] == 281)
+ itemName = " Rubble Pile: ";
+ if (_variableArray[flag] == 291)
+ itemName = " Boulder: ";
+ if (_variableArray[flag] == 331)
+ itemName = " Crate: ";
+ if (_variableArray[flag] == 401 || _variableArray[flag] == 405)
+ itemName = " Cart: ";
+ } else {
+ flag -= 300;
+ if (_variableArray[flag] == 4)
+ itemName = " Hole: ";
+ if (_variableArray[flag] == 5)
+ itemName = " Exit: ";
+ if ((_variableArray[flag] == 5) && (_variableArray[83] == 10))
+ itemName = " Gem: ";
+ if ((_variableArray[flag] > 5) && (_variableArray[flag] < 10))
+ itemName = " Buffer Track: ";
+ if ((_variableArray[flag] > 9) && (_variableArray[flag] < 40))
+ itemName = " Track: ";
+ if (_variableArray[flag] == 300)
+ itemName = " Boulder: ";
+ }
+ break;
+
+ case 83:
+ if (_variableArray[flag]) {
+ if (_variableArray[flag] == 201)
+ itemName = " Broken Floor: ";
+ if (_variableArray[flag] == 231 || _variableArray[flag] == 241)
+ itemName = " Barrel: ";
+ if (_variableArray[flag] == 281)
+ itemName = " Cracked Rock: ";
+ if (_variableArray[flag] == 291)
+ itemName = " Spacehopper: ";
+ if (_variableArray[flag] == 311)
+ itemName = " Key: ";
+ if (_variableArray[flag] == 321)
+ itemName = " Trapdoor: ";
+ if (_variableArray[flag] == 324)
+ itemName = " Trapdoor: ";
+ if (_variableArray[flag] == 331)
+ itemName = " Crate: ";
+ } else {
+ flag -= 300;
+ if (_variableArray[flag] == 4)
+ itemName = " Hole: ";
+ if (_variableArray[flag] == 239 || _variableArray[flag] == 249)
+ itemName = " Barrel: ";
+ }
+ break;
+
+ case 84:
+ if (_variableArray[flag]) {
+ if (_variableArray[flag] == 201)
+ itemName = " Floating Platform: ";
+ if (_variableArray[flag] == 231)
+ itemName = " Cauldron: ";
+ if (_variableArray[flag] == 281)
+ itemName = " Cracked Block: ";
+ if (_variableArray[flag] == 311 || _variableArray[flag] == 312)
+ itemName = " Key: ";
+ if (_variableArray[flag] == 321 || _variableArray[flag] == 361 || _variableArray[flag] == 371)
+ itemName = " Gate: ";
+ if (_variableArray[flag] == 331)
+ itemName = " Chest: ";
+ if (_variableArray[flag] == 332)
+ itemName = " Jewel: ";
+ if (_variableArray[flag] == 351 || _variableArray[flag] == 352)
+ itemName = " Babies: ";
+ } else {
+ flag -= 300;
+ if (_variableArray[flag] == 6)
+ itemName = " Slime: ";
+ if (_variableArray[flag] == 334)
+ itemName = " Chest: ";
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (itemName != NULL) {
+ Common::String buf = Common::String::format("%s\n%s", itemName, itemText);
+ GUI::TimedMessageDialog dialog(buf, 1500);
+ dialog.runModal();
+ }
+}
+
// The Feeble Files specific
void AGOSEngine_Feeble::printScreenText(uint vgaSpriteId, uint color, const char *string, int16 x, int16 y, int16 width) {
char convertedString[320];
diff --git a/engines/agos/subroutine.cpp b/engines/agos/subroutine.cpp
index 8dccded958..733d40e52d 100644
--- a/engines/agos/subroutine.cpp
+++ b/engines/agos/subroutine.cpp
@@ -30,8 +30,6 @@
#include "agos/agos.h"
#include "agos/intern.h"
-using Common::File;
-
namespace AGOS {
// Script opcodes to load into memory
@@ -262,22 +260,22 @@ void AGOSEngine::endCutscene() {
_runScriptReturn1 = true;
}
-File *AGOSEngine::openTablesFile(const char *filename) {
+Common::File *AGOSEngine::openTablesFile(const char *filename) {
if (getFeatures() & GF_OLD_BUNDLE)
return openTablesFile_simon1(filename);
else
return openTablesFile_gme(filename);
}
-File *AGOSEngine::openTablesFile_simon1(const char *filename) {
- File *fo = new File();
+Common::File *AGOSEngine::openTablesFile_simon1(const char *filename) {
+ Common::File *fo = new Common::File();
fo->open(filename);
if (fo->isOpen() == false)
error("openTablesFile: Can't open '%s'", filename);
return fo;
}
-File *AGOSEngine::openTablesFile_gme(const char *filename) {
+Common::File *AGOSEngine::openTablesFile_gme(const char *filename) {
uint res;
uint32 offs;
@@ -291,7 +289,7 @@ File *AGOSEngine::openTablesFile_gme(const char *filename) {
bool AGOSEngine::loadTablesIntoMem(uint16 subrId) {
byte *p;
uint16 min_num, max_num, file_num;
- File *in;
+ Common::File *in;
char filename[30];
if (_tblList == NULL)
@@ -340,7 +338,7 @@ bool AGOSEngine::loadTablesIntoMem(uint16 subrId) {
bool AGOSEngine_Waxworks::loadTablesIntoMem(uint16 subrId) {
byte *p;
uint min_num, max_num;
- File *in;
+ Common::File *in;
p = _tblList;
if (p == NULL)
@@ -407,7 +405,7 @@ bool AGOSEngine::loadXTablesIntoMem(uint16 subrId) {
int i;
uint min_num, max_num;
char filename[30];
- File *in;
+ Common::File *in;
p = _xtblList;
if (p == NULL)
@@ -457,7 +455,7 @@ bool AGOSEngine::loadXTablesIntoMem(uint16 subrId) {
return 0;
}
-void AGOSEngine::closeTablesFile(File *in) {
+void AGOSEngine::closeTablesFile(Common::File *in) {
if (getFeatures() & GF_OLD_BUNDLE) {
in->close();
delete in;
@@ -572,7 +570,7 @@ restart:
_codePtr += 8;
if (_dumpOpcodes)
- printf("; %d\n", sub->id);
+ debug("; %d", sub->id);
result = runScript();
if (result != 0) {
break;
diff --git a/engines/agos/verb_pn.cpp b/engines/agos/verb_pn.cpp
index 129e1dec0e..b36f634ec0 100644
--- a/engines/agos/verb_pn.cpp
+++ b/engines/agos/verb_pn.cpp
@@ -185,7 +185,7 @@ void AGOSEngine_PN::hitBox5(HitArea *ha) {
_mousePrintFG++;
_mouseString = (const char *)"take \0";
- _mouseString1 = getMessage(_objectName1, _dragStore->msg1);
+ _mouseString1 = _dragStore ? getMessage(_objectName1, _dragStore->msg1) : "";
if (_dragStore->flags & kOBFRoomBox)
_mouseString1 = (const char *)"all\r";
diff --git a/engines/agos/vga.cpp b/engines/agos/vga.cpp
index dd2df79c07..8b8b16c9bb 100644
--- a/engines/agos/vga.cpp
+++ b/engines/agos/vga.cpp
@@ -155,7 +155,7 @@ void AGOSEngine::runVgaScript() {
if (_dumpVgaOpcodes) {
if (_vcPtr != (const byte *)&_vcGetOutOfCode) {
- printf("%.5d %.5X: %5d %4d ", _vgaTickCounter, (unsigned int)(_vcPtr - _curVgaFile1), _vgaCurSpriteId, _vgaCurZoneNum);
+ debugN("%.5d %.5X: %5d %4d ", _vgaTickCounter, (unsigned int)(_vcPtr - _curVgaFile1), _vgaCurSpriteId, _vgaCurZoneNum);
dumpVideoScript(_vcPtr, true);
}
}
@@ -383,7 +383,7 @@ void AGOSEngine::vcSkipNextInstruction() {
}
if (_dumpVgaOpcodes)
- printf("; skipped\n");
+ debugN("; skipped\n");
}
// VGA Script commands
diff --git a/engines/agos/vga_ff.cpp b/engines/agos/vga_ff.cpp
index 0a6458ac11..38a3479292 100644
--- a/engines/agos/vga_ff.cpp
+++ b/engines/agos/vga_ff.cpp
@@ -405,9 +405,9 @@ void AGOSEngine_PuzzlePack::vc63_fastFadeIn() {
if (getBitFlag(100)) {
startOverlayAnims();
} else if (getBitFlag(103)) {
- printf("NameAndTime\n");
+ debug("vc63_fastFadeIn: NameAndTime");
} else if (getBitFlag(104)) {
- printf("HiScoreTable\n");
+ debug("vc63_fastFadeIn: HiScoreTable");
}
}
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp
index 5c2119c1e4..38a0eda13e 100644
--- a/engines/cine/cine.cpp
+++ b/engines/cine/cine.cpp
@@ -56,6 +56,7 @@ CineEngine::CineEngine(OSystem *syst, const CINEGameDescription *gameDesc) : Eng
DebugMan.addDebugChannel(kCineDebugScript, "Script", "Script debug level");
DebugMan.addDebugChannel(kCineDebugPart, "Part", "Part debug level");
DebugMan.addDebugChannel(kCineDebugSound, "Sound", "Sound debug level");
+ _console = new CineConsole(this);
// Setup mixer
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
@@ -74,7 +75,9 @@ CineEngine::~CineEngine() {
if (getGameType() == Cine::GType_OS) {
freeErrmessDat();
}
+
DebugMan.clearAllDebugChannels();
+ delete _console;
}
Common::Error CineEngine::run() {
diff --git a/engines/cine/cine.h b/engines/cine/cine.h
index 114d98d442..dd00d9b206 100644
--- a/engines/cine/cine.h
+++ b/engines/cine/cine.h
@@ -49,6 +49,7 @@
#include "cine/anim.h"
#include "cine/bg_list.h"
#include "cine/various.h"
+#include "cine/console.h"
//#define DUMP_SCRIPTS
@@ -71,7 +72,7 @@
* yet been finished. The game is not completable.
*
*
- * Supported games:
+ * Games using this engine:
*
* Cinematique evo.1
* - Future Wars
@@ -99,6 +100,8 @@ struct SeqListElement;
typedef Common::HashMap<Common::String, const char *> StringPtrHashMap;
+class CineConsole;
+
class CineEngine : public Engine {
protected:
@@ -137,6 +140,8 @@ public:
StringPtrHashMap _volumeEntriesMap;
TextHandler _textHandler;
+ GUI::Debugger *getDebugger() { return _console; }
+
bool _restartRequested;
private:
@@ -151,6 +156,7 @@ private:
void mainLoop(int bootScriptIdx);
void readVolCnf();
+ CineConsole *_console;
bool _preLoad;
int _timerDelayMultiplier;
diff --git a/engines/gob/helper.h b/engines/cine/console.cpp
index d1f24792a5..87633a2644 100644
--- a/engines/gob/helper.h
+++ b/engines/cine/console.cpp
@@ -23,18 +23,21 @@
*
*/
-#ifndef GOB_HELPER_H
-#define GOB_HELPER_H
+#include "cine/console.h"
+#include "cine/cine.h"
-namespace Gob {
+namespace Cine {
-/** A strncpy that forces the final \0. */
-inline char *strncpy0(char *dest, const char *src, size_t n) {
- strncpy(dest, src, n);
- dest[n] = 0;
- return dest;
+CineConsole::CineConsole(CineEngine *vm) : GUI::Debugger(), _vm(vm) {
}
-} // End of namespace Gob
+CineConsole::~CineConsole() {
+}
+
+void CineConsole::preEnter() {
+}
+
+void CineConsole::postEnter() {
+}
-#endif // GOB_HELPER_H
+} // End of namespace Cine
diff --git a/backends/platform/sdl/macosx/macosx.h b/engines/cine/console.h
index 3c583a0ac0..256ec16ce6 100644
--- a/backends/platform/sdl/macosx/macosx.h
+++ b/engines/cine/console.h
@@ -23,19 +23,28 @@
*
*/
-#ifndef PLATFORM_SDL_MACOSX_H
-#define PLATFORM_SDL_MACOSX_H
+#ifndef CINE_CONSOLE_H
+#define CINE_CONSOLE_H
-#include "backends/platform/sdl/posix/posix.h"
+#include "gui/debugger.h"
-class OSystem_MacOSX : public OSystem_POSIX {
+namespace Cine {
+
+class CineEngine;
+
+class CineConsole : public GUI::Debugger {
public:
- OSystem_MacOSX();
- virtual ~OSystem_MacOSX() {}
+ CineConsole(CineEngine *vm);
+ virtual ~CineConsole(void);
- virtual void initBackend();
- virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
- virtual void setupIcon();
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+private:
+ CineEngine *_vm;
};
+} // End of namespace Cine
+
#endif
diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp
index 3d280c20ef..644744d3ed 100644
--- a/engines/cine/main_loop.cpp
+++ b/engines/cine/main_loop.cpp
@@ -161,6 +161,12 @@ static void processEvent(Common::Event &event) {
case Common::KEYCODE_KP3:
moveUsingKeyboard(+1, -1); // Down & Right
break;
+ case Common::KEYCODE_d:
+ if (event.kbd.hasFlags(Common::KBD_CTRL)) {
+ g_cine->getDebugger()->attach();
+ g_cine->getDebugger()->onFrame();
+ }
+ // No Break to allow fallthrough to process 'd' without CTRL
default:
lastKeyStroke = event.kbd.keycode;
break;
diff --git a/engines/cine/module.mk b/engines/cine/module.mk
index 2260524dcb..6e77449c59 100644
--- a/engines/cine/module.mk
+++ b/engines/cine/module.mk
@@ -4,6 +4,7 @@ MODULE_OBJS := \
anim.o \
bg.o \
bg_list.o \
+ console.o \
cine.o \
detection.o \
gfx.o \
diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp
index 430a32ac69..5db9a83928 100644
--- a/engines/cine/script_fw.cpp
+++ b/engines/cine/script_fw.cpp
@@ -3098,7 +3098,7 @@ void decompileScript(const byte *scriptPtr, uint16 scriptSize, uint16 scriptIdx)
}
void dumpScript(char *dumpName) {
- Common::DumpFile fHandle;
+ Common::DumpFile fHandle;
uint16 i;
fHandle.open(dumpName);
diff --git a/engines/cruise/background.cpp b/engines/cruise/background.cpp
index 3ac57cc376..edd52d3b4a 100644
--- a/engines/cruise/background.cpp
+++ b/engines/cruise/background.cpp
@@ -216,8 +216,7 @@ int loadBackground(const char *name, int idx) {
if (strlen(name) >= sizeof(backgroundTable[idx].name))
warning("background name length exceeded allowable maximum");
- strncpy(backgroundTable[idx].name, name, sizeof(backgroundTable[idx].name));
- backgroundTable[idx].name[sizeof(backgroundTable[idx].name) - 1] = 0;
+ Common::strlcpy(backgroundTable[idx].name, name, sizeof(backgroundTable[idx].name));
}
return (0);
diff --git a/engines/cruise/cruise.h b/engines/cruise/cruise.h
index 94f5c68ca0..ad3bb20ca1 100644
--- a/engines/cruise/cruise.h
+++ b/engines/cruise/cruise.h
@@ -42,7 +42,7 @@
*
* Status of this engine: Game is completable, engine needs objectifying
*
- * Supported games:
+ * Games using this engine:
* - Cruise for a Corpse
*/
namespace Cruise {
diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp
index aa78f84e3d..ac814b3279 100644
--- a/engines/cruise/cruise_main.cpp
+++ b/engines/cruise/cruise_main.cpp
@@ -44,11 +44,11 @@ gfxEntryStruct* linkedMsgList = NULL;
void MemoryList() {
if (!_vm->_memList.empty()) {
- printf("Current list of un-freed memory blocks:\n");
+ debug("Current list of un-freed memory blocks:");
Common::List<byte *>::iterator i;
for (i = _vm->_memList.begin(); i != _vm->_memList.end(); ++i) {
byte *v = *i;
- printf("%s - %d\n", (const char *)(v - 68), *((int32 *)(v - 72)));
+ debug("%s - %d", (const char *)(v - 68), *((int32 *)(v - 72)));
}
}
}
diff --git a/engines/cruise/dataLoader.cpp b/engines/cruise/dataLoader.cpp
index b2ac7a2fd6..b48240b30e 100644
--- a/engines/cruise/dataLoader.cpp
+++ b/engines/cruise/dataLoader.cpp
@@ -55,7 +55,7 @@ void decodeGfxUnified(dataFileEntry *pCurrentFileEntry, int16 format) {
break;
default:
- error("Unkown gfx format %d", format);
+ error("Unknown gfx format %d", format);
}
uint8 *buffer = (uint8 *)MemAlloc(spriteSize);
diff --git a/engines/cruise/decompiler.cpp b/engines/cruise/decompiler.cpp
index 31d9dcef9b..3298776d0e 100644
--- a/engines/cruise/decompiler.cpp
+++ b/engines/cruise/decompiler.cpp
@@ -62,7 +62,7 @@ unsigned long int currentOffset;
unsigned long int dumpIdx = 0;
-FILE *fHandle = NULL;
+FILE *fHandle = NULL; // FIXME: Use Common::DumpFile instead of FILE
#define DECOMPILER_STACK_DEPTH 100
#define DECOMPILER_STACK_ENTRY_SIZE 5000
@@ -409,7 +409,7 @@ int decompLoadVar() {
return (0);
}
default: {
- printf("Unsupported type %d in opcodeType0\n",
+ debug("Unsupported type %d in opcodeType0",
currentScriptOpcodeType);
failed = 1;
}
@@ -483,7 +483,7 @@ int decompSaveVar() {
break;
}
default: {
- printf("Unsupported type %d in opcodeType1\n",
+ debug("Unsupported type %d in opcodeType1",
currentScriptOpcodeType);
failed = 1;
}
@@ -521,14 +521,14 @@ int decompOpcodeType2() {
pushDecomp("freeString[%d][%s]", short1,
decompSaveOpcodeVar);
} else {
- printf("Unsupported type %d in opcodeType2\n",
+ debug("Unsupported type %d in opcodeType2",
byte1 & 7);
failed = 1;
}
break;
}
default: {
- printf("Unsupported type %d in opcodeType2\n",
+ debug("Unsupported type %d in opcodeType2",
currentScriptOpcodeType);
failed = 1;
}
@@ -1264,7 +1264,7 @@ int decompFunction() {
}
default: {
addDecomp("OP_%X", currentScriptOpcodeType);
- printf("OPCODE: %X\n", currentScriptOpcodeType);
+ debug("OPCODE: %X", currentScriptOpcodeType);
failed = 1;
break;
}
@@ -1354,7 +1354,7 @@ void dumpScript(uint8 *ovlName, ovlDataStruct *ovlData, int idx) {
resolveVarName("0", 0x20, temp, scriptName);
- printf("decompiling script %d - %s\n", idx, scriptName);
+ debug("decompiling script %d - %s", idx, scriptName);
// return;
@@ -1394,17 +1394,17 @@ void dumpScript(uint8 *ovlName, ovlDataStruct *ovlData, int idx) {
currentScriptOpcodeType = opcodeType & 7;
if (!decompOpcodeTypeTable[(opcodeType & 0xFB) >> 3]) {
- printf("Unsupported opcode type %d in decomp\n",
+ debug("Unsupported opcode type %d in decomp",
(opcodeType & 0xFB) >> 3);
return;
}
- //printf("Optype: %d\n",(opcodeType&0xFB)>>3);
+ //debug("Optype: %d",(opcodeType&0xFB)>>3);
decompOpcodeTypeTable[(opcodeType & 0xFB) >> 3]();
if (failed) {
- printf("Aborting decompilation..\n");
+ debug("Aborting decompilation..");
fclose(fHandle);
return;
}
diff --git a/engines/cruise/function.cpp b/engines/cruise/function.cpp
index 3d07abf441..0b25ee59c1 100644
--- a/engines/cruise/function.cpp
+++ b/engines/cruise/function.cpp
@@ -58,17 +58,15 @@ int16 Op_LoadOverlay() {
updateAllScriptsImports();
- strcpy(nextOverlay, overlayName);
+ Common::strlcpy(nextOverlay, overlayName, sizeof(nextOverlay));
- return(overlayLoadResult);
+ return overlayLoadResult;
}
int16 Op_Strcpy() {
char *ptr1 = (char *)popPtr();
char *ptr2 = (char *)popPtr();
- //printf("strcpy %s\n",ptr1);
-
while (*ptr1) {
*ptr2 = *ptr1;
@@ -1994,7 +1992,6 @@ int32 opcodeType8() {
return (-21);
if (opcode < ARRAYSIZE(opcodeTablePtr) && opcodeTablePtr[opcode]) {
- // printf("Function: %d\n",opcode);
pushVar(opcodeTablePtr[opcode]());
return (0);
} else {
diff --git a/engines/cruise/overlay.cpp b/engines/cruise/overlay.cpp
index 729734d261..01920fa8f1 100644
--- a/engines/cruise/overlay.cpp
+++ b/engines/cruise/overlay.cpp
@@ -662,6 +662,7 @@ int loadOverlay(const char *scriptName) {
#endif
#ifdef DUMP_OBJECT
{
+ // TODO: Rewrite this to use Common::DumpFile
int i;
FILE *fHandle;
char nameBundle[100];
diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp
index 24ea2facfe..a1a306705e 100644
--- a/engines/cruise/saveload.cpp
+++ b/engines/cruise/saveload.cpp
@@ -901,8 +901,7 @@ Common::Error loadSavegameData(int saveGameIdx) {
}
/*if (j < 2) {
- printf("Unsupported mono file load!\n");
- ASSERT(0);
+ error("Unsupported mono file load");
//loadFileMode1(filesDatabase[j].subData.name,filesDatabase[j].subData.var4);
} else */
if (strlen(filesDatabase[i].subData.name) > 0) {
diff --git a/engines/cruise/script.cpp b/engines/cruise/script.cpp
index d6c1aa47f3..317dcfbbe6 100644
--- a/engines/cruise/script.cpp
+++ b/engines/cruise/script.cpp
@@ -185,8 +185,9 @@ int32 opcodeType1() {
return 0;
}
case 2: {
+ assert (ptr);
*(ptr + var_A + offset) = var;
- return (0);
+ return 0;
}
default:
error("Unsupported code in opcodeType1 case 1");
@@ -448,7 +449,7 @@ int32 opcodeType3() { // math
}
int32 opcodeType9() { // stop script
- //printf("Stop a script of overlay %s\n",overlayTable[currentScriptPtr->overlayNumber].overlayName);
+ //debug("Stop a script of overlay %s", overlayTable[currentScriptPtr->overlayNumber].overlayName);
currentScriptPtr->scriptNumber = -1;
return (1);
}
@@ -500,7 +501,7 @@ uint8 *attacheNewScriptToTail(scriptInstanceStruct *scriptHandlePtr, int16 overl
int var_C;
scriptInstanceStruct *oldTail;
- //printf("Starting script %d of overlay %s\n",param,overlayTable[overlayNumber].overlayName);
+ //debug("Starting script %d of overlay %s", param,overlayTable[overlayNumber].overlayName);
if (scriptType < 0) {
useArg3Neg = 1;
diff --git a/engines/cruise/vars.cpp b/engines/cruise/vars.cpp
index c61cedc503..07bd646cae 100644
--- a/engines/cruise/vars.cpp
+++ b/engines/cruise/vars.cpp
@@ -51,8 +51,8 @@ int32 volumeDataLoaded = 0;
int16 numOfDisks;
-char lastOverlay[15];
-char nextOverlay[15];
+char lastOverlay[38];
+char nextOverlay[38];
int16 currentActiveMenu;
int16 autoMsg;
diff --git a/engines/cruise/vars.h b/engines/cruise/vars.h
index af39993f2f..54920a1436 100644
--- a/engines/cruise/vars.h
+++ b/engines/cruise/vars.h
@@ -154,8 +154,8 @@ extern int32 volumeDataLoaded;
extern int16 numOfDisks;
-extern char lastOverlay[15];
-extern char nextOverlay[15];
+extern char lastOverlay[38];
+extern char nextOverlay[38];
extern int16 currentActiveMenu;
extern int16 autoMsg;
diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp
index cb081e4683..a8f9327152 100644
--- a/engines/dialogs.cpp
+++ b/engines/dialogs.cpp
@@ -36,6 +36,7 @@
#include "gui/GuiManager.h"
#include "gui/launcher.h"
#include "gui/ListWidget.h"
+#include "gui/message.h"
#include "gui/options.h"
#include "gui/saveload.h"
#include "gui/ThemeEval.h"
@@ -48,9 +49,6 @@
#include "gui/KeysDialog.h"
#endif
-using GUI::CommandSender;
-using GUI::StaticTextWidget;
-
class ConfigDialog : public GUI::OptionsDialog {
protected:
#ifdef SMALL_SCREEN_DEVICE
@@ -75,15 +73,15 @@ MainMenuDialog::MainMenuDialog(Engine *engine)
_logo->useThemeTransparency(true);
_logo->setGfx(g_gui.theme()->getImageSurface(GUI::ThemeEngine::kImageLogoSmall));
} else {
- StaticTextWidget *title = new StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
+ GUI::StaticTextWidget *title = new GUI::StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
title->setAlign(Graphics::kTextAlignCenter);
}
#else
- StaticTextWidget *title = new StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
+ GUI::StaticTextWidget *title = new GUI::StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
title->setAlign(Graphics::kTextAlignCenter);
#endif
- StaticTextWidget *version = new StaticTextWidget(this, "GlobalMenu.Version", gScummVMVersionDate);
+ GUI::StaticTextWidget *version = new GUI::StaticTextWidget(this, "GlobalMenu.Version", gScummVMVersionDate);
version->setAlign(Graphics::kTextAlignCenter);
new GUI::ButtonWidget(this, "GlobalMenu.Resume", _("~R~esume"), 0, kPlayCmd, 'P');
@@ -102,7 +100,6 @@ MainMenuDialog::MainMenuDialog(Engine *engine)
// To enable "Help", an engine needs to use a subclass of MainMenuDialog
// (at least for now, we might change how this works in the future).
_helpButton = new GUI::ButtonWidget(this, "GlobalMenu.Help", _("~H~elp"), 0, kHelpCmd);
- _helpButton->setEnabled(false);
new GUI::ButtonWidget(this, "GlobalMenu.About", _("~A~bout"), 0, kAboutCmd);
@@ -130,7 +127,7 @@ MainMenuDialog::~MainMenuDialog() {
delete _saveDialog;
}
-void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+void MainMenuDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kPlayCmd:
close();
@@ -147,8 +144,13 @@ void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
case kAboutCmd:
_aboutDialog->runModal();
break;
- case kHelpCmd:
- // Not handled here -- needs to be handled by a subclass (for now)
+ case kHelpCmd: {
+ GUI::MessageDialog dialog(
+ "Sorry, this engine does not currently provide in-game help. "
+ "Please consult the README for basic information, and for "
+ "instructions on how to obtain further assistance.");
+ dialog.runModal();
+ }
break;
case kRTLCmd: {
Common::Event eventRTL;
@@ -182,16 +184,16 @@ void MainMenuDialog::reflowLayout() {
_logo->useThemeTransparency(true);
_logo->setGfx(g_gui.theme()->getImageSurface(GUI::ThemeEngine::kImageLogoSmall));
- GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("GlobalMenu.Title");
+ GUI::StaticTextWidget *title = (GUI::StaticTextWidget *)findWidget("GlobalMenu.Title");
if (title) {
removeWidget(title);
title->setNext(0);
delete title;
}
} else {
- GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("GlobalMenu.Title");
+ GUI::StaticTextWidget *title = (GUI::StaticTextWidget *)findWidget("GlobalMenu.Title");
if (!title) {
- title = new StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
+ title = new GUI::StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
title->setAlign(Graphics::kTextAlignCenter);
}
@@ -316,7 +318,7 @@ ConfigDialog::~ConfigDialog() {
#endif
}
-void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+void ConfigDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kKeysCmd:
diff --git a/engines/draci/console.cpp b/engines/draci/console.cpp
new file mode 100644
index 0000000000..96e8e3ae05
--- /dev/null
+++ b/engines/draci/console.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "draci/console.h"
+#include "draci/draci.h"
+
+namespace Draci {
+
+DraciConsole::DraciConsole(DraciEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
+
+DraciConsole::~DraciConsole() {
+}
+
+void DraciConsole::preEnter() {
+}
+
+void DraciConsole::postEnter() {
+}
+
+} // End of namespace Draci
diff --git a/engines/draci/console.h b/engines/draci/console.h
new file mode 100644
index 0000000000..811e14e0be
--- /dev/null
+++ b/engines/draci/console.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef DRACI_CONSOLE_H
+#define DRACI_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Draci {
+
+class DraciEngine;
+
+class DraciConsole : public GUI::Debugger {
+public:
+ DraciConsole(DraciEngine *vm);
+ virtual ~DraciConsole(void);
+
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+private:
+ DraciEngine *_vm;
+};
+
+} // End of namespace Draci
+
+#endif
diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp
index 07a9928cfa..78c5c71605 100644
--- a/engines/draci/detection.cpp
+++ b/engines/draci/detection.cpp
@@ -86,7 +86,7 @@ const ADGameDescription gameDescriptions[] = {
} // End of namespace Draci
-const ADParams detectionParams = {
+static const ADParams detectionParams = {
// Pointer to ADGameDescription or its superset structure
(const byte *)Draci::gameDescriptions,
// Size of that superset structure
@@ -103,7 +103,7 @@ const ADParams detectionParams = {
0,
// Flags
0,
- // Global GUI options
+ // Additional GUI options (for every game}
Common::GUIO_NONE,
// Maximum directory depth
1,
@@ -202,10 +202,7 @@ SaveStateDescriptor DraciMetaEngine::querySaveMetaInfos(const char *target, int
int minutes = header.time & 0xFF;
desc.setSaveTime(hour, minutes);
- minutes = header.playtime / 60;
- hour = minutes / 60;
- minutes %= 60;
- desc.setPlayTime(hour, minutes);
+ desc.setPlayTime(header.playtime * 1000);
return desc;
}
diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp
index 814159dbbb..d0eb511cbd 100644
--- a/engines/draci/draci.cpp
+++ b/engines/draci/draci.cpp
@@ -94,6 +94,8 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc)
DebugMan.addDebugChannel(kDraciSoundDebugLevel, "sound", "Sound debug info");
DebugMan.addDebugChannel(kDraciWalkingDebugLevel, "walking", "Walking debug info");
+ _console = new DraciConsole(this);
+
// Don't forget to register your random source
g_eventRec.registerRandomSource(_rnd, "draci");
}
@@ -346,6 +348,12 @@ void DraciEngine::handleEvents() {
_game->inventorySwitch(event.kbd.keycode);
}
break;
+ case Common::KEYCODE_d:
+ if (event.kbd.hasFlags(Common::KBD_CTRL)) {
+ this->getDebugger()->attach();
+ this->getDebugger()->onFrame();
+ }
+ break;
default:
break;
}
@@ -399,11 +407,13 @@ DraciEngine::~DraciEngine() {
// Remove all of our debug levels here
DebugMan.clearAllDebugChannels();
+
+ delete _console;
}
Common::Error DraciEngine::run() {
init();
- _engineStartTime = _system->getMillis() / 1000;
+ setTotalPlayTime(0);
_game->init();
// Load game from specified slot, if any
@@ -418,8 +428,6 @@ Common::Error DraciEngine::run() {
void DraciEngine::pauseEngineIntern(bool pause) {
Engine::pauseEngineIntern(pause);
if (pause) {
- // Record start of the pause, so that we can later
- // adjust _engineStartTime accordingly.
_pauseStartTime = _system->getMillis();
_anims->pauseAnimations();
@@ -434,7 +442,6 @@ void DraciEngine::pauseEngineIntern(bool pause) {
// Adjust engine start time
const int delta = _system->getMillis() - _pauseStartTime;
- _engineStartTime += delta / 1000;
_game->shiftSpeechAndFadeTick(delta);
_pauseStartTime = 0;
}
diff --git a/engines/draci/draci.h b/engines/draci/draci.h
index 605e8cc238..aa6080ca05 100644
--- a/engines/draci/draci.h
+++ b/engines/draci/draci.h
@@ -28,6 +28,7 @@
#include "engines/engine.h"
#include "common/random.h"
+#include "draci/console.h"
struct ADGameDescription;
@@ -37,10 +38,10 @@ class OSystem;
/**
* This is the namespace of the Draci engine.
*
- * Status of this engine: ???
+ * Status of this engine: Complete
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Dragon History
*/
namespace Draci {
@@ -75,6 +76,8 @@ public:
virtual Common::Error saveGameState(int slot, const char *desc);
virtual bool canSaveGameStateCurrently();
+ GUI::Debugger *getDebugger() { return _console; }
+
Screen *_screen;
Mouse *_mouse;
Game *_game;
@@ -107,8 +110,9 @@ public:
Common::RandomSource _rnd;
- int32 _engineStartTime;
int32 _pauseStartTime;
+private:
+ DraciConsole *_console;
};
enum {
diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp
index 8f3ad12cfd..cb2832552a 100644
--- a/engines/draci/game.cpp
+++ b/engines/draci/game.cpp
@@ -207,7 +207,7 @@ void Game::init() {
_currentItem = _itemUnderCursor = NULL;
_previousItemPosition = -1;
-
+
_vm->_mouse->setCursorType(kHighlightedCursor); // anything different from kNormalCursor
_objUnderCursor = NULL;
@@ -1618,15 +1618,15 @@ int GameObject::addAnim(Animation *anim) {
}
void GameObject::playAnim(int i) {
- _anim[i]->play();
- _playingAnim = i;
+ _anim[i]->play();
+ _playingAnim = i;
}
void GameObject::stopAnim() {
- if (_playingAnim >= 0) {
- _anim[_playingAnim]->stop();
- _playingAnim = -1;
- }
+ if (_playingAnim >= 0) {
+ _anim[_playingAnim]->stop();
+ _playingAnim = -1;
+ }
}
void GameObject::deleteAnims() {
diff --git a/engines/draci/module.mk b/engines/draci/module.mk
index 1f80737135..e6c9511687 100644
--- a/engines/draci/module.mk
+++ b/engines/draci/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/draci
MODULE_OBJS := \
animation.o \
barchive.o \
+ console.o \
detection.o \
draci.o \
font.o \
diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp
index 1d251d24c3..14d1162fed 100644
--- a/engines/draci/mouse.cpp
+++ b/engines/draci/mouse.cpp
@@ -54,10 +54,10 @@ void Mouse::handleEvent(Common::Event event) {
case Common::EVENT_LBUTTONUP:
debugC(6, kDraciGeneralDebugLevel, "Left button up (x: %u y: %u)", _x, _y);
- // Don't set _lButton to false, because some touchpads generate
- // down and up at such a quick succession, that they will
- // cancel each other in the same call of handleEvents(). Let
- // the game clear this flag by calling lButtonSet() instead.
+ // Don't set _lButton to false, because some touchpads generate
+ // down and up at such a quick succession, that they will
+ // cancel each other in the same call of handleEvents(). Let
+ // the game clear this flag by calling lButtonSet() instead.
break;
case Common::EVENT_RBUTTONDOWN:
diff --git a/engines/draci/saveload.cpp b/engines/draci/saveload.cpp
index 856e6da832..32e852d9a6 100644
--- a/engines/draci/saveload.cpp
+++ b/engines/draci/saveload.cpp
@@ -103,7 +103,7 @@ Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName,
header.saveName = saveName;
header.date = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
header.time = ((curTime.tm_hour & 0xFF) << 8) | ((curTime.tm_min) & 0xFF);
- header.playtime = vm._system->getMillis() / 1000 - vm._engineStartTime;
+ header.playtime = vm.getTotalPlayTime() / 1000;
writeSavegameHeader(f, header);
if (f->err()) {
@@ -157,7 +157,7 @@ Common::Error loadSavegameData(int saveGameIdx, DraciEngine *vm) {
vm->_game->inventoryReload();
- vm->_engineStartTime = vm->_system->getMillis() / 1000 - header.playtime;
+ vm->setTotalPlayTime(header.playtime * 1000);
return Common::kNoError;
}
diff --git a/engines/draci/sound.cpp b/engines/draci/sound.cpp
index c9244d7eac..6828066c3a 100644
--- a/engines/draci/sound.cpp
+++ b/engines/draci/sound.cpp
@@ -407,14 +407,14 @@ void Sound::stopVoice() {
}
void Sound::setVolume() {
- if (_mixer->isReady()) {
- _muteSound = ConfMan.getBool("sfx_mute");
- _muteVoice = ConfMan.getBool("speech_mute");
- } else {
- _muteSound = _muteVoice = true;
- }
+ if (_mixer->isReady()) {
+ _muteSound = ConfMan.getBool("sfx_mute");
+ _muteVoice = ConfMan.getBool("speech_mute");
+ } else {
+ _muteSound = _muteVoice = true;
+ }
if (ConfMan.getBool("mute")) {
- _muteSound = _muteVoice = true;
+ _muteSound = _muteVoice = true;
}
_showSubtitles = ConfMan.getBool("subtitles");
_talkSpeed = ConfMan.getInt("talkspeed");
diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp
index 0dafcdc3cd..96de750c9c 100644
--- a/engines/drascula/detection.cpp
+++ b/engines/drascula/detection.cpp
@@ -88,10 +88,17 @@ static const DrasculaGameDescription gameDescriptions[] = {
{
"drascula",
0,
- AD_ENTRY1s("packet.001", "c6a8697396e213a18472542d5f547cb4", 32847563),
+ {
+ {"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563},
+ // HACK: List packet.001 twice to ensure this detector entry
+ // is ranked just as high as the others (which each have two
+ // detection files).
+ {"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563},
+ {NULL, 0, NULL, 0}
+ },
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_KEEPMATCH | GF_PACKED,
+ GF_PACKED,
GUIO_NONE
},
},
@@ -281,7 +288,7 @@ static const ADParams detectionParams = {
// Flags
0,
// Additional GUI options (for every game}
- Common::GUIO_NOMIDI,
+ Common::GUIO_NOMIDI | Common::GUIO_NOLAUNCHLOAD,
// Maximum directory depth
1,
// List of directory globs
diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h
index 0a8b7c8c9b..535a9005d2 100644
--- a/engines/drascula/drascula.h
+++ b/engines/drascula/drascula.h
@@ -47,8 +47,8 @@
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Drascula: The Vampire Strikes Back
*/
namespace Drascula {
diff --git a/engines/drascula/resource.cpp b/engines/drascula/resource.cpp
index 1226bc2e10..57be51da43 100644
--- a/engines/drascula/resource.cpp
+++ b/engines/drascula/resource.cpp
@@ -92,13 +92,19 @@ void TextResourceParser::getLine(char *buf) {
void TextResourceParser::parseInt(int &result) {
char buf[256];
getLine(buf);
- sscanf(buf, "%d", &result);
+
+ if (!sscanf(buf, "%d", &result)) {
+ result = 0;
+ }
}
void TextResourceParser::parseString(char* result) {
char buf[256];
getLine(buf);
- sscanf(buf, "%s", result);
+
+ if (!sscanf(buf, "%s", result)) {
+ *result = 0;
+ }
}
diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp
index 57bfad26af..c6dd9f29db 100644
--- a/engines/drascula/rooms.cpp
+++ b/engines/drascula/rooms.cpp
@@ -1945,7 +1945,9 @@ bool DrasculaEngine::exitRoom(int doorNumber) {
hare_se_ve = 1;
clearRoom();
- sscanf(_targetSurface[doorNumber], "%d", &roomNum);
+ if (!sscanf(_targetSurface[doorNumber], "%d", &roomNum)) {
+ error("Malformed roomNum in targetSurface (%s)", _targetSurface[doorNumber]);
+ }
curX = -1;
enterRoom(roomNum);
diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp
index 4aaec5ec0e..4c288553a2 100644
--- a/engines/drascula/saveload.cpp
+++ b/engines/drascula/saveload.cpp
@@ -221,7 +221,9 @@ bool DrasculaEngine::loadGame(const char *gameName) {
takeObject = sav->readSint32LE();
pickedObject = sav->readSint32LE();
loadedDifferentChapter = 0;
- sscanf(currentData, "%d.ald", &roomNum);
+ if (!sscanf(currentData, "%d.ald", &roomNum)) {
+ error("Bad save format");
+ }
enterRoom(roomNum);
selectVerb(kVerbNone);
diff --git a/engines/engine.cpp b/engines/engine.cpp
index 14715ccaac..4176d003f1 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -94,10 +94,11 @@ Engine::Engine(OSystem *syst)
_saveFileMan(_system->getSavefileManager()),
_targetName(ConfMan.getActiveDomainName()),
_pauseLevel(0),
+ _pauseStartTime(0),
+ _engineStartTime(_system->getMillis()),
_mainMenuDialog(NULL) {
g_engine = this;
- Common::setDebugOutputFormatter(defaultOutputFormatter);
Common::setErrorOutputFormatter(defaultOutputFormatter);
Common::setErrorHandler(defaultErrorHandler);
@@ -154,7 +155,10 @@ void initCommonGFX(bool defaultTo1XScaler) {
// See if the game should default to 1x scaler
if (useDefaultGraphicsMode && defaultTo1XScaler) {
- g_system->resetGraphicsScale();
+ // FIXME: As a hack, we use "1x" here. Would be nicer to use
+ // getDefaultGraphicsMode() instead, but right now, we do not specify
+ // whether that is a 1x scaler or not...
+ g_system->setGraphicsMode("1x");
} else {
// Override global scaler with any game-specific define
if (ConfMan.hasKey("gfx_mode")) {
@@ -377,9 +381,12 @@ void Engine::pauseEngine(bool pause) {
_pauseLevel--;
if (_pauseLevel == 1 && pause) {
+ _pauseStartTime = _system->getMillis();
pauseEngineIntern(true);
} else if (_pauseLevel == 0) {
pauseEngineIntern(false);
+ _engineStartTime += _system->getMillis() - _pauseStartTime;
+ _pauseStartTime = 0;
}
}
@@ -395,6 +402,24 @@ void Engine::openMainMenuDialog() {
syncSoundSettings();
}
+uint32 Engine::getTotalPlayTime() const {
+ if (!_pauseLevel)
+ return _system->getMillis() - _engineStartTime;
+ else
+ return _pauseStartTime - _engineStartTime;
+}
+
+void Engine::setTotalPlayTime(uint32 time) {
+ const uint32 currentTime = _system->getMillis();
+
+ // We need to reset the pause start time here in case the engine is already
+ // paused to avoid any incorrect play time counting.
+ if (_pauseLevel > 0)
+ _pauseStartTime = currentTime;
+
+ _engineStartTime = currentTime - time;
+}
+
int Engine::runDialog(GUI::Dialog &dialog) {
pauseEngine(true);
int result = dialog.runModal();
diff --git a/engines/engine.h b/engines/engine.h
index ead1526d72..b4764319b8 100644
--- a/engines/engine.h
+++ b/engines/engine.h
@@ -74,6 +74,17 @@ private:
*/
int _pauseLevel;
+ /**
+ * The time when the pause was started.
+ */
+ uint32 _pauseStartTime;
+
+ /**
+ * The time when the engine was started. This value is used to calculate
+ * the current play time of the game running.
+ */
+ int32 _engineStartTime;
+
public:
@@ -234,6 +245,24 @@ public:
*/
void openMainMenuDialog();
+ /**
+ * Get the total play time.
+ *
+ * @return How long the player has been playing in ms.
+ */
+ uint32 getTotalPlayTime() const;
+
+ /**
+ * Set the game time counter to the specified time.
+ *
+ * This can be used to set the play time counter after loading a savegame
+ * for example. Another use case is in case the engine wants to exclude
+ * time from the counter the user spent in original engine dialogs.
+ *
+ * @param time Play time to set up in ms.
+ */
+ void setTotalPlayTime(uint32 time = 0);
+
inline Common::TimerManager *getTimerManager() { return _timer; }
inline Common::EventManager *getEventManager() { return _eventMan; }
inline Common::SaveFileManager *getSaveFileManager() { return _saveFileMan; }
diff --git a/engines/engines.mk b/engines/engines.mk
index be119c35d6..eea4ffc0b9 100644
--- a/engines/engines.mk
+++ b/engines/engines.mk
@@ -74,6 +74,11 @@ DEFINES += -DENABLE_LOL
endif
endif
+ifdef ENABLE_LASTEXPRESS
+DEFINES += -DENABLE_LASTEXPRESS=$(ENABLE_LASTEXPRESS)
+MODULES += engines/lastexpress
+endif
+
ifdef ENABLE_LURE
DEFINES += -DENABLE_LURE=$(ENABLE_LURE)
MODULES += engines/lure
diff --git a/engines/game.h b/engines/game.h
index b125421ff6..3e5d7f262c 100644
--- a/engines/game.h
+++ b/engines/game.h
@@ -28,7 +28,6 @@
#include "common/array.h"
#include "common/hash-str.h"
-#include "engines/savestate.h" // TODO: Push this #include out to .cpp files needing it
/**
* A simple structure used to map gameids (like "monkey", "sword1", ...) to
diff --git a/engines/gob/console.cpp b/engines/gob/console.cpp
new file mode 100644
index 0000000000..b6b481f611
--- /dev/null
+++ b/engines/gob/console.cpp
@@ -0,0 +1,163 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "gob/console.h"
+#include "gob/gob.h"
+#include "gob/inter.h"
+#include "gob/dataio.h"
+
+namespace Gob {
+
+GobConsole::GobConsole(GobEngine *vm) : GUI::Debugger(), _vm(vm) {
+ DCmd_Register("varSize", WRAP_METHOD(GobConsole, cmd_varSize));
+ DCmd_Register("var8", WRAP_METHOD(GobConsole, cmd_var8));
+ DCmd_Register("var16", WRAP_METHOD(GobConsole, cmd_var16));
+ DCmd_Register("var32", WRAP_METHOD(GobConsole, cmd_var32));
+ DCmd_Register("varString", WRAP_METHOD(GobConsole, cmd_varString));
+ DCmd_Register("listArchives", WRAP_METHOD(GobConsole, cmd_listArchives));
+}
+
+GobConsole::~GobConsole() {
+}
+
+void GobConsole::preEnter() {
+}
+
+void GobConsole::postEnter() {
+}
+
+bool GobConsole::cmd_varSize(int argc, const char **argv) {
+ DebugPrintf("Size of the variable space: %d bytes\n", _vm->_inter->_variables->getSize());
+ return true;
+}
+
+bool GobConsole::cmd_var8(int argc, const char **argv) {
+ if (argc == 1) {
+ DebugPrintf("Usage: var8 <var offset> (<value>)\n");
+ return true;
+ }
+
+ uint32 varNum = atoi(argv[1]);
+
+ if (varNum >= _vm->_inter->_variables->getSize()) {
+ DebugPrintf("Variable offset out of range\n");
+ return true;
+ }
+
+ if (argc > 2) {
+ uint32 varVal = atoi(argv[2]);
+ _vm->_inter->_variables->writeOff8(varNum, varVal);
+ }
+
+ DebugPrintf("var8_%d = %d\n", varNum, _vm->_inter->_variables->readOff8(varNum));
+
+ return true;
+}
+
+bool GobConsole::cmd_var16(int argc, const char **argv) {
+ if (argc == 1) {
+ DebugPrintf("Usage: var16 <var offset> (<value>)\n");
+ return true;
+ }
+
+ uint32 varNum = atoi(argv[1]);
+
+ if ((varNum + 1) >= _vm->_inter->_variables->getSize()) {
+ DebugPrintf("Variable offset out of range\n");
+ return true;
+ }
+
+ if (argc > 2) {
+ uint32 varVal = atoi(argv[2]);
+ _vm->_inter->_variables->writeOff16(varNum, varVal);
+ }
+
+ DebugPrintf("var16_%d = %d\n", varNum, _vm->_inter->_variables->readOff16(varNum));
+
+ return true;
+}
+
+bool GobConsole::cmd_var32(int argc, const char **argv) {
+ if (argc == 1) {
+ DebugPrintf("Usage: var32 <var offset> (<value>)\n");
+ return true;
+ }
+
+ uint32 varNum = atoi(argv[1]);
+
+ if ((varNum + 3) >= _vm->_inter->_variables->getSize()) {
+ DebugPrintf("Variable offset out of range\n");
+ return true;
+ }
+
+ if (argc > 2) {
+ uint32 varVal = atoi(argv[2]);
+ _vm->_inter->_variables->writeOff32(varNum, varVal);
+ }
+
+ DebugPrintf("var8_%d = %d\n", varNum, _vm->_inter->_variables->readOff32(varNum));
+
+ return true;
+}
+
+bool GobConsole::cmd_varString(int argc, const char **argv) {
+ if (argc == 1) {
+ DebugPrintf("Usage: varString <var offset> (<value>)\n");
+ return true;
+ }
+
+ uint32 varNum = atoi(argv[1]);
+
+ if (varNum >= _vm->_inter->_variables->getSize()) {
+ DebugPrintf("Variable offset out of range\n");
+ return true;
+ }
+
+ if (argc > 2) {
+ uint32 maxLength = _vm->_inter->_variables->getSize() - varNum;
+
+ Common::strlcpy(_vm->_inter->_variables->getAddressOffString(varNum), argv[2], maxLength);
+ }
+
+ DebugPrintf("varString_%d = \"%s\"\n", varNum, _vm->_inter->_variables->getAddressOffString(varNum));
+
+ return true;
+}
+
+bool GobConsole::cmd_listArchives(int argc, const char **argv) {
+ Common::Array<ArchiveInfo> info;
+
+ _vm->_dataIO->getArchiveInfo(info);
+
+ DebugPrintf(" Archive | Base | FileCount\n");
+ DebugPrintf("--------------------------------\n");
+ for (Common::Array<ArchiveInfo>::const_iterator it = info.begin(); it != info.end(); ++it)
+ if (!it->name.empty())
+ DebugPrintf("%13s | %d | %d\n", it->name.c_str(), it->base, it->fileCount);
+
+ return true;
+}
+
+} // End of namespace Gob
diff --git a/backends/platform/sdl/posix/posix.h b/engines/gob/console.h
index 13f9304f1e..f51d74be86 100644
--- a/backends/platform/sdl/posix/posix.h
+++ b/engines/gob/console.h
@@ -23,26 +23,36 @@
*
*/
-#ifndef PLATFORM_SDL_POSIX_H
-#define PLATFORM_SDL_POSIX_H
+#ifndef GOB_CONSOLE_H
+#define GOB_CONSOLE_H
-#include "backends/platform/sdl/sdl.h"
+#include "gui/debugger.h"
-class OSystem_POSIX : public OSystem_SDL {
-public:
- // Let the subclasses be able to change _baseConfigName in the constructor
- OSystem_POSIX(Common::String baseConfigName = ".scummvmrc");
- virtual ~OSystem_POSIX() {}
+namespace Gob {
+
+class GobEngine;
- virtual void init();
- virtual void initBackend();
+class GobConsole : public GUI::Debugger {
+public:
+ GobConsole(GobEngine *vm);
+ virtual ~GobConsole(void);
protected:
- // Base string for creating the default path and filename
- // for the configuration file
- Common::String _baseConfigName;
+ virtual void preEnter();
+ virtual void postEnter();
- virtual Common::String getDefaultConfigFileName();
+private:
+ GobEngine *_vm;
+
+ bool cmd_varSize(int argc, const char **argv);
+ bool cmd_var8(int argc, const char **argv);
+ bool cmd_var16(int argc, const char **argv);
+ bool cmd_var32(int argc, const char **argv);
+ bool cmd_varString(int argc, const char **argv);
+
+ bool cmd_listArchives(int argc, const char **argv);
};
+} // End of namespace Mohawk
+
#endif
diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp
index 694cec6a6f..e409025fc3 100644
--- a/engines/gob/dataio.cpp
+++ b/engines/gob/dataio.cpp
@@ -24,207 +24,114 @@
*/
#include "common/endian.h"
+#include "common/types.h"
+#include "common/stream.h"
#include "gob/gob.h"
#include "gob/dataio.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
namespace Gob {
-DataStream::DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose) {
- _io = &io;
-
- _handle = handle;
- _size = dSize;
- _dispose = dispose;
-
- _data = 0;
- _stream = 0;
+DataIO::File::File() : size(0), offset(0), packed(false), archive(0) {
}
-DataStream::DataStream(byte *buf, uint32 dSize, bool dispose) {
- _data = buf;
- _size = dSize;
- _stream = new Common::MemoryReadStream(_data, _size);
- _dispose = dispose;
-
- _io = 0;
- _handle = -1;
+DataIO::File::File(const Common::String &n, uint32 s, uint32 o, bool p, Archive &a) :
+ name(n), size(s), offset(o), packed(p), archive(&a) {
}
-DataStream::~DataStream() {
- delete _stream;
- if (_dispose) {
- delete[] _data;
- if ((_handle >= 0) && _io)
- _io->closeData(_handle);
- }
+DataIO::DataIO() {
+ // Reserve memory for the standard max amount of archives
+ _archives.reserve(kMaxArchives);
+ for (int i = 0; i < kMaxArchives; i++)
+ _archives.push_back(0);
}
-int32 DataStream::pos() const {
- if (_stream)
- return _stream->pos();
-
- int32 resPos = _io->getChunkPos(_handle);
- if (resPos != -1)
- return resPos;
-
- return _io->file_getHandle(_handle)->pos();
-}
-
-int32 DataStream::size() const {
- if (_stream)
- return _stream->size();
-
- return _size;
-}
+DataIO::~DataIO() {
+ // Close all archives
+ for (Common::Array<Archive *>::iterator it = _archives.begin(); it != _archives.end(); ++it) {
+ if (!*it)
+ continue;
-bool DataStream::seek(int32 offset, int whence) {
- if (_stream)
- return _stream->seek(offset, whence);
- else if (!_io->isDataFileChunk(_handle))
- return _io->file_getHandle(_handle)->seek(offset, whence);
- else {
- _io->seekChunk(_handle, offset, whence);
- return true;
+ closeArchive(**it);
+ delete *it;
}
}
-bool DataStream::eos() const {
- if (_stream)
- return _stream->eos();
-
- return pos() >= size(); // FIXME (eos definition change)
-}
-
-uint32 DataStream::read(void *dataPtr, uint32 dataSize) {
- if (_stream)
- return _stream->read(dataPtr, dataSize);
-
- if (!_io->isDataFileChunk(_handle))
- return _io->file_getHandle(_handle)->read((byte *)dataPtr, dataSize);
-
- byte *data = (byte *)dataPtr;
- uint32 haveRead = 0;
- while (dataSize > 0x3FFF) {
- _io->readChunk(_handle, (byte *)data, 0x3FFF);
- dataSize -= 0x3FFF;
- data += 0x3FFF;
- haveRead += 0x3FFF;
- }
- _io->readChunk(_handle, (byte *)data, dataSize);
-
- return haveRead + dataSize;
-}
+void DataIO::getArchiveInfo(Common::Array<ArchiveInfo> &info) const {
+ info.resize(_archives.size());
-DataIO::DataIO(GobEngine *vm) : _vm(vm) {
- for (int i = 0; i < MAX_DATA_FILES; i++) {
- _dataFiles[i] = 0;
- _numDataChunks[i] = 0;
- _dataFileHandles[i] = -1;
- }
-}
+ for (uint i = 0; i < _archives.size(); i++) {
+ if (!_archives[i])
+ continue;
-DataIO::~DataIO() {
- for (int i = 0; i < MAX_DATA_FILES; i++) {
- if (_dataFiles[i])
- file_getHandle(_dataFileHandles[i])->close();
- delete[] _dataFiles[i];
+ info[i].name = _archives[i]->name;
+ info[i].base = _archives[i]->base;
+ info[i].fileCount = _archives[i]->files.size();
}
}
-bool DataIO::isDataFileChunk(int16 handle) const {
- return (handle >= 50) && (handle < 128);
-}
-
-bool DataIO::isPacked(int16 handle) const {
- if (!isDataFileChunk(handle))
- return false;
-
- return _chunk[getIndex(handle)]->packed != 0;
-}
-
-int DataIO::getFile(int16 handle) const {
- if (!isDataFileChunk(handle))
- return -1;
+byte *DataIO::unpack(const byte *src, uint32 srcSize, int32 &size) {
+ size = READ_LE_UINT32(src);
- return (handle - 50) / 10;
-}
+ byte *data = new byte[size];
-int DataIO::getSlot(int16 handle) const {
- if (!isDataFileChunk(handle))
- return -1;
-
- return (handle - 50) % 10;
+ Common::MemoryReadStream srcStream(src + 4, srcSize - 4);
+ unpack(srcStream, data, size);
+ return data;
}
-int DataIO::getIndex(int16 handle) const {
- if (!isDataFileChunk(handle))
- return -1;
-
- return getIndex(getFile(handle), getSlot(handle));
-}
+Common::SeekableReadStream *DataIO::unpack(Common::SeekableReadStream &src) {
+ uint32 size = src.readUint32LE();
-int DataIO::getIndex(int file, int slot) const {
- return file * MAX_SLOT_COUNT + slot;
-}
+ byte *data = (byte *) malloc(size);
-int16 DataIO::getHandle(int file, int slot) const {
- return file * 10 + slot + 50;
+ unpack(src, data, size);
+ return new Common::MemoryReadStream(data, size, DisposeAfterUse::YES);
}
-int32 DataIO::unpackData(byte *src, byte *dest) {
- uint32 realSize;
- uint32 counter;
- uint16 cmd;
- byte *tmpBuf;
- int16 off;
- byte len;
- uint16 tmpIndex;
-
- tmpBuf = new byte[4114];
+void DataIO::unpack(Common::SeekableReadStream &src, byte *dest, uint32 size) {
+ byte *tmpBuf = new byte[4114];
assert(tmpBuf);
- counter = realSize = READ_LE_UINT32(src);
+ uint32 counter = size;
for (int i = 0; i < 4078; i++)
tmpBuf[i] = 0x20;
- tmpIndex = 4078;
+ uint16 tmpIndex = 4078;
- src += 4;
-
- cmd = 0;
+ uint16 cmd = 0;
while (1) {
cmd >>= 1;
- if ((cmd & 0x0100) == 0) {
- cmd = *src | 0xFF00;
- src++;
- }
+ if ((cmd & 0x0100) == 0)
+ cmd = src.readByte() | 0xFF00;
+
if ((cmd & 1) != 0) { /* copy */
- *dest++ = *src;
- tmpBuf[tmpIndex] = *src;
- src++;
+ byte tmp = src.readByte();
+
+ *dest++ = tmp;
+ tmpBuf[tmpIndex] = tmp;
+
tmpIndex++;
tmpIndex %= 4096;
counter--;
if (counter == 0)
break;
} else { /* copy string */
+ byte tmp1 = src.readByte();
+ byte tmp2 = src.readByte();
- off = *src++;
- off |= (*src & 0xF0) << 4;
- len = (*src & 0x0F) + 3;
- src++;
+ int16 off = tmp1 | ((tmp2 & 0xF0) << 4);
+ byte len = (tmp2 & 0x0F) + 3;
for (int i = 0; i < len; i++) {
*dest++ = tmpBuf[(off + i) % 4096];
counter--;
if (counter == 0) {
delete[] tmpBuf;
- return realSize;
+ return;
}
tmpBuf[tmpIndex] = tmpBuf[(off + i) % 4096];
tmpIndex++;
@@ -233,390 +140,251 @@ int32 DataIO::unpackData(byte *src, byte *dest) {
}
}
- delete[] tmpBuf;
- return realSize;
-}
-
-Common::File *DataIO::file_getHandle(int16 handle) {
- return &_filesHandles[handle];
-}
-const Common::File *DataIO::file_getHandle(int16 handle) const {
- return &_filesHandles[handle];
+ delete[] tmpBuf;
}
-int16 DataIO::file_open(const char *path) {
- int16 i;
-
- for (i = 0; i < MAX_FILES; i++) {
- if (!file_getHandle(i)->isOpen())
+bool DataIO::openArchive(Common::String name, bool base) {
+ // Look for a free archive slot
+ Archive **archive = 0;
+ int i = 0;
+ for (Common::Array<Archive *>::iterator it = _archives.begin(); it != _archives.end(); ++it, i++) {
+ if (!*it) {
+ archive = &*it;
break;
+ }
}
- if (i == MAX_FILES)
- return -1;
-
- if (file_getHandle(i)->open(path))
- return i;
-
- return -1;
-}
-int16 DataIO::getChunk(const char *chunkName) {
- for (int16 file = 0; file < MAX_DATA_FILES; file++) {
- if (_dataFiles[file] == 0)
- return -1;
+ if (!archive) {
+ // No free slot, create a new one
- int16 slot;
- for (slot = 0; slot < MAX_SLOT_COUNT; slot++)
- if (_chunkPos[file * MAX_SLOT_COUNT + slot] == -1)
- break;
+ warning("DataIO::openArchive(): Need to increase archive count to %d", _archives.size() + 1);
+ _archives.push_back(0);
- if (slot == MAX_SLOT_COUNT) {
- warning("Chunk slots full");
- return -1;
- }
-
- ChunkDesc *dataDesc = _dataFiles[file];
- for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) {
- if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0)
- continue;
+ Common::Array<Archive *>::iterator it = _archives.end();
+ archive = &*(--it);
+ }
- int index = getIndex(file, slot);
+ // Add extension if necessary
+ if (!name.contains('.'))
+ name += ".stk";
- _isCurrentSlot[index] = false;
- _chunk [index] = dataDesc;
- _chunkPos [index] = 0;
+ // Try to open
+ *archive = openArchive(name);
+ if (!*archive)
+ return false;
- return getHandle(file, slot);
- }
- }
- return -1;
+ (*archive)->base = base;
+ return true;
}
-char DataIO::freeChunk(int16 handle) {
- if (isDataFileChunk(handle)) {
- _chunkPos[getIndex(handle)] = -1;
+DataIO::Archive *DataIO::openArchive(const Common::String &name) {
+ Archive *archive = new Archive;
+ if (!archive->file.open(name)) {
+ delete archive;
return 0;
}
- return 1;
-}
-
-int32 DataIO::readChunk(int16 handle, byte *buf, uint16 size) {
- if (!isDataFileChunk(handle))
- return -2;
-
- int file = getFile(handle);
- int slot = getSlot(handle);
- int index = getIndex(file, slot);
-
- _chunkPos[index] = CLIP<int32>(_chunkPos[index], 0, _chunk[index]->size);
-
- if (!_isCurrentSlot[index]) {
- for (int16 i = 0; i < MAX_SLOT_COUNT; i++)
- _isCurrentSlot[file * MAX_SLOT_COUNT + i] = false;
- int32 offset = _chunk[index]->offset + _chunkPos[index];
+ archive->name = name;
- debugC(7, kDebugFileIO, "seek: %d, %d", _chunk[index]->offset, _chunkPos[index]);
+ uint16 fileCount = archive->file.readUint16LE();
+ for (uint16 i = 0; i < fileCount; i++) {
+ File file;
- file_getHandle(_dataFileHandles[file])->seek(offset, SEEK_SET);
- }
-
- _isCurrentSlot[index] = true;
- if ((_chunkPos[index] + size) > (int32) (_chunk[index]->size))
- size = _chunk[index]->size - _chunkPos[index];
-
- file_getHandle(_dataFileHandles[file])->read(buf, size);
- _chunkPos[index] += size;
- return size;
-}
+ char fileName[14];
-int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) {
- if (!isDataFileChunk(handle))
- return -1;
+ archive->file.read(fileName, 13);
+ fileName[13] = '\0';
- int file = getFile(handle);
- int slot = getSlot(handle);
- int index = getIndex(file, slot);
+ file.size = archive->file.readUint32LE();
+ file.offset = archive->file.readUint32LE();
+ file.packed = archive->file.readByte() != 0;
- _isCurrentSlot[index] = false;
- if (from == SEEK_SET)
- _chunkPos[index] = pos;
- else if (from == SEEK_CUR)
- _chunkPos[index] += pos;
- else if (from == SEEK_END)
- _chunkPos[index] = _chunk[index]->size - pos;
+ // Replacing cyrillic characters
+ Util::replaceChar(fileName, (char) 0x85, 'E');
+ Util::replaceChar(fileName, (char) 0x8A, 'K');
+ Util::replaceChar(fileName, (char) 0x8E, 'O');
+ Util::replaceChar(fileName, (char) 0x91, 'C');
+ Util::replaceChar(fileName, (char) 0x92, 'T');
- return _chunkPos[index];
-}
+ file.name = fileName;
-uint32 DataIO::getChunkPos(int16 handle) const {
- if (!isDataFileChunk(handle))
- return 0xFFFFFFFF;
+ // Geisha use 0ot files, which are compressed TOT files without the packed byte set.
+ if (file.name.hasSuffix(".0OT")) {
+ file.name.setChar(file.name.size() - 3, 'T');
+ file.packed = true;
+ }
- int file = getFile(handle);
- int slot = getSlot(handle);
+ file.archive = archive;
+ archive->files.setVal(file.name, file);
+ }
- return _chunkPos[file * MAX_SLOT_COUNT + slot];
+ return archive;
}
-int32 DataIO::getChunkSize(const char *chunkName, int32 &packSize) {
- packSize = -1;
-
- for (int file = 0; file < MAX_DATA_FILES; file++) {
- if (_dataFiles[file] == 0)
- return -1;
-
- ChunkDesc *dataDesc = _dataFiles[file];
- for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) {
- if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0)
- continue;
-
- if (dataDesc->packed == 0)
- return dataDesc->size;
+bool DataIO::closeArchive(bool base) {
+ // Look for a matching archive and close it
+ for (int archive = _archives.size() - 1; archive >= 0; archive--) {
+ if (_archives[archive] && (_archives[archive]->base == base)) {
+ closeArchive(*_archives[archive]);
+ delete _archives[archive];
+ _archives[archive] = 0;
- for (int16 slot = 0; slot < MAX_SLOT_COUNT; slot++)
- _isCurrentSlot[slot] = false;
-
- int32 realSize;
-
- file_getHandle(_dataFileHandles[file])->seek(dataDesc->offset, SEEK_SET);
- realSize = file_getHandle(_dataFileHandles[file])->readUint32LE();
- packSize = dataDesc->size;
-
- return realSize;
+ return true;
}
}
- return -1;
-}
-
-void DataIO::openDataFile(const char *src, bool itk) {
- char path[128];
-
- strncpy0(path, src, 127);
- if (!strchr(path, '.')) {
- path[123] = 0;
- strcat(path, ".stk");
- }
-
- int16 file;
- for (file = 0; file < MAX_DATA_FILES; file++)
- if (_dataFiles[file] == 0)
- break;
- if (file == MAX_DATA_FILES)
- error("DataIO::openDataFile(): Data file slots are full");
-
- _dataFileHandles[file] = file_open(path);
+ return false;
+}
- if (_dataFileHandles[file] == -1)
- error("DataIO::openDataFile(): Can't open data file \"%s\"", path);
+bool DataIO::closeArchive(Archive &archive) {
+ archive.file.close();
- _dataFileItk [file] = itk;
- _numDataChunks[file] = file_getHandle(_dataFileHandles[file])->readUint16LE();
+ return true;
+}
- debugC(7, kDebugFileIO, "DataChunks: %d [for %s]", _numDataChunks[file], path);
+bool DataIO::hasFile(const Common::String &name){
+ // Look up the files in the opened archives
+ if (findFile(name))
+ return true;
- ChunkDesc *dataDesc = new ChunkDesc[_numDataChunks[file]];
- _dataFiles[file] = dataDesc;
+ // Else, look if a plain file that matches exists
+ return Common::File::exists(name);
+}
- for (int i = 0; i < _numDataChunks[file]; i++) {
- file_getHandle(_dataFileHandles[file])->read(dataDesc[i].chunkName, 13);
- dataDesc[i].size = file_getHandle(_dataFileHandles[file])->readUint32LE();
- dataDesc[i].offset = file_getHandle(_dataFileHandles[file])->readUint32LE();
- dataDesc[i].packed = file_getHandle(_dataFileHandles[file])->readByte();
+int32 DataIO::fileSize(const Common::String &name) {
+ // Try to find the file in the archives
+ File *file = findFile(name);
+ if (file) {
+ if (!file->packed)
+ return file->size;
- // Replacing cyrillic characters
- Util::replaceChar(dataDesc[i].chunkName, (char) 0x85, 'E');
- Util::replaceChar(dataDesc[i].chunkName, (char) 0x8A, 'K');
- Util::replaceChar(dataDesc[i].chunkName, (char) 0x8E, 'O');
- Util::replaceChar(dataDesc[i].chunkName, (char) 0x91, 'C');
- Util::replaceChar(dataDesc[i].chunkName, (char) 0x92, 'T');
+ // Sanity checks
+ assert(file->size >= 4);
+ assert(file->archive);
+ assert(file->archive->file.isOpen());
- // Geisha use 0ot files, which are compressed TOT files without the packed byte set.
- char *fakeTotPtr = strstr(dataDesc[i].chunkName, "0OT");
- if (fakeTotPtr != 0) {
- strncpy(fakeTotPtr, "TOT", 3);
- dataDesc[i].packed = 1;
- }
+ // Read the full, unpacked size
+ file->archive->file.seek(file->offset);
+ return file->archive->file.readUint32LE();
}
- for (int i = 0; i < _numDataChunks[file]; i++)
- debugC(7, kDebugFileIO, "%d: %s %d", i, dataDesc[i].chunkName, dataDesc[i].size);
+ // Else, try to find a matching plain file
+ Common::File f;
+ if (!f.open(name))
+ return -1;
- for (int i = 0; i < MAX_SLOT_COUNT; i++)
- _chunkPos[file * MAX_SLOT_COUNT + i] = -1;
+ return f.size();
}
-void DataIO::closeDataFile(bool itk) {
- for (int file = MAX_DATA_FILES - 1; file >= 0; file--) {
- if (_dataFiles[file] && (_dataFileItk[file] == itk)) {
- delete[] _dataFiles[file];
- _dataFiles[file] = 0;
- file_getHandle(_dataFileHandles[file])->close();
- return;
- }
+Common::SeekableReadStream *DataIO::getFile(const Common::String &name) {
+ // Try to open the file in the archives
+ File *file = findFile(name);
+ if (file) {
+ Common::SeekableReadStream *data = getFile(*file);
+ if (data)
+ return data;
}
-}
-
-byte *DataIO::getUnpackedData(const char *name) {
- int32 realSize;
- int32 packSize = -1;
-
- realSize = getChunkSize(name, packSize);
- if ((packSize == -1) || (realSize == -1))
+ // Else, try to open a matching plain file
+ Common::File f;
+ if (!f.open(name))
return 0;
- int16 chunk = getChunk(name);
- if (chunk == -1)
- return 0;
-
- byte *unpackBuf = new byte[realSize];
- assert(unpackBuf);
-
- byte *packBuf = new byte[packSize];
- assert(packBuf);
-
- int32 sizeLeft = packSize;
- byte *ptr = packBuf;
- while (sizeLeft > 0x4000) {
- readChunk(chunk, ptr, 0x4000);
- sizeLeft -= 0x4000;
- ptr += 0x4000;
- }
- readChunk(chunk, ptr, sizeLeft);
- freeChunk(chunk);
- unpackData(packBuf, unpackBuf);
-
- delete[] packBuf;
- return unpackBuf;
+ return f.readStream(f.size());
}
-void DataIO::closeData(int16 handle) {
- if (freeChunk(handle) != 0)
- file_getHandle(handle)->close();
-}
-
-int16 DataIO::openData(const char *path) {
- int16 handle = getChunk(path);
- if (handle >= 0)
- return handle;
-
- return file_open(path);
-}
-
-bool DataIO::existData(const char *path) {
- if (!path || (path[0] == '\0'))
- return false;
+byte *DataIO::getFile(const Common::String &name, int32 &size) {
+ // Try to open the file in the archives
+ File *file = findFile(name);
+ if (file) {
+ byte *data = getFile(*file, size);
+ if (data)
+ return data;
+ }
- int16 handle = openData(path);
- if (handle < 0)
- return false;
+ // Else, try to open a matching plain file
+ Common::File f;
+ if (!f.open(name))
+ return 0;
- closeData(handle);
- return true;
-}
+ size = f.size();
-DataStream *DataIO::openAsStream(int16 handle, bool dispose) {
- uint32 curPos = getPos(handle);
- seekData(handle, 0, SEEK_END);
- uint32 size = getPos(handle);
- seekData(handle, curPos, SEEK_SET);
+ byte *data = new byte[size];
+ if (f.read(data, size) != ((uint32) size)) {
+ delete[] data;
+ return 0;
+ }
- return new DataStream(*this, handle, size, dispose);
+ return 0;
}
-uint32 DataIO::getPos(int16 handle) {
- uint32 resPos = getChunkPos(handle);
- if (resPos != 0xFFFFFFFF)
- return resPos;
-
- return file_getHandle(handle)->pos();
-}
+DataIO::File *DataIO::findFile(const Common::String &name) {
+ for (int i = _archives.size() - 1; i >= 0; i--) {
+ Archive *archive = _archives[i];
+ if (!archive)
+ // Empty slot
+ continue;
-void DataIO::seekData(int16 handle, int32 pos, int16 from) {
- int32 resPos = seekChunk(handle, pos, from);
- if (resPos != -1)
- return;
+ // Look up the file in the file map
+ FileMap::iterator file = archive->files.find(name);
+ if (file != archive->files.end())
+ return &file->_value;
+ }
- file_getHandle(handle)->seek(pos, from);
+ return 0;
}
-int32 DataIO::readData(int16 handle, byte *buf, uint16 size) {
- int16 res = readChunk(handle, buf, size);
- if (res >= 0)
- return res;
+Common::SeekableReadStream *DataIO::getFile(File &file) {
+ if (!file.archive)
+ return 0;
- return file_getHandle(handle)->read(buf, size);
-}
+ if (!file.archive->file.isOpen())
+ return 0;
-int32 DataIO::getDataSize(const char *name) {
- char buf[128];
- int32 chunkSize;
- int32 packSize = -1;
+ if (!file.archive->file.seek(file.offset))
+ return 0;
- strncpy0(buf, name, 127);
+ Common::SeekableReadStream *rawData = file.archive->file.readStream(file.size);
+ if (!rawData)
+ return 0;
- chunkSize = getChunkSize(buf, packSize);
- if (chunkSize >= 0)
- return chunkSize;
+ if (!file.packed)
+ return rawData;
- Common::File file;
- if (!file.open(buf))
- error("DataIO::getDataSize(): Can't find data \"%s\"", name);
+ Common::SeekableReadStream *unpackedData = unpack(*rawData);
- chunkSize = file.size();
- file.close();
+ delete rawData;
- return chunkSize;
+ return unpackedData;
}
-byte *DataIO::getData(const char *path) {
- byte *data = getUnpackedData(path);
- if (data)
- return data;
-
- int32 size = getDataSize(path);
-
- data = new byte[size];
- assert(data);
+byte *DataIO::getFile(File &file, int32 &size) {
+ if (!file.archive)
+ return 0;
- int16 handle = openData(path);
+ if (!file.archive->file.isOpen())
+ return 0;
- byte *ptr = data;
- while (size > 0x4000) {
- readData(handle, ptr, 0x4000);
- size -= 0x4000;
- ptr += 0x4000;
- }
- readData(handle, ptr, size);
- closeData(handle);
- return data;
-}
+ if (!file.archive->file.seek(file.offset))
+ return 0;
-DataStream *DataIO::getDataStream(const char *path) {
- if (!existData(path))
- return 0;
+ size = file.size;
- int16 handle = openData(path);
- if (handle < 0)
+ byte *rawData = new byte[file.size];
+ if (file.archive->file.read(rawData, file.size) != file.size) {
+ delete[] rawData;
return 0;
+ }
- if (isDataFileChunk(handle) && isPacked(handle)) {
- // It's a packed chunk in the data files, packed,
- // so we have to read it in completely and unpack it
-
- closeData(handle);
+ if (!file.packed)
+ return rawData;
- uint32 size = getDataSize(path);
- byte *data = getData(path);
+ byte *unpackedData = unpack(rawData, file.size, size);
- return new DataStream(data, size);
+ delete[] rawData;
- } else
- // Otherwise, we can just return a stream
- return openAsStream(handle, true);
+ return unpackedData;
}
} // End of namespace Gob
diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h
index 6a86667e1b..6e12d15af8 100644
--- a/engines/gob/dataio.h
+++ b/engines/gob/dataio.h
@@ -27,113 +27,82 @@
#define GOB_DATAIO_H
#include "common/endian.h"
+#include "common/str.h"
+#include "common/hashmap.h"
+#include "common/array.h"
#include "common/file.h"
-namespace Gob {
-
-#define MAX_FILES 30
-#define MAX_DATA_FILES 8
-#define MAX_SLOT_COUNT 8
-
-class DataIO;
-
-class DataStream : public Common::SeekableReadStream {
-public:
- DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose = false);
- DataStream(byte *buf, uint32 dSize, bool dispose = true);
- virtual ~DataStream();
-
- virtual int32 pos() const;
- virtual int32 size() const;
+namespace Common {
+ class SeekableReadStream;
+}
- virtual bool seek(int32 offset, int whence = SEEK_SET);
-
- virtual bool eos() const;
-
- virtual uint32 read(void *dataPtr, uint32 dataSize);
+namespace Gob {
-private:
- DataIO *_io;
- int16 _handle;
- uint32 _size;
- byte *_data;
- bool _dispose;
- Common::MemoryReadStream *_stream;
+struct ArchiveInfo {
+ Common::String name;
+ bool base;
+ uint32 fileCount;
};
class DataIO {
public:
- struct ChunkDesc {
- char chunkName[13];
- uint32 size;
- uint32 offset;
- byte packed;
- ChunkDesc() : size(0), offset(0), packed(0) { chunkName[0] = 0; }
- };
-
- int32 unpackData(byte *src, byte *dest);
+ DataIO();
+ ~DataIO();
- void openDataFile(const char *src, bool itk = 0);
- void closeDataFile(bool itk = 0);
+ void getArchiveInfo(Common::Array<ArchiveInfo> &info) const;
- byte *getUnpackedData(const char *name);
+ bool openArchive(Common::String name, bool base);
+ bool closeArchive(bool base);
- void closeData(int16 handle);
- int16 openData(const char *path);
- bool existData(const char *path);
+ bool hasFile(const Common::String &name);
- DataStream *openAsStream(int16 handle, bool dispose = false);
+ int32 fileSize(const Common::String &name);
- int32 getDataSize(const char *name);
- byte *getData(const char *path);
- DataStream *getDataStream(const char *path);
+ Common::SeekableReadStream *getFile(const Common::String &name);
+ byte *getFile(const Common::String &name, int32 &size);
- DataIO(class GobEngine *vm);
- ~DataIO();
+ static byte *unpack(const byte *src, uint32 srcSize, int32 &size);
+ static Common::SeekableReadStream *unpack(Common::SeekableReadStream &src);
-protected:
- Common::File _filesHandles[MAX_FILES];
+private:
+ static const int kMaxArchives = 8;
- ChunkDesc *_dataFiles [MAX_DATA_FILES];
- uint16 _numDataChunks [MAX_DATA_FILES];
- int16 _dataFileHandles[MAX_DATA_FILES];
- bool _dataFileItk [MAX_DATA_FILES];
+ struct Archive;
- ChunkDesc *_chunk [MAX_SLOT_COUNT * MAX_DATA_FILES];
- int32 _chunkPos [MAX_SLOT_COUNT * MAX_DATA_FILES];
- bool _isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES];
+ struct File {
+ Common::String name;
+ uint32 size;
+ uint32 offset;
+ bool packed;
- class GobEngine *_vm;
+ Archive *archive;
- bool isDataFileChunk(int16 handle) const;
- bool isPacked (int16 handle) const;
+ File();
+ File(const Common::String &n, uint32 s, uint32 o, bool p, Archive &a);
+ };
- int getFile (int16 handle) const;
- int getSlot (int16 handle) const;
- int getIndex(int16 handle) const;
+ typedef Common::HashMap<Common::String, File, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
- int getIndex (int file, int slot) const;
- int16 getHandle(int file, int slot) const;
+ struct Archive {
+ Common::String name;
+ Common::File file;
- int16 file_open(const char *path);
- Common::File *file_getHandle(int16 handle);
- const Common::File *file_getHandle(int16 handle) const;
+ FileMap files;
- int16 getChunk(const char *chunkName);
- char freeChunk(int16 handle);
- int32 readChunk(int16 handle, byte *buf, uint16 size);
- int16 seekChunk(int16 handle, int32 pos, int16 from);
+ bool base;
+ };
- uint32 getChunkPos(int16 handle) const;
+ Common::Array<Archive *> _archives;
- int32 getChunkSize(const char *chunkName, int32 &packSize);
+ Archive *openArchive(const Common::String &name);
+ bool closeArchive(Archive &archive);
- uint32 getPos(int16 handle);
- void seekData(int16 handle, int32 pos, int16 from);
+ File *findFile(const Common::String &name);
- int32 readData(int16 handle, byte *buf, uint16 size);
+ Common::SeekableReadStream *getFile(File &file);
+ byte *getFile(File &file, int32 &size);
- friend class DataStream;
+ static void unpack(Common::SeekableReadStream &src, byte *dest, uint32 size);
};
} // End of namespace Gob
diff --git a/engines/gob/demos/demoplayer.cpp b/engines/gob/demos/demoplayer.cpp
index 4ceca3ce24..011c524798 100644
--- a/engines/gob/demos/demoplayer.cpp
+++ b/engines/gob/demos/demoplayer.cpp
@@ -28,7 +28,6 @@
#include "gob/gob.h"
#include "gob/demos/demoplayer.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/draw.h"
diff --git a/engines/gob/detection_tables.h b/engines/gob/detection_tables.h
index 93c1cc6d1c..43f15b8845 100644
--- a/engines/gob/detection_tables.h
+++ b/engines/gob/detection_tables.h
@@ -2264,16 +2264,14 @@ static const GOBGameDescription gameDescriptions[] = {
kFeaturesAdLib,
"demo.stk", "demo.tot", 0
},
-// This version is not detected on purpose: it's a pirated version, using a corrupted crack.
-// Tagged ADGF_PIRATED! Do not re-add nor un-tag!
- {
+ { // Supplied by scoriae
{
"fascination",
- "",
+ "VGA",
AD_ENTRY1s("disk0.stk", "c14330d052fe4da5a441ac9d81bc5891", 1061955),
- UNK_LANG,
+ EN_ANY,
kPlatformPC,
- ADGF_PIRATED,
+ ADGF_NO_FLAGS,
GUIO_NOSUBTITLES | GUIO_NOSPEECH
},
kGameTypeFascination,
diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp
index 960f4e9e34..ae1bbd4e8e 100644
--- a/engines/gob/draw.cpp
+++ b/engines/gob/draw.cpp
@@ -24,6 +24,7 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "gob/gob.h"
#include "gob/draw.h"
@@ -328,7 +329,7 @@ void Draw::adjustCoords(char adjust, int16 *coord1, int16 *coord2) {
if (coord2)
*coord2 *= 2;
if (coord1)
- *coord2 *= 2;
+ *coord1 *= 2;
break;
case 1:
@@ -470,10 +471,8 @@ void Draw::oPlaytoons_sub_F_1B(uint16 id, int16 left, int16 top, int16 right, in
else
WRITE_VAR(24, (uint32) 0);
WRITE_VAR(25, (uint32) shortId);
- if (_hotspotText) {
- strncpy(_hotspotText, paramStr, 40);
- _hotspotText[39] = 0;
- }
+ if (_hotspotText)
+ Common::strlcpy(_hotspotText, paramStr, 40);
}
_vm->_inter->funcBlock(0);
_vm->_game->_script->pop();
@@ -640,10 +639,11 @@ void Draw::wobble(Surface &surfDesc) {
}
Font *Draw::loadFont(const char *path) const {
- if (!_vm->_dataIO->existData(path))
+ if (!_vm->_dataIO->hasFile(path))
return 0;
- byte *data = _vm->_dataIO->getData(path);
+ int32 size;
+ byte *data = _vm->_dataIO->getFile(path, size);
return new Font(data);
}
diff --git a/engines/gob/draw_playtoons.cpp b/engines/gob/draw_playtoons.cpp
index 8d8f040924..fc5521a959 100644
--- a/engines/gob/draw_playtoons.cpp
+++ b/engines/gob/draw_playtoons.cpp
@@ -151,7 +151,7 @@ void Draw_Playtoons::spriteOperation(int16 operation) {
case DRAW_PUTPIXEL:
switch (_pattern & 0xFF) {
- case -1:
+ case 0xFF:
warning("oPlaytoons_spriteOperation: operation DRAW_PUTPIXEL, pattern -1");
break;
case 1:
diff --git a/engines/gob/draw_v1.cpp b/engines/gob/draw_v1.cpp
index 6496229282..d130f424c2 100644
--- a/engines/gob/draw_v1.cpp
+++ b/engines/gob/draw_v1.cpp
@@ -24,11 +24,11 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "graphics/cursorman.h"
#include "gob/gob.h"
#include "gob/draw.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/game.h"
@@ -258,7 +258,7 @@ void Draw_v1::printTotText(int16 id) {
} else if (cmd == 1) {
val = READ_LE_UINT16(ptrEnd + 18) * 4;
- strncpy0(buf, GET_VARO_STR(val), 19);
+ Common::strlcpy(buf, GET_VARO_STR(val), 20);
} else {
val = READ_LE_UINT16(ptrEnd + 18) * 4;
diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp
index bb2a57b790..ec678644d5 100644
--- a/engines/gob/draw_v2.cpp
+++ b/engines/gob/draw_v2.cpp
@@ -24,11 +24,11 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "graphics/cursorman.h"
#include "gob/gob.h"
#include "gob/draw.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/game.h"
@@ -550,7 +550,7 @@ void Draw_v2::printTotText(int16 id) {
sprintf(buf, "%d", VAR_OFFSET(val));
} else if (cmd == 1) {
val = READ_LE_UINT16(ptrEnd + 18) * 4;
- strncpy0(buf, GET_VARO_STR(val), 19);
+ Common::strlcpy(buf, GET_VARO_STR(val), 20);
} else {
val = READ_LE_UINT16(ptrEnd + 18) * 4;
sprintf(buf, "%d", VAR_OFFSET(val));
diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp
index f77b3e946a..98c1066cb0 100644
--- a/engines/gob/game.cpp
+++ b/engines/gob/game.cpp
@@ -24,10 +24,10 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "gob/gob.h"
#include "gob/game.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/dataio.h"
#include "gob/variables.h"
@@ -247,7 +247,7 @@ void Game::playTot(int16 skipPlay) {
int16 *oldCaptureCounter;
int16 *oldBreakFrom;
int16 *oldNestLevel;
- int16 _captureCounter;
+ int16 captureCounter = 0;
int16 breakFrom;
int16 nestLevel;
@@ -259,7 +259,7 @@ void Game::playTot(int16 skipPlay) {
_vm->_inter->_nestLevel = &nestLevel;
_vm->_inter->_breakFromLevel = &breakFrom;
- _vm->_scenery->_pCaptureCounter = &_captureCounter;
+ _vm->_scenery->_pCaptureCounter = &captureCounter;
strcpy(savedTotName, _curTotFile);
if (skipPlay <= 0) {
@@ -319,10 +319,12 @@ void Game::playTot(int16 skipPlay) {
_vm->_inter->renewTimeInVars();
- WRITE_VAR(13, _vm->_global->_useMouse);
- WRITE_VAR(14, _vm->_global->_soundFlags);
- WRITE_VAR(15, _vm->_global->_fakeVideoMode);
- WRITE_VAR(16, _vm->_global->_language);
+ if (_vm->_inter->_variables) {
+ WRITE_VAR(13, _vm->_global->_useMouse);
+ WRITE_VAR(14, _vm->_global->_soundFlags);
+ WRITE_VAR(15, _vm->_global->_fakeVideoMode);
+ WRITE_VAR(16, _vm->_global->_language);
+ }
_vm->_inter->callSub(2);
@@ -357,7 +359,8 @@ void Game::playTot(int16 skipPlay) {
if (_totToLoad[0] == 0)
break;
- strcpy(_curTotFile, _totToLoad);
+ Common::strlcpy(_curTotFile, _totToLoad, 14);
+
}
} else {
_vm->_inter->initControlVars(0);
@@ -370,7 +373,7 @@ void Game::playTot(int16 skipPlay) {
_vm->_inter->_terminate = 2;
}
- strcpy(_curTotFile, savedTotName);
+ Common::strlcpy(_curTotFile, savedTotName, 14);
_vm->_inter->_nestLevel = oldNestLevel;
_vm->_inter->_breakFromLevel = oldBreakFrom;
@@ -575,7 +578,7 @@ void Game::totSub(int8 flags, const char *newTotFile) {
if (flags & 1)
_vm->_inter->_variables = 0;
- strncpy0(_curTotFile, newTotFile, 9);
+ Common::strlcpy(_curTotFile, newTotFile, 10);
strcat(_curTotFile, ".TOT");
if (_vm->_inter->_terminate != 0) {
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 65c960bd73..e8cbec270c 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -136,6 +136,8 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) {
_copyProtection = ConfMan.getBool("copy_protection");
+ _console = new GobConsole(this);
+
DebugMan.addDebugChannel(kDebugFuncOp, "FuncOpcodes", "Script FuncOpcodes debug level");
DebugMan.addDebugChannel(kDebugDrawOp, "DrawOpcodes", "Script DrawOpcodes debug level");
DebugMan.addDebugChannel(kDebugGobOp, "GoblinOpcodes", "Script GoblinOpcodes debug level");
@@ -153,6 +155,8 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) {
}
GobEngine::~GobEngine() {
+ delete _console;
+
deinitGameParts();
}
@@ -366,7 +370,7 @@ bool GobEngine::initGameParts() {
_global = new Global(this);
_util = new Util(this);
- _dataIO = new DataIO(this);
+ _dataIO = new DataIO();
_palAnim = new PalAnim(this);
_vidPlayer = new VideoPlayer(this);
_sound = new Sound(this);
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
index f6c03fa617..fe69e27c01 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -32,6 +32,8 @@
#include "engines/engine.h"
+#include "gob/console.h"
+
namespace GUI {
class StaticTextWidget;
}
@@ -41,8 +43,14 @@ namespace GUI {
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Gobliiins
+ * - Gobliins 2
+ * - Goblins 3
+ * - Ween: The Prophecy
+ * - Bargon Attack
+ * - Lost in Time
+ * - The Bizarre Adventures of Woodruff and the Schnibble
*/
namespace Gob {
@@ -62,6 +70,7 @@ class PalAnim;
class Scenery;
class Util;
class SaveLoad;
+class GobConsole;
#define WRITE_VAR_UINT32(var, val) _vm->_inter->_variables->writeVar32(var, val)
#define WRITE_VAR_UINT16(var, val) _vm->_inter->_variables->writeVar16(var, val)
@@ -152,6 +161,7 @@ private:
GameType _gameType;
int32 _features;
Common::Platform _platform;
+ GobConsole *_console;
uint32 _pauseStart;
@@ -221,6 +231,8 @@ public:
bool isTrueColor() const;
bool isDemo() const;
+ GUI::Debugger *getDebugger() { return _console; }
+
const Graphics::PixelFormat &getPixelFormat() const;
GobEngine(OSystem *syst);
diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp
index ee2b4f52c9..402b33d5fd 100644
--- a/engines/gob/goblin.cpp
+++ b/engines/gob/goblin.cpp
@@ -23,9 +23,10 @@
*
*/
+#include "common/str.h"
+
#include "gob/gob.h"
#include "gob/goblin.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/draw.h"
@@ -668,11 +669,11 @@ void Goblin::adjustDest(int16 posX, int16 posY) {
resDelta = i;
}
- for (i = 1; ((i + _pressedMapX) < _vm->_map->_mapWidth) &&
+ for (i = 1; ((i + _pressedMapX) < _vm->_map->getMapWidth()) &&
(_vm->_map->getPass(_pressedMapX + i, _pressedMapY) == 0); i++)
;
- if ((_pressedMapX + i) < _vm->_map->_mapWidth) {
+ if ((_pressedMapX + i) < _vm->_map->getMapWidth()) {
deltaPix = (i * 12) - (posX % 12);
if ((resDelta == -1) || (deltaPix < resDeltaPix)) {
resDeltaPix = deltaPix;
@@ -681,11 +682,11 @@ void Goblin::adjustDest(int16 posX, int16 posY) {
}
}
- for (i = 1; ((i + _pressedMapY) < _vm->_map->_mapHeight) &&
+ for (i = 1; ((i + _pressedMapY) < _vm->_map->getMapHeight()) &&
(_vm->_map->getPass(_pressedMapX, _pressedMapY + i) == 0); i++)
;
- if ((_pressedMapY + i) < _vm->_map->_mapHeight) {
+ if ((_pressedMapY + i) < _vm->_map->getMapHeight()) {
deltaPix = (i * 6) - (posY % 6);
if ((resDelta == -1) || (deltaPix < resDeltaPix)) {
resDeltaPix = deltaPix;
@@ -726,8 +727,8 @@ void Goblin::adjustDest(int16 posX, int16 posY) {
}
}
- _pressedMapX = CLIP((int) _pressedMapX, 0, _vm->_map->_mapWidth - 1);
- _pressedMapY = CLIP((int) _pressedMapY, 0, _vm->_map->_mapHeight - 1);
+ _pressedMapX = CLIP((int) _pressedMapX, 0, _vm->_map->getMapWidth() - 1);
+ _pressedMapY = CLIP((int) _pressedMapY, 0, _vm->_map->getMapHeight() - 1);
}
void Goblin::adjustTarget() {
@@ -737,18 +738,18 @@ void Goblin::adjustTarget() {
if ((_pressedMapY > 0) &&
(_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) {
_pressedMapY--;
- } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
+ } else if ((_pressedMapX < (_vm->_map->getMapWidth() - 1)) &&
(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) {
_pressedMapX++;
- } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
+ } else if ((_pressedMapX < (_vm->_map->getMapWidth() - 1)) &&
(_pressedMapY > 0) &&
(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) {
_pressedMapY--;
_pressedMapX++;
}
}
- _pressedMapX = CLIP((int) _pressedMapX, 0, _vm->_map->_mapWidth - 1);
- _pressedMapY = CLIP((int) _pressedMapY, 0, _vm->_map->_mapHeight - 1);
+ _pressedMapX = CLIP((int) _pressedMapX, 0, _vm->_map->getMapWidth() - 1);
+ _pressedMapY = CLIP((int) _pressedMapY, 0, _vm->_map->getMapHeight() - 1);
}
void Goblin::targetDummyItem(Gob_Object *gobDesc) {
@@ -847,7 +848,7 @@ void Goblin::targetItem() {
}
}
- if (_pressedMapY < (_vm->_map->_mapHeight-1)) {
+ if (_pressedMapY < (_vm->_map->getMapHeight()-1)) {
if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1)) ==
(_vm->_map->getItem(_pressedMapX, _pressedMapY))) {
_pressedMapY++;
@@ -898,8 +899,8 @@ void Goblin::targetItem() {
}
}
}
- _pressedMapX = CLIP((int) _pressedMapX, 0, _vm->_map->_mapWidth - 1);
- _pressedMapY = CLIP((int) _pressedMapY, 0, _vm->_map->_mapHeight - 1);
+ _pressedMapX = CLIP((int) _pressedMapX, 0, _vm->_map->getMapWidth() - 1);
+ _pressedMapY = CLIP((int) _pressedMapY, 0, _vm->_map->getMapHeight() - 1);
}
void Goblin::moveFindItem(int16 posX, int16 posY) {
@@ -933,23 +934,23 @@ void Goblin::moveFindItem(int16 posX, int16 posY) {
break;
}
- _pressedMapX = CLIP(posX / 12, 0, _vm->_map->_mapWidth - 1);
- _pressedMapY = CLIP(posY / 6, 0, _vm->_map->_mapHeight - 1);
+ _pressedMapX = CLIP(posX / 12, 0, _vm->_map->getMapWidth() - 1);
+ _pressedMapY = CLIP(posY / 6, 0, _vm->_map->getMapHeight() - 1);
if ((_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0) && (i < 20)) {
- if ((_pressedMapY < (_vm->_map->_mapHeight - 1)) &&
+ if ((_pressedMapY < (_vm->_map->getMapHeight() - 1)) &&
(_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) != 0)) {
_pressedMapY++;
- } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
- (_pressedMapY < (_vm->_map->_mapHeight - 1)) &&
+ } else if ((_pressedMapX < (_vm->_map->getMapWidth() - 1)) &&
+ (_pressedMapY < (_vm->_map->getMapHeight() - 1)) &&
(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY + 1) != 0)) {
_pressedMapX++;
_pressedMapY++;
- } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
+ } else if ((_pressedMapX < (_vm->_map->getMapWidth() - 1)) &&
(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) {
_pressedMapX++;
- } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
+ } else if ((_pressedMapX < (_vm->_map->getMapWidth() - 1)) &&
(_pressedMapY > 0) &&
(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) {
_pressedMapX++;
@@ -965,15 +966,15 @@ void Goblin::moveFindItem(int16 posX, int16 posY) {
(_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) != 0)) {
_pressedMapX--;
} else if ((_pressedMapX > 0) &&
- (_pressedMapY < (_vm->_map->_mapHeight - 1)) &&
+ (_pressedMapY < (_vm->_map->getMapHeight() - 1)) &&
(_vm->_map->getItem(_pressedMapX - 1, _pressedMapY + 1) != 0)) {
_pressedMapX--;
_pressedMapY++;
}
}
} else {
- _pressedMapX = CLIP(posX / 12, 0, _vm->_map->_mapWidth - 1);
- _pressedMapY = CLIP(posY / 6, 0, _vm->_map->_mapHeight - 1);
+ _pressedMapX = CLIP(posX / 12, 0, _vm->_map->getMapWidth() - 1);
+ _pressedMapY = CLIP(posY / 6, 0, _vm->_map->getMapHeight() - 1);
}
}
@@ -1186,7 +1187,7 @@ void Goblin::loadObjects(const char *source) {
freeObjects();
initList();
- strncpy0(_vm->_map->_sourceFile, source, 14);
+ Common::strlcpy(_vm->_map->_sourceFile, source, 15);
_vm->_map->_sourceFile[strlen(_vm->_map->_sourceFile) - 4] = 0;
_vm->_map->loadMapObjects(source);
@@ -1386,8 +1387,8 @@ void Goblin::pickItem(int16 indexToPocket, int16 idToPocket) {
_itemIndInPocket = indexToPocket;
_itemIdInPocket = idToPocket;
- for (int y = 0; y < _vm->_map->_mapHeight; y++) {
- for (int x = 0; x < _vm->_map->_mapWidth; x++) {
+ for (int y = 0; y < _vm->_map->getMapHeight(); y++) {
+ for (int x = 0; x < _vm->_map->getMapWidth(); x++) {
if (_itemByteFlag == 1) {
if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPocket)
_vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF);
@@ -1450,7 +1451,7 @@ void Goblin::placeItem(int16 indexInPocket, int16 idInPocket) {
_vm->_map->placeItem(xPos, yPos - 1, idInPocket);
if (lookDir == 4) {
- if (xPos < _vm->_map->_mapWidth - 1) {
+ if (xPos < _vm->_map->getMapWidth() - 1) {
_vm->_map->placeItem(xPos + 1, yPos, idInPocket);
if (yPos > 0)
@@ -1497,16 +1498,16 @@ void Goblin::swapItems(int16 indexToPick, int16 idToPick) {
_itemIdInPocket = idToPick;
if (_itemByteFlag == 0) {
- for (y = 0; y < _vm->_map->_mapHeight; y++) {
- for (x = 0; x < _vm->_map->_mapWidth; x++) {
+ for (y = 0; y < _vm->_map->getMapHeight(); y++) {
+ for (x = 0; x < _vm->_map->getMapWidth(); x++) {
if ((_vm->_map->getItem(x, y) & 0xFF) == idToPick)
_vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF00) + idToPlace);
}
}
} else {
- for (y = 0; y < _vm->_map->_mapHeight; y++) {
- for (x = 0; x < _vm->_map->_mapWidth; x++) {
+ for (y = 0; y < _vm->_map->getMapHeight(); y++) {
+ for (x = 0; x < _vm->_map->getMapWidth(); x++) {
if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPick)
_vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF) + (idToPlace << 8));
}
@@ -1704,15 +1705,15 @@ void Goblin::setState(int16 index, int16 state) {
animData->newCycle = _vm->_scenery->getAnimLayer(animation, layer)->framesCount;
_vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 1);
- if (_vm->_map->_bigTiles) {
- *obj->pPosY = ((obj->goblinY + 1) * _vm->_map->_tilesHeight) -
+ if (_vm->_map->hasBigTiles()) {
+ *obj->pPosY = ((obj->goblinY + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) -
(obj->goblinY + 1) / 2;
} else {
- *obj->pPosY = (obj->goblinY + 1) * _vm->_map->_tilesHeight -
+ *obj->pPosY = (obj->goblinY + 1) * _vm->_map->getTilesHeight() -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
}
- *obj->pPosX = obj->goblinX * _vm->_map->_tilesWidth;
+ *obj->pPosX = obj->goblinX * _vm->_map->getTilesWidth();
}
void Goblin::animate(Mult::Mult_Object *obj) {
@@ -1780,40 +1781,69 @@ void Goblin::animate(Mult::Mult_Object *obj) {
}
void Goblin::move(int16 destX, int16 destY, int16 objIndex) {
- Mult::Mult_Object *obj;
- Mult::Mult_AnimData *animData;
- int16 mouseX;
- int16 mouseY;
- int16 gobDestX;
- int16 gobDestY;
- obj = &_vm->_mult->_objects[objIndex];
- animData = obj->pAnimData;
+ Mult::Mult_Object *obj = &_vm->_mult->_objects[objIndex];
+ Mult::Mult_AnimData *animData = obj->pAnimData;
- obj->gobDestX = destX;
- obj->gobDestY = destY;
+ obj->gobDestX = destX;
+ obj->gobDestY = destY;
animData->destX = destX;
animData->destY = destY;
if (animData->isBusy != 0) {
if ((destX == -1) && (destY == -1)) {
- mouseX = _vm->_global->_inter_mouseX;
- mouseY = _vm->_global->_inter_mouseY;
- if (_vm->_map->_bigTiles)
- mouseY += ((_vm->_global->_inter_mouseY / _vm->_map->_tilesHeight) + 1) / 2;
+ int16 mouseX = _vm->_global->_inter_mouseX;
+ int16 mouseY = _vm->_global->_inter_mouseY;
+
+ if (_vm->_map->hasBigTiles())
+ mouseY += ((_vm->_global->_inter_mouseY / _vm->_map->getTilesHeight()) + 1) / 2;
- gobDestX = mouseX / _vm->_map->_tilesWidth;
- gobDestY = mouseY / _vm->_map->_tilesHeight;
+ int16 gobDestX = mouseX / _vm->_map->getTilesWidth();
+ int16 gobDestY = mouseY / _vm->_map->getTilesHeight();
if (_vm->_map->getPass(gobDestX, gobDestY) == 0)
_vm->_map->findNearestWalkable(gobDestX, gobDestY, mouseX, mouseY);
- animData->destX = obj->gobDestX =
- (gobDestX == -1) ? obj->goblinX : gobDestX;
- animData->destY = obj->gobDestY =
- (gobDestY == -1) ? obj->goblinY : gobDestY;
+ obj->gobDestX = (gobDestX == -1) ? obj->goblinX : gobDestX;
+ obj->gobDestY = (gobDestY == -1) ? obj->goblinY : gobDestY;
+
+ animData->destX = obj->gobDestX;
+ animData->destY = obj->gobDestY;
+ }
+ }
+
+ WRITE_VAR(56, 0);
+
+ byte passType = _vm->_map->getPass(obj->gobDestX, obj->gobDestY);
+
+ // Prevent continuous walking on wide stairs
+ if (passType == 11) {
+ if (_vm->_map->getScreenWidth() == 640) {
+ obj->gobDestY++;
+ animData->destY++;
}
}
+
+ // Prevent stopping in the middle of big ladders
+ if ((passType == 19) || (passType == 20)) {
+ int ladderTop = 0;
+ while (_vm->_map->getPass(obj->gobDestX, obj->gobDestY + ladderTop) == passType)
+ ladderTop++;
+
+ int ladderBottom = 0;
+ while (_vm->_map->getPass(obj->gobDestX, obj->gobDestY + ladderBottom) == passType)
+ ladderBottom--;
+
+ int ladderDest;
+ if (ABS(ladderBottom) <= ladderTop)
+ ladderDest = obj->gobDestY + ladderBottom;
+ else
+ ladderDest = obj->gobDestY + ladderTop;
+
+ obj->gobDestY = ladderDest;
+ animData->destY = ladderDest;
+ }
+
initiateMove(obj);
}
diff --git a/engines/gob/goblin_v1.cpp b/engines/gob/goblin_v1.cpp
index f55fec433c..3dc4c6611d 100644
--- a/engines/gob/goblin_v1.cpp
+++ b/engines/gob/goblin_v1.cpp
@@ -154,8 +154,10 @@ void Goblin_v1::initiateMove(Mult::Mult_Object *obj) {
_vm->_map->_nearestWayPoint, _vm->_map->_nearestDest) == 0) {
_pathExistence = 0;
} else {
- _vm->_map->_destX = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].x;
- _vm->_map->_destY = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].y;
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(_vm->_map->_nearestWayPoint);
+
+ _vm->_map->_destX = wayPoint.x;
+ _vm->_map->_destY = wayPoint.y;
}
}
}
@@ -173,10 +175,10 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
_pathExistence = 0;
}
- nextAct = _vm->_map->getDirection(_vm->_map->_curGoblinX,
+ nextAct = (int16) _vm->_map->getDirection(_vm->_map->_curGoblinX,
_vm->_map->_curGoblinY, _vm->_map->_destX, _vm->_map->_destY);
- if (nextAct == 0)
+ if (nextAct == kDirNone)
_pathExistence = 0;
} else if (_pathExistence == 3) {
_vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
@@ -199,20 +201,20 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
if (_vm->_map->_nearestWayPoint > _vm->_map->_nearestDest) {
_vm->_map->optimizePoints(0, 0, 0);
- _vm->_map->_destX =
- _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].x;
- _vm->_map->_destY =
- _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].y;
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(_vm->_map->_nearestWayPoint);
+
+ _vm->_map->_destX = wayPoint.x;
+ _vm->_map->_destY = wayPoint.y;
if (_vm->_map->_nearestWayPoint > _vm->_map->_nearestDest)
_vm->_map->_nearestWayPoint--;
} else if (_vm->_map->_nearestWayPoint < _vm->_map->_nearestDest) {
_vm->_map->optimizePoints(0, 0, 0);
- _vm->_map->_destX =
- _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].x;
- _vm->_map->_destY =
- _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].y;
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(_vm->_map->_nearestWayPoint);
+
+ _vm->_map->_destX = wayPoint.x;
+ _vm->_map->_destY = wayPoint.y;
if (_vm->_map->_nearestWayPoint < _vm->_map->_nearestDest)
_vm->_map->_nearestWayPoint++;
@@ -220,8 +222,12 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
if ((_vm->_map->checkDirectPath(0, _vm->_map->_curGoblinX,
_vm->_map->_curGoblinY, _gobDestX, _gobDestY) == 3) &&
(_vm->_map->getPass(_pressedMapX, _pressedMapY) != 0)) {
- _vm->_map->_destX = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].x;
- _vm->_map->_destY = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].y;
+
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(_vm->_map->_nearestWayPoint);
+
+ _vm->_map->_destX = wayPoint.x;
+ _vm->_map->_destY = wayPoint.y;
+
} else {
_pathExistence = 1;
_vm->_map->_destX = _pressedMapX;
@@ -229,7 +235,7 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
}
}
}
- nextAct = _vm->_map->getDirection(_vm->_map->_curGoblinX,
+ nextAct = (int16) _vm->_map->getDirection(_vm->_map->_curGoblinX,
_vm->_map->_curGoblinY, _vm->_map->_destX, _vm->_map->_destY);
}
}
@@ -238,11 +244,11 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
nextAct = 0x4DC8;
switch (nextAct) {
- case Map::kDirW:
+ case kDirW:
gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
break;
- case Map::kDirE:
+ case kDirE:
gobDesc->nextState = rotateState(gobDesc->curLookDir, 4);
break;
@@ -254,7 +260,7 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
gobDesc->nextState = 23;
break;
- case Map::kDirN:
+ case kDirN:
if ((_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY - 1) == 6) &&
(_currentGoblin != 1)) {
_pathExistence = 0;
@@ -275,7 +281,7 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
gobDesc->nextState = rotateState(gobDesc->curLookDir, 2);
break;
- case Map::kDirS:
+ case kDirS:
if ((_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY + 1) == 6) &&
(_currentGoblin != 1)) {
_pathExistence = 0;
@@ -296,7 +302,7 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
gobDesc->nextState = rotateState(gobDesc->curLookDir, 6);
break;
- case Map::kDirSE:
+ case kDirSE:
if ((_vm->_map->getPass(_vm->_map->_curGoblinX + 1, _vm->_map->_curGoblinY + 1) == 6) &&
(_currentGoblin != 1)) {
_pathExistence = 0;
@@ -310,7 +316,7 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
gobDesc->nextState = rotateState(gobDesc->curLookDir, 4);
break;
- case Map::kDirSW:
+ case kDirSW:
if ((_vm->_map->getPass(_vm->_map->_curGoblinX - 1, _vm->_map->_curGoblinY + 1) == 6) &&
(_currentGoblin != 1)) {
_pathExistence = 0;
@@ -324,7 +330,7 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
break;
- case Map::kDirNW:
+ case kDirNW:
if ((_vm->_map->getPass(_vm->_map->_curGoblinX - 1, _vm->_map->_curGoblinY - 1) == 6) &&
(_currentGoblin != 1)) {
_pathExistence = 0;
@@ -338,7 +344,7 @@ void Goblin_v1::movePathFind(Mult::Mult_Object *obj,
gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
break;
- case Map::kDirNE:
+ case kDirNE:
if ((_vm->_map->getPass(_vm->_map->_curGoblinX + 1, _vm->_map->_curGoblinY - 1) == 6) &&
(_currentGoblin != 1)) {
_pathExistence = 0;
diff --git a/engines/gob/goblin_v2.cpp b/engines/gob/goblin_v2.cpp
index 2747750abb..503377c19b 100644
--- a/engines/gob/goblin_v2.cpp
+++ b/engines/gob/goblin_v2.cpp
@@ -39,10 +39,10 @@ namespace Gob {
Goblin_v2::Goblin_v2(GobEngine *vm) : Goblin_v1(vm) {
_gobsCount = -1;
- _rotStates[0][0] = 0; _rotStates[0][1] = 18; _rotStates[0][2] = 19; _rotStates[0][3] = 20;
- _rotStates[1][0] = 13; _rotStates[1][1] = 2; _rotStates[1][2] = 12; _rotStates[1][3] = 14;
- _rotStates[2][0] = 16; _rotStates[2][1] = 15; _rotStates[2][2] = 4; _rotStates[2][3] = 17;
- _rotStates[3][0] = 23; _rotStates[3][1] = 21; _rotStates[3][2] = 22; _rotStates[3][3] = 6;
+ _rotStates[0][0] = 0; _rotStates[0][1] = 18; _rotStates[0][2] = 19; _rotStates[0][3] = 20;
+ _rotStates[1][0] = 13; _rotStates[1][1] = 2; _rotStates[1][2] = 12; _rotStates[1][3] = 14;
+ _rotStates[2][0] = 16; _rotStates[2][1] = 15; _rotStates[2][2] = 4; _rotStates[2][3] = 17;
+ _rotStates[3][0] = 23; _rotStates[3][1] = 21; _rotStates[3][2] = 22; _rotStates[3][3] = 6;
}
void Goblin_v2::freeObjects() {
@@ -80,13 +80,13 @@ void Goblin_v2::placeObject(Gob_Object *objDesc, char animated,
objAnim->newCycle = 0;
_vm->_scenery->updateAnim(objAnim->layer, 0, objAnim->animation, 0,
*obj->pPosX, *obj->pPosY, 0);
- if (!_vm->_map->_bigTiles)
- *obj->pPosY = (y + 1) * _vm->_map->_tilesHeight
+ if (!_vm->_map->hasBigTiles())
+ *obj->pPosY = (y + 1) * _vm->_map->getTilesHeight()
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
else
- *obj->pPosY = ((y + 1) * _vm->_map->_tilesHeight) -
+ *obj->pPosY = ((y + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (y + 1) / 2;
- *obj->pPosX = x * _vm->_map->_tilesWidth;
+ *obj->pPosX = x * _vm->_map->getTilesWidth();
} else {
if ((obj->goblinStates != 0) && (obj->goblinStates[state] != 0)) {
layer = obj->goblinStates[state][0].layer;
@@ -99,13 +99,13 @@ void Goblin_v2::placeObject(Gob_Object *objDesc, char animated,
objAnim->isStatic = 0;
objAnim->newCycle = _vm->_scenery->getAnimLayer(animation, layer)->framesCount;
_vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0);
- if (!_vm->_map->_bigTiles)
- *obj->pPosY = (y + 1) * _vm->_map->_tilesHeight
+ if (!_vm->_map->hasBigTiles())
+ *obj->pPosY = (y + 1) * _vm->_map->getTilesHeight()
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
else
- *obj->pPosY = ((y + 1) * _vm->_map->_tilesHeight) -
+ *obj->pPosY = ((y + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (y + 1) / 2;
- *obj->pPosX = x * _vm->_map->_tilesWidth;
+ *obj->pPosX = x * _vm->_map->getTilesWidth();
initiateMove(obj);
} else
initiateMove(obj);
@@ -121,54 +121,55 @@ void Goblin_v2::initiateMove(Mult::Mult_Object *obj) {
obj->pAnimData->pathExistence = _vm->_map->checkDirectPath(obj,
obj->goblinX, obj->goblinY, obj->gobDestX, obj->gobDestY);
if (obj->pAnimData->pathExistence == 3) {
- obj->destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x;
- obj->destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y;
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(obj->nearestWayPoint);
+
+ obj->destX = wayPoint.x;
+ obj->destY = wayPoint.y;
}
}
void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16 nextAct) {
- Mult::Mult_AnimData *animData;
- int16 framesCount;
- int16 gobX;
- int16 gobY;
- int16 gobDestX;
- int16 gobDestY;
- int16 destX;
- int16 destY;
- int16 dir;
-
- dir = 0;
- animData = obj->pAnimData;
- framesCount = _vm->_scenery->getAnimLayer(animData->animation, animData->layer)->framesCount;
- animData->newCycle = framesCount;
- gobX = obj->goblinX;
- gobY = obj->goblinY;
- animData->order = gobY;
- gobDestX = obj->gobDestX;
- gobDestY = obj->gobDestY;
+ Mult::Mult_AnimData *animData = obj->pAnimData;
+
+ animData->newCycle = _vm->_scenery->getAnimLayer(animData->animation, animData->layer)->framesCount;
+
+ int16 gobX = obj->goblinX;
+ int16 gobY = obj->goblinY;
+ int16 destX = obj->destX;
+ int16 destY = obj->destY;
+ int16 gobDestX = obj->gobDestX;
+ int16 gobDestY = obj->gobDestY;
+
animData->destX = gobDestX;
animData->destY = gobDestY;
- destX = obj->destX;
- destY = obj->destY;
+ animData->order = gobY;
+
+ Direction dir = kDirNone;
if (animData->pathExistence == 1) {
+
dir = _vm->_map->getDirection(gobX, gobY, destX, destY);
- if (dir == 0)
+ if (dir == kDirNone)
animData->pathExistence = 0;
- if ((gobX == destX) && (gobY == destY))
+ if ((gobX == gobDestX) && (gobY == gobDestY))
animData->pathExistence = 4;
+
} else if (animData->pathExistence == 3) {
- if ((gobX == gobDestX) && (gobY == gobDestY)) {
- animData->pathExistence = 4;
- destX = gobDestX;
- destY = gobDestY;
- } else {
+
+ if ((gobX != gobDestX) || (gobY != gobDestY)) {
+
if (_vm->_map->checkDirectPath(obj, gobX, gobY, gobDestX, gobDestY) != 1) {
+
if ((gobX == destX) && (gobY == destY)) {
+
if (obj->nearestWayPoint > obj->nearestDest) {
_vm->_map->optimizePoints(obj, gobX, gobY);
- destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x;
- destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y;
+
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(obj->nearestWayPoint);
+
+ destX = wayPoint.x;
+ destY = wayPoint.y;
+
if (_vm->_map->checkDirectPath(obj, gobX, gobY, destX, destY) == 3) {
WRITE_VAR(56, 1);
animData->pathExistence = 0;
@@ -177,8 +178,12 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
obj->nearestWayPoint--;
} else if (obj->nearestWayPoint < obj->nearestDest) {
_vm->_map->optimizePoints(obj, gobX, gobY);
- destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x;
- destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y;
+
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(obj->nearestWayPoint);
+
+ destX = wayPoint.x;
+ destY = wayPoint.y;
+
if (_vm->_map->checkDirectPath(obj, gobX, gobY, destX, destY) == 3) {
WRITE_VAR(56, 1);
animData->pathExistence = 0;
@@ -188,8 +193,12 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
} else {
if ((_vm->_map->checkDirectPath(obj, gobX, gobY, gobDestX, gobDestY) == 3) &&
(_vm->_map->getPass(gobDestX, gobDestY) != 0)) {
- destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x;
- destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y;
+
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(obj->nearestWayPoint);
+
+ destX = wayPoint.x;
+ destY = wayPoint.y;
+
WRITE_VAR(56, 1);
} else {
animData->pathExistence = 1;
@@ -197,26 +206,35 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
destY = gobDestY;
}
}
+
}
+
} else {
destX = gobDestX;
destY = gobDestY;
}
+
dir = _vm->_map->getDirection(gobX, gobY, destX, destY);
+
+ } else {
+ animData->pathExistence = 4;
+ destX = gobDestX;
+ destY = gobDestY;
}
+
}
- obj->goblinX = gobX;
- obj->goblinY = gobY;
- obj->gobDestX = gobDestX;
- obj->gobDestY = gobDestY;
- obj->destX = destX;
- obj->destY = destY;
+ obj->goblinX = gobX;
+ obj->goblinY = gobY;
+ obj->destX = destX;
+ obj->destY = destY;
+ obj->gobDestX = gobDestX;
+ obj->gobDestY = gobDestY;
switch (dir) {
- case Map::kDirNW:
+ case kDirNW:
animData->nextState = 1;
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10)
animData->nextState = 40;
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10)
@@ -224,28 +242,29 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirN:
+ case kDirN:
animData->nextState =
(animData->curLookDir == 2) ? 2 : rotateState(animData->curLookDir, 2);
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) {
- if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10) {
- if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) == 10)
- animData->nextState = 42;
- else
- animData->nextState = 2;
- } else
+ if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) == 10)
animData->nextState = 40;
- } else if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 20)
+ else if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) == 10)
+ animData->nextState = 42;
+ else
+ animData->nextState = 2;
+ }
+
+ if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 20)
animData->nextState = 38;
- else if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 19)
+ if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 19)
animData->nextState = 26;
}
break;
- case Map::kDirNE:
- animData->nextState = 3;
- if (_vm->_map->_screenWidth == 640) {
+ case kDirNE:
+ animData->nextState = 3;
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10)
animData->nextState = 42;
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) != 10)
@@ -253,17 +272,17 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirW:
+ case kDirW:
animData->nextState = rotateState(animData->curLookDir, 0);
break;
- case Map::kDirE:
+ case kDirE:
animData->nextState = rotateState(animData->curLookDir, 4);
break;
- case Map::kDirSW:
+ case kDirSW:
animData->nextState = 7;
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10)
animData->nextState = 41;
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY + 2) != 10)
@@ -271,10 +290,10 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirS:
+ case kDirS:
animData->nextState =
(animData->curLookDir == 6) ? 6 : rotateState(animData->curLookDir, 6);
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 20)
animData->nextState = 39;
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 19)
@@ -282,9 +301,9 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirSE:
+ case kDirSE:
animData->nextState = 5;
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10)
animData->nextState = 43;
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY + 2) != 10)
@@ -293,7 +312,7 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
break;
default:
- if (animData->curLookDir == 0)
+ if (animData->curLookDir == 0)
animData->nextState = 8;
else if (animData->curLookDir == 2)
animData->nextState = 29;
@@ -307,12 +326,6 @@ void Goblin_v2::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
void Goblin_v2::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc,
int16 nextAct, int16 framesCount) {
- Mult::Mult_AnimData *animData;
- int16 gobX;
- int16 gobY;
- int16 animation;
- int16 state;
- int16 layer;
if (!obj->goblinStates)
return;
@@ -320,7 +333,7 @@ void Goblin_v2::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc,
movePathFind(obj, 0, 0);
playSounds(obj);
- animData = obj->pAnimData;
+ Mult::Mult_AnimData *animData = obj->pAnimData;
framesCount = _vm->_scenery->getAnimLayer(animData->animation, animData->layer)->framesCount;
@@ -395,72 +408,87 @@ void Goblin_v2::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc,
}
if ((animData->newState != -1) && (animData->frame == framesCount) &&
- (animData->newState != animData->state)) {
+ (animData->newState != animData->state)) {
+
animData->nextState = animData->newState;
- animData->newState = -1;
- animData->state = animData->nextState;
+ animData->newState = -1;
+ animData->state = animData->nextState;
Scenery::AnimLayer *animLayer =
_vm->_scenery->getAnimLayer(animData->animation, animData->layer);
+
*obj->pPosX += animLayer->animDeltaX;
*obj->pPosY += animLayer->animDeltaY;
- animation = obj->goblinStates[animData->nextState][0].animation;
- layer = obj->goblinStates[animData->nextState][0].layer;
- animData->layer = layer;
+ int16 animation = obj->goblinStates[animData->nextState][0].animation;
+ int16 layer = obj->goblinStates[animData->nextState][0].layer;
+
+ animData->layer = layer;
animData->animation = animation;
- animData->frame = 0;
- } else {
- if (isMovement(animData->state)) {
- state = animData->nextState;
- if (animData->frame == ((framesCount + 1) / 2)) {
- gobX = obj->goblinX;
- gobY = obj->goblinY;
-
- advMovement(obj, state);
-
- if (animData->state != state) {
- animation = obj->goblinStates[state][0].animation;
- layer = obj->goblinStates[state][0].layer;
- animData->layer = layer;
- animData->animation = animation;
- animData->frame = 0;
- animData->state = state;
- _vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0);
- if (_vm->_map->_bigTiles)
- *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) -
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (gobY + 1) / 2;
- else
- *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) -
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
- *obj->pPosX = gobX * _vm->_map->_tilesWidth;
- }
- }
- }
+ animData->frame = 0;
- if (animData->frame >= framesCount) {
- state = animData->nextState;
- animation = obj->goblinStates[state][0].animation;
- layer = obj->goblinStates[state][0].layer;
- animData->layer = layer;
- animData->animation = animation;
- animData->frame = 0;
- animData->state = state;
- gobX = obj->goblinX;
- gobY = obj->goblinY;
+ return;
+ }
+
+ if (isMovement(animData->state)) {
+ int16 state = animData->nextState;
+
+ if (animData->frame == ((framesCount + 1) / 2)) {
+ int16 gobX = obj->goblinX;
+ int16 gobY = obj->goblinY + 1;
advMovement(obj, state);
- _vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0);
- if (_vm->_map->_bigTiles)
- *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) -
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (gobY + 1) / 2;
- else
- *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) -
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
- *obj->pPosX = gobX * _vm->_map->_tilesWidth;
+ if (animData->state != state) {
+ int16 animation = obj->goblinStates[state][0].animation;
+ int16 layer = obj->goblinStates[state][0].layer;
+
+ animData->layer = layer;
+ animData->animation = animation;
+ animData->frame = 0;
+ animData->state = state;
+
+ _vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0);
+ uint32 gobPosX = gobX * _vm->_map->getTilesWidth();
+ uint32 gobPosY = (gobY * _vm->_map->getTilesHeight()) -
+ (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
+
+ if (_vm->_map->hasBigTiles())
+ gobPosY -= gobY / 2;
+
+ *obj->pPosX = gobPosX;
+ *obj->pPosY = gobPosY;
+ }
}
}
+
+ if (animData->frame < framesCount)
+ return;
+
+ int16 state = animData->nextState;
+ int16 animation = obj->goblinStates[state][0].animation;
+ int16 layer = obj->goblinStates[state][0].layer;
+
+ animData->layer = layer;
+ animData->animation = animation;
+ animData->frame = 0;
+ animData->state = state;
+
+ int16 gobX = obj->goblinX;
+ int16 gobY = obj->goblinY + 1;
+
+ advMovement(obj, state);
+
+ _vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0);
+ uint32 gobPosX = gobX * _vm->_map->getTilesWidth();
+ uint32 gobPosY = (gobY * _vm->_map->getTilesHeight()) -
+ (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
+
+ if (_vm->_map->hasBigTiles())
+ gobPosY -= gobY / 2;
+
+ *obj->pPosX = gobPosX;
+ *obj->pPosY = gobPosY;
}
void Goblin_v2::handleGoblins() {
diff --git a/engines/gob/goblin_v4.cpp b/engines/gob/goblin_v4.cpp
index 25c52cef35..523357aab1 100644
--- a/engines/gob/goblin_v4.cpp
+++ b/engines/gob/goblin_v4.cpp
@@ -77,8 +77,12 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
if ((gobX == destX) && (gobY == destY)) {
if (obj->nearestWayPoint > obj->nearestDest) {
_vm->_map->optimizePoints(obj, gobX, gobY);
- destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x;
- destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y;
+
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(obj->nearestWayPoint);
+
+ destX = wayPoint.x;
+ destY = wayPoint.y;
+
if (_vm->_map->checkDirectPath(obj, gobX, gobY, destX, destY) == 3) {
WRITE_VAR(56, 1);
animData->pathExistence = 0;
@@ -87,8 +91,12 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
obj->nearestWayPoint--;
} else if (obj->nearestWayPoint < obj->nearestDest) {
_vm->_map->optimizePoints(obj, gobX, gobY);
- destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x;
- destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y;
+
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(obj->nearestWayPoint);
+
+ destX = wayPoint.x;
+ destY = wayPoint.y;
+
if (_vm->_map->checkDirectPath(obj, gobX, gobY, destX, destY) == 3) {
WRITE_VAR(56, 1);
animData->pathExistence = 0;
@@ -98,8 +106,12 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
} else {
if ((_vm->_map->checkDirectPath(obj, gobX, gobY, gobDestX, gobDestY) == 3) &&
(_vm->_map->getPass(gobDestX, gobDestY) != 0)) {
- destX = _vm->_map->_wayPoints[obj->nearestWayPoint].x;
- destY = _vm->_map->_wayPoints[obj->nearestWayPoint].y;
+
+ const WayPoint &wayPoint = _vm->_map->getWayPoint(obj->nearestWayPoint);
+
+ destX = wayPoint.x;
+ destY = wayPoint.y;
+
WRITE_VAR(56, 1);
} else {
animData->pathExistence = 1;
@@ -123,20 +135,20 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
obj->destX = destX;
obj->destY = destY;
- if (_vm->_map->_widthByte == 4) {
+ if (_vm->_map->getVersion() == 4) {
switch (dir) {
- case Map::kDirNW:
- animData->nextState = turnState(animData->state, Map::kDirNW);
+ case kDirNW:
+ animData->nextState = turnState(animData->state, kDirNW);
if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) &&
(animData->nextState == 1))
animData->nextState = 40;
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10)
- animData->nextState = turnState(animData->state, Map::kDirNW);
+ animData->nextState = turnState(animData->state, kDirNW);
break;
- case Map::kDirN:
+ case kDirN:
animData->nextState =
- (animData->curLookDir == 2) ? 2 : turnState(animData->state, Map::kDirN);
+ (animData->curLookDir == 2) ? 2 : turnState(animData->state, kDirN);
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) {
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10) {
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) == 10)
@@ -154,35 +166,35 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
animData->nextState = 26;
break;
- case Map::kDirNE:
- animData->nextState = turnState(animData->state, Map::kDirNE);
+ case kDirNE:
+ animData->nextState = turnState(animData->state, kDirNE);
if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) &&
(animData->nextState == 3))
animData->nextState = 42;
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) != 10)
- animData->nextState = turnState(animData->state, Map::kDirNE);
+ animData->nextState = turnState(animData->state, kDirNE);
break;
- case Map::kDirW:
- animData->nextState = turnState(animData->state, Map::kDirW);
+ case kDirW:
+ animData->nextState = turnState(animData->state, kDirW);
break;
- case Map::kDirE:
- animData->nextState = turnState(animData->state, Map::kDirE);
+ case kDirE:
+ animData->nextState = turnState(animData->state, kDirE);
break;
- case Map::kDirSW:
- animData->nextState = turnState(animData->state, Map::kDirSW);
+ case kDirSW:
+ animData->nextState = turnState(animData->state, kDirSW);
if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) &&
(animData->nextState == 7))
animData->nextState = 41;
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY) != 10)
- animData->nextState = turnState(animData->state, Map::kDirSW);
+ animData->nextState = turnState(animData->state, kDirSW);
break;
- case Map::kDirS:
+ case kDirS:
animData->nextState =
- (animData->curLookDir == 6) ? 6 : turnState(animData->state, Map::kDirS);
+ (animData->curLookDir == 6) ? 6 : turnState(animData->state, kDirS);
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) {
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY + 2) != 10) {
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY + 2) == 10)
@@ -201,13 +213,13 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
animData->nextState = 27;
break;
- case Map::kDirSE:
- animData->nextState = turnState(animData->state, Map::kDirSE);
+ case kDirSE:
+ animData->nextState = turnState(animData->state, kDirSE);
if ((_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) &&
(animData->nextState == 5))
animData->nextState = 43;
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY) != 10)
- animData->nextState = turnState(animData->state, Map::kDirSE);
+ animData->nextState = turnState(animData->state, kDirSE);
break;
default:
@@ -260,9 +272,9 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
} else {
switch (dir) {
- case Map::kDirNW:
+ case kDirNW:
animData->nextState = 1;
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10)
animData->nextState = 40;
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10)
@@ -270,10 +282,10 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirN:
+ case kDirN:
animData->nextState =
(animData->curLookDir == 2) ? 2 : rotateState(animData->curLookDir, 2);
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10) {
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY - 2) != 10) {
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) == 10)
@@ -289,9 +301,9 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirNE:
+ case kDirNE:
animData->nextState = 3;
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10)
animData->nextState = 42;
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY - 2) != 10)
@@ -299,17 +311,17 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirW:
+ case kDirW:
animData->nextState = rotateState(animData->curLookDir, 0);
break;
- case Map::kDirE:
+ case kDirE:
animData->nextState = rotateState(animData->curLookDir, 4);
break;
- case Map::kDirSW:
+ case kDirSW:
animData->nextState = 7;
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10)
animData->nextState = 41;
if (_vm->_map->getPass(obj->goblinX - 1, obj->goblinY + 2) != 10)
@@ -317,10 +329,10 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirS:
+ case kDirS:
animData->nextState =
(animData->curLookDir == 6) ? 6 : rotateState(animData->curLookDir, 6);
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 20)
animData->nextState = 39;
else if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 19)
@@ -328,9 +340,9 @@ void Goblin_v4::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16
}
break;
- case Map::kDirSE:
+ case kDirSE:
animData->nextState = 5;
- if (_vm->_map->_screenWidth == 640) {
+ if (_vm->_map->getScreenWidth() == 640) {
if (_vm->_map->getPass(obj->goblinX, obj->goblinY) == 10)
animData->nextState = 43;
if (_vm->_map->getPass(obj->goblinX + 1, obj->goblinY + 2) != 10)
@@ -496,13 +508,13 @@ void Goblin_v4::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc,
animData->frame = 0;
animData->state = state;
_vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0);
- if (_vm->_map->_bigTiles)
- *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) -
+ if (_vm->_map->hasBigTiles())
+ *obj->pPosY = ((gobY + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (gobY + 1) / 2;
else
- *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) -
+ *obj->pPosY = ((gobY + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
- *obj->pPosX = gobX * _vm->_map->_tilesWidth;
+ *obj->pPosX = gobX * _vm->_map->getTilesWidth();
}
}
}
@@ -521,13 +533,13 @@ void Goblin_v4::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc,
advMovement(obj, state);
_vm->_scenery->updateAnim(layer, 0, animation, 0, *obj->pPosX, *obj->pPosY, 0);
- if (_vm->_map->_bigTiles)
- *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) -
+ if (_vm->_map->hasBigTiles())
+ *obj->pPosY = ((gobY + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (gobY + 1) / 2;
else
- *obj->pPosY = ((gobY + 1) * _vm->_map->_tilesHeight) -
+ *obj->pPosY = ((gobY + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
- *obj->pPosX = gobX * _vm->_map->_tilesWidth;
+ *obj->pPosX = gobX * _vm->_map->getTilesWidth();
}
}
}
@@ -589,35 +601,35 @@ int16 Goblin_v4::turnState(int16 state, uint16 dir) {
}
switch (dir) {
- case Map::kDirNW:
+ case kDirNW:
cx = 1;
break;
- case Map::kDirN:
+ case kDirN:
cx = 2;
break;
- case Map::kDirNE:
+ case kDirNE:
cx = 3;
break;
- case Map::kDirW:
+ case kDirW:
cx = 0;
break;
- case Map::kDirE:
+ case kDirE:
cx = 4;
break;
- case Map::kDirSW:
+ case kDirSW:
cx = 7;
break;
- case Map::kDirS:
+ case kDirS:
cx = 6;
break;
- case Map::kDirSE:
+ case kDirSE:
cx = 5;
break;
}
diff --git a/engines/gob/hotspots.cpp b/engines/gob/hotspots.cpp
index dad141a254..94c3c6fb24 100644
--- a/engines/gob/hotspots.cpp
+++ b/engines/gob/hotspots.cpp
@@ -23,9 +23,10 @@
*
*/
+#include "common/str.h"
+
#include "gob/hotspots.h"
#include "gob/global.h"
-#include "gob/helper.h"
#include "gob/draw.h"
#include "gob/game.h"
#include "gob/script.h"
@@ -880,10 +881,10 @@ uint16 Hotspots::updateInput(uint16 xPos, uint16 yPos, uint16 width, uint16 heig
while (1) {
// If we the edit field has enough space, add a space for the new character
- strncpy0(tempStr, str, 254);
+ Common::strlcpy(tempStr, str, 255);
strcat(tempStr, " ");
if ((editSize != 0) && strlen(tempStr) > editSize)
- strncpy0(tempStr, str, 255);
+ Common::strlcpy(tempStr, str, 256);
// Clear input area
fillRect(xPos, yPos,
@@ -2006,14 +2007,14 @@ void Hotspots::checkStringMatch(const Hotspot &spot, const InputDesc &input,
char tempStr[256];
char spotStr[256];
- strncpy0(tempStr, GET_VARO_STR(spot.key), 255);
+ Common::strlcpy(tempStr, GET_VARO_STR(spot.key), 256);
if (spot.getType() < kTypeInput3NoLeave)
_vm->_util->cleanupStr(tempStr);
uint16 pos = 0;
do {
- strncpy0(spotStr, str, 255);
+ Common::strlcpy(spotStr, str, 256);
pos += strlen(str) + 1;
str += strlen(str) + 1;
@@ -2140,7 +2141,7 @@ void Hotspots::updateAllTexts(const InputDesc *inputs) const {
// Get its text
char tempStr[256];
- strncpy0(tempStr, GET_VARO_STR(spot.key), 255);
+ Common::strlcpy(tempStr, GET_VARO_STR(spot.key), 256);
// Coordinates
uint16 x = spot.left;
diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp
index 5c59a5692f..fa209c317f 100644
--- a/engines/gob/init.cpp
+++ b/engines/gob/init.cpp
@@ -57,7 +57,7 @@ void Init::cleanup() {
_vm->_sound->speakerOff();
_vm->_sound->blasterStop(0);
- _vm->_dataIO->closeDataFile();
+ _vm->_dataIO->closeArchive(true);
}
void Init::doDemo() {
@@ -81,17 +81,12 @@ void Init::doDemo() {
}
void Init::initGame() {
- byte *infBuf;
- char *infPtr;
- char *infEnd;
- char buffer[128];
-
initVideo();
updateConfig();
if (!_vm->isDemo()) {
- if (_vm->_dataIO->existData(_vm->_startStk.c_str()))
- _vm->_dataIO->openDataFile(_vm->_startStk.c_str());
+ if (_vm->_dataIO->hasFile(_vm->_startStk))
+ _vm->_dataIO->openArchive(_vm->_startStk, true);
}
_vm->_util->initInput();
@@ -126,37 +121,31 @@ void Init::initGame() {
return;
}
- if (!_vm->_dataIO->existData("intro.inf")) {
+ Common::SeekableReadStream *infFile = _vm->_dataIO->getFile("intro.inf");
+ if (!infFile) {
for (int i = 0; i < 4; i++)
_vm->_draw->loadFont(i, _fontNames[i]);
} else {
- infBuf = _vm->_dataIO->getData("intro.inf");
- infPtr = (char *)infBuf;
-
- infEnd = (char *)(infBuf + _vm->_dataIO->getDataSize("intro.inf"));
-
- for (int i = 0; i < 8; i++, infPtr++) {
- int j;
-
- for (j = 0; infPtr < infEnd && *infPtr >= ' '; j++, infPtr++)
- buffer[j] = *infPtr;
- buffer[j] = 0;
- strcat(buffer, ".let");
-
- _vm->_draw->loadFont(i, buffer);
+ for (int i = 0; i < 8; i++) {
+ if (infFile->eos())
+ break;
- if ((infPtr + 1) >= infEnd)
+ Common::String font = infFile->readLine();
+ if (infFile->eos() && font.empty())
break;
- infPtr++;
+ font += ".let";
+
+ _vm->_draw->loadFont(i, font.c_str());
}
- delete[] infBuf;
+
+ delete infFile;
}
- if (_vm->_dataIO->existData(_vm->_startTot.c_str())) {
+ if (_vm->_dataIO->hasFile(_vm->_startTot)) {
_vm->_inter->allocateVars(Script::getVariablesCount(_vm->_startTot.c_str(), _vm));
strcpy(_vm->_game->_curTotFile, _vm->_startTot.c_str());
@@ -165,7 +154,7 @@ void Init::initGame() {
_vm->_sound->cdLoadLIC("gob.lic");
// Search for a Coktel logo animation or image to display
- if (_vm->_dataIO->existData("coktel.imd")) {
+ if (_vm->_dataIO->hasFile("coktel.imd")) {
_vm->_draw->initScreen();
_vm->_draw->_cursorIndex = -1;
@@ -179,26 +168,28 @@ void Init::initGame() {
}
_vm->_draw->closeScreen();
- } else if (_vm->_dataIO->existData("coktel.clt")) {
- _vm->_draw->initScreen();
- _vm->_util->clearPalette();
-
- DataStream *stream = _vm->_dataIO->getDataStream("coktel.clt");
- stream->read((byte *)_vm->_draw->_vgaPalette, 768);
- delete stream;
-
- if (_vm->_dataIO->existData("coktel.ims")) {
- byte *sprBuf;
-
- sprBuf = _vm->_dataIO->getData("coktel.ims");
- _vm->_video->drawPackedSprite(sprBuf, 320, 200, 0, 0, 0,
- *_vm->_draw->_frontSurface);
- _vm->_palAnim->fade(_palDesc, 0, 0);
- _vm->_util->delay(500);
-
- delete[] sprBuf;
+ } else if (_vm->_dataIO->hasFile("coktel.clt")) {
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile("coktel.clt");
+ if (stream) {
+ _vm->_draw->initScreen();
+ _vm->_util->clearPalette();
+
+ stream->read((byte *)_vm->_draw->_vgaPalette, 768);
+ delete stream;
+
+ int32 size;
+ byte *sprite = _vm->_dataIO->getFile("coktel.ims", size);
+ if (sprite) {
+ _vm->_video->drawPackedSprite(sprite, 320, 200, 0, 0, 0,
+ *_vm->_draw->_frontSurface);
+ _vm->_palAnim->fade(_palDesc, 0, 0);
+ _vm->_util->delay(500);
+
+ delete[] sprite;
+ }
+
+ _vm->_draw->closeScreen();
}
- _vm->_draw->closeScreen();
}
_vm->_game->start();
@@ -209,7 +200,7 @@ void Init::initGame() {
}
delete _palDesc;
- _vm->_dataIO->closeDataFile();
+ _vm->_dataIO->closeArchive(true);
_vm->_video->initPrimary(-1);
cleanup();
}
diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp
index f6e6d41100..8db42b217c 100644
--- a/engines/gob/inter.cpp
+++ b/engines/gob/inter.cpp
@@ -268,23 +268,23 @@ void Inter::funcBlock(int16 retFlag) {
int addr = _vm->_game->_script->pos();
if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie, EGA
- !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) ||
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt005.tot")) ||
(startaddr == 0x188D && addr == 0x1A58 && // Zombie, Mac
- !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) ||
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt005.tot")) ||
(startaddr == 0x1299 && addr == 0x139A && // Dungeon
- !strncmp(_vm->_game->_curTotFile, "avt006.tot", 10)) ||
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt006.tot")) ||
(startaddr == 0x11C0 && addr == 0x12C9 && // Cauldron, EGA
- !strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) ||
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt012.tot")) ||
(startaddr == 0x11C8 && addr == 0x1341 && // Cauldron, Mac
- !strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) ||
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt012.tot")) ||
(startaddr == 0x09F2 && addr == 0x0AF3 && // Statue
- !strncmp(_vm->_game->_curTotFile, "avt016.tot", 10)) ||
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt016.tot")) ||
(startaddr == 0x0B92 && addr == 0x0C93 && // Castle
- !strncmp(_vm->_game->_curTotFile, "avt019.tot", 10)) ||
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt019.tot")) ||
(startaddr == 0x17D9 && addr == 0x18DA && // Finale, EGA
- !strncmp(_vm->_game->_curTotFile, "avt022.tot", 10)) ||
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt022.tot")) ||
(startaddr == 0x17E9 && addr == 0x19A8 && // Finale, Mac
- !strncmp(_vm->_game->_curTotFile, "avt022.tot", 10))) {
+ !scumm_stricmp(_vm->_game->_curTotFile, "avt022.tot"))) {
_vm->_util->longDelay(5000);
}
@@ -295,7 +295,7 @@ void Inter::funcBlock(int16 retFlag) {
// of Fascination have a too short delay between the storage room and the lab.
// We manually add it here.
if ((_vm->getGameType() == kGameTypeFascination) &&
- !strncmp(_vm->_game->_curTotFile, "PLANQUE.tot", 9)) {
+ !scumm_stricmp(_vm->_game->_curTotFile, "PLANQUE.tot")) {
int addr = _vm->_game->_script->pos();
if ((startaddr == 0x0202 && addr == 0x0330) || // Before Lab, Amiga & Atari, English
(startaddr == 0x023D && addr == 0x032D) || // Before Lab, PC floppy, German
@@ -306,6 +306,21 @@ void Inter::funcBlock(int16 retFlag) {
} // End of workaround
cmd = _vm->_game->_script->readByte();
+
+ // WORKAROUND:
+ // A VGA version has some broken code in its scripts, this workaround skips the corrupted parts.
+ if (_vm->getGameType() == kGameTypeFascination) {
+ int addr = _vm->_game->_script->pos();
+ if ((startaddr == 0x212D) && (addr == 0x290E) && (cmd == 0x90) && !scumm_stricmp(_vm->_game->_curTotFile, "INTRO1.tot")) {
+ _vm->_game->_script->skip(2);
+ cmd = _vm->_game->_script->readByte();
+ }
+ if ((startaddr == 0x207D) && (addr == 0x22CE) && (cmd == 0x90) && !scumm_stricmp(_vm->_game->_curTotFile, "INTRO2.tot")) {
+ _vm->_game->_script->skip(2);
+ cmd = _vm->_game->_script->readByte();
+ }
+ }
+
if ((cmd >> 4) >= 12) {
cmd2 = 16 - (cmd >> 4);
cmd &= 0xF;
diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp
index 3afb70d6c0..5ed24c614e 100644
--- a/engines/gob/inter_bargon.cpp
+++ b/engines/gob/inter_bargon.cpp
@@ -175,10 +175,12 @@ void Inter_Bargon::oBargon_intro3(OpGobParams &params) {
static const char *sndFiles[] = {"1INTROIV.snd", "2INTROIV.snd"};
static const char *palFiles[] = {"2ou2.clt", "2ou3.clt", "2ou4.clt", "2ou5.clt"};
+ int32 size;
+
for (int i = 0; i < 2; i++)
_vm->_sound->sampleLoad(&samples[i], SOUND_SND, sndFiles[i]);
for (int i = 0; i < 4; i++)
- palettes[i] = _vm->_dataIO->getData(palFiles[i]);
+ palettes[i] = _vm->_dataIO->getFile(palFiles[i], size);
palBak = _vm->_global->_pPaletteDesc->vgaPal;
_vm->_sound->blasterPlayComposition(comp, 0, samples, 2);
diff --git a/engines/gob/inter_playtoons.cpp b/engines/gob/inter_playtoons.cpp
index befed4b1c2..05032d712c 100644
--- a/engines/gob/inter_playtoons.cpp
+++ b/engines/gob/inter_playtoons.cpp
@@ -24,12 +24,12 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "gui/message.h"
#include "gob/gob.h"
#include "gob/inter.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/dataio.h"
@@ -246,10 +246,10 @@ bool Inter_Playtoons::oPlaytoons_checkData(OpFuncParams &params) {
mode = _vm->_saveLoad->getSaveMode(file);
if (mode == SaveLoad::kSaveModeNone) {
- if (_vm->_dataIO->existData(file))
- size = _vm->_dataIO->getDataSize(file);
- else
+ size = _vm->_dataIO->fileSize(file);
+ if (size == -1)
warning("File \"%s\" not found", file);
+
} else if (mode == SaveLoad::kSaveModeSave)
size = _vm->_saveLoad->getSize(file);
else if (mode == SaveLoad::kSaveModeExists)
@@ -272,7 +272,6 @@ bool Inter_Playtoons::oPlaytoons_readData(OpFuncParams &params) {
int32 size;
int32 offset;
uint16 dataVar;
- int16 handle;
byte *buf;
SaveLoad::SaveMode mode;
@@ -329,13 +328,10 @@ bool Inter_Playtoons::oPlaytoons_readData(OpFuncParams &params) {
}
WRITE_VAR(1, 1);
- handle = _vm->_dataIO->openData(file);
-
- if (handle < 0)
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(file);
+ if (!stream)
return false;
- DataStream *stream = _vm->_dataIO->openAsStream(handle, true);
-
_vm->_draw->animateCursor(4);
if (offset < 0)
stream->seek(offset + 1, SEEK_END);
@@ -415,9 +411,9 @@ void Inter_Playtoons::oPlaytoons_copyFile() {
char fileName2[128];
_vm->_game->_script->evalExpr(0);
- strncpy0(fileName1, _vm->_game->_script->getResultStr(), 127);
+ Common::strlcpy(fileName1, _vm->_game->_script->getResultStr(), 128);
_vm->_game->_script->evalExpr(0);
- strncpy0(fileName2, _vm->_game->_script->getResultStr(), 127);
+ Common::strlcpy(fileName2, _vm->_game->_script->getResultStr(), 128);
warning("Playtoons Stub: copy file from \"%s\" to \"%s\"", fileName1, fileName2);
}
@@ -427,7 +423,7 @@ void Inter_Playtoons::oPlaytoons_openItk() {
char *backSlash;
_vm->_game->_script->evalExpr(0);
- strncpy0(fileName, _vm->_game->_script->getResultStr(), 124);
+ Common::strlcpy(fileName, _vm->_game->_script->getResultStr(), 124);
if (!strchr(fileName, '.'))
strcat(fileName, ".ITK");
@@ -435,9 +431,9 @@ void Inter_Playtoons::oPlaytoons_openItk() {
// Workaround for Bambou : In the script, the path is hardcoded (!!)
if ((backSlash = strrchr(fileName, '\\'))) {
debugC(2, kDebugFileIO, "Opening ITK file \"%s\" instead of \"%s\"", backSlash + 1, fileName);
- _vm->_dataIO->openDataFile(backSlash + 1, true);
+ _vm->_dataIO->openArchive(backSlash + 1, false);
} else
- _vm->_dataIO->openDataFile(fileName, true);
+ _vm->_dataIO->openArchive(fileName, false);
// All the other checks are meant to verify (if not found at the first try)
// if the file is present on the CD or not. As everything is supposed to
// be copied, those checks are skipped
diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp
index 3bf7fc8fd4..933bb2f2ed 100644
--- a/engines/gob/inter_v1.cpp
+++ b/engines/gob/inter_v1.cpp
@@ -24,11 +24,11 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "common/file.h"
#include "gob/gob.h"
#include "gob/inter.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/dataio.h"
@@ -812,12 +812,12 @@ bool Inter_v1::o1_if(OpFuncParams &params) {
byte cmd;
bool boolRes;
- // WORKAROUND: Windows Gob1 OUTODDV reload goblin stuck bug present in original
- if ((_vm->getGameType() == kGameTypeGob1) && (_vm->_game->_script->pos() == 11294) &&
- !scumm_stricmp(_vm->_game->_curTotFile, "avt00.tot") && VAR(59) == 1) {
- warning("Workaround for Win Gob1 OUTODDV Reload Goblin Stuck Bug...");
+ // WORKAROUND: Gob1 goblin stuck on reload bugs present in original - bugs #3018918 and 3065914
+ if ((_vm->getGameType() == kGameTypeGob1) && (_vm->_game->_script->pos() == 2933) &&
+ !scumm_stricmp(_vm->_game->_curTotFile, "inter.tot") && VAR(285) != 0) {
+ warning("Workaround for Gob1 Goblin Stuck On Reload Bug applied...");
+ // VAR(59) actually locks goblin movement, but these variables trigger this in the script.
WRITE_VAR(285, 0);
- WRITE_VAR(59, 0);
}
boolRes = _vm->_game->_script->evalBoolResult();
@@ -971,7 +971,7 @@ bool Inter_v1::o1_loadTot(OpFuncParams &params) {
if ((_vm->_game->_script->peekByte() & 0x80) != 0) {
_vm->_game->_script->skip(1);
_vm->_game->_script->evalExpr(0);
- strncpy0(buf, _vm->_game->_script->getResultStr(), 15);
+ Common::strlcpy(buf, _vm->_game->_script->getResultStr(), 16);
} else {
size = _vm->_game->_script->readInt8();
memcpy(buf, _vm->_game->_script->readString(size), size);
@@ -1512,7 +1512,7 @@ bool Inter_v1::o1_strToLong(OpFuncParams &params) {
int32 res;
strVar = _vm->_game->_script->readVarIndex();
- strncpy0(str, GET_VARO_STR(strVar), 19);
+ Common::strlcpy(str, GET_VARO_STR(strVar), 20);
res = atoi(str);
destVar = _vm->_game->_script->readVarIndex();
@@ -1630,18 +1630,17 @@ bool Inter_v1::o1_getFreeMem(OpFuncParams &params) {
}
bool Inter_v1::o1_checkData(OpFuncParams &params) {
- int16 handle;
int16 varOff;
_vm->_game->_script->evalExpr(0);
varOff = _vm->_game->_script->readVarIndex();
- handle = _vm->_dataIO->openData(_vm->_game->_script->getResultStr());
- WRITE_VAR_OFFSET(varOff, handle);
- if (handle >= 0)
- _vm->_dataIO->closeData(handle);
- else
+ if (!_vm->_dataIO->hasFile(_vm->_game->_script->getResultStr())) {
warning("File \"%s\" not found", _vm->_game->_script->getResultStr());
+ WRITE_VAR_OFFSET(varOff, (uint32) -1);
+ } else
+ WRITE_VAR_OFFSET(varOff, 50); // "handle" between 50 and 128 = in archive
+
return false;
}
@@ -1767,7 +1766,6 @@ bool Inter_v1::o1_readData(OpFuncParams &params) {
int16 size;
int16 dataVar;
int16 offset;
- int16 handle;
_vm->_game->_script->evalExpr(0);
dataVar = _vm->_game->_script->readVarIndex();
@@ -1776,26 +1774,26 @@ bool Inter_v1::o1_readData(OpFuncParams &params) {
retSize = 0;
WRITE_VAR(1, 1);
- handle = _vm->_dataIO->openData(_vm->_game->_script->getResultStr());
- if (handle >= 0) {
- DataStream *stream = _vm->_dataIO->openAsStream(handle, true);
- _vm->_draw->animateCursor(4);
- if (offset < 0)
- stream->seek(offset + 1, SEEK_END);
- else
- stream->seek(offset);
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_vm->_game->_script->getResultStr());
+ if (!stream)
+ return false;
- if (((dataVar >> 2) == 59) && (size == 4))
- WRITE_VAR(59, stream->readUint32LE());
- else
- retSize = stream->read((byte *)_variables->getAddressOff8(dataVar), size);
+ _vm->_draw->animateCursor(4);
+ if (offset < 0)
+ stream->seek(offset + 1, SEEK_END);
+ else
+ stream->seek(offset);
- if (retSize == size)
- WRITE_VAR(1, 0);
+ if (((dataVar >> 2) == 59) && (size == 4))
+ WRITE_VAR(59, stream->readUint32LE());
+ else
+ retSize = stream->read((byte *)_variables->getAddressOff8(dataVar), size);
- delete stream;
- }
+ if (retSize == size)
+ WRITE_VAR(1, 0);
+
+ delete stream;
return false;
}
@@ -1824,9 +1822,9 @@ bool Inter_v1::o1_manageDataFile(OpFuncParams &params) {
_vm->_game->_script->evalExpr(0);
if (_vm->_game->_script->getResultStr()[0] != 0)
- _vm->_dataIO->openDataFile(_vm->_game->_script->getResultStr());
+ _vm->_dataIO->openArchive(_vm->_game->_script->getResultStr(), true);
else
- _vm->_dataIO->closeDataFile();
+ _vm->_dataIO->closeArchive(true);
return false;
}
@@ -2562,8 +2560,8 @@ void Inter_v1::animPalette() {
}
void Inter_v1::manipulateMap(int16 xPos, int16 yPos, int16 item) {
- for (int y = 0; y < _vm->_map->_mapHeight; y++) {
- for (int x = 0; x < _vm->_map->_mapWidth; x++) {
+ for (int y = 0; y < _vm->_map->getMapHeight(); y++) {
+ for (int x = 0; x < _vm->_map->getMapWidth(); x++) {
if ((_vm->_map->getItem(x, y) & 0xFF) == item)
_vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00);
else if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == item)
@@ -2571,7 +2569,7 @@ void Inter_v1::manipulateMap(int16 xPos, int16 yPos, int16 item) {
}
}
- if (xPos < _vm->_map->_mapWidth - 1) {
+ if (xPos < _vm->_map->getMapWidth() - 1) {
if (yPos > 0) {
if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) ||
((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0) ||
@@ -2660,7 +2658,7 @@ void Inter_v1::manipulateMap(int16 xPos, int16 yPos, int16 item) {
return;
}
- if ((xPos < _vm->_map->_mapWidth - 2) &&
+ if ((xPos < _vm->_map->getMapWidth() - 2) &&
(_vm->_map->getPass(xPos + 2, yPos) == 1)) {
_vm->_map->_itemPoses[item].x = xPos + 2;
_vm->_map->_itemPoses[item].y = yPos;
@@ -2668,7 +2666,7 @@ void Inter_v1::manipulateMap(int16 xPos, int16 yPos, int16 item) {
return;
}
- if ((xPos < _vm->_map->_mapWidth - 1) &&
+ if ((xPos < _vm->_map->getMapWidth() - 1) &&
(_vm->_map->getPass(xPos + 1, yPos) == 1)) {
_vm->_map->_itemPoses[item].x = xPos + 1;
_vm->_map->_itemPoses[item].y = yPos;
diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp
index 0003332e47..d8d36d7a41 100644
--- a/engines/gob/inter_v2.cpp
+++ b/engines/gob/inter_v2.cpp
@@ -24,6 +24,7 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "gui/message.h"
@@ -32,7 +33,6 @@
#include "gob/gob.h"
#include "gob/inter.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/dataio.h"
@@ -432,7 +432,7 @@ void Inter_v2::o2_loadMultObject() {
obj.gobDestY = val;
obj.goblinY = val;
- *(obj.pPosX) *= _vm->_map->_tilesWidth;
+ *(obj.pPosX) *= _vm->_map->getTilesWidth();
layer = objAnim.layer;
animation = obj.goblinStates[layer][0].animation;
@@ -447,14 +447,14 @@ void Inter_v2::o2_loadMultObject() {
_vm->_scenery->updateAnim(layer, 0, animation, 0,
*(obj.pPosX), *(obj.pPosY), 0);
- if (!_vm->_map->_bigTiles)
- *(obj.pPosY) = (obj.goblinY + 1) * _vm->_map->_tilesHeight
+ if (!_vm->_map->hasBigTiles())
+ *(obj.pPosY) = (obj.goblinY + 1) * _vm->_map->getTilesHeight()
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
else
- *(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->_tilesHeight) -
+ *(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) -
((obj.goblinY + 1) / 2);
- *(obj.pPosX) = obj.goblinX * _vm->_map->_tilesWidth;
+ *(obj.pPosX) = obj.goblinX * _vm->_map->getTilesWidth();
} else if ((objAnim.animType == 101) && (objIndex < _vm->_goblin->_gobsCount)) {
@@ -530,7 +530,7 @@ void Inter_v2::o2_readLIC() {
char path[40];
_vm->_game->_script->evalExpr(0);
- strncpy0(path, _vm->_game->_script->getResultStr(), 35);
+ Common::strlcpy(path, _vm->_game->_script->getResultStr(), 36);
strcat(path, ".LIC");
_vm->_sound->cdLoadLIC(path);
@@ -778,14 +778,14 @@ void Inter_v2::o2_setGoblinState() {
_vm->_scenery->updateAnim(layer, 0, animation, 0,
*(obj.pPosX), *(obj.pPosY), 0);
- if (_vm->_map->_bigTiles)
- *(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->_tilesHeight) -
+ if (_vm->_map->hasBigTiles())
+ *(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) -
((obj.goblinY + 1) / 2);
else
- *(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->_tilesHeight) -
+ *(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->getTilesHeight()) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
- *(obj.pPosX) = obj.goblinX * _vm->_map->_tilesWidth;
+ *(obj.pPosX) = obj.goblinX * _vm->_map->getTilesWidth();
break;
}
}
@@ -963,7 +963,7 @@ void Inter_v2::o2_playImd() {
_vm->_game->_script->evalExpr(0);
_vm->_game->_script->getResultStr()[8] = 0;
- strncpy0(imd, _vm->_game->_script->getResultStr(), 127);
+ Common::strlcpy(imd, _vm->_game->_script->getResultStr(), 128);
VideoPlayer::Properties props;
@@ -1031,15 +1031,15 @@ void Inter_v2::o2_openItk() {
char fileName[32];
_vm->_game->_script->evalExpr(0);
- strncpy0(fileName, _vm->_game->_script->getResultStr(), 27);
+ Common::strlcpy(fileName, _vm->_game->_script->getResultStr(), 28);
if (!strchr(fileName, '.'))
strcat(fileName, ".ITK");
- _vm->_dataIO->openDataFile(fileName, true);
+ _vm->_dataIO->openArchive(fileName, false);
}
void Inter_v2::o2_closeItk() {
- _vm->_dataIO->closeDataFile(true);
+ _vm->_dataIO->closeArchive(false);
}
void Inter_v2::o2_setImdFrontSurf() {
@@ -1292,7 +1292,6 @@ bool Inter_v2::o2_getFreeMem(OpFuncParams &params) {
}
bool Inter_v2::o2_checkData(OpFuncParams &params) {
- int16 handle;
int16 varOff;
int32 size;
SaveLoad::SaveMode mode;
@@ -1301,7 +1300,6 @@ bool Inter_v2::o2_checkData(OpFuncParams &params) {
varOff = _vm->_game->_script->readVarIndex();
size = -1;
- handle = 1;
char *file = _vm->_game->_script->getResultStr();
@@ -1313,9 +1311,8 @@ bool Inter_v2::o2_checkData(OpFuncParams &params) {
mode = _vm->_saveLoad->getSaveMode(file);
if (mode == SaveLoad::kSaveModeNone) {
- if (_vm->_dataIO->existData(file))
- size = _vm->_dataIO->getDataSize(file);
- else
+ size = _vm->_dataIO->fileSize(file);
+ if (size == -1)
warning("File \"%s\" not found", file);
} else if (mode == SaveLoad::kSaveModeSave)
@@ -1323,13 +1320,10 @@ bool Inter_v2::o2_checkData(OpFuncParams &params) {
else if (mode == SaveLoad::kSaveModeExists)
size = 23;
- if (size == -1)
- handle = -1;
-
debugC(2, kDebugFileIO, "Requested size of file \"%s\": %d",
file, size);
- WRITE_VAR_OFFSET(varOff, handle);
+ WRITE_VAR_OFFSET(varOff, (size == -1) ? -1 : 50);
WRITE_VAR(16, (uint32) size);
return false;
@@ -1340,7 +1334,6 @@ bool Inter_v2::o2_readData(OpFuncParams &params) {
int32 size;
int32 offset;
int16 dataVar;
- int16 handle;
byte *buf;
SaveLoad::SaveMode mode;
@@ -1391,13 +1384,10 @@ bool Inter_v2::o2_readData(OpFuncParams &params) {
}
WRITE_VAR(1, 1);
- handle = _vm->_dataIO->openData(file);
-
- if (handle < 0)
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(file);
+ if (!file)
return false;
- DataStream *stream = _vm->_dataIO->openAsStream(handle, true);
-
_vm->_draw->animateCursor(4);
if (offset < 0)
stream->seek(offset + 1, SEEK_END);
@@ -1462,7 +1452,7 @@ void Inter_v2::o2_loadInfogramesIns(OpGobParams &params) {
varName = _vm->_game->_script->readInt16();
- strncpy0(fileName, GET_VAR_STR(varName), 15);
+ Common::strlcpy(fileName, GET_VAR_STR(varName), 16);
strcat(fileName, ".INS");
_vm->_sound->infogramesLoadInstruments(fileName);
@@ -1474,7 +1464,7 @@ void Inter_v2::o2_playInfogrames(OpGobParams &params) {
varName = _vm->_game->_script->readInt16();
- strncpy0(fileName, GET_VAR_STR(varName), 15);
+ Common::strlcpy(fileName, GET_VAR_STR(varName), 16);
strcat(fileName, ".DUM");
_vm->_sound->infogramesLoadSong(fileName);
@@ -1512,16 +1502,13 @@ void Inter_v2::o2_handleGoblins(OpGobParams &params) {
}
int16 Inter_v2::loadSound(int16 search) {
- byte *dataPtr;
int16 id;
int16 slot;
uint16 slotIdMask;
- uint32 dataSize;
SoundType type;
type = SOUND_SND;
slotIdMask = 0;
- dataSize = 0;
if (!search) {
slot = _vm->_game->_script->readValExpr();
@@ -1560,15 +1547,15 @@ int16 Inter_v2::loadSound(int16 search) {
if (id == -1) {
char sndfile[14];
- strncpy0(sndfile, _vm->_game->_script->readString(9), 9);
+ Common::strlcpy(sndfile, _vm->_game->_script->readString(9), 10);
if (type == SOUND_ADL)
strcat(sndfile, ".ADL");
else
strcat(sndfile, ".SND");
- dataPtr = _vm->_dataIO->getData(sndfile);
- dataSize = _vm->_dataIO->getDataSize(sndfile);
+ int32 dataSize;
+ byte *dataPtr = _vm->_dataIO->getFile(sndfile, dataSize);
if (!dataPtr)
return 0;
diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp
index 26eff4f675..698dddeae9 100644
--- a/engines/gob/inter_v4.cpp
+++ b/engines/gob/inter_v4.cpp
@@ -24,11 +24,11 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "common/file.h"
#include "gob/gob.h"
#include "gob/inter.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/draw.h"
#include "gob/game.h"
@@ -145,7 +145,7 @@ void Inter_v4::o4_playVmdOrMusic() {
bool close;
_vm->_game->_script->evalExpr(0);
- strncpy0(fileName, _vm->_game->_script->getResultStr(), 127);
+ Common::strlcpy(fileName, _vm->_game->_script->getResultStr(), 128);
// WORKAROUND: The nut rolling animation in the administration center
// in Woodruff is called "noixroul", but the scripts think it's "noixroule".
diff --git a/engines/gob/inter_v6.cpp b/engines/gob/inter_v6.cpp
index c6d0211c8f..b6884c6fbe 100644
--- a/engines/gob/inter_v6.cpp
+++ b/engines/gob/inter_v6.cpp
@@ -24,12 +24,12 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "common/file.h"
#include "graphics/dither.h"
#include "gob/gob.h"
#include "gob/inter.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/dataio.h"
#include "gob/game.h"
@@ -104,7 +104,7 @@ void Inter_v6::o6_playVmdOrMusic() {
bool close;
_vm->_game->_script->evalExpr(0);
- strncpy0(fileName, _vm->_game->_script->getResultStr(), 127);
+ Common::strlcpy(fileName, _vm->_game->_script->getResultStr(), 128);
VideoPlayer::Properties props;
@@ -187,20 +187,20 @@ void Inter_v6::o6_openItk() {
char fileName[32];
_vm->_game->_script->evalExpr(0);
- strncpy0(fileName, _vm->_game->_script->getResultStr(), 27);
+ Common::strlcpy(fileName, _vm->_game->_script->getResultStr(), 28);
if (!strchr(fileName, '.'))
strcat(fileName, ".ITK");
- _vm->_dataIO->openDataFile(fileName, true);
+ _vm->_dataIO->openArchive(fileName, false);
// WORKAROUND: The CD number detection in Urban Runner is quite daft
// (it checks CD1.ITK - CD4.ITK and the first that's found determines
// the CD number), while its NO_CD modus wants everything in CD1.ITK.
// So we just open the other ITKs, too.
if (_vm->_global->_noCd && !scumm_stricmp(fileName, "CD1.ITK")) {
- _vm->_dataIO->openDataFile("CD2.ITK", true);
- _vm->_dataIO->openDataFile("CD3.ITK", true);
- _vm->_dataIO->openDataFile("CD4.ITK", true);
+ _vm->_dataIO->openArchive("CD2.ITK", false);
+ _vm->_dataIO->openArchive("CD3.ITK", false);
+ _vm->_dataIO->openArchive("CD4.ITK", false);
}
}
@@ -439,7 +439,7 @@ void Inter_v6::probe16bitMusic(char *fileName) {
fileName[len - 1] = 'V';
- if (_vm->_dataIO->existData(fileName))
+ if (_vm->_dataIO->hasFile(fileName))
return;
fileName[len - 1] = '8';
diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp
index 9f1f5bdc59..500f6515ec 100644
--- a/engines/gob/map.cpp
+++ b/engines/gob/map.cpp
@@ -32,33 +32,40 @@
namespace Gob {
Map::Map(GobEngine *vm) : _vm(vm) {
- _widthByte = 0;
- _mapWidth = -1;
+ _mapVersion = 0;
+
+ _passWidth = 0;
+ _mapWidth = -1;
_mapHeight = -1;
- _screenWidth = 0;
+ _passMap = 0;
+
+ _screenWidth = 0;
_screenHeight = 0;
- _tilesWidth = 0;
+
+ _tilesWidth = 0;
_tilesHeight = 0;
- _passWidth = 0;
- _passMap = 0;
- _itemsMap = 0;
- _wayPointsCount = 0;
- _wayPoints = 0;
_bigTiles = false;
+ _wayPointCount = 0;
+ _wayPoints = 0;
+
+ _nearestWayPoint = 0;
+ _nearestDest = 0;
+
+ _itemsMap = 0;
+
for (int i = 0; i < 40; i++) {
- _itemPoses[i].x = 0;
- _itemPoses[i].y = 0;
+ _itemPoses[i].x = 0;
+ _itemPoses[i].y = 0;
_itemPoses[i].orient = 0;
}
- _nearestWayPoint = 0;
- _nearestDest = 0;
_curGoblinX = 0;
_curGoblinY = 0;
_destX = 0;
_destY = 0;
+
_sourceFile[0] = 0;
_loadFromAvo = false;
@@ -76,6 +83,87 @@ Map::~Map() {
delete[] _wayPoints;
}
+uint8 Map::getVersion() const {
+ return _mapVersion;
+}
+
+int16 Map::getMapWidth() const {
+ return _mapWidth;
+}
+
+int16 Map::getMapHeight() const {
+ return _mapHeight;
+}
+
+int16 Map::getScreenWidth() const {
+ return _screenWidth;
+}
+
+int16 Map::getScreenHeight() const {
+ return _screenHeight;
+}
+
+int16 Map::getTilesWidth() const {
+ return _tilesWidth;
+}
+
+int16 Map::getTilesHeight() const {
+ return _tilesHeight;
+}
+
+bool Map::hasBigTiles() const {
+ return _bigTiles;
+}
+
+int8 Map::getPass(int x, int y, int width) const {
+ if (!_passMap)
+ return 0;
+
+ if ((x < 0) || (y < 0) || (x >= _mapWidth) || (y >= _mapHeight))
+ return 0;
+
+ if (width == -1)
+ width = _passWidth;
+ return _passMap[y * width + x];
+}
+
+void Map::setPass(int x, int y, int8 pass, int width) {
+ if (!_passMap)
+ return;
+
+ if ((x < 0) || (y < 0) || (x >= _mapWidth) || (y >= _mapHeight))
+ return;
+
+ if (width == -1)
+ width = _passWidth;
+ _passMap[y * width + x] = pass;
+}
+
+const WayPoint &Map::getWayPoint(int n) const {
+ assert(_wayPoints);
+ assert(n < _wayPointCount);
+
+ return _wayPoints[n];
+}
+
+int16 Map::getItem(int x, int y) const {
+ assert(_itemsMap);
+
+ x = CLIP<int>(x, 0, _mapWidth - 1);
+ y = CLIP<int>(y, 0, _mapHeight - 1);
+
+ return _itemsMap[y][x];
+}
+
+void Map::setItem(int x, int y, int16 item) {
+ assert(_itemsMap);
+
+ x = CLIP<int>(x, 0, _mapWidth - 1);
+ y = CLIP<int>(y, 0, _mapHeight - 1);
+
+ _itemsMap[y][x] = item;
+}
+
void Map::placeItem(int16 x, int16 y, int16 id) {
if ((getItem(x, y) & 0xFF00) != 0)
setItem(x, y, (getItem(x, y) & 0xFF00) | id);
@@ -83,150 +171,175 @@ void Map::placeItem(int16 x, int16 y, int16 id) {
setItem(x, y, (getItem(x, y) & 0x00FF) | (id << 8));
}
-enum {
- kLeft = (1 << 0),
- kUp = (1 << 1),
- kRight = (1 << 2),
- kDown = (1 << 3)
-};
-
-int16 Map::getDirection(int16 x0, int16 y0, int16 x1, int16 y1) {
- int16 dir = 0;
-
+Direction Map::getDirection(int16 x0, int16 y0, int16 x1, int16 y1) {
if ((x0 == x1) && (y0 == y1))
- return 0;
+ // Already at the destination
+ return kDirNone;
if ((x1 < 0) || (x1 > _mapWidth) || (y1 < 0) || (y1 > _mapHeight))
- return 0;
+ // Destination out of range
+ return kDirNone;
+ RelativeDirection relDir = kRelDirNone;
+
+ // Find the direct direction we want to move
if (y1 > y0)
- dir |= kDown;
+ relDir = kRelDirDown;
else if (y1 < y0)
- dir |= kUp;
+ relDir = kRelDirUp;
if (x1 > x0)
- dir |= kRight;
+ relDir = (RelativeDirection)(relDir | kRelDirRight);
else if (x1 < x0)
- dir |= kLeft;
+ relDir = (RelativeDirection)(relDir | kRelDirLeft);
- if ((getPass(x0, y0) == 3) && (dir & kUp)) {
- if ((getPass(x0, y0 - 1) != 0))
- return kDirN;
- }
- if ((getPass(x0, y0) == 3) && (dir & kDown)) {
- if ((getPass(x0, y0 + 1) != 0))
- return kDirS;
- }
+ // Are we on ladders and can continue the ladder in the wanted direction?
+ if ((getPass(x0, y0) == 3) && (relDir & kRelDirUp ) && (getPass(x0, y0 - 1) != 0))
+ return kDirN;
- if ((getPass(x0, y0) == 6) && (dir & kUp)) {
- if ((getPass(x0, y0 - 1) != 0))
- return kDirN;
- }
+ if ((getPass(x0, y0) == 3) && (relDir & kRelDirDown) && (getPass(x0, y0 + 1) != 0))
+ return kDirS;
- if ((getPass(x0, y0) == 6) && (dir & kDown)) {
- if ((getPass(x0, y0 + 1) != 0))
- return kDirS;
- }
+ if ((getPass(x0, y0) == 6) && (relDir & kRelDirUp ) && (getPass(x0, y0 - 1) != 0))
+ return kDirN;
- if (dir == kLeft) {
- if (((x0 - 1) >= 0) && (getPass(x0 - 1, y0) != 0))
+ if ((getPass(x0, y0) == 6) && (relDir & kRelDirDown) && (getPass(x0, y0 + 1) != 0))
+ return kDirS;
+
+
+ // Want to go left
+ if (relDir == kRelDirLeft) {
+ if (getPass(x0 - 1, y0) != 0)
+ // Can go west
return kDirW;
- return 0;
+
+ // Can't go
+ return kDirNone;
}
- if (dir == kRight) {
- if (((x0 + 1) < _mapWidth) && (getPass(x0 + 1, y0) != 0))
+ // Want to go left
+ if (relDir == kRelDirRight) {
+ if (getPass(x0 + 1, y0) != 0)
+ // Can go east
return kDirE;
- return 0;
+
+ // Can't go
+ return kDirNone;
}
- if (dir == kUp) {
- if (((y0 - 1) >= 0) && (getPass(x0, y0 - 1) != 0))
+
+ // Want to go up
+ if (relDir == kRelDirUp) {
+ if (getPass(x0 , y0 - 1) != 0)
+ // Can go north
return kDirN;
- if (((y0 - 1) >= 0) && ((x0 - 1) >= 0) &&
- (getPass(x0 - 1, y0 - 1) != 0))
+ if (getPass(x0 - 1, y0 - 1) != 0)
+ // Can up north-west instead
return kDirNW;
- if (((y0 - 1) >= 0) && ((x0 + 1) < _mapWidth) &&
- (getPass(x0 + 1, y0 - 1) != 0))
+ if (getPass(x0 + 1, y0 - 1) != 0)
+ // Can up north-east instead
return kDirNE;
- return 0;
+ // Can't go at all
+ return kDirNone;
}
- if (dir == kDown) {
- if (((y0 + 1) < _mapHeight) && (getPass(x0, y0 + 1) != 0))
+ // Want to go down
+ if (relDir == kRelDirDown) {
+ if (getPass(x0 , y0 + 1) != 0)
+ // Can go south
return kDirS;
- if (((y0 + 1) < _mapHeight) && ((x0 - 1) >= 0) &&
- (getPass(x0 - 1, y0 + 1) != 0))
+ if (getPass(x0 - 1, y0 + 1) != 0)
+ // Can up south-west instead
return kDirSW;
- if (((y0 + 1) < _mapHeight) && ((x0 + 1) < _mapWidth) &&
- (getPass(x0 + 1, y0 + 1) != 0))
+ if (getPass(x0 + 1, y0 + 1) != 0)
+ // Can up south-east instead
return kDirSE;
- return 0;
+ // Can't go at all
+ return kDirNone;
}
- if (dir == (kRight | kUp)) {
- if (((y0 - 1) >= 0) && ((x0 + 1) < _mapWidth) &&
- (getPass(x0 + 1, y0 - 1) != 0))
+
+ // Want to go up and right
+ if (relDir == kRelDirRightUp) {
+ if (getPass(x0 + 1, y0 - 1) != 0)
+ // Can go north-east
return kDirNE;
- if (((y0 - 1) >= 0) && (getPass(x0, y0 - 1) != 0))
+ if (getPass(x0 , y0 - 1) != 0)
+ // Can only go north
return kDirN;
- if (((x0 + 1) < _mapWidth) && (getPass(x0 + 1, y0) != 0))
+ if (getPass(x0 + 1, y0 ) != 0)
+ // Can only go east
return kDirE;
- return 0;
+ // Can't go at all
+ return kDirNone;
}
- if (dir == (kRight | kDown)) {
- if (((x0 + 1) < _mapWidth) && ((y0 + 1) < _mapHeight) &&
- (getPass(x0 + 1, y0 + 1) != 0))
+ // Want to go down and right
+ if (relDir == kRelDirRightDown) {
+ if (getPass(x0 + 1, y0 + 1) != 0)
+ // Can go south-east
return kDirSE;
- if (((y0 + 1) < _mapHeight) && (getPass(x0, y0 + 1) != 0))
+ if (getPass(x0 , y0 + 1) != 0)
+ // Can only go south
return kDirS;
- if (((x0 + 1) < _mapWidth) && (getPass(x0 + 1, y0) != 0))
+ if (getPass(x0 + 1, y0 ) != 0)
+ // Can only go east
return kDirE;
- return 0;
+ // Can't go at all
+ return kDirNone;
}
- if (dir == (kLeft | kUp)) {
- if (((x0 - 1) >= 0) && ((y0 - 1) >= 0) &&
- (getPass(x0 - 1, y0 - 1) != 0))
+ // Want to go up and left
+ if (relDir == kRelDirLeftUp) {
+ if (getPass(x0 - 1, y0 - 1) != 0)
+ // Can go north-west
return kDirNW;
- if (((y0 - 1) >= 0) && (getPass(x0, y0 - 1) != 0))
+ if (getPass(x0 , y0 - 1) != 0)
+ // Can only go north
return kDirN;
- if (((x0 - 1) >= 0) && (getPass(x0 - 1, y0) != 0))
+ if (getPass(x0 - 1, y0 ) != 0)
+ // Can only go west
return kDirW;
- return 0;
+ // Can't go at all
+ return kDirNone;
}
- if (dir == (kLeft | kDown)) {
- if (((x0 - 1) >= 0) && ((y0 + 1) < _mapHeight) &&
- (getPass(x0 - 1, y0 + 1) != 0))
+ // Want to go left and down
+ if (relDir == kRelDirLeftDown) {
+ if (getPass(x0 - 1, y0 + 1) != 0)
+ // Can go south-west
return kDirSW;
- if (((y0 + 1) < _mapHeight) && (getPass(x0, y0 + 1) != 0))
+ if (getPass(x0 , y0 + 1) != 0)
+ // Can only go south
return kDirS;
- if (((x0 - 1) >= 0) && (getPass(x0 - 1, y0) != 0))
+ if (getPass(x0 - 1, y0 ) != 0)
+ // Can only go west
return kDirW;
- return 0;
+ // Can't go at all
+ return kDirNone;
}
- return -1;
+
+ warning("Map::getDirection(): Invalid direction?!?");
+ return kDirNone;
}
int16 Map::findNearestWayPoint(int16 x, int16 y) {
@@ -236,7 +349,7 @@ int16 Map::findNearestWayPoint(int16 x, int16 y) {
length = 30000;
- for (int i = 0; i < _wayPointsCount; i++) {
+ for (int i = 0; i < _wayPointCount; i++) {
if ((_wayPoints[i].x < 0) || (_wayPoints[i].x >= _mapWidth) ||
(_wayPoints[i].y < 0) || (_wayPoints[i].y >= _mapHeight))
break;
@@ -318,73 +431,81 @@ void Map::findNearestWalkable(int16 &gobDestX, int16 &gobDestY,
gobDestY -= distance;
}
-int16 Map::checkDirectPath(Mult::Mult_Object *obj,
- int16 x0, int16 y0, int16 x1, int16 y1) {
- uint16 dir;
+void Map::moveDirection(Direction dir, int16 &x, int16 &y) {
+ switch (dir) {
+ case kDirNW:
+ x--;
+ y--;
+ break;
+
+ case kDirN:
+ y--;
+ break;
+
+ case kDirNE:
+ x++;
+ y--;
+ break;
+
+ case kDirW:
+ x--;
+ break;
+
+ case kDirE:
+ x++;
+ break;
+
+ case kDirSW:
+ x--;
+ y++;
+ break;
+
+ case kDirS:
+ y++;
+ break;
+
+ case kDirSE:
+ x++;
+ y++;
+ break;
+
+ default:
+ break;
+ }
+}
+
+int16 Map::checkDirectPath(Mult::Mult_Object *obj, int16 x0, int16 y0, int16 x1, int16 y1) {
while (1) {
- dir = getDirection(x0, y0, x1, y1);
+ Direction dir = getDirection(x0, y0, x1, y1);
if (obj) {
- if (obj->nearestWayPoint < obj->nearestDest) {
- if (_wayPoints[obj->nearestWayPoint + 1].notWalkable == 1)
- return 3;
- } else if (obj->nearestWayPoint > obj->nearestDest) {
- if (obj->nearestDest > 0)
- if (_wayPoints[obj->nearestDest - 1].notWalkable == 1)
+ // Check for a blocking waypoint
+
+ if (obj->nearestWayPoint < obj->nearestDest)
+ if ((obj->nearestWayPoint + 1) < _wayPointCount)
+ if (_wayPoints[obj->nearestWayPoint + 1].notWalkable == 1)
+ return 3;
+
+ if (obj->nearestWayPoint > obj->nearestDest)
+ if (obj->nearestWayPoint > 0)
+ if (_wayPoints[obj->nearestWayPoint - 1].notWalkable == 1)
return 3;
- }
}
if ((x0 == x1) && (y0 == y1))
+ // Successfully reached the destination
return 1;
- if (dir == 0)
+ if (dir == kDirNone)
+ // No way
return 3;
- switch (dir) {
- case kDirNW:
- x0--;
- y0--;
- break;
-
- case kDirN:
- y0--;
- break;
-
- case kDirNE:
- x0++;
- y0--;
- break;
-
- case kDirW:
- x0--;
- break;
-
- case kDirE:
- x0++;
- break;
-
- case kDirSW:
- x0--;
- y0++;
- break;
-
- case kDirS:
- y0++;
- break;
-
- case kDirSE:
- x0++;
- y0++;
- break;
- }
+ moveDirection(dir, x0, y0);
}
}
-int16 Map::checkLongPath(int16 x0, int16 y0,
- int16 x1, int16 y1, int16 i0, int16 i1) {
- uint16 dir = 0;
+int16 Map::checkLongPath(int16 x0, int16 y0, int16 x1, int16 y1, int16 i0, int16 i1) {
int16 curX = x0;
int16 curY = y0;
int16 nextLink = 1;
@@ -417,47 +538,13 @@ int16 Map::checkLongPath(int16 x0, int16 y0,
return 1;
return 0;
}
- dir = getDirection(x0, y0, curX, curY);
- switch (dir) {
- case 0:
- return 0;
-
- case kDirNW:
- x0--;
- y0--;
- break;
- case kDirN:
- y0--;
- break;
-
- case kDirNE:
- x0++;
- y0--;
- break;
-
- case kDirW:
- x0--;
- break;
-
- case kDirE:
- x0++;
- break;
-
- case kDirSW:
- x0--;
- y0++;
- break;
-
- case kDirS:
- y0++;
- break;
+ Direction dir = getDirection(x0, y0, curX, curY);
+ if (dir == kDirNone)
+ // No way
+ return 0;
- case kDirSE:
- x0++;
- y0++;
- break;
- }
+ moveDirection(dir, x0, y0);
}
}
diff --git a/engines/gob/map.h b/engines/gob/map.h
index 4a63e84a63..4bf2dc6228 100644
--- a/engines/gob/map.h
+++ b/engines/gob/map.h
@@ -30,54 +30,48 @@
namespace Gob {
+enum RelativeDirection {
+ kRelDirNone = 0 ,
+
+ kRelDirLeft = (1 << 0),
+ kRelDirUp = (1 << 1),
+ kRelDirRight = (1 << 2),
+ kRelDirDown = (1 << 3),
+
+ kRelDirLeftUp = kRelDirLeft | kRelDirUp,
+ kRelDirLeftDown = kRelDirLeft | kRelDirDown,
+ kRelDirRightUp = kRelDirRight | kRelDirUp,
+ kRelDirRightDown = kRelDirRight | kRelDirDown
+};
+
// The same numeric values are also used for the arrow keys.
+enum Direction {
+ kDirNone = 0x0000,
+ kDirNW = 0x4700,
+ kDirN = 0x4800,
+ kDirNE = 0x4900,
+ kDirW = 0x4B00,
+ kDirE = 0x4D00,
+ kDirSW = 0x4F00,
+ kDirS = 0x5000,
+ kDirSE = 0x5100
+};
+
+struct WayPoint {
+ int16 x;
+ int16 y;
+ int16 notWalkable;
+};
+
+struct ItemPos {
+ int8 x;
+ int8 y;
+ int8 orient;
+};
+
class Map {
public:
- enum {
- kDirNW = 0x4700,
- kDirN = 0x4800,
- kDirNE = 0x4900,
- kDirW = 0x4B00,
- kDirE = 0x4D00,
- kDirSW = 0x4F00,
- kDirS = 0x5000,
- kDirSE = 0x5100
- };
-
-#include "common/pack-start.h" // START STRUCT PACKING
-
- struct Point {
- int16 x;
- int16 y;
- int16 notWalkable;
- } PACKED_STRUCT;
-
-#define szMap_ItemPos 3
-
- struct ItemPos {
- int8 x;
- int8 y;
- int8 orient;
- } PACKED_STRUCT;
-
-#include "common/pack-end.h" // END STRUCT PACKING
-
- byte _widthByte;
- int16 _mapWidth;
- int16 _mapHeight;
- int16 _screenWidth;
- int16 _screenHeight;
- int16 _tilesWidth;
- int16 _tilesHeight;
- int16 _passWidth;
- bool _bigTiles;
- bool _mapUnknownBool;
-
- int8 *_passMap; // [y * _mapWidth + x], getPass(x, y);
- int16 **_itemsMap; // [y][x]
- int16 _wayPointsCount;
- Point *_wayPoints;
int16 _nearestWayPoint;
int16 _nearestDest;
@@ -89,12 +83,36 @@ public:
ItemPos _itemPoses[40];
char _sourceFile[15];
+ Map(GobEngine *vm);
+ virtual ~Map();
+
+ uint8 getVersion() const;
+
+ int16 getMapWidth() const;
+ int16 getMapHeight() const;
+
+ int16 getScreenWidth() const;
+ int16 getScreenHeight() const;
+
+ int16 getTilesWidth() const;
+ int16 getTilesHeight() const;
+
+ bool hasBigTiles() const;
+
+ int8 getPass(int x, int y, int width = -1) const;
+ void setPass(int x, int y, int8 pass, int width = -1);
+
+ const WayPoint &getWayPoint(int n) const;
+
void findNearestWalkable(int16 &gobDestX, int16 &gobDestY,
int16 mouseX, int16 mouseY);
+ int16 getItem(int x, int y) const;
+ void setItem(int x, int y, int16 item);
void placeItem(int16 x, int16 y, int16 id);
- int16 getDirection(int16 x0, int16 y0, int16 x1, int16 y1);
+ Direction getDirection(int16 x0, int16 y0, int16 x1, int16 y1);
+
int16 checkDirectPath(Mult::Mult_Object *obj, int16 x0,
int16 y0, int16 x1, int16 y1);
int16 checkLongPath(int16 x0, int16 y0,
@@ -102,65 +120,52 @@ public:
void loadMapsInitGobs();
- virtual int16 getItem(int x, int y) = 0;
- virtual void setItem(int x, int y, int16 item) = 0;
-
- virtual int8 getPass(int x, int y, int heightOff = -1) = 0;
- virtual void setPass(int x, int y, int8 pass, int heightOff = -1) = 0;
-
virtual void loadMapObjects(const char *avjFile) = 0;
virtual void findNearestToGob(Mult::Mult_Object *obj) = 0;
virtual void findNearestToDest(Mult::Mult_Object *obj) = 0;
virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y) = 0;
- Map(GobEngine *vm);
- virtual ~Map();
-
protected:
+ GobEngine *_vm;
+
bool _loadFromAvo;
- GobEngine *_vm;
+ uint8 _mapVersion;
- int16 findNearestWayPoint(int16 x, int16 y);
-};
+ int16 _mapWidth;
+ int16 _mapHeight;
-class Map_v1 : public Map {
-public:
- virtual void loadMapObjects(const char *avjFile);
- virtual void findNearestToGob(Mult::Mult_Object *obj);
- virtual void findNearestToDest(Mult::Mult_Object *obj);
- virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y);
+ int16 _screenWidth;
+ int16 _screenHeight;
- virtual int16 getItem(int x, int y) {
- assert(_itemsMap);
+ int16 _tilesWidth;
+ int16 _tilesHeight;
- x = CLIP<int>(x, 0, _mapWidth - 1);
- y = CLIP<int>(y, 0, _mapHeight - 1);
+ bool _bigTiles;
- return _itemsMap[y][x];
- }
- virtual void setItem(int x, int y, int16 item) {
- assert(_itemsMap);
+ bool _mapUnknownBool;
- x = CLIP<int>(x, 0, _mapWidth - 1);
- y = CLIP<int>(y, 0, _mapHeight - 1);
+ int16 _passWidth;
+ int8 *_passMap; // [y * _mapWidth + x], getPass(x, y);
- _itemsMap[y][x] = item;
- }
+ int16 _wayPointCount;
+ WayPoint *_wayPoints;
- virtual int8 getPass(int x, int y, int heightOff = -1) {
- if (!_passMap)
- return 0;
+ int16 **_itemsMap; // [y][x]
- return _passMap[y * _mapWidth + x];
- }
+ int16 findNearestWayPoint(int16 x, int16 y);
- virtual void setPass(int x, int y, int8 pass, int heightOff = -1) {
- if (!_passMap)
- return;
+private:
+ // Move the x and y values according to the direction
+ void moveDirection(Direction dir, int16 &x, int16 &y);
+};
- _passMap[y * _mapWidth + x] = pass;
- }
+class Map_v1 : public Map {
+public:
+ virtual void loadMapObjects(const char *avjFile);
+ virtual void findNearestToGob(Mult::Mult_Object *obj);
+ virtual void findNearestToDest(Mult::Mult_Object *obj);
+ virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y);
Map_v1(GobEngine *vm);
virtual ~Map_v1();
@@ -180,24 +185,6 @@ public:
virtual void findNearestToDest(Mult::Mult_Object *obj);
virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y);
- virtual int8 getPass(int x, int y, int heightOff = -1) {
- if (!_passMap)
- return 0;
-
- if (heightOff == -1)
- heightOff = _passWidth;
- return _passMap[y * heightOff + x];
- }
-
- virtual void setPass(int x, int y, int8 pass, int heightOff = -1) {
- if (!_passMap)
- return;
-
- if (heightOff == -1)
- heightOff = _passWidth;
- _passMap[y * heightOff + x] = pass;
- }
-
Map_v2(GobEngine *vm);
virtual ~Map_v2();
diff --git a/engines/gob/map_v1.cpp b/engines/gob/map_v1.cpp
index d8898c83d3..3df1cb8512 100644
--- a/engines/gob/map_v1.cpp
+++ b/engines/gob/map_v1.cpp
@@ -44,7 +44,8 @@ void Map_v1::init() {
if (_passMap || _itemsMap)
return;
- _mapWidth = 26;
+ _passWidth = 26;
+ _mapWidth = 26;
_mapHeight = 28;
_passMap = new int8[_mapHeight * _mapWidth];
@@ -56,9 +57,9 @@ void Map_v1::init() {
memset(_itemsMap[i], 0, _mapWidth * sizeof(int16));
}
- _wayPointsCount = 40;
- _wayPoints = new Point[40];
- memset(_wayPoints, 0, sizeof(Point));
+ _wayPointCount = 40;
+ _wayPoints = new WayPoint[40];
+ memset(_wayPoints, 0, sizeof(WayPoint));
}
void Map_v1::loadMapObjects(const char *avjFile) {
@@ -74,13 +75,13 @@ void Map_v1::loadMapObjects(const char *avjFile) {
strcpy(avoName, _sourceFile);
strcat(avoName, ".avo");
- if (_vm->_dataIO->existData(avoName)) {
- _loadFromAvo = true;
- dataBuf = _vm->_dataIO->getData(avoName);
- } else {
+ int32 size;
+ dataBuf = _vm->_dataIO->getFile(avoName, size);
+ if (!dataBuf) {
+ dataBuf = _vm->_dataIO->getFile(avjFile, size);
_loadFromAvo = false;
- dataBuf = _vm->_dataIO->getData(avjFile);
- }
+ } else
+ _loadFromAvo = true;
Common::MemoryReadStream mapData(dataBuf, 4294967295U);
@@ -97,7 +98,12 @@ void Map_v1::loadMapObjects(const char *avjFile) {
_wayPoints[i].x = mapData.readUint16LE();
_wayPoints[i].y = mapData.readUint16LE();
}
- mapData.read(_itemPoses, szMap_ItemPos * 20);
+
+ for (int i = 0; i < 20; i++) {
+ _itemPoses[i].x = mapData.readByte();
+ _itemPoses[i].y = mapData.readByte();
+ _itemPoses[i].orient = mapData.readByte();
+ }
}
mapData.skip(32 + 76 + 4 + 20);
@@ -159,7 +165,7 @@ void Map_v1::loadSounds(Common::SeekableReadStream &data) {
_vm->_sound->sampleLoad(&_vm->_goblin->_soundData[14], SOUND_SND, "diamant1.snd");
for (int i = 0; i < count; i++) {
- if (!_vm->_dataIO->existData(sndNames[i]))
+ if (!_vm->_dataIO->hasFile(sndNames[i]))
continue;
_vm->_sound->sampleLoad(&_vm->_goblin->_soundData[i], SOUND_SND, sndNames[i]);
diff --git a/engines/gob/map_v2.cpp b/engines/gob/map_v2.cpp
index e2f9207003..f81d3e6002 100644
--- a/engines/gob/map_v2.cpp
+++ b/engines/gob/map_v2.cpp
@@ -100,11 +100,11 @@ void Map_v2::loadMapObjects(const char *avjFile) {
Common::SeekableReadStream &mapData = *resource->stream();
- _widthByte = mapData.readByte();
- if (_widthByte == 4) {
+ _mapVersion = mapData.readByte();
+ if (_mapVersion == 4) {
_screenWidth = 640;
_screenHeight = 400;
- } else if (_widthByte == 3) {
+ } else if (_mapVersion == 3) {
_passWidth = 65;
_screenWidth = 640;
_screenHeight = 200;
@@ -114,14 +114,14 @@ void Map_v2::loadMapObjects(const char *avjFile) {
_screenHeight = 200;
}
- _wayPointsCount = mapData.readByte();
+ _wayPointCount = mapData.readByte();
_tilesWidth = mapData.readSint16LE();
_tilesHeight = mapData.readSint16LE();
_bigTiles = !(_tilesHeight & 0xFF00);
_tilesHeight &= 0xFF;
- if (_widthByte == 4) {
+ if (_mapVersion == 4) {
_screenWidth = mapData.readSint16LE();
_screenHeight = mapData.readSint16LE();
}
@@ -133,19 +133,19 @@ void Map_v2::loadMapObjects(const char *avjFile) {
mapData.skip(_mapWidth * _mapHeight);
if (resource->getData()[0] == 1)
- wayPointsCount = _wayPointsCount = 40;
+ wayPointsCount = _wayPointCount = 40;
else
- wayPointsCount = _wayPointsCount == 0 ? 1 : _wayPointsCount;
+ wayPointsCount = _wayPointCount == 0 ? 1 : _wayPointCount;
delete[] _wayPoints;
- _wayPoints = new Point[wayPointsCount];
- for (int i = 0; i < _wayPointsCount; i++) {
+ _wayPoints = new WayPoint[wayPointsCount];
+ for (int i = 0; i < _wayPointCount; i++) {
_wayPoints[i].x = mapData.readSByte();
_wayPoints[i].y = mapData.readSByte();
_wayPoints[i].notWalkable = mapData.readSByte();
}
- if (_widthByte == 4) {
+ if (_mapVersion == 4) {
_mapWidth = VAR(17);
_passWidth = _mapWidth;
}
@@ -258,17 +258,24 @@ void Map_v2::findNearestToDest(Mult::Mult_Object *obj) {
void Map_v2::optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y) {
if (obj->nearestWayPoint < obj->nearestDest) {
+
for (int i = obj->nearestWayPoint; i <= obj->nearestDest; i++) {
if (checkDirectPath(obj, x, y, _wayPoints[i].x, _wayPoints[i].y) == 1)
obj->nearestWayPoint = i;
}
+
} else {
- for (int i = obj->nearestWayPoint;
- i >= obj->nearestDest && (_wayPoints[i].notWalkable != 1); i--) {
+
+ for (int i = obj->nearestWayPoint; i >= obj->nearestDest; i--) {
+ if (_wayPoints[i].notWalkable == 1)
+ break;
+
if (checkDirectPath(obj, x, y, _wayPoints[i].x, _wayPoints[i].y) == 1)
obj->nearestWayPoint = i;
}
+
}
+
}
} // End of namespace Gob
diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 05658e0ca8..882a67bd45 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/gob
MODULE_OBJS := \
+ console.o \
dataio.o \
detection.o \
draw.o \
diff --git a/engines/gob/resources.cpp b/engines/gob/resources.cpp
index 8241821039..b5b3d7aaa2 100644
--- a/engines/gob/resources.cpp
+++ b/engines/gob/resources.cpp
@@ -293,7 +293,7 @@ bool Resources::loadTOTResourceTable() {
bool Resources::loadEXTResourceTable() {
_extResourceTable = new EXTResourceTable;
- DataStream *stream = _vm->_dataIO->getDataStream(_extFile.c_str());
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_extFile);
if (!stream)
return false;
@@ -396,7 +396,7 @@ bool Resources::loadIMFile() {
imFile += num;
- DataStream *stream = _vm->_dataIO->getDataStream(imFile.c_str());
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(imFile);
if (!stream)
return true;
@@ -431,7 +431,7 @@ bool Resources::loadEXFile() {
_exFile = "commun.ex";
_exFile += totProps.exFileNumber + '0';
- if (!_vm->_dataIO->existData(_exFile.c_str())) {
+ if (!_vm->_dataIO->hasFile(_exFile)) {
_exFile.clear();
return true;
}
@@ -473,7 +473,7 @@ Common::String Resources::getLocTextFile(const Common::String &fileBase,
break;
}
- if (!_vm->_dataIO->existData(locTextFile.c_str()))
+ if (!_vm->_dataIO->hasFile(locTextFile))
locTextFile.clear();
return locTextFile;
@@ -525,8 +525,7 @@ byte *Resources::loadTOTLocTexts(const Common::String &fileBase, int32 &size) {
if (locTextFile.empty())
return 0;
- size = _vm->_dataIO->getDataSize(locTextFile.c_str());
- return _vm->_dataIO->getData(locTextFile.c_str());
+ return _vm->_dataIO->getFile(locTextFile, size);
}
Resource *Resources::getResource(uint16 id, int16 *width, int16 *height) const {
@@ -682,10 +681,10 @@ Resource *Resources::getEXTResource(uint16 id) const {
if (extItem.packed) {
byte *packedData = data;
- size = READ_LE_UINT32(packedData);
- data = new byte[size];
+ int32 unpackSize;
+ data = _vm->_dataIO->unpack(packedData, size, unpackSize);
- _vm->_dataIO->unpackData(packedData, data);
+ size = unpackSize;
delete[] packedData;
}
@@ -724,7 +723,7 @@ byte *Resources::getIMData(TOTResourceItem &totItem) const {
}
byte *Resources::getEXTData(EXTResourceItem &extItem, uint32 size) const {
- DataStream *stream = _vm->_dataIO->getDataStream(_extFile.c_str());
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_extFile);
if (!stream)
return 0;
@@ -745,7 +744,7 @@ byte *Resources::getEXTData(EXTResourceItem &extItem, uint32 size) const {
}
byte *Resources::getEXData(EXTResourceItem &extItem, uint32 size) const {
- DataStream *stream = _vm->_dataIO->getDataStream(_exFile.c_str());
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_exFile);
if (!stream)
return 0;
diff --git a/engines/gob/save/savefile.h b/engines/gob/save/savefile.h
index da3696dee8..980616bb74 100644
--- a/engines/gob/save/savefile.h
+++ b/engines/gob/save/savefile.h
@@ -35,13 +35,14 @@ namespace Gob {
class GobEngine;
class Surface;
-/** A class wrapping a save part header.
- *
- * A save part header consists of 4 fields:
- * ID : The 8 character ID \0SCVMGOB
- * Type : The 4 character ID for this part's type
- * Version : This part's version. Each type has its own version counter
- * Size : The size of the contents, i.e. excluding this header
+/**
+ * A class wrapping a save part header.
+ *
+ * A save part header consists of 4 fields:
+ * ID : The 8 character ID \0SCVMGOB
+ * Type : The 4 character ID for this part's type
+ * Version : This part's version. Each type has its own version counter
+ * Size : The size of the contents, i.e. excluding this header
*/
class SaveHeader {
public:
@@ -186,13 +187,13 @@ public:
static const uint32 kVersion = 1;
static const uint32 kID = MKID_BE('INFO');
- /** The constructor.
- *
- * @param descMaxLength The maximal number of bytes that fit into the description.
- * @param gameID An ID for the game (Gob1, Gob2, Gob3, ...).
- * @param gameVersion An ID for game specific versioning
- * @param endian Endianness of the platform the game originally ran on.
- * @param varCount The number of script variables.
+ /**
+ * The constructor.
+ * @param descMaxLength The maximal number of bytes that fit into the description.
+ * @param gameID An ID for the game (Gob1, Gob2, Gob3, ...).
+ * @param gameVersion An ID for game specific versioning
+ * @param endian Endianness of the platform the game originally ran on.
+ * @param varCount The number of script variables.
*/
SavePartInfo(uint32 descMaxLength, uint32 gameID,
uint32 gameVersion, byte endian, uint32 varCount);
@@ -228,10 +229,10 @@ public:
static const uint32 kVersion = 1;
static const uint32 kID = MKID_BE('CONT');
- /** The constructor.
- *
- * @param partCount The number parts this container shall hold.
- * @param slot The save slot this save's for.
+ /**
+ * The constructor.
+ * @param partCount The number parts this container shall hold.
+ * @param slot The save slot this save's for.
*/
SaveContainer(uint32 partCount, uint32 slot);
~SaveContainer();
diff --git a/engines/gob/script.cpp b/engines/gob/script.cpp
index 339199c9b1..0b0fcd4cda 100644
--- a/engines/gob/script.cpp
+++ b/engines/gob/script.cpp
@@ -43,7 +43,7 @@ Script::Script(GobEngine *vm) : _vm(vm) {
_totPtr = 0;
_totSize = 0;
- _lomHandle = -1;
+ _lom = 0;
memset(&_totProperties, 0, sizeof(TOTFile::Properties));
}
@@ -380,20 +380,16 @@ bool Script::loadTOT(const Common::String &fileName) {
bool Script::loadLOM(const Common::String &fileName) {
warning("Stub: Script::loadLOM(%s)", _totFile.c_str());
- _lomHandle = _vm->_dataIO->openData(_totFile.c_str());
- if (_lomHandle < 0)
+ _lom = _vm->_dataIO->getFile(_totFile);
+ if (!_lom)
return false;
- DataStream *stream = _vm->_dataIO->openAsStream(_lomHandle);
-
- stream->seek(48);
- _totSize = stream->readUint32LE();
- stream->seek(0);
+ _lom->seek(48);
+ _totSize = _lom->readUint32LE();
+ _lom->seek(0);
_totData = new byte[_totSize];
- stream->read(_totData, _totSize);
-
- delete stream;
+ _lom->read(_totData, _totSize);
return false;
}
@@ -403,8 +399,8 @@ void Script::unload() {
}
void Script::unloadTOT() {
- if (_lomHandle >= 0)
- _vm->_dataIO->closeData(_lomHandle);
+ delete _lom;
+ _lom = 0;
// Unwind the call stack
while (!_callStack.empty())
@@ -415,7 +411,6 @@ void Script::unloadTOT() {
_totData = 0;
_totSize = 0;
_totPtr = 0;
- _lomHandle = -1;
_totFile.clear();
_finished = true;
@@ -518,7 +513,7 @@ uint16 Script::getFunctionOffset(uint8 function) const {
}
uint32 Script::getVariablesCount(const char *fileName, GobEngine *vm) {
- DataStream *stream = vm->_dataIO->getDataStream(fileName);
+ Common::SeekableReadStream *stream = vm->_dataIO->getFile(fileName);
if (!stream)
return 0;
diff --git a/engines/gob/script.h b/engines/gob/script.h
index 84daeaf1af..cf9eb246ce 100644
--- a/engines/gob/script.h
+++ b/engines/gob/script.h
@@ -150,7 +150,7 @@ private:
byte *_totPtr;
uint32 _totSize;
- int16 _lomHandle;
+ Common::SeekableReadStream *_lom;
TOTFile::Properties _totProperties;
diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp
index 28123668cc..d643ae511b 100644
--- a/engines/gob/sound/adlib.cpp
+++ b/engines/gob/sound/adlib.cpp
@@ -240,7 +240,7 @@ void AdLib::setKey(byte voice, byte note, bool on, bool spec) {
freq = _freqs[_notLin[voice]][note - octa * 12];
writeOPL(0xA0 + voice, freq & 0xFF);
- writeOPL(0xB0 + voice, (freq >> 8) | (octa << 2) | 0x20 * on);
+ writeOPL(0xB0 + voice, (freq >> 8) | (octa << 2) | (0x20 * (on ? 1 : 0)));
if (!freq)
warning("AdLib::setKey Voice %d, note %02X unknown", voice, note);
diff --git a/engines/gob/sound/cdrom.cpp b/engines/gob/sound/cdrom.cpp
index ec7da29fdb..3316b760ef 100644
--- a/engines/gob/sound/cdrom.cpp
+++ b/engines/gob/sound/cdrom.cpp
@@ -24,11 +24,11 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "common/util.h"
#include "gob/gob.h"
#include "gob/sound/cdrom.h"
-#include "gob/helper.h"
#include "gob/dataio.h"
namespace Gob {
@@ -48,7 +48,7 @@ CDROM::~CDROM() {
stop();
}
-void CDROM::readLIC(DataStream &stream) {
+void CDROM::readLIC(Common::SeekableReadStream &stream) {
uint16 version, startChunk, pos;
freeLICBuffer();
@@ -91,7 +91,7 @@ void CDROM::startTrack(const char *trackName) {
return;
}
- strncpy0(_curTrack, trackName, 15);
+ Common::strlcpy(_curTrack, trackName, 16);
stopPlaying();
_curTrackBuffer = matchPtr;
diff --git a/engines/gob/sound/cdrom.h b/engines/gob/sound/cdrom.h
index 6f01e6f90a..894744ca15 100644
--- a/engines/gob/sound/cdrom.h
+++ b/engines/gob/sound/cdrom.h
@@ -28,14 +28,12 @@
namespace Gob {
-class DataStream;
-
class CDROM {
public:
CDROM();
~CDROM();
- void readLIC(DataStream &stream);
+ void readLIC(Common::SeekableReadStream &stream);
void freeLICBuffer();
void startTrack(const char *trackName);
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index bc4495fafd..dc80699ce0 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -114,19 +114,13 @@ bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName,
debugC(2, kDebugSound, "Loading sample \"%s\"", fileName);
- if (!_vm->_dataIO->existData(fileName)) {
+ int32 size;
+ byte *data = _vm->_dataIO->getFile(fileName, size);
+ if (!data) {
warning("Can't open sample file \"%s\"", fileName);
return false;
}
- byte *data;
- uint32 size;
-
- data = (byte *)_vm->_dataIO->getData(fileName);
- if (!data)
- return false;
-
- size = _vm->_dataIO->getDataSize(fileName);
return sndDesc->load(type, data, size);
}
@@ -279,13 +273,12 @@ bool Sound::adlibLoadMDY(const char *fileName) {
debugC(1, kDebugSound, "AdLib: Loading MDY data (\"%s\")", fileName);
- if (!_vm->_dataIO->existData(fileName)) {
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName);
+ if (!stream) {
warning("Can't open MDY file \"%s\"", fileName);
return false;
}
- DataStream *stream = _vm->_dataIO->getDataStream(fileName);
-
bool loaded = _mdyPlayer->loadMDY(*stream);
delete stream;
@@ -300,15 +293,14 @@ bool Sound::adlibLoadTBR(const char *fileName) {
if (!_mdyPlayer)
_mdyPlayer = new MDYPlayer(*_vm->_mixer);
- if (!_vm->_dataIO->existData(fileName)) {
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName);
+ if (!stream) {
warning("Can't open TBR file \"%s\"", fileName);
return false;
}
debugC(1, kDebugSound, "AdLib: Loading MDY instruments (\"%s\")", fileName);
- DataStream *stream = _vm->_dataIO->getDataStream(fileName);
-
bool loaded = _mdyPlayer->loadTBR(*stream);
delete stream;
@@ -522,13 +514,10 @@ void Sound::cdLoadLIC(const char *fname) {
debugC(1, kDebugSound, "CDROM: Loading LIC \"%s\"", fname);
- if (!_vm->_dataIO->existData(fname))
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fname);
+ if (!stream)
return;
- _vm->_dataIO->getUnpackedData(fname);
-
- DataStream *stream = _vm->_dataIO->getDataStream(fname);
-
_cdrom->readLIC(*stream);
delete stream;
diff --git a/engines/gob/totfile.cpp b/engines/gob/totfile.cpp
index 178deeaf58..82dd0c38c0 100644
--- a/engines/gob/totfile.cpp
+++ b/engines/gob/totfile.cpp
@@ -45,11 +45,11 @@ TOTFile::~TOTFile() {
bool TOTFile::load(const Common::String &fileName) {
// Trying to open normally
- _stream = _vm->_dataIO->getDataStream(fileName.c_str());
+ _stream = _vm->_dataIO->getFile(fileName);
if (!_stream)
// Trying to open from video
- _stream = _vm->_vidPlayer->getEmbeddedFile(fileName.c_str());
+ _stream = _vm->_vidPlayer->getEmbeddedFile(fileName);
if (!_stream)
return false;
diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp
index 00d8c2c9ac..8e2b3d89cd 100644
--- a/engines/gob/util.cpp
+++ b/engines/gob/util.cpp
@@ -121,6 +121,10 @@ void Util::processInput(bool scroll) {
_fastMode ^= 2;
else if (event.kbd.keycode == Common::KEYCODE_p)
_vm->pauseGame();
+ else if (event.kbd.keycode == Common::KEYCODE_d) {
+ _vm->getDebugger()->attach();
+ _vm->getDebugger()->onFrame();
+ }
break;
}
addKeyToBuffer(event.kbd);
@@ -146,7 +150,7 @@ void Util::processInput(bool scroll) {
// WORKAROUND:
// Force a check of the mouse in order to fix the sofa bug. This apply only for Gob3, and only
// in the impacted TOT file so that the second screen animation is not broken.
- if ((_vm->getGameType() == kGameTypeGob3) && !strncmp(_vm->_game->_curTotFile, "EMAP1008.TOT", 12))
+ if ((_vm->getGameType() == kGameTypeGob3) && !scumm_stricmp(_vm->_game->_curTotFile, "EMAP1008.TOT"))
_vm->_game->evaluateScroll();
}
}
diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp
index 11c5f08bb2..4f6bad52f0 100644
--- a/engines/gob/variables.cpp
+++ b/engines/gob/variables.cpp
@@ -24,10 +24,10 @@
*/
#include "common/endian.h"
+#include "common/str.h"
#include "gob/gob.h"
#include "gob/variables.h"
-#include "gob/helper.h"
namespace Gob {
@@ -112,7 +112,7 @@ uint32 Variables::readOff32(uint32 offset) const {
}
void Variables::readOffString(uint32 offset, char *value, uint32 length) {
- strncpy0(value, (const char *)(_vars + offset), length - 1);
+ Common::strlcpy(value, (const char *)(_vars + offset), length);
}
const uint8 *Variables::getAddressVar8(uint32 var) const {
diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp
index ee73f14dfa..91e3737832 100644
--- a/engines/gob/video.cpp
+++ b/engines/gob/video.cpp
@@ -331,9 +331,9 @@ void Video::drawPackedSprite(byte *sprBuf, int16 width, int16 height,
}
void Video::drawPackedSprite(const char *path, Surface &dest, int width) {
- byte *data;
+ int32 size;
+ byte *data = _vm->_dataIO->getFile(path, size);
- data = _vm->_dataIO->getData(path);
drawPackedSprite(data, width, dest.getHeight(), 0, 0, 0, dest);
delete[] data;
}
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index f349413b93..917bdc66c5 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -25,7 +25,6 @@
#include "gob/videoplayer.h"
-#include "gob/helper.h"
#include "gob/global.h"
#include "gob/dataio.h"
#include "gob/video.h"
@@ -687,7 +686,7 @@ Common::String VideoPlayer::findFile(const Common::String &file, Properties &pro
if ((properties.type == kVideoTypeTry) || (properties.type == ((Type) i))) {
fileName = base + "." + _extensions[i];
- if (_vm->_dataIO->existData(fileName.c_str())) {
+ if (_vm->_dataIO->hasFile(fileName)) {
properties.type = (Type) i;
break;
}
@@ -708,7 +707,7 @@ Graphics::CoktelDecoder *VideoPlayer::openVideo(const Common::String &file, Prop
if (fileName.empty())
return 0;
- Common::SeekableReadStream *stream = _vm->_dataIO->getDataStream(fileName.c_str());
+ Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName);
if (!stream)
return 0;
diff --git a/engines/groovie/font.cpp b/engines/groovie/font.cpp
index dc1d7ae73a..b9d6dbf687 100644
--- a/engines/groovie/font.cpp
+++ b/engines/groovie/font.cpp
@@ -62,6 +62,10 @@ bool T7GFont::load(Common::SeekableReadStream &stream) {
delete[] _glyphs;
_glyphs = new Glyph[numGlyphs];
+ // Ensure we're ready to read the first glyph. (Most versions don't
+ // need it, but the russian one does. This fixes bug #3095031.)
+ stream.seek(glyphOffsets[0]);
+
// Read the glyphs
_maxHeight = _maxWidth = 0;
for (int i = 0; (i < numGlyphs) && !stream.eos(); i++) {
diff --git a/engines/groovie/groovie.h b/engines/groovie/groovie.h
index 8ae5f4157f..f8fad8d91f 100644
--- a/engines/groovie/groovie.h
+++ b/engines/groovie/groovie.h
@@ -44,7 +44,7 @@ namespace Common {
* now fully completable. All remaining Groovie games use V2 of the engine,
* which is under slow development.
*
- * Supported games:
+ * Games using this engine:
* - The 7th Guest (completable)
* - The 11th Hour
* - Clandestiny
diff --git a/engines/groovie/saveload.h b/engines/groovie/saveload.h
index b2b81cb6db..24a0ddfbf8 100644
--- a/engines/groovie/saveload.h
+++ b/engines/groovie/saveload.h
@@ -28,6 +28,7 @@
#include "common/savefile.h"
#include "engines/game.h"
+#include "engines/savestate.h"
namespace Groovie {
diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp
index 9fd7fa7d63..4abfff74f2 100644
--- a/engines/groovie/script.cpp
+++ b/engines/groovie/script.cpp
@@ -214,7 +214,7 @@ void Script::directGameLoad(int slot) {
void Script::step() {
// Prepare the base debug string
- _debugString = _scriptFile + Common::String::printf("@0x%04X: ", _currentInstruction);
+ _debugString = _scriptFile + Common::String::format("@0x%04X: ", _currentInstruction);
// Get the current opcode
byte opcode = readScript8bits();
@@ -222,7 +222,7 @@ void Script::step() {
opcode = opcode & 0x7F;
// Show the opcode debug string
- _debugString += Common::String::printf("op 0x%02X: ", opcode);
+ _debugString += Common::String::format("op 0x%02X: ", opcode);
// Only output if we're not re-doing the previous instruction
if (_currentInstruction != _oldInstruction) {
diff --git a/engines/hugo/engine.h b/engines/hugo/console.cpp
index 0d14d244b5..4c4f5934f8 100644
--- a/engines/hugo/engine.h
+++ b/engines/hugo/console.cpp
@@ -23,22 +23,21 @@
*
*/
-/*
- * This code is based on original Hugo 1-3 Trilogy source code
- *
- * Copyright (c) 1989-1995 David P. Gray
- *
- */
+#include "hugo/console.h"
+#include "hugo/hugo.h"
-#ifndef HUGO_ENGINE_H
-#define HUGO_ENGINE_H
namespace Hugo {
-enum seqTextEngine {
- // Strings used by the engine
- kEsAdvertise = 0
-};
+HugoConsole::HugoConsole(HugoEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
-} // End of namespace Hugo
+HugoConsole::~HugoConsole() {
+}
-#endif // HUGO_ENGINE_H
+void HugoConsole::preEnter() {
+}
+
+void HugoConsole::postEnter() {
+}
+
+} // End of namespace Hugo
diff --git a/engines/hugo/console.h b/engines/hugo/console.h
new file mode 100644
index 0000000000..f6c651459e
--- /dev/null
+++ b/engines/hugo/console.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef HUGO_CONSOLE_H
+#define HUGO_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Hugo {
+
+class HugoEngine;
+
+class HugoConsole : public GUI::Debugger {
+public:
+ HugoConsole(HugoEngine *vm);
+ virtual ~HugoConsole(void);
+
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+private:
+ HugoEngine *_vm;
+};
+
+} // End of namespace Hugo
+
+#endif
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp
index 0064a39434..d10b50d0b7 100644
--- a/engines/hugo/detection.cpp
+++ b/engines/hugo/detection.cpp
@@ -41,8 +41,8 @@ uint32 HugoEngine::getFeatures() const {
static const PlainGameDescriptor hugoGames[] = {
// Games
{"hugo1", "Hugo 1: Hugo's House of Horrors"},
- {"hugo2", "Hugo 2: Hugo's Mystery Adventure"},
- {"hugo3", "Hugo 3: Hugo's Amazon Adventure"},
+ {"hugo2", "Hugo 2: Whodunit?"},
+ {"hugo3", "Hugo 3: Jungle of Doom"},
{0, 0}
};
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index 3a8d0d4e89..db83f8debe 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -48,8 +48,11 @@ namespace Hugo {
#define INY(Y, B) (Y >= B->y && Y <= B->y + B->dy)
#define OVERLAP(A, B) ((INX(A->x, B) || INX(A->x + A->dx, B) || INX(B->x, A) || INX(B->x + B->dx, A)) && (INY(A->y, B) || INY(A->y + A->dy, B) || INY(B->y, A) || INY(B->y + B->dy, A)))
-Screen::Screen(HugoEngine &vm) : _vm(vm) {
-
+Screen::Screen(HugoEngine *vm) : _vm(vm), _palette(0) {
+ for (int j = 0; j < NUM_FONTS; j++) {
+ _arrayFont[j] = 0;
+ fontLoadedFl[j] = false;
+ }
}
Screen::~Screen() {
@@ -58,16 +61,20 @@ Screen::~Screen() {
void Screen::createPal() {
debugC(1, kDebugDisplay, "createPal");
- g_system->setPalette(_vm._palette, 0, NUM_COLORS);
+ g_system->setPalette(_palette, 0, NUM_COLORS);
}
+/**
+* Create logical palette
+*/
void Screen::initDisplay() {
debugC(1, kDebugDisplay, "initDisplay");
- // Create logical palette
createPal();
}
-// Move an image from source to destination
+/**
+* Move an image from source to destination
+*/
void Screen::moveImage(image_pt srcImage, uint16 x1, uint16 y1, uint16 dx, uint16 dy, uint16 width1, image_pt dstImage, uint16 x2, uint16 y2, uint16 width2) {
debugC(3, kDebugDisplay, "moveImage(srcImage, %d, %d, %d, %d, %d, dstImage, %d, %d, %d)", x1, y1, dx, dy, width1, x2, y2, width2);
@@ -91,19 +98,29 @@ void Screen::displayBackground() {
g_system->copyRectToScreen(_frontBuffer, 320, 0, 0, 320, 200);
}
-// Blit the supplied rectangle from _frontBuffer to the screen
+/**
+* Blit the supplied rectangle from _frontBuffer to the screen
+*/
void Screen::displayRect(int16 x, int16 y, int16 dx, int16 dy) {
debugC(3, kDebugDisplay, "displayRect(%d, %d, %d, %d)", x, y, dx, dy);
g_system->copyRectToScreen(&_frontBuffer[x + y * 320], 320, x, y, dx, dy);
}
+/**
+* Change a color by remapping supplied palette index with new index
+*/
void Screen::remapPal(uint16 oldIndex, uint16 newIndex) {
-// Change a color by remapping supplied palette index with new index
debugC(1, kDebugDisplay, "Remap_pal(%d, %d)", oldIndex, newIndex);
- warning("STUB: Remap_pal()");
- //bminfo.bmiColors[oldIndex] = ctab[newIndex];
+ byte pal[4];
+
+ pal[0] = _palette[newIndex * 4 + 0];
+ pal[1] = _palette[newIndex * 4 + 1];
+ pal[2] = _palette[newIndex * 4 + 2];
+ pal[3] = _palette[newIndex * 4 + 3];
+
+ g_system->setPalette(pal, oldIndex, 1);
}
void Screen::savePal(Common::WriteStream *f) {
@@ -121,21 +138,25 @@ void Screen::restorePal(Common::SeekableReadStream *f) {
}
-// Set the new background color
+/**
+* Set the new background color
+*/
void Screen::setBackgroundColor(long color) {
debugC(1, kDebugDisplay, "setBackgroundColor(%ld)", color);
// How??? Translate existing pixels in dib before objects rendered?
}
-// Return the overlay state (Foreground/Background) of the currently
-// processed object by looking down the current column for an overlay
-// base bit set (in which case the object is foreground).
+/**
+* Return the overlay state (Foreground/Background) of the currently
+* processed object by looking down the current column for an overlay
+* base bit set (in which case the object is foreground).
+*/
overlayState_t Screen::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) {
debugC(4, kDebugDisplay, "findOvl");
for (; y < seq_p->lines; y++) { // Each line in object
- image_pt ovb_p = _vm.getBaseBoundaryOverlay() + ((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits
+ image_pt ovb_p = _vm->getBaseBoundaryOverlay() + ((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits
if (*ovb_p & (0x80 >> ((uint16)(dst_p - _frontBuffer) & 7))) // Overlay bit is set
return FG; // Found a bit - must be foreground
dst_p += XPIX;
@@ -144,14 +165,16 @@ overlayState_t Screen::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) {
return BG; // No bits set, must be background
}
-// Merge an object frame into _frontBuffer at sx, sy and update rectangle list.
-// If fore TRUE, force object above any overlay
+/**
+* Merge an object frame into _frontBuffer at sx, sy and update rectangle list.
+* If fore TRUE, force object above any overlay
+*/
void Screen::displayFrame(int sx, int sy, seq_t *seq, bool foreFl) {
debugC(3, kDebugDisplay, "displayFrame(%d, %d, seq, %d)", sx, sy, (foreFl) ? 1 : 0);
image_pt image = seq->imagePtr; // Ptr to object image data
image_pt subFrontBuffer = &_frontBuffer[sy * XPIX + sx]; // Ptr to offset in _frontBuffer
- image_pt overlay = &_vm.getFirstOverlay()[(sy * XPIX + sx) >> 3]; // Ptr to overlay data
+ image_pt overlay = &_vm->getFirstOverlay()[(sy * XPIX + sx) >> 3]; // Ptr to overlay data
int16 frontBufferwrap = XPIX - seq->x2 - 1; // Wraps dest_p after each line
int16 imageWrap = seq->bytesPerLine8 - seq->x2 - 1;
@@ -159,7 +182,7 @@ void Screen::displayFrame(int sx, int sy, seq_t *seq, bool foreFl) {
for (uint16 y = 0; y < seq->lines; y++) { // Each line in object
for (uint16 x = 0; x <= seq->x2; x++) {
if (*image) { // Non-transparent
- overlay = _vm.getFirstOverlay() + ((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits
+ overlay = _vm->getFirstOverlay() + ((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits
if (*overlay & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set
if (overlayState == UNDEF) // Overlay defined yet?
overlayState = findOvl(seq, subFrontBuffer, y);// No, find it.
@@ -180,7 +203,9 @@ void Screen::displayFrame(int sx, int sy, seq_t *seq, bool foreFl) {
displayList(D_ADD, sx, sy, seq->x2 + 1, seq->lines);
}
-// Merge rectangles A,B leaving result in B
+/**
+* Merge rectangles A,B leaving result in B
+*/
void Screen::merge(rect_t *rectA, rect_t *rectB) {
debugC(6, kDebugDisplay, "merge");
@@ -195,10 +220,12 @@ void Screen::merge(rect_t *rectA, rect_t *rectB) {
rectB->dy = MAX(ya, yb) - rectB->y;
}
-// Coalesce the rectangles in the restore/add list into one unified
-// blist. len is the sizes of alist or rlist. blen is current length
-// of blist. bmax is the max size of the blist. Note that blist can
-// have holes, in which case dx = 0. Returns used length of blist.
+/**
+* Coalesce the rectangles in the restore/add list into one unified
+* blist. len is the sizes of alist or rlist. blen is current length
+* of blist. bmax is the max size of the blist. Note that blist can
+* have holes, in which case dx = 0. Returns used length of blist.
+*/
int16 Screen::mergeLists(rect_t *list, rect_t *blist, int16 len, int16 blen, int16 bmax) {
debugC(4, kDebugDisplay, "mergeLists");
@@ -213,7 +240,7 @@ int16 Screen::mergeLists(rect_t *list, rect_t *blist, int16 len, int16 blen, int
if (OVERLAP(list, bp))
coalesce[c++] = b;
}
-
+
// Any overlapping blit rects?
if (c == 0) { // None, add a new entry
blist[blen++] = *list;
@@ -233,8 +260,10 @@ int16 Screen::mergeLists(rect_t *list, rect_t *blist, int16 len, int16 blen, int
return blen;
}
-// Process the display list
-// Trailing args are int16 x,y,dx,dy for the D_ADD operation
+/**
+* Process the display list
+* Trailing args are int16 x,y,dx,dy for the D_ADD operation
+*/
void Screen::displayList(dupdate_t update, ...) {
debugC(6, kDebugDisplay, "displayList");
@@ -253,7 +282,7 @@ void Screen::displayList(dupdate_t update, ...) {
break;
case D_ADD: // Add a rectangle to list
if (addIndex >= DMAX) {
- Utils::Warn("%s", "Display list exceeded");
+ warning("Display list exceeded");
return;
}
va_start(marker, update); // Initialize variable arguments
@@ -269,8 +298,8 @@ void Screen::displayList(dupdate_t update, ...) {
// Don't blit if newscreen just loaded because _frontBuffer will
// get blitted via InvalidateRect() at end of this cycle
// and blitting here causes objects to appear too soon.
- if (_vm.getGameStatus().newScreenFl) {
- _vm.getGameStatus().newScreenFl = false;
+ if (_vm->getGameStatus().newScreenFl) {
+ _vm->getGameStatus().newScreenFl = false;
break;
}
@@ -295,13 +324,14 @@ void Screen::displayList(dupdate_t update, ...) {
}
}
+/**
+* Write supplied character (font data) at sx,sy in supplied color
+* Font data as follows:
+* *(fontdata+1) = Font Height (pixels)
+* *(fontdata+1) = Font Width (pixels)
+* *(fontdata+x) = Font Bitmap (monochrome)
+*/
void Screen::writeChr(int sx, int sy, byte color, char *local_fontdata) {
-// Write supplied character (font data) at sx,sy in supplied color
-// Font data as follows:
-//
-// *(fontdata+1) = Font Height (pixels)
-// *(fontdata+1) = Font Width (pixels)
-// *(fontdata+x) = Font Bitmap (monochrome)
debugC(2, kDebugDisplay, "writeChr(%d, %d, %d, %d)", sx, sy, color, local_fontdata[0]);
byte height = local_fontdata[0];
@@ -320,7 +350,9 @@ void Screen::writeChr(int sx, int sy, byte color, char *local_fontdata) {
}
}
-// Returns height of characters in current font
+/**
+* Returns height of characters in current font
+*/
int16 Screen::fontHeight() {
debugC(2, kDebugDisplay, "fontHeight");
@@ -328,8 +360,9 @@ int16 Screen::fontHeight() {
return height[_fnt - FIRST_FONT];
}
-
-// Returns length of supplied string in pixels
+/**
+* Returns length of supplied string in pixels
+*/
int16 Screen::stringLength(const char *s) {
debugC(2, kDebugDisplay, "stringLength(%s)", s);
@@ -341,15 +374,19 @@ int16 Screen::stringLength(const char *s) {
return sum;
}
-// Return x which would center supplied string
+/**
+* Return x which would center supplied string
+*/
int16 Screen::center(const char *s) {
debugC(1, kDebugDisplay, "center(%s)", s);
return (int16)((XPIX - stringLength(s)) >> 1);
}
-// Write string at sx,sy in supplied color in current font
-// If sx == CENTER, center it
+/**
+* Write string at sx,sy in supplied color in current font
+* If sx == CENTER, center it
+*/
void Screen::writeStr(int16 sx, int16 sy, const char *s, byte color) {
debugC(2, kDebugDisplay, "writeStr(%d, %d, %s, %d)", sx, sy, s, color);
@@ -363,7 +400,9 @@ void Screen::writeStr(int16 sx, int16 sy, const char *s, byte color) {
}
}
-// Shadowed version of writestr
+/**
+* Shadowed version of writestr
+*/
void Screen::shadowStr(int16 sx, int16 sy, const char *s, byte color) {
debugC(1, kDebugDisplay, "shadowStr(%d, %d, %s, %d)", sx, sy, s, color);
@@ -374,10 +413,11 @@ void Screen::shadowStr(int16 sx, int16 sy, const char *s, byte color) {
writeStr(sx, sy, s, color);
}
+/** Introduce user to the game
+* DOS versions Only
+*/
void Screen::userHelp() {
-// Introduce user to the game
-// DOS versions Only
- Utils::Box(BOX_ANY , "%s",
+ Utils::Box(BOX_ANY , "%s",
"F1 - Press F1 again\n"
" for instructions\n"
"F2 - Sound on/off\n"
@@ -394,18 +434,18 @@ void Screen::drawStatusText() {
debugC(4, kDebugDisplay, "drawStatusText");
loadFont(U_FONT8);
- uint16 sdx = stringLength(_vm._statusLine);
+ uint16 sdx = stringLength(_vm->_statusLine);
uint16 sdy = fontHeight() + 1; // + 1 for shadow
uint16 posX = 0;
uint16 posY = YPIX - sdy;
// Display the string and add rect to display list
- writeStr(posX, posY, _vm._statusLine, _TLIGHTYELLOW);
+ writeStr(posX, posY, _vm->_statusLine, _TLIGHTYELLOW);
displayList(D_ADD, posX, posY, sdx, sdy);
- sdx = stringLength(_vm._scoreLine);
+ sdx = stringLength(_vm->_scoreLine);
posY = 0;
- writeStr(posX, posY, _vm._scoreLine, _TCYAN);
+ writeStr(posX, posY, _vm->_scoreLine, _TCYAN);
displayList(D_ADD, posX, posY, sdx, sdy);
}
@@ -421,7 +461,7 @@ void Screen::drawShape(int x, int y, int color1, int color2) {
_backBuffer[320 * (y + (2 * shapeSize - 1) - i) + (x + shapeSize + j)] = color2;
_frontBuffer[320 * (y + (2 * shapeSize - 1) - i) + (x + shapeSize + j)] = color2;
}
- }
+ }
}
void Screen::drawRectangle(bool filledFl, uint16 x1, uint16 y1, uint16 x2, uint16 y2, int color) {
@@ -440,5 +480,44 @@ void Screen::drawRectangle(bool filledFl, uint16 x1, uint16 y1, uint16 x2, uint1
}
}
+/**
+* Initialize screen components and display results
+*/
+void Screen::initNewScreenDisplay() {
+ displayList(D_INIT);
+ setBackgroundColor(_TBLACK);
+ displayBackground();
+
+ // Stop premature object display in Display_list(D_DISPLAY)
+ _vm->getGameStatus().newScreenFl = true;
+}
+
+/**
+* Load palette from Hugo.dat
+*/
+void Screen::loadPalette(Common::File &in) {
+ // Read palette
+ _paletteSize = in.readUint16BE();
+ _palette = (byte *)malloc(sizeof(byte) * _paletteSize);
+ for (int i = 0; i < _paletteSize; i++)
+ _palette[i] = in.readByte();
+}
+
+/**
+* Free palette
+*/
+void Screen::freePalette() {
+ free(_palette);
+}
+
+/**
+* Free fonts
+*/
+void Screen::freeFonts() {
+ for (int i = 0; i < NUM_FONTS; i++) {
+ if (_arrayFont[i])
+ free(_arrayFont[i]);
+ }
+}
} // End of namespace Hugo
diff --git a/engines/hugo/display.h b/engines/hugo/display.h
index 16dd87fc6f..ec9f29f016 100644
--- a/engines/hugo/display.h
+++ b/engines/hugo/display.h
@@ -46,9 +46,12 @@ struct rect_t { // Rectangle used in Display
class Screen {
public:
- Screen(HugoEngine &vm);
+ Screen(HugoEngine *vm);
virtual ~Screen();
+ virtual void loadFont(int16 fontId) = 0;
+ virtual void loadFontArr(Common::File &in) = 0;
+
int16 fontHeight();
int16 stringLength(const char *s);
@@ -59,8 +62,11 @@ public:
void drawRectangle(bool filledFl, uint16 x1, uint16 y1, uint16 x2, uint16 y2, int color);
void drawShape(int x, int y, int color1, int color2);
void drawStatusText();
+ void freeFonts();
+ void freePalette();
void initDisplay();
- virtual void loadFont(int16 fontId) = 0;
+ void initNewScreenDisplay();
+ void loadPalette(Common::File &in);
void moveImage(image_pt srcImage, uint16 x1, uint16 y1, uint16 dx, uint16 dy, uint16 width1, image_pt dstImage, uint16 x2, uint16 y2, uint16 width2);
void remapPal(uint16 oldIndex, uint16 newIndex);
void restorePal(Common::SeekableReadStream *f);
@@ -92,12 +98,19 @@ public:
}
protected:
- HugoEngine &_vm;
+ HugoEngine *_vm;
+
+ bool fontLoadedFl[NUM_FONTS];
// Fonts used in dib (non-GDI)
- byte _fnt; // Current font number
- byte _fontdata[NUM_FONTS][FONTSIZE]; // Font data
+ byte *_arrayFont[NUM_FONTS];
+ byte _fnt; // Current font number
+ byte _fontdata[NUM_FONTS][FONTSIZE]; // Font data
byte *_font[NUM_FONTS][FONT_LEN]; // Ptrs to each char
+ byte *_palette;
+ byte _paletteSize;
+
+ int16 _arrayFontSize[NUM_FONTS];
private:
viewdib_t _frontBuffer;
@@ -115,18 +128,20 @@ private:
class Screen_v1d : public Screen {
public:
- Screen_v1d(HugoEngine &vm);
+ Screen_v1d(HugoEngine *vm);
~Screen_v1d();
- virtual void loadFont(int16 fontId);
+ void loadFont(int16 fontId);
+ void loadFontArr(Common::File &in);
};
class Screen_v1w : public Screen {
public:
- Screen_v1w(HugoEngine &vm);
+ Screen_v1w(HugoEngine *vm);
~Screen_v1w();
- virtual void loadFont(int16 fontId);
+ void loadFont(int16 fontId);
+ void loadFontArr(Common::File &in);
};
} // End of namespace Hugo
diff --git a/engines/hugo/display_v1d.cpp b/engines/hugo/display_v1d.cpp
index 6cf20d413f..28c8e4407a 100644
--- a/engines/hugo/display_v1d.cpp
+++ b/engines/hugo/display_v1d.cpp
@@ -40,31 +40,33 @@
namespace Hugo {
-Screen_v1d::Screen_v1d(HugoEngine &vm) : Screen(vm) {
+Screen_v1d::Screen_v1d(HugoEngine *vm) : Screen(vm) {
}
Screen_v1d::~Screen_v1d() {
}
-// Load font file, construct font ptrs and reverse data bytes
-// TODO: This uses hardcoded fonts in hugo.dat, it should be replaced
-// by a proper implementation of .FON files
+/**
+* Load font file, construct font ptrs and reverse data bytes
+* TODO: This uses hardcoded fonts in hugo.dat, it should be replaced
+* by a proper implementation of .FON files
+*/
void Screen_v1d::loadFont(int16 fontId) {
debugC(2, kDebugDisplay, "loadFont(%d)", fontId);
- static bool fontLoadedFl[NUM_FONTS] = {false, false, false};
+ assert(fontId < NUM_FONTS);
_fnt = fontId - FIRST_FONT; // Set current font number
- if (fontLoadedFl[_fnt]) // If already loaded, return
+ if (fontLoadedFl[_fnt]) // If already loaded, return
return;
fontLoadedFl[_fnt] = true;
- memcpy(_fontdata[_fnt], _vm._arrayFont[_fnt], _vm._arrayFontSize[_fnt]);
+ memcpy(_fontdata[_fnt], _arrayFont[_fnt], _arrayFontSize[_fnt]);
_font[_fnt][0] = _fontdata[_fnt]; // Store height,width of fonts
- int16 offset = 2; // Start at fontdata[2] ([0],[1] used for height,width)
+ int16 offset = 2; // Start at fontdata[2] ([0],[1] used for height,width)
// Setup the font array (127 characters)
for (int i = 1; i < 128; i++) {
@@ -79,5 +81,20 @@ void Screen_v1d::loadFont(int16 fontId) {
offset += 2 + size;
}
}
+
+/**
+* Load fonts from Hugo.dat
+* These fonts are a workaround to avoid handling TTF fonts used by DOS versions
+* TODO: Properly handle the vector based font files (win31)
+*/
+void Screen_v1d::loadFontArr(Common::File &in) {
+ for (int i = 0; i < NUM_FONTS; i++) {
+ _arrayFontSize[i] = in.readUint16BE();
+ _arrayFont[i] = (byte *)malloc(sizeof(byte) * _arrayFontSize[i]);
+ for (int j = 0; j < _arrayFontSize[i]; j++) {
+ _arrayFont[i][j] = in.readByte();
+ }
+ }
+}
} // End of namespace Hugo
diff --git a/engines/hugo/display_v1w.cpp b/engines/hugo/display_v1w.cpp
index c98374dcde..7cc94cc85a 100644
--- a/engines/hugo/display_v1w.cpp
+++ b/engines/hugo/display_v1w.cpp
@@ -41,25 +41,25 @@
namespace Hugo {
-Screen_v1w::Screen_v1w(HugoEngine &vm) : Screen(vm) {
+Screen_v1w::Screen_v1w(HugoEngine *vm) : Screen(vm) {
}
Screen_v1w::~Screen_v1w() {
}
-// Load font file, construct font ptrs and reverse data bytes
+/**
+* Load font file, construct font ptrs and reverse data bytes
+*/
void Screen_v1w::loadFont(int16 fontId) {
debugC(2, kDebugDisplay, "loadFont(%d)", fontId);
- static bool fontLoadedFl[NUM_FONTS] = {false, false, false};
-
_fnt = fontId - FIRST_FONT; // Set current font number
if (fontLoadedFl[_fnt]) // If already loaded, return
return;
fontLoadedFl[_fnt] = true;
- _vm.file().readUIFItem(fontId, _fontdata[_fnt]);
+ _vm->_file->readUIFItem(fontId, _fontdata[_fnt]);
// Compile font ptrs. Note: First ptr points to height,width of font
_font[_fnt][0] = _fontdata[_fnt]; // Store height,width of fonts
@@ -79,5 +79,16 @@ void Screen_v1w::loadFont(int16 fontId) {
offset += 2 + size;
}
}
+
+/**
+* Skips the fonts used by the DOS versions
+*/
+void Screen_v1w::loadFontArr(Common::File &in) {
+ for (int i = 0; i < NUM_FONTS; i++) {
+ uint16 numElem = in.readUint16BE();
+ for (int j = 0; j < numElem; j++)
+ in.readByte();
+ }
+}
} // End of namespace Hugo
diff --git a/engines/hugo/engine.cpp b/engines/hugo/engine.cpp
deleted file mode 100644
index d1d3e92cb2..0000000000
--- a/engines/hugo/engine.cpp
+++ /dev/null
@@ -1,968 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on original Hugo 1-3 Trilogy source code
- *
- * Copyright (c) 1989-1995 David P. Gray
- *
- */
-
-#include "common/system.h"
-#include "common/random.h"
-#include "common/EventRecorder.h"
-
-#include "hugo/game.h"
-#include "hugo/hugo.h"
-#include "hugo/engine.h"
-#include "hugo/global.h"
-#include "hugo/file.h"
-#include "hugo/schedule.h"
-#include "hugo/display.h"
-#include "hugo/parser.h"
-#include "hugo/route.h"
-#include "hugo/util.h"
-#include "hugo/sound.h"
-
-namespace Hugo {
-
-#define EDGE 10 // Closest object can get to edge of screen
-#define EDGE2 (EDGE * 2) // Push object further back on edge collision
-#define SHIFT 8 // Place hero this far inside bounding box
-#define MAX_OBJECTS 128 // Used in Update_images()
-#define BOUND(X, Y) ((_boundary[Y * XBYTES + X / 8] & (0x80 >> X % 8)) != 0) // Boundary bit set
-
-config_t _config; // User's config
-maze_t _maze = {false, 0, 0, 0, 0, 0, 0, 0, 0};// Default to not in maze
-hugo_boot_t _boot; // Boot info structure file
-char _textBoxBuffer[MAX_BOX]; // Buffer for text box
-command_t _line = ""; // Line of user text input
-
-
-// Sets the playlist to be the default tune selection
-void HugoEngine::initPlaylist(bool playlist[MAX_TUNES]) {
- debugC(1, kDebugEngine, "initPlaylist");
-
- for (int16 i = 0; i < MAX_TUNES; i++)
- playlist[i] = false;
- for (int16 i = 0; _defltTunes[i] != -1; i++)
- playlist[_defltTunes[i]] = true;
-}
-
-// Initialize the dynamic game status
-void HugoEngine::initStatus() {
- debugC(1, kDebugEngine, "initStatus");
- _status.initSaveFl = true; // Force initial save
- _status.storyModeFl = false; // Not in story mode
- _status.gameOverFl = false; // Hero not knobbled yet
- _status.recordFl = false; // Not record mode
- _status.playbackFl = false; // Not playback mode
- _status.demoFl = false; // Not demo mode
- _status.textBoxFl = false; // Not processing a text box
-// Strangerke - Not used ?
-// _status.mmtime = false; // Multimedia timer support
- _status.lookFl = false; // Toolbar "look" button
- _status.recallFl = false; // Toolbar "recall" button
- _status.leftButtonFl = false; // Left mouse button pressed
- _status.rightButtonFl = false; // Right mouse button pressed
- _status.newScreenFl = false; // Screen not just loaded
- _status.jumpExitFl = false; // Can't jump to a screen exit
- _status.godModeFl = false; // No special cheats allowed
- _status.helpFl = false; // Not calling WinHelp()
- _status.doQuitFl = false;
- _status.path[0] = 0; // Path to write files
- _status.saveSlot = 0; // Slot to save/restore game
- _status.screenWidth = 0; // Desktop screen width
-
- // Initialize every start of new game
- _status.tick = 0; // Tick count
- _status.saveTick = 0; // Time of last save
- _status.viewState = V_IDLE; // View state
- _status.inventoryState = I_OFF; // Inventory icon bar state
- _status.inventoryHeight = 0; // Inventory icon bar pos
- _status.inventoryObjId = -1; // Inventory object selected (none)
- _status.routeIndex = -1; // Hero not following a route
- _status.go_for = GO_SPACE; // Hero walking to space
- _status.go_id = -1; // Hero not walking to anything
-}
-
-// Initialize default config values. Must be done before Initialize().
-// Reset needed to save config.cx,cy which get splatted during OnFileNew()
-void HugoEngine::initConfig(inst_t action) {
- debugC(1, kDebugEngine, "initConfig(%d)", action);
-
- switch (action) {
- case INSTALL:
- _config.musicFl = true; // Music state initially on
- _config.soundFl = true; // Sound state initially on
- _config.turboFl = false; // Turbo state initially off
- _config.backgroundMusicFl = false; // No music when inactive
- _config.musicVolume = 85; // Music volume %
- _config.soundVolume = 100; // Sound volume %
- initPlaylist(_config.playlist); // Initialize default tune playlist
-
- file().readBootFile(); // Read startup structure
- break;
- case RESET:
- // Find first tune and play it
- for (int16 i = 0; i < MAX_TUNES; i++) {
- if (_config.playlist[i]) {
- sound().playMusic(i);
- break;
- }
- }
-
- file().initSavedGame(); // Initialize saved game
- break;
- case RESTORE:
- warning("Unhandled action RESTORE");
- break;
- }
-}
-
-void HugoEngine::initialize() {
- debugC(1, kDebugEngine, "initialize");
-
- sound().initSound();
- scheduler().initEventQueue(); // Init scheduler stuff
- screen().initDisplay(); // Create Dibs and palette
- file().openDatabaseFiles(); // Open database files
- calcMaxScore(); // Initialise maxscore
-
- _rnd = new Common::RandomSource();
- g_eventRec.registerRandomSource(*_rnd, "hugo");
-
- _rnd->setSeed(42); // Kick random number generator
-
- switch (getGameType()) {
- case kGameTypeHugo1:
- _episode = "\"HUGO'S HOUSE OF HORRORS\"";
- _picDir = "";
- break;
- case kGameTypeHugo2:
- _episode = "\"Hugo's Mystery Adventure\"";
- _picDir = "hugo2/";
- break;
- case kGameTypeHugo3:
- _episode = "\"Hugo's Amazon Adventure\"";
- _picDir = "hugo3/";
- break;
- default:
- error("Unknown game");
- }
-}
-
-// Restore all resources before termination
-void HugoEngine::shutdown() {
- debugC(1, kDebugEngine, "shutdown");
-
- file().closeDatabaseFiles();
- if (_status.recordFl || _status.playbackFl)
- file().closePlaybackFile();
- freeObjects();
-}
-
-void HugoEngine::readObjectImages() {
- debugC(1, kDebugEngine, "readObjectImages");
-
- for (int i = 0; i < _numObj; i++)
- file().readImage(i, &_objects[i]);
-}
-
-// Read the uif image file (inventory icons)
-void HugoEngine::readUIFImages() {
- debugC(1, kDebugEngine, "readUIFImages");
-
- file().readUIFItem(UIF_IMAGES, screen().getGUIBuffer()); // Read all uif images
-}
-
-// Read scenery, overlay files for given screen number
-void HugoEngine::readScreenFiles(int screenNum) {
- debugC(1, kDebugEngine, "readScreenFiles(%d)", screenNum);
-
- file().readBackground(screenNum); // Scenery file
- memcpy(screen().getBackBuffer(), screen().getFrontBuffer(), sizeof(screen().getFrontBuffer()));// Make a copy
- file().readOverlay(screenNum, _boundary, BOUNDARY); // Boundary file
- file().readOverlay(screenNum, _overlay, OVERLAY); // Overlay file
- file().readOverlay(screenNum, _ovlBase, OVLBASE); // Overlay base file
-}
-
-// Update all object positions. Process object 'local' events
-// including boundary events and collisions
-void HugoEngine::moveObjects() {
- debugC(4, kDebugEngine, "moveObjects");
-
- // If route mode enabled, do special route processing
- if (_status.routeIndex >= 0)
- route().processRoute();
-
- // Perform any adjustments to velocity based on special path types
- // and store all (visible) object baselines into the boundary file.
- // Don't store foreground or background objects
- for (int i = 0; i < _numObj; i++) {
- object_t *obj = &_objects[i]; // Get pointer to object
- seq_t *currImage = obj->currImagePtr; // Get ptr to current image
- if (obj->screenIndex == *_screen_p) {
- switch (obj->pathType) {
- case CHASE:
- case CHASE2: {
- int8 radius = obj->radius; // Default to object's radius
- if (radius < 0) // If radius infinity, use closer value
- radius = DX;
-
- // Allowable motion wrt boundary
- int dx = _hero->x + _hero->currImagePtr->x1 - obj->x - currImage->x1;
- int dy = _hero->y + _hero->currImagePtr->y2 - obj->y - currImage->y2 - 1;
- if (abs(dx) <= radius)
- obj->vx = 0;
- else
- obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath);
- if (abs(dy) <= radius)
- obj->vy = 0;
- else
- obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath);
-
- // Set first image in sequence (if multi-seq object)
- switch (obj->seqNumb) {
- case 4:
- if (!obj->vx) { // Got 4 directions
- if (obj->vx != obj->oldvx) { // vx just stopped
- if (dy >= 0)
- obj->currImagePtr = obj->seqList[DOWN].seqPtr;
- else
- obj->currImagePtr = obj->seqList[_UP].seqPtr;
- }
- } else if (obj->vx != obj->oldvx) {
- if (dx > 0)
- obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
- else
- obj->currImagePtr = obj->seqList[LEFT].seqPtr;
- }
- break;
- case 3:
- case 2:
- if (obj->vx != obj->oldvx) { // vx just stopped
- if (dx > 0) // Left & right only
- obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
- else
- obj->currImagePtr = obj->seqList[LEFT].seqPtr;
- }
- break;
- }
-
- if (obj->vx || obj->vy)
- obj->cycling = CYCLE_FORWARD;
- else {
- obj->cycling = NOT_CYCLING;
- boundaryCollision(obj); // Must have got hero!
- }
- obj->oldvx = obj->vx;
- obj->oldvy = obj->vy;
- currImage = obj->currImagePtr; // Get (new) ptr to current image
- break;
- }
- case WANDER2:
- case WANDER:
- if (!_rnd->getRandomNumber(3 * NORMAL_TPS)) { // Kick on random interval
- obj->vx = _rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath;
- obj->vy = _rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath;
-
- // Set first image in sequence (if multi-seq object)
- if (obj->seqNumb > 1) {
- if (!obj->vx && (obj->seqNumb >= 4)) {
- if (obj->vx != obj->oldvx) { // vx just stopped
- if (obj->vy > 0)
- obj->currImagePtr = obj->seqList[DOWN].seqPtr;
- else
- obj->currImagePtr = obj->seqList[_UP].seqPtr;
- }
- } else if (obj->vx != obj->oldvx) {
- if (obj->vx > 0)
- obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
- else
- obj->currImagePtr = obj->seqList[LEFT].seqPtr;
- }
- }
- obj->oldvx = obj->vx;
- obj->oldvy = obj->vy;
- currImage = obj->currImagePtr; // Get (new) ptr to current image
- }
- if (obj->vx || obj->vy)
- obj->cycling = CYCLE_FORWARD;
- break;
- default:
- ; // Really, nothing
- }
- // Store boundaries
- if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
- storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2);
- }
- }
-
- // Move objects, allowing for boundaries
- for (int i = 0; i < _numObj; i++) {
- object_t *obj = &_objects[i]; // Get pointer to object
- if ((obj->screenIndex == *_screen_p) && (obj->vx || obj->vy)) {
- // Only process if it's moving
-
- // Do object movement. Delta_x,y return allowed movement in x,y
- // to move as close to a boundary as possible without crossing it.
- seq_t *currImage = obj->currImagePtr; // Get ptr to current image
- // object coordinates
- int x1 = obj->x + currImage->x1; // Left edge of object
- int x2 = obj->x + currImage->x2; // Right edge
- int y1 = obj->y + currImage->y1; // Top edge
- int y2 = obj->y + currImage->y2; // Bottom edge
-
- if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
- clearBoundary(x1, x2, y2); // Clear our own boundary
-
- // Allowable motion wrt boundary
- int dx = deltaX(x1, x2, obj->vx, y2);
- if (dx != obj->vx) {
- // An object boundary collision!
- boundaryCollision(obj);
- obj->vx = 0;
- }
-
- int dy = deltaY(x1, x2, obj->vy, y2);
- if (dy != obj->vy) {
- // An object boundary collision!
- boundaryCollision(obj);
- obj->vy = 0;
- }
-
- if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
- storeBoundary(x1, x2, y2); // Re-store our own boundary
-
- obj->x += dx; // Update object position
- obj->y += dy;
-
- // Don't let object go outside screen
- if (x1 < EDGE)
- obj->x = EDGE2;
- if (x2 > (XPIX - EDGE))
- obj->x = XPIX - EDGE2 - (x2 - x1);
- if (y1 < EDGE)
- obj->y = EDGE2;
- if (y2 > (YPIX - EDGE))
- obj->y = YPIX - EDGE2 - (y2 - y1);
-
- if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != WANDER2) && (obj->pathType != CHASE2))
- obj->cycling = NOT_CYCLING;
- }
- }
-
- // Clear all object baselines from the boundary file.
- for (int i = 0; i < _numObj; i++) {
- object_t *obj = &_objects[i]; // Get pointer to object
- seq_t *currImage = obj->currImagePtr; // Get ptr to current image
- if ((obj->screenIndex == *_screen_p) && (obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
- clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2);
- }
-
- // If maze mode is enabled, do special maze processing
- if (_maze.enabledFl)
- processMaze();
-}
-
-// Return maximum allowed movement (from zero to vx) such that object does
-// not cross a boundary (either background or another object)
-int HugoEngine::deltaX(int x1, int x2, int vx, int y) {
-// Explanation of algorithm: The boundaries are drawn as contiguous
-// lines 1 pixel wide. Since DX,DY are not necessarily 1, we must
-// detect boundary crossing. If vx positive, examine each pixel from
-// x1 old to x2 new, else x2 old to x1 new, both at the y2 line.
-// If vx zero, no need to check. If vy non-zero then examine each
-// pixel on the line segment x1 to x2 from y old to y new.
-// Fix from Hugo I v1.5:
-// Note the diff is munged in the return statement to cater for a special
-// cases arising from differences in image widths from one sequence to
-// another. The problem occurs reversing direction at a wall where the
-// new image intersects before the object can move away. This is cured
-// by comparing the intersection with half the object width pos. If the
-// intersection is in the other half wrt the intended direction, use the
-// desired vx, else use the computed delta. i.e. believe the desired vx
-
- debugC(3, kDebugEngine, "deltaX(%d, %d, %d, %d)", x1, x2, vx, y);
-
- if (vx == 0)
- return 0 ; // Object stationary
-
- y *= XBYTES; // Offset into boundary file
- if (vx > 0) {
- // Moving to right
- for (int i = x1 >> 3; i <= (x2 + vx) >> 3; i++) {// Search by byte
- int b = Utils::firstBit((byte)(_boundary[y + i] | _objBound[y + i]));
- if (b < 8) { // b is index or 8
- // Compute x of boundary and test if intersection
- b += i << 3;
- if ((b >= x1) && (b <= x2 + vx))
- return (b < x1 + ((x2 - x1) >> 1)) ? vx : b - x2 - 1; // return dx
- }
- }
- } else {
- // Moving to left
- for (int i = x2 >> 3; i >= (x1 + vx) >> 3; i--) {// Search by byte
- int b = Utils::lastBit((byte)(_boundary[y + i] | _objBound[y + i]));
- if (b < 8) { // b is index or 8
- // Compute x of boundary and test if intersection
- b += i << 3;
- if ((b >= x1 + vx) && (b <= x2))
- return (b > x1 + ((x2 - x1) >> 1)) ? vx : b - x1 + 1; // return dx
- }
- }
- }
- return vx;
-}
-
-// Similar to Delta_x, but for movement in y direction. Special case of
-// bytes at end of line segment; must only count boundary bits falling on
-// line segment.
-int HugoEngine::deltaY(int x1, int x2, int vy, int y) {
- debugC(3, kDebugEngine, "deltaY(%d, %d, %d, %d)", x1, x2, vy, y);
-
- if (vy == 0)
- return 0; // Object stationary
-
- int inc = (vy > 0) ? 1 : -1;
- for (int j = y + inc; j != (y + vy + inc); j += inc) { //Search by byte
- for (int i = x1 >> 3; i <= x2 >> 3; i++) {
- int b = _boundary[j * XBYTES + i] | _objBound[j * XBYTES + i];
- if (b != 0) { // Any bit set
- // Make sure boundary bits fall on line segment
- if (i == (x2 >> 3)) // Adjust right end
- b &= 0xff << ((i << 3) + 7 - x2);
- else if (i == (x1 >> 3)) // Adjust left end
- b &= 0xff >> (x1 - (i << 3));
- if (b)
- return j - y - inc;
- }
- }
- }
- return vy;
-}
-
-// Store a horizontal line segment in the object boundary file
-void HugoEngine::storeBoundary(int x1, int x2, int y) {
- debugC(5, kDebugEngine, "storeBoundary(%d, %d, %d)", x1, x2, y);
-
- for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line
- byte *b = &_objBound[y * XBYTES + i]; // get boundary byte
- if (i == x2 >> 3) // Adjust right end
- *b |= 0xff << ((i << 3) + 7 - x2);
- else if (i == x1 >> 3) // Adjust left end
- *b |= 0xff >> (x1 - (i << 3));
- else
- *b = 0xff;
- }
-}
-
-// Clear a horizontal line segment in the object boundary file
-void HugoEngine::clearBoundary(int x1, int x2, int y) {
- debugC(5, kDebugEngine, "clearBoundary(%d, %d, %d)", x1, x2, y);
-
- for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line
- byte *b = &_objBound[y * XBYTES + i]; // get boundary byte
- if (i == x2 >> 3) // Adjust right end
- *b &= ~(0xff << ((i << 3) + 7 - x2));
- else if (i == x1 >> 3) // Adjust left end
- *b &= ~(0xff >> (x1 - (i << 3)));
- else
- *b = 0;
- }
-}
-
-// Maze mode is enabled. Check to see whether hero has crossed the maze
-// bounding box, if so, go to the next room */
-void HugoEngine::processMaze() {
- debugC(1, kDebugEngine, "processMaze");
-
- seq_t *currImage = _hero->currImagePtr; // Get ptr to current image
-
- // hero coordinates
- int x1 = _hero->x + currImage->x1; // Left edge of object
- int x2 = _hero->x + currImage->x2; // Right edge
- int y1 = _hero->y + currImage->y1; // Top edge
- int y2 = _hero->y + currImage->y2; // Bottom edge
-
- if (x1 < _maze.x1) {
- // Exit west
- _actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p - 1;
- _actListArr[_alNewscrIndex][0].a2.x = _maze.x2 - SHIFT - (x2 - x1);
- _actListArr[_alNewscrIndex][0].a2.y = _hero->y;
- _status.routeIndex = -1;
- scheduler().insertActionList(_alNewscrIndex);
- } else if (x2 > _maze.x2) {
- // Exit east
- _actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p + 1;
- _actListArr[_alNewscrIndex][0].a2.x = _maze.x1 + SHIFT;
- _actListArr[_alNewscrIndex][0].a2.y = _hero->y;
- _status.routeIndex = -1;
- scheduler().insertActionList(_alNewscrIndex);
- } else if (y1 < _maze.y1 - SHIFT) {
- // Exit north
- _actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p - _maze.size;
- _actListArr[_alNewscrIndex][0].a2.x = _maze.x3;
- _actListArr[_alNewscrIndex][0].a2.y = _maze.y2 - SHIFT - (y2 - y1);
- _status.routeIndex = -1;
- scheduler().insertActionList(_alNewscrIndex);
- } else if (y2 > _maze.y2 - SHIFT / 2) {
- // Exit south
- _actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p + _maze.size;
- _actListArr[_alNewscrIndex][0].a2.x = _maze.x4;
- _actListArr[_alNewscrIndex][0].a2.y = _maze.y1 + SHIFT;
- _status.routeIndex = -1;
- scheduler().insertActionList(_alNewscrIndex);
- }
-}
-
-// Compare function for the quicksort. The sort is to order the objects in
-// increasing vertical position, using y+y2 as the baseline
-// Returns -1 if ay2 < by2 else 1 if ay2 > by2 else 0
-int HugoEngine::y2comp(const void *a, const void *b) {
- debugC(6, kDebugEngine, "y2comp");
-
- const object_t *p1 = &s_Engine->_objects[*(const byte *)a];
- const object_t *p2 = &s_Engine->_objects[*(const byte *)b];
-
- if (p1 == p2)
- // Why does qsort try the same indexes?
- return 0;
-
- if (p1->priority == BACKGROUND)
- return -1;
-
- if (p2->priority == BACKGROUND)
- return 1;
-
- if (p1->priority == FOREGROUND)
- return 1;
-
- if (p2->priority == FOREGROUND)
- return -1;
-
- int ay2 = p1->y + p1->currImagePtr->y2;
- int by2 = p2->y + p2->currImagePtr->y2;
-
- return ay2 - by2;
-}
-
-// Draw all objects on screen as follows:
-// 1. Sort 'FLOATING' objects in order of y2 (base of object)
-// 2. Display new object frames/positions in dib
-// Finally, cycle any animating objects to next frame
-void HugoEngine::updateImages() {
- debugC(5, kDebugEngine, "updateImages");
-
- // Initialise the index array to visible objects in current screen
- int num_objs = 0;
- byte objindex[MAX_OBJECTS]; // Array of indeces to objects
-
- for (int i = 0; i < _numObj; i++) {
- object_t *obj = &_objects[i];
- if ((obj->screenIndex == *_screen_p) && (obj->cycling >= ALMOST_INVISIBLE))
- objindex[num_objs++] = i;
- }
-
- // Sort the objects into increasing y+y2 (painter's algorithm)
- qsort(objindex, num_objs, sizeof(objindex[0]), y2comp);
-
- // Add each visible object to display list
- for (int i = 0; i < num_objs; i++) {
- object_t *obj = &_objects[objindex[i]];
- // Count down inter-frame timer
- if (obj->frameTimer)
- obj->frameTimer--;
-
- if (obj->cycling > ALMOST_INVISIBLE) { // Only if visible
- switch (obj->cycling) {
- case NOT_CYCLING:
- screen().displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL);
- break;
- case CYCLE_FORWARD:
- if (obj->frameTimer) // Not time to see next frame yet
- screen().displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL);
- else
- screen().displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, obj->priority == OVEROVL);
- break;
- case CYCLE_BACKWARD: {
- seq_t *seqPtr = obj->currImagePtr;
- if (!obj->frameTimer) { // Show next frame
- while (seqPtr->nextSeqPtr != obj->currImagePtr)
- seqPtr = seqPtr->nextSeqPtr;
- }
- screen().displayFrame(obj->x, obj->y, seqPtr, obj->priority == OVEROVL);
- break;
- }
- default:
- break;
- }
- }
- }
-
- // Cycle any animating objects
- for (int i = 0; i < num_objs; i++) {
- object_t *obj = &_objects[objindex[i]];
- if (obj->cycling != INVISIBLE) {
- // Only if it's visible
- if (obj->cycling == ALMOST_INVISIBLE)
- obj->cycling = INVISIBLE;
-
- // Now Rotate to next picture in sequence
- switch (obj->cycling) {
- case NOT_CYCLING:
- break;
- case CYCLE_FORWARD:
- if (!obj->frameTimer) {
- // Time to step to next frame
- obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
- // Find out if this is last frame of sequence
- // If so, reset frame_timer and decrement n_cycle
- if (obj->frameInterval || obj->cycleNumb) {
- obj->frameTimer = obj->frameInterval;
- for (int j = 0; j < obj->seqNumb; j++) {
- if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) {
- if (obj->cycleNumb) { // Decr cycleNumb if Non-continous
- if (!--obj->cycleNumb)
- obj->cycling = NOT_CYCLING;
- }
- }
- }
- }
- }
- break;
- case CYCLE_BACKWARD: {
- if (!obj->frameTimer) {
- // Time to step to prev frame
- seq_t *seqPtr = obj->currImagePtr;
- while (obj->currImagePtr->nextSeqPtr != seqPtr)
- obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
- // Find out if this is first frame of sequence
- // If so, reset frame_timer and decrement n_cycle
- if (obj->frameInterval || obj->cycleNumb) {
- obj->frameTimer = obj->frameInterval;
- for (int j = 0; j < obj->seqNumb; j++) {
- if (obj->currImagePtr == obj->seqList[j].seqPtr) {
- if (obj->cycleNumb){ // Decr cycleNumb if Non-continous
- if (!--obj->cycleNumb)
- obj->cycling = NOT_CYCLING;
- }
- }
- }
- }
- }
- break;
- }
- default:
- break;
- }
- obj->oldx = obj->x;
- obj->oldy = obj->y;
- }
- }
-}
-
-// Return object index of the topmost object under the cursor, or -1 if none
-// Objects are filtered if not "useful"
-int16 HugoEngine::findObject(uint16 x, uint16 y) {
- debugC(3, kDebugEngine, "findObject(%d, %d)", x, y);
-
- int16 objIndex = -1; // Index of found object
- uint16 y2Max = 0; // Greatest y2
- object_t *obj = _objects;
- // Check objects on screen
- for (int i = 0; i < _numObj; i++, obj++) {
- // Object must be in current screen and "useful"
- if (obj->screenIndex == *_screen_p && (obj->genericCmd || obj->objValue || obj->cmdIndex)) {
- seq_t *curImage = obj->currImagePtr;
- // Object must have a visible image...
- if (curImage != 0 && obj->cycling != INVISIBLE) {
- // If cursor inside object
- if (x >= (uint16)obj->x && x <= obj->x + curImage->x2 && y >= (uint16)obj->y && y <= obj->y + curImage->y2) {
- // If object is closest so far
- if (obj->y + curImage->y2 > y2Max) {
- y2Max = obj->y + curImage->y2;
- objIndex = i; // Found an object!
- }
- }
- } else {
- // ...or a dummy object that has a hotspot rectangle
- if (curImage == 0 && obj->vxPath != 0 && !obj->carriedFl) {
- // If cursor inside special rectangle
- if ((int16)x >= obj->oldx && (int16)x < obj->oldx + obj->vxPath && (int16)y >= obj->oldy && (int16)y < obj->oldy + obj->vyPath) {
- // If object is closest so far
- if (obj->oldy + obj->vyPath - 1 > (int16)y2Max) {
- y2Max = obj->oldy + obj->vyPath - 1;
- objIndex = i; // Found an object!
- }
- }
- }
- }
- }
- }
- return objIndex;
-}
-
-// Find a clear space around supplied object that hero can walk to
-bool HugoEngine::findObjectSpace(object_t *obj, int16 *destx, int16 *desty) {
- debugC(1, kDebugEngine, "findObjectSpace(obj, %d, %d)", *destx, *desty);
-
- seq_t *curImage = obj->currImagePtr;
- int16 y = obj->y + curImage->y2 - 1;
-
- bool foundFl = true;
- // Try left rear corner
- for (int16 x = *destx = obj->x + curImage->x1; x < *destx + HERO_MAX_WIDTH; x++) {
- if (BOUND(x, y))
- foundFl = false;
- }
-
- if (!foundFl) { // Try right rear corner
- foundFl = true;
- for (int16 x = *destx = obj->x + curImage->x2 - HERO_MAX_WIDTH + 1; x <= obj->x + (int16)curImage->x2; x++) {
- if (BOUND(x, y))
- foundFl = false;
- }
- }
-
- if (!foundFl) { // Try left front corner
- foundFl = true;
- y += 2;
- for (int16 x = *destx = obj->x + curImage->x1; x < *destx + HERO_MAX_WIDTH; x++) {
- if (BOUND(x, y))
- foundFl = false;
- }
- }
-
- if (!foundFl) { // Try right rear corner
- foundFl = true;
- for (int16 x = *destx = obj->x + curImage->x2 - HERO_MAX_WIDTH + 1; x <= obj->x + (int16)curImage->x2; x++) {
- if (BOUND(x, y))
- foundFl = false;
- }
- }
-
- *desty = y;
- return foundFl;
-}
-
-// Search background command list for this screen for supplied object.
-// Return first associated verb (not "look") or 0 if none found.
-char *HugoEngine::useBG(char *name) {
- debugC(1, kDebugEngine, "useBG(%s)", name);
-
- objectList_t p = _backgroundObjects[*_screen_p];
- for (int i = 0; *_arrayVerbs[p[i].verbIndex]; i++) {
- if ((name == _arrayNouns[p[i].nounIndex][0] &&
- p[i].verbIndex != _look) &&
- ((p[i].roomState == DONT_CARE) || (p[i].roomState == _screenStates[*_screen_p])))
- return _arrayVerbs[p[i].verbIndex][0];
- }
-
- return 0;
-}
-
-// If status.objid = -1, pick up objid, else use status.objid on objid,
-// if objid can't be picked up, use it directly
-void HugoEngine::useObject(int16 objId) {
- debugC(1, kDebugEngine, "useObject(%d)", objId);
-
- char *verb; // Background verb to use directly
- object_t *obj = &_objects[objId]; // Ptr to object
- if (_status.inventoryObjId == -1) {
- // Get or use objid directly
- if ((obj->genericCmd & TAKE) || obj->objValue) // Get collectible item
- sprintf(_line, "%s %s", _arrayVerbs[_take][0], _arrayNouns[obj->nounIndex][0]);
- else if (obj->genericCmd & LOOK) // Look item
- sprintf(_line, "%s %s", _arrayVerbs[_look][0], _arrayNouns[obj->nounIndex][0]);
- else if (obj->genericCmd & DROP) // Drop item
- sprintf(_line, "%s %s", _arrayVerbs[_drop][0], _arrayNouns[obj->nounIndex][0]);
- else if (obj->cmdIndex != 0) // Use non-collectible item if able
- sprintf(_line, "%s %s", _arrayVerbs[_cmdList[obj->cmdIndex][1].verbIndex][0], _arrayNouns[obj->nounIndex][0]);
- else if ((verb = useBG(_arrayNouns[obj->nounIndex][0])) != 0)
- sprintf(_line, "%s %s", verb, _arrayNouns[obj->nounIndex][0]);
- else
- return; // Can't use object directly
- } else {
- // Use status.objid on objid
- // Default to first cmd verb
- sprintf(_line, "%s %s %s", _arrayVerbs[_cmdList[_objects[_status.inventoryObjId].cmdIndex][1].verbIndex][0], _arrayNouns[_objects[_status.inventoryObjId].nounIndex][0], _arrayNouns[obj->nounIndex][0]);
-
- // Check valid use of objects and override verb if necessary
- for (uses_t *use = _uses; use->objId != _numObj; use++) {
- if (_status.inventoryObjId == use->objId) {
- // Look for secondary object, if found use matching verb
- bool foundFl = false;
- for (target_t *target = use->targets; _arrayNouns[target->nounIndex] != 0; target++)
- if (_arrayNouns[target->nounIndex][0] == _arrayNouns[obj->nounIndex][0]) {
- foundFl = true;
- sprintf(_line, "%s %s %s", _arrayVerbs[target->verbIndex][0], _arrayNouns[_objects[_status.inventoryObjId].nounIndex][0], _arrayNouns[obj->nounIndex][0]);
- }
-
- // No valid use of objects found, print failure string
- if (!foundFl) {
- // Deselect dragged icon if inventory not active
- if (_status.inventoryState != I_ACTIVE)
- _status.inventoryObjId = -1;
- Utils::Box(BOX_ANY, "%s", _textData[use->dataIndex]);
- return;
- }
- }
- }
- }
-
- if (_status.inventoryState == I_ACTIVE) // If inventory active, remove it
- _status.inventoryState = I_UP;
- _status.inventoryObjId = -1; // Deselect any dragged icon
- parser().lineHandler(); // and process command
-}
-
-// Issue "Look at <object>" command
-// Note special case of swapped hero image
-void HugoEngine::lookObject(object_t *obj) {
- debugC(1, kDebugEngine, "lookObject");
-
- if (obj == _hero)
- // Hero swapped - look at other
- obj = &_objects[_heroImage];
-
- parser().command("%s %s", _arrayVerbs[_look][0], _arrayNouns[obj->nounIndex][0]);
-}
-
-// Free all object images
-void HugoEngine::freeObjects() {
- debugC(1, kDebugEngine, "freeObjects");
-
- // Nothing to do if not allocated yet
- if (_hero->seqList[0].seqPtr == 0)
- return;
-
- // Free all sequence lists and image data
- for (int i = 0; i < _numObj; i++) {
- object_t *obj = &_objects[i];
- for (int j = 0; j < obj->seqNumb; j++) { // for each sequence
- seq_t *seq = obj->seqList[j].seqPtr; // Free image
- if (seq == 0) // Failure during database load
- break;
- do {
- free(seq->imagePtr);
- seq = seq->nextSeqPtr;
- } while (seq != obj->seqList[j].seqPtr);
- free(seq); // Free sequence record
- }
- }
-}
-
-// Add action lists for this screen to event queue
-void HugoEngine::screenActions(int screenNum) {
- debugC(1, kDebugEngine, "screenActions(%d)", screenNum);
-
- uint16 *screenAct = _screenActs[screenNum];
- if (screenAct) {
- for (int i = 0; screenAct[i]; i++)
- scheduler().insertActionList(screenAct[i]);
- }
-}
-
-// Set the new screen number into the hero object and any carried objects
-void HugoEngine::setNewScreen(int screenNum) {
- debugC(1, kDebugEngine, "setNewScreen(%d)", screenNum);
-
- *_screen_p = screenNum; // HERO object
- for (int i = HERO + 1; i < _numObj; i++) { // Any others
- if (_objects[i].carriedFl) // being carried
- _objects[i].screenIndex = screenNum;
- }
-}
-
-// An object has collided with a boundary. See if any actions are required
-void HugoEngine::boundaryCollision(object_t *obj) {
- debugC(1, kDebugEngine, "boundaryCollision");
-
- if (obj == _hero) {
- // Hotspots only relevant to HERO
- int x;
- if (obj->vx > 0)
- x = obj->x + obj->currImagePtr->x2;
- else
- x = obj->x + obj->currImagePtr->x1;
- int y = obj->y + obj->currImagePtr->y2;
-
- for (int i = 0; _hotspots[i].screenIndex >= 0; i++) {
- hotspot_t *hotspot = &_hotspots[i];
- if (hotspot->screenIndex == obj->screenIndex)
- if ((x >= hotspot->x1) && (x <= hotspot->x2) && (y >= hotspot->y1) && (y <= hotspot->y2)) {
- scheduler().insertActionList(hotspot->actIndex);
- break;
- }
- }
- } else {
- // Check whether an object collided with HERO
- int dx = _hero->x + _hero->currImagePtr->x1 - obj->x - obj->currImagePtr->x1;
- int dy = _hero->y + _hero->currImagePtr->y2 - obj->y - obj->currImagePtr->y2;
- // If object's radius is infinity, use a closer value
- int8 radius = obj->radius;
- if (radius < 0)
- radius = DX * 2;
- if ((abs(dx) <= radius) && (abs(dy) <= radius))
- scheduler().insertActionList(obj->actIndex);
- }
-}
-
-// Initialize screen components and display results
-void HugoEngine::initNewScreenDisplay() {
- debugC(1, kDebugEngine, "initNewScreenDisplay");
-
- screen().displayList(D_INIT);
- screen().setBackgroundColor(_TBLACK);
- screen().displayBackground();
-
- // Stop premature object display in Display_list(D_DISPLAY)
- _status.newScreenFl = true;
-}
-
-// Add up all the object values and all the bonus points
-void HugoEngine::calcMaxScore() {
- debugC(1, kDebugEngine, "calcMaxScore");
-
- for (int i = 0; i < _numObj; i++)
- _maxscore += _objects[i].objValue;
-
- for (int i = 0; i < _numBonuses; i++)
- _maxscore += _points[i].score;
-}
-
-// Exit game, advertise trilogy, show copyright
-void HugoEngine::endGame() {
- debugC(1, kDebugEngine, "endGame");
-
- if (!_boot.registered)
- Utils::Box(BOX_ANY, "%s", _textEngine[kEsAdvertise]);
- Utils::Box(BOX_ANY, "%s\n%s", _episode, COPYRIGHT);
- _status.viewState = V_EXIT;
-}
-
-} // End of namespace Hugo
diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp
index fa8d5b9947..c3e59b19c9 100644
--- a/engines/hugo/file.cpp
+++ b/engines/hugo/file.cpp
@@ -39,17 +39,20 @@
#include "hugo/schedule.h"
#include "hugo/display.h"
#include "hugo/util.h"
+#include "hugo/object.h"
namespace Hugo {
-FileManager::FileManager(HugoEngine &vm) : _vm(vm) {
+FileManager::FileManager(HugoEngine *vm) : _vm(vm) {
}
FileManager::~FileManager() {
}
+/**
+* Convert 4 planes (RGBI) data to 8-bit DIB format
+* Return original plane data ptr
+*/
byte *FileManager::convertPCC(byte *p, uint16 y, uint16 bpl, image_pt dataPtr) {
-// Convert 4 planes (RGBI) data to 8-bit DIB format
-// Return original plane data ptr
debugC(2, kDebugFile, "convertPCC(byte *p, %d, %d, image_pt data_p)", y, bpl);
dataPtr += y * bpl * 8; // Point to correct DIB line
@@ -64,10 +67,12 @@ byte *FileManager::convertPCC(byte *p, uint16 y, uint16 bpl, image_pt dataPtr) {
return p;
}
+/**
+* Read a pcx file of length len. Use supplied seq_p and image_p or
+* allocate space if NULL. Name used for errors. Returns address of seq_p
+* Set first TRUE to initialize b_index (i.e. not reading a sequential image in file).
+*/
seq_t *FileManager::readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool firstFl, const char *name) {
-// Read a pcx file of length len. Use supplied seq_p and image_p or
-// allocate space if NULL. Name used for errors. Returns address of seq_p
-// Set first TRUE to initialize b_index (i.e. not reading a sequential image in file).
debugC(1, kDebugFile, "readPCX(..., %s)", name);
// Read in the PCC header and check consistency
@@ -96,7 +101,7 @@ seq_t *FileManager::readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool
if ((seqPtr = (seq_t *)malloc(sizeof(seq_t))) == 0)
Utils::Error(HEAP_ERR, "%s", name);
}
-
+
// Find size of image data in 8-bit DIB format
// Note save of x2 - marks end of valid data before garbage
uint16 bytesPerLine4 = PCC_header.bytesPerLine * 4; // 4-bit bpl
@@ -136,14 +141,16 @@ seq_t *FileManager::readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool
return seqPtr;
}
+/**
+* Read object file of PCC images into object supplied
+*/
void FileManager::readImage(int objNum, object_t *objPtr) {
-// Read object file of PCC images into object supplied
debugC(1, kDebugFile, "readImage(%d, object_t *objPtr)", objNum);
if (!objPtr->seqNumb) // This object has no images
return;
- if (_vm.isPacked()) {
+ if (_vm->isPacked()) {
_objectsArchive.seek((uint32)objNum * sizeof(objBlock_t), SEEK_SET);
objBlock_t objBlock; // Info on file within database
@@ -153,10 +160,10 @@ void FileManager::readImage(int objNum, object_t *objPtr) {
_objectsArchive.seek(objBlock.objOffset, SEEK_SET);
} else {
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
- strcat(strcat(strcpy(buf, _vm._picDir), _vm._arrayNouns[objPtr->nounIndex][0]), OBJEXT);
+ strcat(strcat(strcpy(buf, _vm->_picDir), _vm->_arrayNouns[objPtr->nounIndex][0]), OBJEXT);
if (!_objectsArchive.open(buf)) {
- warning("File %s not found, trying again with %s%s", buf, _vm._arrayNouns[objPtr->nounIndex][0], OBJEXT);
- strcat(strcpy(buf, _vm._arrayNouns[objPtr->nounIndex][0]), OBJEXT);
+ warning("File %s not found, trying again with %s%s", buf, _vm->_arrayNouns[objPtr->nounIndex][0], OBJEXT);
+ strcat(strcpy(buf, _vm->_arrayNouns[objPtr->nounIndex][0]), OBJEXT);
if (!_objectsArchive.open(buf))
Utils::Error(FILE_ERR, "%s", buf);
}
@@ -170,12 +177,12 @@ void FileManager::readImage(int objNum, object_t *objPtr) {
for (int k = 0; k < objPtr->seqList[j].imageNbr; k++) { // each image
if (k == 0) { // First image
// Read this image - allocate both seq and image memory
- seqPtr = readPCX(_objectsArchive, 0, 0, firstFl, _vm._arrayNouns[objPtr->nounIndex][0]);
+ seqPtr = readPCX(_objectsArchive, 0, 0, firstFl, _vm->_arrayNouns[objPtr->nounIndex][0]);
objPtr->seqList[j].seqPtr = seqPtr;
firstFl = false;
} else { // Subsequent image
// Read this image - allocate both seq and image memory
- seqPtr->nextSeqPtr = readPCX(_objectsArchive, 0, 0, firstFl, _vm._arrayNouns[objPtr->nounIndex][0]);
+ seqPtr->nextSeqPtr = readPCX(_objectsArchive, 0, 0, firstFl, _vm->_arrayNouns[objPtr->nounIndex][0]);
seqPtr = seqPtr->nextSeqPtr;
}
@@ -203,6 +210,7 @@ void FileManager::readImage(int objNum, object_t *objPtr) {
}
}
}
+ assert(seqPtr);
seqPtr->nextSeqPtr = objPtr->seqList[j].seqPtr; // loop linked list to head
}
@@ -221,17 +229,19 @@ void FileManager::readImage(int objNum, object_t *objPtr) {
warning("Unexpected cycling: %d", objPtr->cycling);
}
- if (!_vm.isPacked())
+ if (!_vm->isPacked())
_objectsArchive.close();
}
+/**
+* Read sound (or music) file data. Call with SILENCE to free-up
+* any allocated memory. Also returns size of data
+*/
sound_pt FileManager::getSound(int16 sound, uint16 *size) {
-// Read sound (or music) file data. Call with SILENCE to free-up
-// any allocated memory. Also returns size of data
debugC(1, kDebugFile, "getSound(%d, %d)", sound, *size);
// No more to do if SILENCE (called for cleanup purposes)
- if (sound == _vm._soundSilence)
+ if (sound == _vm->_soundSilence)
return 0;
// Open sounds file
@@ -258,7 +268,7 @@ sound_pt FileManager::getSound(int16 sound, uint16 *size) {
// Allocate memory for sound or music, if possible
sound_pt soundPtr = (byte *)malloc(s_hdr[sound].size); // Ptr to sound data
if (soundPtr == 0) {
- Utils::Warn("%s", "Low on memory");
+ warning("Low on memory");
return 0;
}
@@ -272,8 +282,10 @@ sound_pt FileManager::getSound(int16 sound, uint16 *size) {
return soundPtr;
}
+/**
+* Return whether file exists or not
+*/
bool FileManager::fileExists(char *filename) {
-// Return whether file exists or not
Common::File f;
if (f.open(filename)) {
f.close();
@@ -282,48 +294,21 @@ bool FileManager::fileExists(char *filename) {
return false;
}
-void FileManager::saveSeq(object_t *obj) {
-// Save sequence number and image number in given object
- debugC(1, kDebugFile, "saveSeq");
-
- bool found = false;
- for (int j = 0; !found && (j < obj->seqNumb); j++) {
- seq_t *q = obj->seqList[j].seqPtr;
- for (int k = 0; !found && (k < obj->seqList[j].imageNbr); k++) {
- if (obj->currImagePtr == q) {
- found = true;
- obj->curSeqNum = j;
- obj->curImageNum = k;
- } else {
- q = q->nextSeqPtr;
- }
- }
- }
-}
-
-void FileManager::restoreSeq(object_t *obj) {
-// Set up cur_seq_p from stored sequence and image number in object
- debugC(1, kDebugFile, "restoreSeq");
-
- seq_t *q = obj->seqList[obj->curSeqNum].seqPtr;
- for (int j = 0; j < obj->curImageNum; j++)
- q = q->nextSeqPtr;
- obj->currImagePtr = q;
-}
-
+/**
+* Save game to supplied slot (-1 is INITFILE)
+*/
void FileManager::saveGame(int16 slot, const char *descrip) {
-// Save game to supplied slot (-1 is INITFILE)
debugC(1, kDebugFile, "saveGame(%d, %s)", slot, descrip);
// Get full path of saved game file - note test for INITFILE
Common::String path; // Full path of saved game
if (slot == -1)
- path = _vm._initFilename;
+ path = _vm->_initFilename;
else
- path = Common::String::printf(_vm._saveFilename.c_str(), slot);
+ path = Common::String::format(_vm->_saveFilename.c_str(), slot);
- Common::WriteStream *out = _vm.getSaveFileManager()->openForSaving(path);
+ Common::WriteStream *out = _vm->getSaveFileManager()->openForSaving(path);
if (!out) {
warning("Can't create file '%s', game not saved", path.c_str());
return;
@@ -336,19 +321,19 @@ void FileManager::saveGame(int16 slot, const char *descrip) {
out->write(descrip, DESCRIPLEN);
// Save objects
- for (int i = 0; i < _vm._numObj; i++) {
+ for (int i = 0; i < _vm->_numObj; i++) {
// Save where curr_seq_p is pointing to
- saveSeq(&_vm._objects[i]);
- out->write(&_vm._objects[i], sizeof(object_t));
+ _vm->_object->saveSeq(&_vm->_object->_objects[i]);
+ out->write(&_vm->_object->_objects[i], sizeof(object_t));
}
- const status_t &gameStatus = _vm.getGameStatus();
+ const status_t &gameStatus = _vm->getGameStatus();
// Save whether hero image is swapped
- out->write(&_vm._heroImage, sizeof(_vm._heroImage));
+ out->write(&_vm->_heroImage, sizeof(_vm->_heroImage));
// Save score
- int score = _vm.getScore();
+ int score = _vm->getScore();
out->write(&score, sizeof(score));
// Save story mode
@@ -361,16 +346,16 @@ void FileManager::saveGame(int16 slot, const char *descrip) {
out->write(&gameStatus.gameOverFl, sizeof(gameStatus.gameOverFl));
// Save screen states
- out->write(_vm._screenStates, sizeof(*_vm._screenStates) * _vm._numScreens);
+ out->write(_vm->_screenStates, sizeof(*_vm->_screenStates) * _vm->_numScreens);
// Save points table
- out->write(_vm._points, sizeof(point_t) * _vm._numBonuses);
+ out->write(_vm->_points, sizeof(point_t) * _vm->_numBonuses);
// Now save current time and all current events in event queue
- _vm.scheduler().saveEvents(out);
+ _vm->_scheduler->saveEvents(out);
// Save palette table
- _vm.screen().savePal(out);
+ _vm->_screen->savePal(out);
// Save maze status
out->write(&_maze, sizeof(maze_t));
@@ -380,22 +365,24 @@ void FileManager::saveGame(int16 slot, const char *descrip) {
delete out;
}
+/**
+* Restore game from supplied slot number (-1 is INITFILE)
+*/
void FileManager::restoreGame(int16 slot) {
-// Restore game from supplied slot number (-1 is INITFILE)
debugC(1, kDebugFile, "restoreGame(%d)", slot);
// Initialize new-game status
- _vm.initStatus();
+ _vm->initStatus();
// Get full path of saved game file - note test for INITFILE
Common::String path; // Full path of saved game
if (slot == -1)
- path = _vm._initFilename;
+ path = _vm->_initFilename;
else
- path = Common::String::printf(_vm._saveFilename.c_str(), slot);
+ path = Common::String::format(_vm->_saveFilename.c_str(), slot);
- Common::SeekableReadStream *in = _vm.getSaveFileManager()->openForLoading(path);
+ Common::SeekableReadStream *in = _vm->getSaveFileManager()->openForLoading(path);
if (!in)
return;
@@ -411,13 +398,13 @@ void FileManager::restoreGame(int16 slot) {
in->seek(DESCRIPLEN, SEEK_CUR);
// If hero image is currently swapped, swap it back before restore
- if (_vm._heroImage != HERO)
- _vm.scheduler().swapImages(HERO, _vm._heroImage);
+ if (_vm->_heroImage != HERO)
+ _vm->_object->swapImages(HERO, _vm->_heroImage);
// Restore objects, retain current seqList which points to dynamic mem
// Also, retain cmnd_t pointers
- for (int i = 0; i < _vm._numObj; i++) {
- object_t *p = &_vm._objects[i];
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *p = &_vm->_object->_objects[i];
seqList_t seqList[MAX_SEQUENCES];
memcpy(seqList, p->seqList, sizeof(seqList_t));
uint16 cmdIndex = p->cmdIndex;
@@ -426,37 +413,37 @@ void FileManager::restoreGame(int16 slot) {
memcpy(p->seqList, seqList, sizeof(seqList_t));
}
- in->read(&_vm._heroImage, sizeof(_vm._heroImage));
+ in->read(&_vm->_heroImage, sizeof(_vm->_heroImage));
// If hero swapped in saved game, swap it
- int heroImg = _vm._heroImage;
+ int heroImg = _vm->_heroImage;
if (heroImg != HERO)
- _vm.scheduler().swapImages(HERO, _vm._heroImage);
- _vm._heroImage = heroImg;
+ _vm->_object->swapImages(HERO, _vm->_heroImage);
+ _vm->_heroImage = heroImg;
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
int score;
in->read(&score, sizeof(score));
- _vm.setScore(score);
+ _vm->setScore(score);
in->read(&gameStatus.storyModeFl, sizeof(gameStatus.storyModeFl));
in->read(&gameStatus.jumpExitFl, sizeof(gameStatus.jumpExitFl));
in->read(&gameStatus.gameOverFl, sizeof(gameStatus.gameOverFl));
- in->read(_vm._screenStates, sizeof(*_vm._screenStates) * _vm._numScreens);
+ in->read(_vm->_screenStates, sizeof(*_vm->_screenStates) * _vm->_numScreens);
// Restore points table
- in->read(_vm._points, sizeof(point_t) * _vm._numBonuses);
+ in->read(_vm->_points, sizeof(point_t) * _vm->_numBonuses);
// Restore ptrs to currently loaded objects
- for (int i = 0; i < _vm._numObj; i++)
- restoreSeq(&_vm._objects[i]);
+ for (int i = 0; i < _vm->_numObj; i++)
+ _vm->_object->restoreSeq(&_vm->_object->_objects[i]);
// Now restore time of the save and the event queue
- _vm.scheduler().restoreEvents(in);
+ _vm->_scheduler->restoreEvents(in);
// Restore palette and change it if necessary
- _vm.screen().restorePal(in);
+ _vm->_screen->restorePal(in);
// Restore maze status
in->read(&_maze, sizeof(maze_t));
@@ -464,62 +451,50 @@ void FileManager::restoreGame(int16 slot) {
delete in;
}
+/**
+* Initialize the size of a saved game (from the fixed initial game).
+* If status.initsave is TRUE, or the initial saved game is not found,
+* force a save to create one. Normally the game will be shipped with
+* the initial game file but useful to force a write during development
+* when the size is changeable.
+* The net result is a valid INITFILE, with status.savesize initialized.
+*/
void FileManager::initSavedGame() {
-// Initialize the size of a saved game (from the fixed initial game).
-// If status.initsave is TRUE, or the initial saved game is not found,
-// force a save to create one. Normally the game will be shipped with
-// the initial game file but useful to force a write during development
-// when the size is changeable.
-// The net result is a valid INITFILE, with status.savesize initialized.
debugC(1, kDebugFile, "initSavedGame");
// Force save of initial game
- if (_vm.getGameStatus().initSaveFl)
+ if (_vm->getGameStatus().initSaveFl)
saveGame(-1, "");
// If initial game doesn't exist, create it
- Common::SeekableReadStream *in = _vm.getSaveFileManager()->openForLoading(_vm._initFilename);
+ Common::SeekableReadStream *in = _vm->getSaveFileManager()->openForLoading(_vm->_initFilename);
if (!in) {
saveGame(-1, "");
- in = _vm.getSaveFileManager()->openForLoading(_vm._initFilename);
+ in = _vm->getSaveFileManager()->openForLoading(_vm->_initFilename);
if (!in) {
- Utils::Error(WRITE_ERR, "%s", _vm._initFilename.c_str());
+ Utils::Error(WRITE_ERR, "%s", _vm->_initFilename.c_str());
return;
}
}
// Must have an open saved game now
- _vm.getGameStatus().saveSize = in->size();
+ _vm->getGameStatus().saveSize = in->size();
delete in;
// Check sanity - maybe disk full or path set to read-only drive?
- if (_vm.getGameStatus().saveSize == -1)
- Utils::Error(WRITE_ERR, "%s", _vm._initFilename.c_str());
-}
-
-void FileManager::openPlaybackFile(bool playbackFl, bool recordFl) {
- debugC(1, kDebugFile, "openPlaybackFile(%d, %d)", (playbackFl) ? 1 : 0, (recordFl) ? 1 : 0);
-
- if (playbackFl) {
- if (!(fpb = fopen(PBFILE, "r+b")))
- Utils::Error(FILE_ERR, "%s", PBFILE);
- } else if (recordFl) {
- fpb = fopen(PBFILE, "wb");
- }
- pbdata.time = 0; // Say no key available
-}
-
-void FileManager::closePlaybackFile() {
- fclose(fpb);
+ if (_vm->getGameStatus().saveSize == -1)
+ Utils::Error(WRITE_ERR, "%s", _vm->_initFilename.c_str());
}
+/**
+* Read the encrypted text from the boot file and print it
+*/
void FileManager::printBootText() {
-// Read the encrypted text from the boot file and print it
debugC(1, kDebugFile, "printBootText");
Common::File ofp;
if (!ofp.open(BOOTFILE)) {
- if (_vm._gameVariant == 3) {
+ if (_vm->_gameVariant == 3) {
//TODO initialize properly _boot structure
warning("printBootText - Skipping as H1 Dos may be a freeware");
return;
@@ -551,14 +526,16 @@ void FileManager::printBootText() {
ofp.close();
}
+/**
+* Reads boot file for program environment. Fatal error if not there or
+* file checksum is bad. De-crypts structure while checking checksum
+*/
void FileManager::readBootFile() {
-// Reads boot file for program environment. Fatal error if not there or
-// file checksum is bad. De-crypts structure while checking checksum
debugC(1, kDebugFile, "readBootFile");
Common::File ofp;
if (!ofp.open(BOOTFILE)) {
- if (_vm._gameVariant == 3) {
+ if (_vm->_gameVariant == 3) {
//TODO initialize properly _boot structure
warning("readBootFile - Skipping as H1 Dos may be a freeware");
return;
@@ -589,8 +566,10 @@ void FileManager::readBootFile() {
Utils::Error(GEN_ERR, "%s", "Program startup file invalid");
}
+/**
+* Returns address of uif_hdr[id], reading it in if first call
+*/
uif_hdr_t *FileManager::getUIFHeader(uif_t id) {
-// Returns address of uif_hdr[id], reading it in if first call
debugC(1, kDebugFile, "getUIFHeader(%d)", id);
static bool firstFl = true;
@@ -617,8 +596,10 @@ uif_hdr_t *FileManager::getUIFHeader(uif_t id) {
return &UIFHeader[id];
}
+/**
+* Read uif item into supplied buffer.
+*/
void FileManager::readUIFItem(int16 id, byte *buf) {
-// Read uif item into supplied buffer.
debugC(1, kDebugFile, "readUIFItem(%d, ...)", id);
// Open uif file to read data
@@ -645,10 +626,11 @@ void FileManager::readUIFItem(int16 id, byte *buf) {
ip.close();
}
+/**
+* Simple instructions given when F1 pressed twice in a row
+* Only in DOS versions
+*/
void FileManager::instructions() {
-// Simple instructions given when F1 pressed twice in a row
-// Only in DOS versions
-
Common::File f;
if (!f.open(HELPFILE)) {
warning("help.dat not found");
@@ -672,5 +654,14 @@ void FileManager::instructions() {
f.close();
}
+/**
+* Read the uif image file (inventory icons)
+*/
+void FileManager::readUIFImages() {
+ debugC(1, kDebugFile, "readUIFImages");
+
+ readUIFItem(UIF_IMAGES, _vm->_screen->getGUIBuffer()); // Read all uif images
+}
+
} // End of namespace Hugo
diff --git a/engines/hugo/file.h b/engines/hugo/file.h
index a5679d0e1b..47a5235ca8 100644
--- a/engines/hugo/file.h
+++ b/engines/hugo/file.h
@@ -47,33 +47,25 @@ struct PCC_header_t { // Structure of PCX file hea
byte fill2[60];
}; // Header of a PCC file
-// Record and playback handling stuff:
-struct pbdata_t {
-// int key; // Character
- uint32 time; // Time at which character was pressed
-};
-
namespace Hugo {
class FileManager {
public:
- FileManager(HugoEngine &vm);
+ FileManager(HugoEngine *vm);
virtual ~FileManager();
bool fileExists(char *filename);
sound_pt getSound(short sound, uint16 *size);
- void closePlaybackFile();
void initSavedGame();
void instructions();
void readBootFile();
void readImage(int objNum, object_t *objPtr);
+ void readUIFImages();
void readUIFItem(short id, byte *buf);
void restoreGame(short slot);
- void restoreSeq(object_t *obj);
void saveGame(short slot, const char *descrip);
- void saveSeq(object_t *obj);
virtual void openDatabaseFiles() = 0;
virtual void closeDatabaseFiles() = 0;
@@ -84,7 +76,7 @@ public:
virtual char *fetchString(int index) = 0;
protected:
- HugoEngine &_vm;
+ HugoEngine *_vm;
Common::File _stringArchive; // Handle for string file
Common::File _sceneryArchive1; // Handle for scenery file
@@ -96,19 +88,13 @@ private:
byte *convertPCC(byte *p, uint16 y, uint16 bpl, image_pt data_p);
uif_hdr_t *getUIFHeader(uif_t id);
- pbdata_t pbdata;
- FILE *fpb;
-
//Strangerke : Not used?
- void openPlaybackFile(bool playbackFl, bool recordFl);
void printBootText();
-// bool pkkey();
-// char pbget();
};
class FileManager_v1d : public FileManager {
public:
- FileManager_v1d(HugoEngine &vm);
+ FileManager_v1d(HugoEngine *vm);
~FileManager_v1d();
void openDatabaseFiles();
@@ -120,7 +106,7 @@ public:
class FileManager_v2d : public FileManager {
public:
- FileManager_v2d(HugoEngine &vm);
+ FileManager_v2d(HugoEngine *vm);
~FileManager_v2d();
void openDatabaseFiles();
@@ -132,7 +118,7 @@ public:
class FileManager_v3d : public FileManager_v2d {
public:
- FileManager_v3d(HugoEngine &vm);
+ FileManager_v3d(HugoEngine *vm);
~FileManager_v3d();
void openDatabaseFiles();
@@ -145,7 +131,7 @@ private:
class FileManager_v1w : public FileManager_v2d {
public:
- FileManager_v1w(HugoEngine &vm);
+ FileManager_v1w(HugoEngine *vm);
~FileManager_v1w();
void readOverlay(int screenNum, image_pt image, ovl_t overlayType);
diff --git a/engines/hugo/file_v1d.cpp b/engines/hugo/file_v1d.cpp
index b6239aa5dc..059f1a25b7 100644
--- a/engines/hugo/file_v1d.cpp
+++ b/engines/hugo/file_v1d.cpp
@@ -38,7 +38,7 @@
#include "hugo/util.h"
namespace Hugo {
-FileManager_v1d::FileManager_v1d(HugoEngine &vm) : FileManager(vm) {
+FileManager_v1d::FileManager_v1d(HugoEngine *vm) : FileManager(vm) {
}
FileManager_v1d::~FileManager_v1d() {
@@ -52,14 +52,16 @@ void FileManager_v1d::closeDatabaseFiles() {
debugC(1, kDebugFile, "closeDatabaseFiles");
}
+/**
+* Open and read in an overlay file, close file
+*/
void FileManager_v1d::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
-// Open and read in an overlay file, close file
debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum);
const char *ovl_ext[] = {".b", ".o", ".ob"};
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
- strcat(strcpy(buf, _vm._screenNames[screenNum]), ovl_ext[overlayType]);
+ strcat(strcpy(buf, _vm->_screenNames[screenNum]), ovl_ext[overlayType]);
if (!fileExists(buf)) {
for (uint32 i = 0; i < OVL_SIZE; i++)
@@ -76,17 +78,19 @@ void FileManager_v1d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
_sceneryArchive1.close();
}
+/**
+* Read a PCX image into dib_a
+*/
void FileManager_v1d::readBackground(int screenIndex) {
-// Read a PCX image into dib_a
debugC(1, kDebugFile, "readBackground(%d)", screenIndex);
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
- strcat(strcpy(buf, _vm._screenNames[screenIndex]), ".ART");
+ strcat(strcpy(buf, _vm->_screenNames[screenIndex]), ".ART");
if (!_sceneryArchive1.open(buf))
Utils::Error(FILE_ERR, "%s", buf);
// Read the image into dummy seq and static dib_a
seq_t dummySeq; // Image sequence structure for Read_pcx
- readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
+ readPCX(_sceneryArchive1, &dummySeq, _vm->_screen->getFrontBuffer(), true, _vm->_screenNames[screenIndex]);
_sceneryArchive1.close();
}
@@ -94,7 +98,7 @@ void FileManager_v1d::readBackground(int screenIndex) {
char *FileManager_v1d::fetchString(int index) {
debugC(1, kDebugFile, "fetchString(%d)", index);
- return _vm._stringtData[index];
+ return _vm->_stringtData[index];
}
} // End of namespace Hugo
diff --git a/engines/hugo/file_v1w.cpp b/engines/hugo/file_v1w.cpp
index 6ab21a853e..9e9d380200 100644
--- a/engines/hugo/file_v1w.cpp
+++ b/engines/hugo/file_v1w.cpp
@@ -37,14 +37,16 @@
#include "hugo/util.h"
namespace Hugo {
-FileManager_v1w::FileManager_v1w(HugoEngine &vm) : FileManager_v2d(vm) {
+FileManager_v1w::FileManager_v1w(HugoEngine *vm) : FileManager_v2d(vm) {
}
FileManager_v1w::~FileManager_v1w() {
}
+/**
+* Open and read in an overlay file, close file
+*/
void FileManager_v1w::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
-// Open and read in an overlay file, close file
debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum);
image_pt tmpImage = image; // temp ptr to overlay file
diff --git a/engines/hugo/file_v2d.cpp b/engines/hugo/file_v2d.cpp
index 43de3fac4c..a6f2ec6bb0 100644
--- a/engines/hugo/file_v2d.cpp
+++ b/engines/hugo/file_v2d.cpp
@@ -40,12 +40,15 @@
#include "hugo/util.h"
namespace Hugo {
-FileManager_v2d::FileManager_v2d(HugoEngine &vm) : FileManager(vm) {
+FileManager_v2d::FileManager_v2d(HugoEngine *vm) : FileManager(vm) {
}
FileManager_v2d::~FileManager_v2d() {
}
+/**
+* Open "database" file (packed files)
+*/
void FileManager_v2d::openDatabaseFiles() {
debugC(1, kDebugFile, "openDatabaseFiles");
@@ -57,6 +60,9 @@ void FileManager_v2d::openDatabaseFiles() {
Utils::Error(FILE_ERR, "%s", OBJECTS_FILE);
}
+/**
+* Close "Database" files
+*/
void FileManager_v2d::closeDatabaseFiles() {
debugC(1, kDebugFile, "closeDatabaseFiles");
@@ -65,8 +71,10 @@ void FileManager_v2d::closeDatabaseFiles() {
_objectsArchive.close();
}
+/**
+* Read a PCX image into dib_a
+*/
void FileManager_v2d::readBackground(int screenIndex) {
-// Read a PCX image into dib_a
debugC(1, kDebugFile, "readBackground(%d)", screenIndex);
_sceneryArchive1.seek((uint32) screenIndex * sizeof(sceneBlock_t), SEEK_SET);
@@ -85,14 +93,16 @@ void FileManager_v2d::readBackground(int screenIndex) {
// Read the image into dummy seq and static dib_a
seq_t dummySeq; // Image sequence structure for Read_pcx
- readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
+ readPCX(_sceneryArchive1, &dummySeq, _vm->_screen->getFrontBuffer(), true, _vm->_screenNames[screenIndex]);
}
+/**
+* Open and read in an overlay file, close file
+*/
void FileManager_v2d::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
-// Open and read in an overlay file, close file
debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum);
- image_pt tmpImage = image; // temp ptr to overlay file
+ image_pt tmpImage = image; // temp ptr to overlay file
_sceneryArchive1.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET);
sceneBlock_t sceneBlock; // Database header entry
@@ -147,8 +157,10 @@ void FileManager_v2d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
} while (k < OVL_SIZE);
}
+/**
+* Fetch string from file, decode and return ptr to string in memory
+*/
char *FileManager_v2d::fetchString(int index) {
-// Fetch string from file, decode and return ptr to string in memory
debugC(1, kDebugFile, "fetchString(%d)", index);
// Get offset to string[index] (and next for length calculation)
@@ -170,7 +182,7 @@ char *FileManager_v2d::fetchString(int index) {
// Null terminate, decode and return it
_textBoxBuffer[off2-off1] = '\0';
- _vm.scheduler().decodeString(_textBoxBuffer);
+ _vm->_scheduler->decodeString(_textBoxBuffer);
return _textBoxBuffer;
}
} // End of namespace Hugo
diff --git a/engines/hugo/file_v3d.cpp b/engines/hugo/file_v3d.cpp
index e4809a7208..e7af41b93f 100644
--- a/engines/hugo/file_v3d.cpp
+++ b/engines/hugo/file_v3d.cpp
@@ -39,18 +39,20 @@
#include "hugo/util.h"
namespace Hugo {
-FileManager_v3d::FileManager_v3d(HugoEngine &vm) : FileManager_v2d(vm) {
+FileManager_v3d::FileManager_v3d(HugoEngine *vm) : FileManager_v2d(vm) {
}
FileManager_v3d::~FileManager_v3d() {
}
+/**
+* Read a PCX image into dib_a
+*/
void FileManager_v3d::readBackground(int screenIndex) {
-// Read a PCX image into dib_a
debugC(1, kDebugFile, "readBackground(%d)", screenIndex);
_sceneryArchive1.seek((uint32) screenIndex * sizeof(sceneBlock_t), SEEK_SET);
-
+
sceneBlock_t sceneBlock; // Read a database header entry
sceneBlock.scene_off = _sceneryArchive1.readUint32LE();
sceneBlock.scene_len = _sceneryArchive1.readUint32LE();
@@ -65,14 +67,17 @@ void FileManager_v3d::readBackground(int screenIndex) {
if (screenIndex < 20) {
_sceneryArchive1.seek(sceneBlock.scene_off, SEEK_SET);
// Read the image into dummy seq and static dib_a
- readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
+ readPCX(_sceneryArchive1, &dummySeq, _vm->_screen->getFrontBuffer(), true, _vm->_screenNames[screenIndex]);
} else {
_sceneryArchive2.seek(sceneBlock.scene_off, SEEK_SET);
// Read the image into dummy seq and static dib_a
- readPCX(_sceneryArchive2, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
+ readPCX(_sceneryArchive2, &dummySeq, _vm->_screen->getFrontBuffer(), true, _vm->_screenNames[screenIndex]);
}
}
+/**
+* Open "database" file (packed files)
+*/
void FileManager_v3d::openDatabaseFiles() {
debugC(1, kDebugFile, "openDatabaseFiles");
@@ -86,6 +91,9 @@ void FileManager_v3d::openDatabaseFiles() {
Utils::Error(FILE_ERR, "%s", OBJECTS_FILE);
}
+/**
+* Close "Database" files
+*/
void FileManager_v3d::closeDatabaseFiles() {
debugC(1, kDebugFile, "closeDatabaseFiles");
@@ -95,13 +103,15 @@ void FileManager_v3d::closeDatabaseFiles() {
_objectsArchive.close();
}
+/**
+* Open and read in an overlay file, close file
+*/
void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
-// Open and read in an overlay file, close file
debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum);
image_pt tmpImage = image; // temp ptr to overlay file
_sceneryArchive1.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET);
-
+
sceneBlock_t sceneBlock; // Database header entry
sceneBlock.scene_off = _sceneryArchive1.readUint32LE();
sceneBlock.scene_len = _sceneryArchive1.readUint32LE();
@@ -113,7 +123,7 @@ void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
sceneBlock.ob_len = _sceneryArchive1.readUint32LE();
uint32 i = 0;
-
+
if (screenNum < 20) {
switch (overlayType) {
case BOUNDARY:
@@ -137,7 +147,7 @@ void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
image[i] = 0;
return;
}
-
+
// Read in the overlay file using MAC Packbits. (We're not proud!)
int16 k = 0; // byte count
do {
@@ -149,7 +159,7 @@ void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
*tmpImage++ = _sceneryArchive1.readByte();
} else { // Repeat next byte -data+1 times
int16 j = _sceneryArchive1.readByte();
-
+
for (i = 0; i < (byte)(-data + 1); i++, k++)
*tmpImage++ = j;
}
@@ -177,7 +187,7 @@ void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
image[i] = 0;
return;
}
-
+
// Read in the overlay file using MAC Packbits. (We're not proud!)
int16 k = 0; // byte count
do {
@@ -189,7 +199,7 @@ void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
*tmpImage++ = _sceneryArchive2.readByte();
} else { // Repeat next byte -data+1 times
int16 j = _sceneryArchive2.readByte();
-
+
for (i = 0; i < (byte)(-data + 1); i++, k++)
*tmpImage++ = j;
}
diff --git a/engines/hugo/game.h b/engines/hugo/game.h
index 869aa1baa4..25c4375595 100644
--- a/engines/hugo/game.h
+++ b/engines/hugo/game.h
@@ -123,28 +123,42 @@ enum TEXTCOLORS {
enum uif_t {U_FONT5, U_FONT6, U_FONT8, UIF_IMAGES, NUM_UIF_ITEMS};
-// Enumerate overlay file types
+/**
+* Enumerate overlay file types
+*/
enum ovl_t {BOUNDARY, OVERLAY, OVLBASE};
-// Enumerate error types
+/**
+* Enumerate error types
+*/
enum {
GEN_ERR, FILE_ERR, WRITE_ERR, PCCH_ERR, HEAP_ERR, EVNT_ERR, SOUND_ERR
//MOUSE_ERR, VID_ERR, FONT_ERR, ARG_ERR, CHK_ERR, TIMER_ERR, VBX_ERR
};
-// Enumerate ways of cycling a sequence of frames
+/**
+* Enumerate ways of cycling a sequence of frames
+*/
enum cycle_t {INVISIBLE, ALMOST_INVISIBLE, NOT_CYCLING, CYCLE_FORWARD, CYCLE_BACKWARD};
-// Enumerate sequence index matching direction of travel
+/**
+* Enumerate sequence index matching direction of travel
+*/
enum {RIGHT, LEFT, DOWN, _UP};
-// Channel requirement during sound effect
+/**
+* Channel requirement during sound effect
+*/
enum stereo_t {BOTH_CHANNELS, RIGHT_CHANNEL, LEFT_CHANNEL};
-// Priority for sound effect
+/**
+* Priority for sound effect
+*/
enum priority_t {LOW_PRI, MED_PRI, HIGH_PRI};
-// Enumerate the different path types for an object
+/**
+* Enumerate the different path types for an object
+*/
enum path_t {
USER, // User has control of object via cursor keys
AUTO, // Computer has control, controlled by action lists
@@ -155,42 +169,62 @@ enum path_t {
WANDER2 // Same as WANDER, except keeps cycling when stationary
};
-// Enumerate whether object is foreground, background or 'floating'
-// If floating, HERO can collide with it and fore/back ground is determined
-// by relative y-coord of object base. This is the general case.
-// If fore or background, no collisions can take place and object is either
-// behind or in front of all others, although can still be hidden by the
-// the overlay plane. OVEROVL means the object is FLOATING (to other
-// objects) but is never hidden by the overlay plane
+/**
+* Enumerate whether object is foreground, background or 'floating'
+* If floating, HERO can collide with it and fore/back ground is determined
+* by relative y-coord of object base. This is the general case.
+* If fore or background, no collisions can take place and object is either
+* behind or in front of all others, although can still be hidden by the
+* the overlay plane. OVEROVL means the object is FLOATING (to other
+* objects) but is never hidden by the overlay plane
+*/
enum {FOREGROUND, BACKGROUND, FLOATING, OVEROVL};
-// Game view state machine
+/**
+* Game view state machine
+*/
enum vstate_t {V_IDLE, V_INTROINIT, V_INTRO, V_PLAY, V_INVENT, V_EXIT};
enum font_t {LARGE_ROMAN, MED_ROMAN, NUM_GDI_FONTS, INIT_FONTS, DEL_FONTS};
-// Ways to dismiss a text/prompt box
+/**
+* Ways to dismiss a text/prompt box
+*/
enum box_t {BOX_ANY, BOX_OK, BOX_PROMPT, BOX_YESNO};
-// Standard viewport sizes
+/**
+* Standard viewport sizes
+*/
enum wsize_t {SIZE_DEF, SIZE_1, SIZE_2, SIZE_3};
-// Display list functions
+/**
+* Display list functions
+*/
enum dupdate_t {D_INIT, D_ADD, D_DISPLAY, D_RESTORE};
-// General device installation commands
+/**
+* General device installation commands
+*/
enum inst_t {INSTALL, RESTORE, RESET};
-// Inventory icon bar states
+/**
+* Inventory icon bar states
+*/
enum istate_t {I_OFF, I_UP, I_DOWN, I_ACTIVE};
-// Actions for Process_inventory()
+/**
+* Actions for Process_inventory()
+*/
enum invact_t {INV_INIT, INV_LEFT, INV_RIGHT, INV_GET};
-// Purpose of an automatic route
+/**
+* Purpose of an automatic route
+*/
enum go_t {GO_SPACE, GO_EXIT, GO_LOOK, GO_GET};
-// Following defines the action types and action list
+/**
+* Following defines the action types and action list
+*/
enum action_t { // Parameters:
ANULL = 0xff, // Special NOP used to 'delete' events in DEL_EVENTS
ASCHEDULE = 0, // 0 - Ptr to action list to be rescheduled
@@ -259,17 +293,23 @@ struct uif_hdr_t { // UIF font/image look up
uint32 offset; // Offset of item in file
};
-// Game specific type definitions
+/**
+* Game specific type definitions
+*/
typedef byte *image_pt; // ptr to an object image (sprite)
typedef byte *sound_pt; // ptr to sound (or music) data
-// Following are points for achieving certain actions.
+/**
+* Following are points for achieving certain actions.
+*/
struct point_t {
byte score; // The value of the point
bool scoredFl; // Whether scored yet
};
-// Structure for initializing maze processing
+/**
+* Structure for initializing maze processing
+*/
struct maze_t {
bool enabledFl; // TRUE when maze processing enabled
byte size; // Size of (square) maze matrix
@@ -684,7 +724,9 @@ union act {
act49 a49;
};
-// The following determines how a verb is acted on, for an object
+/**
+* The following determines how a verb is acted on, for an object
+*/
struct cmd {
uint16 verbIndex; // the verb
uint16 reqIndex; // ptr to list of required objects
@@ -696,8 +738,10 @@ struct cmd {
uint16 actIndex; // Ptr to action list if verb done
};
-// The following is a linked list of images in an animation sequence
-// The image data is in 8-bit DIB format, i.e. 1 byte = 1 pixel
+/**
+* The following is a linked list of images in an animation sequence
+* The image data is in 8-bit DIB format, i.e. 1 byte = 1 pixel
+*/
struct seq_t { // Linked list of images
byte *imagePtr; // ptr to image
uint16 bytesPerLine8; // bytes per line (8bits)
@@ -706,13 +750,17 @@ struct seq_t { // Linked list of images
seq_t *nextSeqPtr; // ptr to next record
};
-// The following is an array of structures of above sequences
+/**
+* The following is an array of structures of above sequences
+*/
struct seqList_t {
uint16 imageNbr; // Number of images in sequence
seq_t *seqPtr; // Ptr to sequence structure
};
-// Following is definition of object attributes
+/**
+* Following is definition of object attributes
+*/
struct object_t {
uint16 nounIndex; // String identifying object
uint16 dataIndex; // String describing the object
@@ -747,10 +795,12 @@ struct object_t {
int8 oldvy; // Previous vy
};
-// Following is structure of verbs and nouns for 'background' objects
-// These are objects that appear in the various screens, but nothing
-// interesting ever happens with them. Rather than just be dumb and say
-// "don't understand" we produce an interesting msg to keep user sane.
+/**
+* Following is structure of verbs and nouns for 'background' objects
+* These are objects that appear in the various screens, but nothing
+* interesting ever happens with them. Rather than just be dumb and say
+* "don't understand" we produce an interesting msg to keep user sane.
+*/
struct background_t {
uint16 verbIndex;
uint16 nounIndex;
@@ -769,7 +819,9 @@ typedef byte icondib_t[XPIX *INV_DY]; // Icon bar dib
typedef char command_t[MAX_CHARS + 8]; // Command line (+spare for prompt,cursor)
typedef char fpath_t[MAX_FPATH]; // File path
-// Structure to define an EXIT or other collision-activated hotspot
+/**
+* Structure to define an EXIT or other collision-activated hotspot
+*/
struct hotspot_t {
int screenIndex; // Screen in which hotspot appears
int x1, y1, x2, y2; // Bounding box of hotspot
@@ -781,12 +833,13 @@ struct status_t { // Game status (not saved)
bool initSaveFl; // Force save of initial game
bool storyModeFl; // Game is telling story - no commands
bool gameOverFl; // Game is over - hero knobbled
- bool playbackFl; // Game is in playback mode
- bool recordFl; // Game is in record mode
+// Strangerke - Suppress as related to playback
+// bool playbackFl; // Game is in playback mode
+// bool recordFl; // Game is in record mode
bool demoFl; // Game is in demo mode
bool debugFl; // Game is in debug mode
bool textBoxFl; // Game is (halted) in text box
-// Strangerke - Not used ?
+// Strangerke - Not used ?
// bool mmtimeFl; // Multimedia timer supported
bool lookFl; // Toolbar "look" button pressed
bool recallFl; // Toolbar "recall" button pressed
@@ -842,7 +895,9 @@ extern hugo_boot_t _boot; // Boot info structure
extern char _textBoxBuffer[]; // Useful box text buffer
extern command_t _line; // Line of user text input
-// Structure of scenery file lookup entry
+/**
+* Structure of scenery file lookup entry
+*/
struct sceneBlock_t {
uint32 scene_off;
uint32 scene_len;
@@ -854,7 +909,9 @@ struct sceneBlock_t {
uint32 ob_len;
};
-// Structure of object file lookup entry
+/**
+* Structure of object file lookup entry
+*/
struct objBlock_t {
uint32 objOffset;
uint32 objLength;
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index cdc74b5ae5..ef3352829d 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -24,7 +24,9 @@
*/
#include "common/system.h"
+#include "common/random.h"
#include "common/events.h"
+#include "common/EventRecorder.h"
#include "common/debug-channels.h"
#include "hugo/hugo.h"
@@ -37,8 +39,10 @@
#include "hugo/inventory.h"
#include "hugo/parser.h"
#include "hugo/route.h"
+#include "hugo/util.h"
#include "hugo/sound.h"
#include "hugo/intro.h"
+#include "hugo/object.h"
#include "engines/util.h"
@@ -51,12 +55,18 @@ overlay_t HugoEngine::_overlay;
overlay_t HugoEngine::_ovlBase;
overlay_t HugoEngine::_objBound;
+config_t _config; // User's config
+maze_t _maze; // Default to not in maze
+hugo_boot_t _boot; // Boot info structure file
+char _textBoxBuffer[MAX_BOX]; // Buffer for text box
+command_t _line; // Line of user text input
+
HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(syst), _gameDescription(gd), _mouseX(0), _mouseY(0),
- _textData(0), _stringtData(0), _screenNames(0), _textEngine(0), _textIntro(0), _textMouse(0), _textParser(0), _textSchedule(0), _textUtil(0),
- _arrayNouns(0), _arrayVerbs(0), _arrayReqs(0), _hotspots(0), _invent(0), _uses(0), _catchallList(0), _backgroundObjects(0),
- _points(0), _cmdList(0), _screenActs(0), _objects(0), _actListArr(0), _heroImage(0), _defltTunes(0), _palette(0), _introX(0),
- _introY(0), _maxInvent(0), _numBonuses(0), _numScreens(0), _tunesNbr(0), _soundSilence(0), _soundTest(0), _screenStates(0), _numObj(0),
- _score(0), _maxscore(0)
+ _textData(0), _stringtData(0), _screenNames(0), _textEngine(0), _textIntro(0), _textMouse(0), _textParser(0), _textSchedule(0),
+ _textUtil(0), _arrayNouns(0), _arrayVerbs(0), _arrayReqs(0), _hotspots(0), _invent(0), _uses(0), _catchallList(0),
+ _backgroundObjects(0), _points(0), _cmdList(0), _screenActs(0), _heroImage(0), _defltTunes(0), _introX(0),
+ _introY(0), _maxInvent(0), _numBonuses(0), _numScreens(0), _tunesNbr(0), _soundSilence(0), _soundTest(0), _screenStates(0),
+ _numObj(0), _score(0), _maxscore(0), _backgroundObjectsSize(0), _screenActsSize(0), _usesSize(0)
{
DebugMan.addDebugChannel(kDebugSchedule, "Schedule", "Script Schedule debug level");
@@ -67,73 +77,89 @@ HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(sy
DebugMan.addDebugChannel(kDebugFile, "File", "File IO debug level");
DebugMan.addDebugChannel(kDebugRoute, "Route", "Route debug level");
DebugMan.addDebugChannel(kDebugInventory, "Inventory", "Inventory debug level");
+ DebugMan.addDebugChannel(kDebugObject, "Object", "Object debug level");
- for (int j = 0; j < NUM_FONTS; j++)
- _arrayFont[j] = 0;
+ _console = new HugoConsole(this);
}
HugoEngine::~HugoEngine() {
- delete _soundHandler;
- delete _route;
- delete _parser;
- delete _inventoryHandler;
- delete _mouseHandler;
- delete _screen;
- delete _scheduler;
- delete _fileManager;
-
- free(_palette);
- free(_introX);
- free(_introY);
-
-#if 0
- freeTexts(_textData);
- freeTexts(_stringtData);
- freeTexts(_textEngine);
- freeTexts(_textIntro);
- freeTexts(_textMouse);
- freeTexts(_textParser);
- freeTexts(_textSchedule);
- freeTexts(_textUtil);
-#endif
free(_textData);
free(_stringtData);
+
+ if (_arrayNouns) {
+ for (int i = 0; _arrayNouns[i]; i++)
+ free(_arrayNouns[i]);
+ free(_arrayNouns);
+ }
+
+ if (_arrayVerbs) {
+ for (int i = 0; _arrayVerbs[i]; i++)
+ free(_arrayVerbs[i]);
+ free(_arrayVerbs);
+ }
+
free(_screenNames);
+ _screen->freePalette();
free(_textEngine);
free(_textIntro);
+ free(_introX);
+ free(_introY);
free(_textMouse);
free(_textParser);
free(_textSchedule);
free(_textUtil);
-
- warning("Missing: free _arrayNouns");
- warning("Missing: free _arrayVerbs");
-
free(_arrayReqs);
free(_hotspots);
free(_invent);
- free(_uses);
+
+ if (_uses) {
+ for (int i = 0; i < _usesSize; i++)
+ free(_uses[i].targets);
+ free(_uses);
+ }
+
free(_catchallList);
- warning("Missing: free _background_objects");
+ if (_backgroundObjects) {
+ for (int i = 0; i < _backgroundObjectsSize; i++)
+ free(_backgroundObjects[i]);
+ free(_backgroundObjects);
+ }
free(_points);
- warning("Missing: free _cmdList");
- warning("Missing: free _screenActs");
- warning("Missing: free _objects");
+ if (_cmdList) {
+ for (int i = 0; i < _cmdListSize; i++)
+ free(_cmdList[i]);
+ free(_cmdList);
+ }
+
+ if (_cmdList) {
+ for (int i = 0; i < _screenActsSize; i++)
+ free(_screenActs[i]);
+ free(_screenActs);
+ }
+
+ _object->freeObjectArr();
+ _scheduler->freeActListArr();
free(_defltTunes);
free(_screenStates);
- if (_arrayFont[0])
- free(_arrayFont[0]);
+ _screen->freeFonts();
- if (_arrayFont[1])
- free(_arrayFont[1]);
+ delete _object;
+ delete _sound;
+ delete _route;
+ delete _parser;
+ delete _inventory;
+ delete _mouse;
+ delete _screen;
+ delete _scheduler;
+ delete _file;
- if (_arrayFont[2])
- free(_arrayFont[2]);
+ DebugMan.clearAllDebugChannels();
+ delete _console;
}
GameType HugoEngine::getGameType() const {
@@ -152,53 +178,59 @@ Common::Error HugoEngine::run() {
s_Engine = this;
initGraphics(320, 200, false);
- _mouseHandler = new MouseHandler(*this);
- _inventoryHandler = new InventoryHandler(*this);
- _route = new Route(*this);
- _soundHandler = new SoundHandler(*this);
+ _mouse = new MouseHandler(this);
+ _inventory = new InventoryHandler(this);
+ _route = new Route(this);
+ _sound = new SoundHandler(this);
switch (_gameVariant) {
case 0: // H1 Win
- _fileManager = new FileManager_v1w(*this);
- _scheduler = new Scheduler_v3d(*this);
- _introHandler = new intro_v1w(*this);
- _screen = new Screen_v1w(*this);
- _parser = new Parser_v1w(*this);
+ _file = new FileManager_v1w(this);
+ _scheduler = new Scheduler_v1w(this);
+ _intro = new intro_v1w(this);
+ _screen = new Screen_v1w(this);
+ _parser = new Parser_v1w(this);
+ _object = new ObjectHandler_v1w(this);
break;
case 1:
- _fileManager = new FileManager_v2d(*this);
- _scheduler = new Scheduler_v3d(*this);
- _introHandler = new intro_v2w(*this);
- _screen = new Screen_v1w(*this);
- _parser = new Parser_v1w(*this);
+ _file = new FileManager_v2d(this);
+ _scheduler = new Scheduler_v1w(this);
+ _intro = new intro_v2w(this);
+ _screen = new Screen_v1w(this);
+ _parser = new Parser_v1w(this);
+ _object = new ObjectHandler_v1w(this);
break;
case 2:
- _fileManager = new FileManager_v2d(*this);
- _scheduler = new Scheduler_v3d(*this);
- _introHandler = new intro_v3w(*this);
- _screen = new Screen_v1w(*this);
- _parser = new Parser_v1w(*this);
+ _file = new FileManager_v2d(this);
+ _scheduler = new Scheduler_v1w(this);
+ _intro = new intro_v3w(this);
+ _screen = new Screen_v1w(this);
+ _parser = new Parser_v1w(this);
+ _object = new ObjectHandler_v1w(this);
break;
case 3: // H1 DOS
- _fileManager = new FileManager_v1d(*this);
- _scheduler = new Scheduler_v1d(*this);
- _introHandler = new intro_v1d(*this);
- _screen = new Screen_v1d(*this);
- _parser = new Parser_v1d(*this);
+ _file = new FileManager_v1d(this);
+ _scheduler = new Scheduler_v1d(this);
+ _intro = new intro_v1d(this);
+ _screen = new Screen_v1d(this);
+ _parser = new Parser_v1d(this);
+ _object = new ObjectHandler_v1d(this);
break;
case 4:
- _fileManager = new FileManager_v2d(*this);
- _scheduler = new Scheduler_v1d(*this);
- _introHandler = new intro_v2d(*this);
- _screen = new Screen_v1d(*this);
- _parser = new Parser_v2d(*this);
+ _file = new FileManager_v2d(this);
+ _scheduler = new Scheduler_v2d(this);
+ _intro = new intro_v2d(this);
+ _screen = new Screen_v1d(this);
+ _parser = new Parser_v2d(this);
+ _object = new ObjectHandler_v2d(this);
break;
case 5:
- _fileManager = new FileManager_v3d(*this);
- _scheduler = new Scheduler_v3d(*this);
- _introHandler = new intro_v3d(*this);
- _screen = new Screen_v1d(*this);
- _parser = new Parser_v3d(*this);
+ _file = new FileManager_v3d(this);
+ _scheduler = new Scheduler_v3d(this);
+ _intro = new intro_v3d(this);
+ _screen = new Screen_v1d(this);
+ _parser = new Parser_v3d(this);
+ _object = new ObjectHandler_v1d(this);
break;
}
@@ -216,7 +248,7 @@ Common::Error HugoEngine::run() {
initialize();
initConfig(RESET); // Reset user's config
- file().restoreGame(-1);
+ _file->restoreGame(-1);
initMachine();
@@ -234,7 +266,11 @@ Common::Error HugoEngine::run() {
while (_eventMan->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_KEYDOWN:
- parser().keyHandler(event.kbd.keycode, 0);
+ if (event.kbd.keycode == Common::KEYCODE_d && event.kbd.hasFlags(Common::KBD_CTRL)) {
+ this->getDebugger()->attach();
+ this->getDebugger()->onFrame();
+ }
+ _parser->keyHandler(event.kbd.keycode, 0);
break;
case Common::EVENT_MOUSEMOVE:
_mouseX = event.mouse.x;
@@ -259,6 +295,7 @@ Common::Error HugoEngine::run() {
break;
}
}
+ _status.doQuitFl |= shouldQuit(); // update game quit flag
}
return Common::kNoError;
}
@@ -267,14 +304,16 @@ void HugoEngine::initMachine() {
if (_gameVariant == kGameVariantH1Dos)
readScreenFiles(0);
else
- file().readBackground(_numScreens - 1); // Splash screen
+ _file->readBackground(_numScreens - 1); // Splash screen
readObjectImages(); // Read all object images
if (_platform == Common::kPlatformWindows)
- readUIFImages(); // Read all uif images (only in Win versions)
+ _file->readUIFImages(); // Read all uif images (only in Win versions)
}
+/**
+* Hugo game state machine - called during onIdle
+*/
void HugoEngine::runMachine() {
-// Hugo game state machine - called during onIdle
static uint32 lastTime;
status_t &gameStatus = getGameStatus();
@@ -293,32 +332,32 @@ void HugoEngine::runMachine() {
switch (gameStatus.viewState) {
case V_IDLE: // Not processing state machine
- intro().preNewGame(); // Any processing before New Game selected
+ _intro->preNewGame(); // Any processing before New Game selected
break;
case V_INTROINIT: // Initialization before intro begins
- intro().introInit();
+ _intro->introInit();
g_system->showMouse(false);
gameStatus.viewState = V_INTRO;
break;
case V_INTRO: // Do any game-dependant preamble
- if (intro().introPlay()) { // Process intro screen
- scheduler().newScreen(0); // Initialize first screen
+ if (_intro->introPlay()) { // Process intro screen
+ _scheduler->newScreen(0); // Initialize first screen
gameStatus.viewState = V_PLAY;
}
break;
case V_PLAY: // Playing game
g_system->showMouse(true);
- parser().charHandler(); // Process user cmd input
- moveObjects(); // Process object movement
- scheduler().runScheduler(); // Process any actions
- screen().displayList(D_RESTORE); // Restore previous background
- updateImages(); // Draw into _frontBuffer, compile display list
- mouse().mouseHandler(); // Mouse activity - adds to display list
- screen().drawStatusText();
- screen().displayList(D_DISPLAY); // Blit the display list to screen
+ _parser->charHandler(); // Process user cmd input
+ _object->moveObjects(); // Process object movement
+ _scheduler->runScheduler(); // Process any actions
+ _screen->displayList(D_RESTORE); // Restore previous background
+ _object->updateImages(); // Draw into _frontBuffer, compile display list
+ _mouse->mouseHandler(); // Mouse activity - adds to display list
+ _screen->drawStatusText();
+ _screen->displayList(D_DISPLAY); // Blit the display list to screen
break;
case V_INVENT: // Accessing inventory
- inventory().runInventory(); // Process Inventory state machine
+ _inventory->runInventory(); // Process Inventory state machine
break;
case V_EXIT: // Game over or user exited
gameStatus.viewState = V_IDLE;
@@ -327,6 +366,9 @@ void HugoEngine::runMachine() {
}
}
+/**
+* Loads Hugo.dat file, which contains all the hardcoded data in the original executables
+*/
bool HugoEngine::loadHugoDat() {
Common::File in;
in.open("hugo.dat");
@@ -379,11 +421,7 @@ bool HugoEngine::loadHugoDat() {
// Read screenNames
_screenNames = loadTextsVariante(in, &_numScreens);
- // Read palette
- _paletteSize = in.readUint16BE();
- _palette = (byte *)malloc(sizeof(byte) * _paletteSize);
- for (int i = 0; i < _paletteSize; i++)
- _palette[i] = in.readByte();
+ _screen->loadPalette(in);
// Read textEngine
_textEngine = loadTexts(in);
@@ -456,7 +494,7 @@ bool HugoEngine::loadHugoDat() {
}
}
- int numElem, numSubElem, numSubAct;
+ int numElem, numSubElem;
//Read _invent
for (int varnt = 0; varnt < _numVariant; varnt++) {
numElem = in.readUint16BE();
@@ -475,6 +513,7 @@ bool HugoEngine::loadHugoDat() {
for (int varnt = 0; varnt < _numVariant; varnt++) {
numElem = in.readUint16BE();
if (varnt == _gameVariant) {
+ _usesSize = numElem;
_uses = (uses_t *)malloc(sizeof(uses_t) * numElem);
for (int i = 0; i < numElem; i++) {
_uses[i].objId = in.readSint16BE();
@@ -528,8 +567,9 @@ bool HugoEngine::loadHugoDat() {
for (int varnt = 0; varnt < _numVariant; varnt++) {
numElem = in.readUint16BE();
if (varnt == _gameVariant) {
- _backgroundObjects = (background_t **)malloc(sizeof(background_t *) * numElem);
- for (int i = 0; i < numElem; i++) {
+ _backgroundObjectsSize = numElem;
+ _backgroundObjects = (background_t **)malloc(sizeof(background_t *) * _backgroundObjectsSize);
+ for (int i = 0; i < _backgroundObjectsSize; i++) {
numSubElem = in.readUint16BE();
_backgroundObjects[i] = (background_t *)malloc(sizeof(background_t) * numSubElem);
for (int j = 0; j < numSubElem; j++) {
@@ -576,8 +616,9 @@ bool HugoEngine::loadHugoDat() {
for (int varnt = 0; varnt < _numVariant; varnt++) {
numElem = in.readUint16BE();
if (varnt == _gameVariant) {
- _cmdList = (cmd **)malloc(sizeof(cmd *) * numElem);
- for (int i = 0; i < numElem; i++) {
+ _cmdListSize = numElem;
+ _cmdList = (cmd **)malloc(sizeof(cmd *) * _cmdListSize);
+ for (int i = 0; i < _cmdListSize; i++) {
numSubElem = in.readUint16BE();
_cmdList[i] = (cmd *)malloc(sizeof(cmd) * numSubElem);
for (int j = 0; j < numSubElem; j++) {
@@ -608,13 +649,14 @@ bool HugoEngine::loadHugoDat() {
}
}
-// TODO: For Hugo2 and Hugo3, if not in story mode, increment _screenActs[0][0] (ex: kALcrashStory + 1 == kALcrashNoStory)
// Read _screenActs
+ // TODO: For Hugo2 and Hugo3, if not in story mode, increment _screenActs[0][0] (ex: kALcrashStory + 1 == kALcrashNoStory)
for (int varnt = 0; varnt < _numVariant; varnt++) {
numElem = in.readUint16BE();
if (varnt == _gameVariant) {
- _screenActs = (uint16 **)malloc(sizeof(uint16 *) * numElem);
- for (int i = 0; i < numElem; i++) {
+ _screenActsSize = numElem;
+ _screenActs = (uint16 **)malloc(sizeof(uint16 *) * _screenActsSize);
+ for (int i = 0; i < _screenActsSize; i++) {
numSubElem = in.readUint16BE();
if (numSubElem == 0) {
_screenActs[i] = 0;
@@ -633,682 +675,23 @@ bool HugoEngine::loadHugoDat() {
}
}
-// TODO: For Hugo3, if not in story mode, set _objects[2].state to 3
- for (int varnt = 0; varnt < _numVariant; varnt++) {
- numElem = in.readUint16BE();
- if (varnt == _gameVariant) {
- _objects = (object_t *)malloc(sizeof(object_t) * numElem);
- for (int i = 0; i < numElem; i++) {
- _objects[i].nounIndex = in.readUint16BE();
- _objects[i].dataIndex = in.readUint16BE();
- numSubElem = in.readUint16BE();
- if (numSubElem == 0)
- _objects[i].stateDataIndex = 0;
- else
- _objects[i].stateDataIndex = (uint16 *)malloc(sizeof(uint16) * numSubElem);
- for (int j = 0; j < numSubElem; j++)
- _objects[i].stateDataIndex[j] = in.readUint16BE();
- _objects[i].pathType = (path_t) in.readSint16BE();
- _objects[i].vxPath = in.readSint16BE();
- _objects[i].vyPath = in.readSint16BE();
- _objects[i].actIndex = in.readUint16BE();
- _objects[i].seqNumb = in.readByte();
- _objects[i].currImagePtr = 0;
- if (_objects[i].seqNumb == 0) {
- _objects[i].seqList[0].imageNbr = 0;
- _objects[i].seqList[0].seqPtr = 0;
- }
- for (int j = 0; j < _objects[i].seqNumb; j++) {
- _objects[i].seqList[j].imageNbr = in.readUint16BE();
- _objects[i].seqList[j].seqPtr = 0;
- }
- _objects[i].cycling = (cycle_t)in.readByte();
- _objects[i].cycleNumb = in.readByte();
- _objects[i].frameInterval = in.readByte();
- _objects[i].frameTimer = in.readByte();
- _objects[i].radius = in.readByte();
- _objects[i].screenIndex = in.readByte();
- _objects[i].x = in.readSint16BE();
- _objects[i].y = in.readSint16BE();
- _objects[i].oldx = in.readSint16BE();
- _objects[i].oldy = in.readSint16BE();
- _objects[i].vx = in.readByte();
- _objects[i].vy = in.readByte();
- _objects[i].objValue = in.readByte();
- _objects[i].genericCmd = in.readSint16BE();
- _objects[i].cmdIndex = in.readUint16BE();
- _objects[i].carriedFl = (in.readByte() != 0);
- _objects[i].state = in.readByte();
- _objects[i].verbOnlyFl = (in.readByte() != 0);
- _objects[i].priority = in.readByte();
- _objects[i].viewx = in.readSint16BE();
- _objects[i].viewy = in.readSint16BE();
- _objects[i].direction = in.readSint16BE();
- _objects[i].curSeqNum = in.readByte();
- _objects[i].curImageNum = in.readByte();
- _objects[i].oldvx = in.readByte();
- _objects[i].oldvy = in.readByte();
- }
- } else {
- for (int i = 0; i < numElem; i++) {
- in.readUint16BE();
- in.readUint16BE();
- numSubElem = in.readUint16BE();
- for (int j = 0; j < numSubElem; j++)
- in.readUint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- numSubElem = in.readByte();
- for (int j = 0; j < numSubElem; j++)
- in.readUint16BE();
- in.readByte();
- in.readByte();
- in.readByte();
- in.readByte();
- in.readByte();
- in.readByte();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- in.readByte();
- in.readByte();
- in.readSint16BE();
- in.readUint16BE();
- in.readByte();
- in.readByte();
- in.readByte();
- in.readByte();
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- in.readByte();
- in.readByte();
- in.readByte();
- in.readByte();
- }
- }
- }
-//#define HERO 0
- _hero = &_objects[HERO]; // This always points to hero
- _screen_p = &(_objects[HERO].screenIndex); // Current screen is hero's
- _heroImage = HERO; // Current in use hero image
+ _object->loadObjectArr(in);
+
+ _hero = &_object->_objects[HERO]; // This always points to hero
+ _screen_p = &(_object->_objects[HERO].screenIndex); // Current screen is hero's
+ _heroImage = HERO; // Current in use hero image
+
+ _scheduler->loadActListArr(in);
-//read _actListArr
- for (int varnt = 0; varnt < _numVariant; varnt++) {
- numElem = in.readUint16BE();
- if (varnt == _gameVariant) {
- _actListArr = (act **)malloc(sizeof(act *) * numElem);
- for (int i = 0; i < numElem; i++) {
- numSubElem = in.readUint16BE();
- _actListArr[i] = (act *) malloc(sizeof(act) * (numSubElem + 1));
- for (int j = 0; j < numSubElem; j++) {
- _actListArr[i][j].a0.actType = (action_t) in.readByte();
- switch (_actListArr[i][j].a0.actType) {
- case ANULL: // -1
- break;
- case ASCHEDULE: // 0
- _actListArr[i][j].a0.timer = in.readSint16BE();
- _actListArr[i][j].a0.actIndex = in.readUint16BE();
- break;
- case START_OBJ: // 1
- _actListArr[i][j].a1.timer = in.readSint16BE();
- _actListArr[i][j].a1.objNumb = in.readSint16BE();
- _actListArr[i][j].a1.cycleNumb = in.readSint16BE();
- _actListArr[i][j].a1.cycle = (cycle_t) in.readByte();
- break;
- case INIT_OBJXY: // 2
- _actListArr[i][j].a2.timer = in.readSint16BE();
- _actListArr[i][j].a2.objNumb = in.readSint16BE();
- _actListArr[i][j].a2.x = in.readSint16BE();
- _actListArr[i][j].a2.y = in.readSint16BE();
- break;
- case PROMPT: // 3
- _actListArr[i][j].a3.timer = in.readSint16BE();
- _actListArr[i][j].a3.promptIndex = in.readSint16BE();
- numSubAct = in.readUint16BE();
- _actListArr[i][j].a3.responsePtr = (int *) malloc(sizeof(int) * numSubAct);
- for (int k = 0; k < numSubAct; k++)
- _actListArr[i][j].a3.responsePtr[k] = in.readSint16BE();
- _actListArr[i][j].a3.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a3.actFailIndex = in.readUint16BE();
- _actListArr[i][j].a3.encodedFl = (in.readByte() == 1) ? true : false;
- break;
- case BKGD_COLOR: // 4
- _actListArr[i][j].a4.timer = in.readSint16BE();
- _actListArr[i][j].a4.newBackgroundColor = in.readUint32BE();
- break;
- case INIT_OBJVXY: // 5
- _actListArr[i][j].a5.timer = in.readSint16BE();
- _actListArr[i][j].a5.objNumb = in.readSint16BE();
- _actListArr[i][j].a5.vx = in.readSint16BE();
- _actListArr[i][j].a5.vy = in.readSint16BE();
- break;
- case INIT_CARRY: // 6
- _actListArr[i][j].a6.timer = in.readSint16BE();
- _actListArr[i][j].a6.objNumb = in.readSint16BE();
- _actListArr[i][j].a6.carriedFl = (in.readByte() == 1) ? true : false;
- break;
- case INIT_HF_COORD: // 7
- _actListArr[i][j].a7.timer = in.readSint16BE();
- _actListArr[i][j].a7.objNumb = in.readSint16BE();
- break;
- case NEW_SCREEN: // 8
- _actListArr[i][j].a8.timer = in.readSint16BE();
- _actListArr[i][j].a8.screenIndex = in.readSint16BE();
- break;
- case INIT_OBJSTATE: // 9
- _actListArr[i][j].a9.timer = in.readSint16BE();
- _actListArr[i][j].a9.objNumb = in.readSint16BE();
- _actListArr[i][j].a9.newState = in.readByte();
- break;
- case INIT_PATH: // 10
- _actListArr[i][j].a10.timer = in.readSint16BE();
- _actListArr[i][j].a10.objNumb = in.readSint16BE();
- _actListArr[i][j].a10.newPathType = in.readSint16BE();
- _actListArr[i][j].a10.vxPath = in.readByte();
- _actListArr[i][j].a10.vyPath = in.readByte();
- break;
- case COND_R: // 11
- _actListArr[i][j].a11.timer = in.readSint16BE();
- _actListArr[i][j].a11.objNumb = in.readSint16BE();
- _actListArr[i][j].a11.stateReq = in.readByte();
- _actListArr[i][j].a11.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a11.actFailIndex = in.readUint16BE();
- break;
- case TEXT: // 12
- _actListArr[i][j].a12.timer = in.readSint16BE();
- _actListArr[i][j].a12.stringIndex = in.readSint16BE();
- break;
- case SWAP_IMAGES: // 13
- _actListArr[i][j].a13.timer = in.readSint16BE();
- _actListArr[i][j].a13.obj1 = in.readSint16BE();
- _actListArr[i][j].a13.obj2 = in.readSint16BE();
- break;
- case COND_SCR: // 14
- _actListArr[i][j].a14.timer = in.readSint16BE();
- _actListArr[i][j].a14.objNumb = in.readSint16BE();
- _actListArr[i][j].a14.screenReq = in.readSint16BE();
- _actListArr[i][j].a14.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a14.actFailIndex = in.readUint16BE();
- break;
- case AUTOPILOT: // 15
- _actListArr[i][j].a15.timer = in.readSint16BE();
- _actListArr[i][j].a15.obj1 = in.readSint16BE();
- _actListArr[i][j].a15.obj2 = in.readSint16BE();
- _actListArr[i][j].a15.dx = in.readByte();
- _actListArr[i][j].a15.dy = in.readByte();
- break;
- case INIT_OBJ_SEQ: // 16
- _actListArr[i][j].a16.timer = in.readSint16BE();
- _actListArr[i][j].a16.objNumb = in.readSint16BE();
- _actListArr[i][j].a16.seqIndex = in.readSint16BE();
- break;
- case SET_STATE_BITS: // 17
- _actListArr[i][j].a17.timer = in.readSint16BE();
- _actListArr[i][j].a17.objNumb = in.readSint16BE();
- _actListArr[i][j].a17.stateMask = in.readSint16BE();
- break;
- case CLEAR_STATE_BITS: // 18
- _actListArr[i][j].a18.timer = in.readSint16BE();
- _actListArr[i][j].a18.objNumb = in.readSint16BE();
- _actListArr[i][j].a18.stateMask = in.readSint16BE();
- break;
- case TEST_STATE_BITS: // 19
- _actListArr[i][j].a19.timer = in.readSint16BE();
- _actListArr[i][j].a19.objNumb = in.readSint16BE();
- _actListArr[i][j].a19.stateMask = in.readSint16BE();
- _actListArr[i][j].a19.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a19.actFailIndex = in.readUint16BE();
- break;
- case DEL_EVENTS: // 20
- _actListArr[i][j].a20.timer = in.readSint16BE();
- _actListArr[i][j].a20.actTypeDel = (action_t) in.readByte();
- break;
- case GAMEOVER: // 21
- _actListArr[i][j].a21.timer = in.readSint16BE();
- break;
- case INIT_HH_COORD: // 22
- _actListArr[i][j].a22.timer = in.readSint16BE();
- _actListArr[i][j].a22.objNumb = in.readSint16BE();
- break;
- case EXIT: // 23
- _actListArr[i][j].a23.timer = in.readSint16BE();
- break;
- case BONUS: // 24
- _actListArr[i][j].a24.timer = in.readSint16BE();
- _actListArr[i][j].a24.pointIndex = in.readSint16BE();
- break;
- case COND_BOX: // 25
- _actListArr[i][j].a25.timer = in.readSint16BE();
- _actListArr[i][j].a25.objNumb = in.readSint16BE();
- _actListArr[i][j].a25.x1 = in.readSint16BE();
- _actListArr[i][j].a25.y1 = in.readSint16BE();
- _actListArr[i][j].a25.x2 = in.readSint16BE();
- _actListArr[i][j].a25.y2 = in.readSint16BE();
- _actListArr[i][j].a25.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a25.actFailIndex = in.readUint16BE();
- break;
- case SOUND: // 26
- _actListArr[i][j].a26.timer = in.readSint16BE();
- _actListArr[i][j].a26.soundIndex = in.readSint16BE();
- break;
- case ADD_SCORE: // 27
- _actListArr[i][j].a27.timer = in.readSint16BE();
- _actListArr[i][j].a27.objNumb = in.readSint16BE();
- break;
- case SUB_SCORE: // 28
- _actListArr[i][j].a28.timer = in.readSint16BE();
- _actListArr[i][j].a28.objNumb = in.readSint16BE();
- break;
- case COND_CARRY: // 29
- _actListArr[i][j].a29.timer = in.readSint16BE();
- _actListArr[i][j].a29.objNumb = in.readSint16BE();
- _actListArr[i][j].a29.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a29.actFailIndex = in.readUint16BE();
- break;
- case INIT_MAZE: // 30
- _actListArr[i][j].a30.timer = in.readSint16BE();
- _actListArr[i][j].a30.mazeSize = in.readByte();
- _actListArr[i][j].a30.x1 = in.readSint16BE();
- _actListArr[i][j].a30.y1 = in.readSint16BE();
- _actListArr[i][j].a30.x2 = in.readSint16BE();
- _actListArr[i][j].a30.y2 = in.readSint16BE();
- _actListArr[i][j].a30.x3 = in.readSint16BE();
- _actListArr[i][j].a30.x4 = in.readSint16BE();
- _actListArr[i][j].a30.firstScreenIndex = in.readByte();
- break;
- case EXIT_MAZE: // 31
- _actListArr[i][j].a31.timer = in.readSint16BE();
- break;
- case INIT_PRIORITY: // 32
- _actListArr[i][j].a32.timer = in.readSint16BE();
- _actListArr[i][j].a32.objNumb = in.readSint16BE();
- _actListArr[i][j].a32.priority = in.readByte();
- break;
- case INIT_SCREEN: // 33
- _actListArr[i][j].a33.timer = in.readSint16BE();
- _actListArr[i][j].a33.objNumb = in.readSint16BE();
- _actListArr[i][j].a33.screenIndex = in.readSint16BE();
- break;
- case AGSCHEDULE: // 34
- _actListArr[i][j].a34.timer = in.readSint16BE();
- _actListArr[i][j].a34.actIndex = in.readUint16BE();
- break;
- case REMAPPAL: // 35
- _actListArr[i][j].a35.timer = in.readSint16BE();
- _actListArr[i][j].a35.oldColorIndex = in.readSint16BE();
- _actListArr[i][j].a35.newColorIndex = in.readSint16BE();
- break;
- case COND_NOUN: // 36
- _actListArr[i][j].a36.timer = in.readSint16BE();
- _actListArr[i][j].a36.nounIndex = in.readUint16BE();
- _actListArr[i][j].a36.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a36.actFailIndex = in.readUint16BE();
- break;
- case SCREEN_STATE: // 37
- _actListArr[i][j].a37.timer = in.readSint16BE();
- _actListArr[i][j].a37.screenIndex = in.readSint16BE();
- _actListArr[i][j].a37.newState = in.readByte();
- break;
- case INIT_LIPS: // 38
- _actListArr[i][j].a38.timer = in.readSint16BE();
- _actListArr[i][j].a38.lipsObjNumb = in.readSint16BE();
- _actListArr[i][j].a38.objNumb = in.readSint16BE();
- _actListArr[i][j].a38.dxLips = in.readByte();
- _actListArr[i][j].a38.dyLips = in.readByte();
- break;
- case INIT_STORY_MODE: // 39
- _actListArr[i][j].a39.timer = in.readSint16BE();
- _actListArr[i][j].a39.storyModeFl = (in.readByte() == 1);
- break;
- case WARN: // 40
- _actListArr[i][j].a40.timer = in.readSint16BE();
- _actListArr[i][j].a40.stringIndex = in.readSint16BE();
- break;
- case COND_BONUS: // 41
- _actListArr[i][j].a41.timer = in.readSint16BE();
- _actListArr[i][j].a41.BonusIndex = in.readSint16BE();
- _actListArr[i][j].a41.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a41.actFailIndex = in.readUint16BE();
- break;
- case TEXT_TAKE: // 42
- _actListArr[i][j].a42.timer = in.readSint16BE();
- _actListArr[i][j].a42.objNumb = in.readSint16BE();
- break;
- case YESNO: // 43
- _actListArr[i][j].a43.timer = in.readSint16BE();
- _actListArr[i][j].a43.promptIndex = in.readSint16BE();
- _actListArr[i][j].a43.actYesIndex = in.readUint16BE();
- _actListArr[i][j].a43.actNoIndex = in.readUint16BE();
- break;
- case STOP_ROUTE: // 44
- _actListArr[i][j].a44.timer = in.readSint16BE();
- break;
- case COND_ROUTE: // 45
- _actListArr[i][j].a45.timer = in.readSint16BE();
- _actListArr[i][j].a45.routeIndex = in.readSint16BE();
- _actListArr[i][j].a45.actPassIndex = in.readUint16BE();
- _actListArr[i][j].a45.actFailIndex = in.readUint16BE();
- break;
- case INIT_JUMPEXIT: // 46
- _actListArr[i][j].a46.timer = in.readSint16BE();
- _actListArr[i][j].a46.jumpExitFl = (in.readByte() == 1);
- break;
- case INIT_VIEW: // 47
- _actListArr[i][j].a47.timer = in.readSint16BE();
- _actListArr[i][j].a47.objNumb = in.readSint16BE();
- _actListArr[i][j].a47.viewx = in.readSint16BE();
- _actListArr[i][j].a47.viewy = in.readSint16BE();
- _actListArr[i][j].a47.direction = in.readSint16BE();
- break;
- case INIT_OBJ_FRAME: // 48
- _actListArr[i][j].a48.timer = in.readSint16BE();
- _actListArr[i][j].a48.objNumb = in.readSint16BE();
- _actListArr[i][j].a48.seqIndex = in.readSint16BE();
- _actListArr[i][j].a48.frameIndex = in.readSint16BE();
- break;
- case OLD_SONG: //49
- _actListArr[i][j].a49.timer = in.readSint16BE();
- _actListArr[i][j].a49.soundIndex = in.readUint16BE();
- break;
- default:
- error("Engine - Unknown action type encountered: %d", _actListArr[i][j].a0.actType);
- }
- }
- _actListArr[i][numSubElem].a0.actType = ANULL;
- }
- } else {
- for (int i = 0; i < numElem; i++) {
- numSubElem = in.readUint16BE();
- for (int j = 0; j < numSubElem; j++) {
- numSubAct = in.readByte();
- switch (numSubAct) {
- case ANULL: // -1
- break;
- case ASCHEDULE: // 0
- in.readSint16BE();
- in.readUint16BE();
- break;
- case START_OBJ: // 1
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- break;
- case INIT_OBJXY: // 2
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case PROMPT: // 3
- in.readSint16BE();
- in.readSint16BE();
- numSubAct = in.readUint16BE();
- for (int k = 0; k < numSubAct; k++)
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- in.readByte();
- break;
- case BKGD_COLOR: // 4
- in.readSint16BE();
- in.readUint32BE();
- break;
- case INIT_OBJVXY: // 5
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case INIT_CARRY: // 6
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- break;
- case INIT_HF_COORD: // 7
- in.readSint16BE();
- in.readSint16BE();
- break;
- case NEW_SCREEN: // 8
- in.readSint16BE();
- in.readSint16BE();
- break;
- case INIT_OBJSTATE: // 9
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- break;
- case INIT_PATH: // 10
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- in.readByte();
- break;
- case COND_R: // 11
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case TEXT: // 12
- in.readSint16BE();
- in.readSint16BE();
- break;
- case SWAP_IMAGES: // 13
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case COND_SCR: // 14
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case AUTOPILOT: // 15
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- in.readByte();
- break;
- case INIT_OBJ_SEQ: // 16
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case SET_STATE_BITS: // 17
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case CLEAR_STATE_BITS: // 18
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case TEST_STATE_BITS: // 19
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case DEL_EVENTS: // 20
- in.readSint16BE();
- in.readByte();
- break;
- case GAMEOVER: // 21
- in.readSint16BE();
- break;
- case INIT_HH_COORD: // 22
- in.readSint16BE();
- in.readSint16BE();
- break;
- case EXIT: // 23
- in.readSint16BE();
- break;
- case BONUS: // 24
- in.readSint16BE();
- in.readSint16BE();
- break;
- case COND_BOX: // 25
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case SOUND: // 26
- in.readSint16BE();
- in.readSint16BE();
- break;
- case ADD_SCORE: // 27
- in.readSint16BE();
- in.readSint16BE();
- break;
- case SUB_SCORE: // 28
- in.readSint16BE();
- in.readSint16BE();
- break;
- case COND_CARRY: // 29
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case INIT_MAZE: // 30
- in.readSint16BE();
- in.readByte();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- break;
- case EXIT_MAZE: // 31
- in.readSint16BE();
- break;
- case INIT_PRIORITY: // 32
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- break;
- case INIT_SCREEN: // 33
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case AGSCHEDULE: // 34
- in.readSint16BE();
- in.readUint16BE();
- break;
- case REMAPPAL: // 35
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case COND_NOUN: // 36
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case SCREEN_STATE: // 37
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- break;
- case INIT_LIPS: // 38
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readByte();
- in.readByte();
- break;
- case INIT_STORY_MODE: // 39
- in.readSint16BE();
- in.readByte();
- break;
- case WARN: // 40
- in.readSint16BE();
- in.readSint16BE();
- break;
- case COND_BONUS: // 41
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case TEXT_TAKE: // 42
- in.readSint16BE();
- in.readSint16BE();
- break;
- case YESNO: // 43
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case STOP_ROUTE: // 44
- in.readSint16BE();
- break;
- case COND_ROUTE: // 45
- in.readSint16BE();
- in.readSint16BE();
- in.readUint16BE();
- in.readUint16BE();
- break;
- case INIT_JUMPEXIT: // 46
- in.readSint16BE();
- in.readByte();
- break;
- case INIT_VIEW: // 47
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case INIT_OBJ_FRAME: // 48
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- in.readSint16BE();
- break;
- case OLD_SONG: //49
- in.readSint16BE();
- in.readUint16BE();
- break;
- default:
- error("Engine - Unknown action type encountered %d - variante %d pos %d.%d", numSubAct, varnt, i, j);
- }
- }
- }
- }
- }
for (int varnt = 0; varnt < _numVariant; varnt++) {
if (varnt == _gameVariant) {
- _tunesNbr = in.readByte();
- _soundSilence = in.readByte();
- _soundTest = in.readByte();
+ _tunesNbr = in.readSByte();
+ _soundSilence = in.readSByte();
+ _soundTest = in.readSByte();
} else {
- in.readByte();
- in.readByte();
- in.readByte();
+ in.readSByte();
+ in.readSByte();
+ in.readSByte();
}
}
@@ -1356,41 +739,9 @@ bool HugoEngine::loadHugoDat() {
_numObj = numElem;
}
- //Read kALnewscr used by maze (Hugo 2)
- for (int varnt = 0; varnt < _numVariant; varnt++) {
- numElem = in.readUint16BE();
- if (varnt == _gameVariant)
- _alNewscrIndex = numElem;
- }
-
- if (_gameVariant > 2) {
- _arrayFontSize[0] = in.readUint16BE();
- _arrayFont[0] = (byte *)malloc(sizeof(byte) * _arrayFontSize[0]);
- for (int j = 0; j < _arrayFontSize[0]; j++)
- _arrayFont[0][j] = in.readByte();
-
- _arrayFontSize[1] = in.readUint16BE();
- _arrayFont[1] = (byte *)malloc(sizeof(byte) * _arrayFontSize[1]);
- for (int j = 0; j < _arrayFontSize[1]; j++)
- _arrayFont[1][j] = in.readByte();
-
- _arrayFontSize[2] = in.readUint16BE();
- _arrayFont[2] = (byte *)malloc(sizeof(byte) * _arrayFontSize[2]);
- for (int j = 0; j < _arrayFontSize[2]; j++)
- _arrayFont[2][j] = in.readByte();
- } else {
- numElem = in.readUint16BE();
- for (int j = 0; j < numElem; j++)
- in.readByte();
+ _scheduler->loadAlNewscrIndex(in);
+ _screen->loadFontArr(in);
- numElem = in.readUint16BE();
- for (int j = 0; j < numElem; j++)
- in.readByte();
-
- numElem = in.readUint16BE();
- for (int j = 0; j < numElem; j++)
- in.readByte();
- }
return true;
}
@@ -1459,14 +810,15 @@ uint16 **HugoEngine::loadLongArray(Common::File &in) {
char ***HugoEngine::loadTextsArray(Common::File &in) {
char ***resArray = 0;
+ uint16 arraySize;
for (int varnt = 0; varnt < _numVariant; varnt++) {
- int numNouns = in.readUint16BE();
+ arraySize = in.readUint16BE();
if (varnt == _gameVariant) {
- resArray = (char ** *)malloc(sizeof(char **) * (numNouns + 1));
- resArray[numNouns] = 0;
+ resArray = (char ***)malloc(sizeof(char **) * (arraySize + 1));
+ resArray[arraySize] = 0;
}
- for (int i = 0; i < numNouns; i++) {
+ for (int i = 0; i < arraySize; i++) {
int numTexts = in.readUint16BE();
int entryLen = in.readUint16BE();
char *pos = (char *)malloc(entryLen);
@@ -1528,4 +880,389 @@ void HugoEngine::freeTexts(char **ptr) {
free(ptr);
}
+/**
+* Sets the playlist to be the default tune selection
+*/
+void HugoEngine::initPlaylist(bool playlist[MAX_TUNES]) {
+ debugC(1, kDebugEngine, "initPlaylist");
+
+ for (int16 i = 0; i < MAX_TUNES; i++)
+ playlist[i] = false;
+ for (int16 i = 0; _defltTunes[i] != -1; i++)
+ playlist[_defltTunes[i]] = true;
+}
+
+/**
+* Initialize the dynamic game status
+*/
+void HugoEngine::initStatus() {
+ debugC(1, kDebugEngine, "initStatus");
+ _status.initSaveFl = true; // Force initial save
+ _status.storyModeFl = false; // Not in story mode
+ _status.gameOverFl = false; // Hero not knobbled yet
+// Strangerke - Suppress as related to playback
+// _status.recordFl = false; // Not record mode
+// _status.playbackFl = false; // Not playback mode
+ _status.demoFl = false; // Not demo mode
+ _status.textBoxFl = false; // Not processing a text box
+// Strangerke - Not used ?
+// _status.mmtime = false; // Multimedia timer support
+ _status.lookFl = false; // Toolbar "look" button
+ _status.recallFl = false; // Toolbar "recall" button
+ _status.leftButtonFl = false; // Left mouse button pressed
+ _status.rightButtonFl = false; // Right mouse button pressed
+ _status.newScreenFl = false; // Screen not just loaded
+ _status.jumpExitFl = false; // Can't jump to a screen exit
+ _status.godModeFl = false; // No special cheats allowed
+ _status.helpFl = false; // Not calling WinHelp()
+ _status.doQuitFl = false;
+ _status.path[0] = 0; // Path to write files
+ _status.saveSlot = 0; // Slot to save/restore game
+ _status.screenWidth = 0; // Desktop screen width
+
+ // Initialize every start of new game
+ _status.tick = 0; // Tick count
+ _status.saveTick = 0; // Time of last save
+ _status.viewState = V_IDLE; // View state
+ _status.inventoryState = I_OFF; // Inventory icon bar state
+ _status.inventoryHeight = 0; // Inventory icon bar pos
+ _status.inventoryObjId = -1; // Inventory object selected (none)
+ _status.routeIndex = -1; // Hero not following a route
+ _status.go_for = GO_SPACE; // Hero walking to space
+ _status.go_id = -1; // Hero not walking to anything
+}
+
+/**
+* Initialize default config values. Must be done before Initialize().
+* Reset needed to save config.cx,cy which get splatted during OnFileNew()
+*/
+void HugoEngine::initConfig(inst_t action) {
+ debugC(1, kDebugEngine, "initConfig(%d)", action);
+
+ switch (action) {
+ case INSTALL:
+ _config.musicFl = true; // Music state initially on
+ _config.soundFl = true; // Sound state initially on
+ _config.turboFl = false; // Turbo state initially off
+ _config.backgroundMusicFl = false; // No music when inactive
+ _config.musicVolume = 85; // Music volume %
+ _config.soundVolume = 100; // Sound volume %
+ initPlaylist(_config.playlist); // Initialize default tune playlist
+
+ _file->readBootFile(); // Read startup structure
+ break;
+ case RESET:
+ // Find first tune and play it
+ for (int16 i = 0; i < MAX_TUNES; i++) {
+ if (_config.playlist[i]) {
+ _sound->playMusic(i);
+ break;
+ }
+ }
+
+ _file->initSavedGame(); // Initialize saved game
+ break;
+ case RESTORE:
+ warning("Unhandled action RESTORE");
+ break;
+ }
+}
+
+void HugoEngine::initialize() {
+ debugC(1, kDebugEngine, "initialize");
+
+ _maze.enabledFl = false;
+ _line[0] = '\0';
+
+ _sound->initSound();
+ _scheduler->initEventQueue(); // Init scheduler stuff
+ _screen->initDisplay(); // Create Dibs and palette
+ _file->openDatabaseFiles(); // Open database files
+ calcMaxScore(); // Initialise maxscore
+
+ _rnd = new Common::RandomSource();
+ g_eventRec.registerRandomSource(*_rnd, "hugo");
+
+ _rnd->setSeed(42); // Kick random number generator
+
+ switch (_gameVariant) {
+ case kGameVariantH1Dos:
+ _episode = "\"Hugo's House of Horrors\"";
+ _picDir = "";
+ break;
+ case kGameVariantH2Dos:
+ _episode = "\"Hugo 2: Whodunit?\"";
+ _picDir = "hugo2/";
+ break;
+ case kGameVariantH3Dos:
+ _episode = "\"Hugo III: Jungle of Doom\"";
+ _picDir = "hugo3/";
+ break;
+ case kGameVariantH1Win:
+ _episode = "\"Hugo's Horrific Adventure\"";
+ _picDir = "";
+ break;
+ case kGameVariantH2Win:
+ _episode = "\"Hugo's Mystery Adventure\"";
+ _picDir = "hugo2/";
+ break;
+ case kGameVariantH3Win:
+ _episode = "\"Hugo's Amazon Adventure\"";
+ _picDir = "hugo3/";
+ break;
+ default:
+ error("Unknown game");
+ }
+}
+
+/**
+* Restore all resources before termination
+*/
+void HugoEngine::shutdown() {
+ debugC(1, kDebugEngine, "shutdown");
+
+ _file->closeDatabaseFiles();
+ _object->freeObjects();
+}
+
+void HugoEngine::readObjectImages() {
+ debugC(1, kDebugEngine, "readObjectImages");
+
+ for (int i = 0; i < _numObj; i++)
+ _file->readImage(i, &_object->_objects[i]);
+}
+
+/**
+* Read scenery, overlay files for given screen number
+*/
+void HugoEngine::readScreenFiles(int screenNum) {
+ debugC(1, kDebugEngine, "readScreenFiles(%d)", screenNum);
+
+ _file->readBackground(screenNum); // Scenery file
+ memcpy(_screen->getBackBuffer(), _screen->getFrontBuffer(), sizeof(_screen->getFrontBuffer()));// Make a copy
+ _file->readOverlay(screenNum, _boundary, BOUNDARY); // Boundary file
+ _file->readOverlay(screenNum, _overlay, OVERLAY); // Overlay file
+ _file->readOverlay(screenNum, _ovlBase, OVLBASE); // Overlay base file
+}
+
+/**
+* Return maximum allowed movement (from zero to vx) such that object does
+* not cross a boundary (either background or another object)
+*/
+int HugoEngine::deltaX(int x1, int x2, int vx, int y) {
+// Explanation of algorithm: The boundaries are drawn as contiguous
+// lines 1 pixel wide. Since DX,DY are not necessarily 1, we must
+// detect boundary crossing. If vx positive, examine each pixel from
+// x1 old to x2 new, else x2 old to x1 new, both at the y2 line.
+// If vx zero, no need to check. If vy non-zero then examine each
+// pixel on the line segment x1 to x2 from y old to y new.
+// Fix from Hugo I v1.5:
+// Note the diff is munged in the return statement to cater for a special
+// cases arising from differences in image widths from one sequence to
+// another. The problem occurs reversing direction at a wall where the
+// new image intersects before the object can move away. This is cured
+// by comparing the intersection with half the object width pos. If the
+// intersection is in the other half wrt the intended direction, use the
+// desired vx, else use the computed delta. i.e. believe the desired vx
+
+ debugC(3, kDebugEngine, "deltaX(%d, %d, %d, %d)", x1, x2, vx, y);
+
+ if (vx == 0)
+ return 0 ; // Object stationary
+
+ y *= XBYTES; // Offset into boundary file
+ if (vx > 0) {
+ // Moving to right
+ for (int i = x1 >> 3; i <= (x2 + vx) >> 3; i++) {// Search by byte
+ int b = Utils::firstBit((byte)(_boundary[y + i] | _objBound[y + i]));
+ if (b < 8) { // b is index or 8
+ // Compute x of boundary and test if intersection
+ b += i << 3;
+ if ((b >= x1) && (b <= x2 + vx))
+ return (b < x1 + ((x2 - x1) >> 1)) ? vx : b - x2 - 1; // return dx
+ }
+ }
+ } else {
+ // Moving to left
+ for (int i = x2 >> 3; i >= (x1 + vx) >> 3; i--) {// Search by byte
+ int b = Utils::lastBit((byte)(_boundary[y + i] | _objBound[y + i]));
+ if (b < 8) { // b is index or 8
+ // Compute x of boundary and test if intersection
+ b += i << 3;
+ if ((b >= x1 + vx) && (b <= x2))
+ return (b > x1 + ((x2 - x1) >> 1)) ? vx : b - x1 + 1; // return dx
+ }
+ }
+ }
+ return vx;
+}
+
+/**
+* Similar to Delta_x, but for movement in y direction. Special case of
+* bytes at end of line segment; must only count boundary bits falling on
+* line segment.
+*/
+int HugoEngine::deltaY(int x1, int x2, int vy, int y) {
+ debugC(3, kDebugEngine, "deltaY(%d, %d, %d, %d)", x1, x2, vy, y);
+
+ if (vy == 0)
+ return 0; // Object stationary
+
+ int inc = (vy > 0) ? 1 : -1;
+ for (int j = y + inc; j != (y + vy + inc); j += inc) { //Search by byte
+ for (int i = x1 >> 3; i <= x2 >> 3; i++) {
+ int b = _boundary[j * XBYTES + i] | _objBound[j * XBYTES + i];
+ if (b != 0) { // Any bit set
+ // Make sure boundary bits fall on line segment
+ if (i == (x2 >> 3)) // Adjust right end
+ b &= 0xff << ((i << 3) + 7 - x2);
+ else if (i == (x1 >> 3)) // Adjust left end
+ b &= 0xff >> (x1 - (i << 3));
+ if (b)
+ return j - y - inc;
+ }
+ }
+ }
+ return vy;
+}
+
+/**
+* Store a horizontal line segment in the object boundary file
+*/
+void HugoEngine::storeBoundary(int x1, int x2, int y) {
+ debugC(5, kDebugEngine, "storeBoundary(%d, %d, %d)", x1, x2, y);
+
+ for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line
+ byte *b = &_objBound[y * XBYTES + i]; // get boundary byte
+ if (i == x2 >> 3) // Adjust right end
+ *b |= 0xff << ((i << 3) + 7 - x2);
+ else if (i == x1 >> 3) // Adjust left end
+ *b |= 0xff >> (x1 - (i << 3));
+ else
+ *b = 0xff;
+ }
+}
+
+/**
+* Clear a horizontal line segment in the object boundary file
+*/
+void HugoEngine::clearBoundary(int x1, int x2, int y) {
+ debugC(5, kDebugEngine, "clearBoundary(%d, %d, %d)", x1, x2, y);
+
+ for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line
+ byte *b = &_objBound[y * XBYTES + i]; // get boundary byte
+ if (i == x2 >> 3) // Adjust right end
+ *b &= ~(0xff << ((i << 3) + 7 - x2));
+ else if (i == x1 >> 3) // Adjust left end
+ *b &= ~(0xff >> (x1 - (i << 3)));
+ else
+ *b = 0;
+ }
+}
+
+/**
+* Search background command list for this screen for supplied object.
+* Return first associated verb (not "look") or 0 if none found.
+*/
+char *HugoEngine::useBG(char *name) {
+ debugC(1, kDebugEngine, "useBG(%s)", name);
+
+ objectList_t p = _backgroundObjects[*_screen_p];
+ for (int i = 0; *_arrayVerbs[p[i].verbIndex]; i++) {
+ if ((name == _arrayNouns[p[i].nounIndex][0] &&
+ p[i].verbIndex != _look) &&
+ ((p[i].roomState == DONT_CARE) || (p[i].roomState == _screenStates[*_screen_p])))
+ return _arrayVerbs[p[i].verbIndex][0];
+ }
+
+ return 0;
+}
+
+/**
+* Add action lists for this screen to event queue
+*/
+void HugoEngine::screenActions(int screenNum) {
+ debugC(1, kDebugEngine, "screenActions(%d)", screenNum);
+
+ uint16 *screenAct = _screenActs[screenNum];
+ if (screenAct) {
+ for (int i = 0; screenAct[i]; i++)
+ _scheduler->insertActionList(screenAct[i]);
+ }
+}
+
+/**
+* Set the new screen number into the hero object and any carried objects
+*/
+void HugoEngine::setNewScreen(int screenNum) {
+ debugC(1, kDebugEngine, "setNewScreen(%d)", screenNum);
+
+ *_screen_p = screenNum; // HERO object
+ for (int i = HERO + 1; i < _numObj; i++) { // Any others
+ if (_object->isCarried(i)) // being carried
+ _object->_objects[i].screenIndex = screenNum;
+ }
+}
+
+/**
+* An object has collided with a boundary. See if any actions are required
+*/
+void HugoEngine::boundaryCollision(object_t *obj) {
+ debugC(1, kDebugEngine, "boundaryCollision");
+
+ if (obj == _hero) {
+ // Hotspots only relevant to HERO
+ int x;
+ if (obj->vx > 0)
+ x = obj->x + obj->currImagePtr->x2;
+ else
+ x = obj->x + obj->currImagePtr->x1;
+ int y = obj->y + obj->currImagePtr->y2;
+
+ for (int i = 0; _hotspots[i].screenIndex >= 0; i++) {
+ hotspot_t *hotspot = &_hotspots[i];
+ if (hotspot->screenIndex == obj->screenIndex)
+ if ((x >= hotspot->x1) && (x <= hotspot->x2) && (y >= hotspot->y1) && (y <= hotspot->y2)) {
+ _scheduler->insertActionList(hotspot->actIndex);
+ break;
+ }
+ }
+ } else {
+ // Check whether an object collided with HERO
+ int dx = _hero->x + _hero->currImagePtr->x1 - obj->x - obj->currImagePtr->x1;
+ int dy = _hero->y + _hero->currImagePtr->y2 - obj->y - obj->currImagePtr->y2;
+ // If object's radius is infinity, use a closer value
+ int8 radius = obj->radius;
+ if (radius < 0)
+ radius = DX * 2;
+ if ((abs(dx) <= radius) && (abs(dy) <= radius))
+ _scheduler->insertActionList(obj->actIndex);
+ }
+}
+
+/**
+* Add up all the object values and all the bonus points
+*/
+void HugoEngine::calcMaxScore() {
+ debugC(1, kDebugEngine, "calcMaxScore");
+
+ for (int i = 0; i < _numObj; i++)
+ _maxscore += _object->_objects[i].objValue;
+
+ for (int i = 0; i < _numBonuses; i++)
+ _maxscore += _points[i].score;
+}
+
+/**
+* Exit game, advertise trilogy, show copyright
+*/
+void HugoEngine::endGame() {
+ debugC(1, kDebugEngine, "endGame");
+
+ if (!_boot.registered)
+ Utils::Box(BOX_ANY, "%s", _textEngine[kEsAdvertise]);
+ Utils::Box(BOX_ANY, "%s\n%s", _episode, COPYRIGHT);
+ _status.viewState = V_EXIT;
+}
+
} // End of namespace Hugo
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index 1d3657b473..4cfd9b0485 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -28,19 +28,37 @@
#include "engines/engine.h"
#include "common/file.h"
+#include "hugo/console.h"
// This include is here temporarily while the engine is being refactored.
#include "hugo/game.h"
-#define HUGO_DAT_VER_MAJ 0 // 1 byte
-#define HUGO_DAT_VER_MIN 25 // 1 byte
-#define DATAALIGNMENT 4
+#define HUGO_DAT_VER_MAJ 0 // 1 byte
+#define HUGO_DAT_VER_MIN 27 // 1 byte
+#define DATAALIGNMENT 4
+#define EDGE 10 // Closest object can get to edge of screen
+#define EDGE2 (EDGE * 2) // Push object further back on edge collision
+#define SHIFT 8 // Place hero this far inside bounding box
namespace Common {
class RandomSource;
}
+/**
+ * This is the namespace of the Hugo engine.
+ *
+ * Status of this engine: ???
+ *
+ * Games using this engine:
+ * - Hugo's House of Horror
+ * - Whodunit?
+ * - Jungle of Doom
+ * - Hugo's Horrific Adventure
+ * - Hugo's Mystery Adventure
+ * - Hugo's Amazon Adventure
+ */
namespace Hugo {
+
enum GameType {
kGameTypeNone = 0,
kGameTypeHugo1,
@@ -58,20 +76,25 @@ enum GameVariant {
};
enum HugoDebugChannels {
- kDebugSchedule = 1 << 0,
- kDebugEngine = 1 << 1,
- kDebugDisplay = 1 << 2,
- kDebugMouse = 1 << 3,
- kDebugParser = 1 << 4,
- kDebugFile = 1 << 5,
- kDebugRoute = 1 << 6,
- kDebugInventory = 1 << 7
+ kDebugSchedule = 1 << 0,
+ kDebugEngine = 1 << 1,
+ kDebugDisplay = 1 << 2,
+ kDebugMouse = 1 << 3,
+ kDebugParser = 1 << 4,
+ kDebugFile = 1 << 5,
+ kDebugRoute = 1 << 6,
+ kDebugInventory = 1 << 7,
+ kDebugObject = 1 << 8
};
enum HugoGameFeatures {
GF_PACKED = (1 << 0) // Database
};
+// Strings used by the engine
+enum seqTextEngine {
+ kEsAdvertise = 0
+};
struct HugoGameDescription;
class FileManager;
@@ -83,6 +106,8 @@ class Parser;
class Route;
class SoundHandler;
class IntroHandler;
+class ObjectHandler;
+
class HugoEngine : public Engine {
public:
@@ -93,21 +118,18 @@ public:
byte _gameVariant;
byte _maxInvent;
byte _numBonuses;
- byte _soundSilence;
- byte _soundTest;
- byte _tunesNbr;
+ int8 _soundSilence;
+ int8 _soundTest;
+ int8 _tunesNbr;
uint16 _numScreens;
object_t *_hero;
byte *_screen_p;
byte _heroImage;
- byte *_palette;
byte *_introX;
byte *_introY;
byte *_screenStates;
- byte *_arrayFont[3];
- int16 _arrayFontSize[3];
char **_textData;
char **_stringtData;
char **_screenNames;
@@ -123,19 +145,22 @@ public:
hotspot_t *_hotspots;
int16 *_invent;
uses_t *_uses;
+ uint16 _usesSize;
background_t *_catchallList;
background_t **_backgroundObjects;
+ uint16 _backgroundObjectsSize;
point_t *_points;
cmd **_cmdList;
+ uint16 _cmdListSize;
uint16 **_screenActs;
- object_t *_objects;
- act **_actListArr;
+ uint16 _screenActsSize;
int16 *_defltTunes;
uint16 _look;
uint16 _take;
uint16 _drop;
uint16 _numObj;
- uint16 _alNewscrIndex;
+
+ GUI::Debugger *getDebugger() { return _console; }
Common::RandomSource *_rnd;
@@ -160,34 +185,6 @@ public:
return *s_Engine;
}
- FileManager &file() {
- return *_fileManager;
- }
- Scheduler &scheduler() {
- return *_scheduler;
- }
- Screen &screen() {
- return *_screen;
- }
- MouseHandler &mouse() {
- return *_mouseHandler;
- }
- InventoryHandler &inventory() {
- return *_inventoryHandler;
- }
- Parser &parser() {
- return *_parser;
- }
- Route &route() {
- return *_route;
- }
- SoundHandler &sound() {
- return *_soundHandler;
- }
- IntroHandler &intro() {
- return *_introHandler;
- }
-
void initGame(const HugoGameDescription *gd);
void initGamePart(const HugoGameDescription *gd);
bool loadHugoDat();
@@ -199,23 +196,21 @@ public:
return _mouseY;
}
- void initStatus();
- void readObjectImages();
- void readUIFImages();
- void updateImages();
- void moveObjects();
- void useObject(int16 objId);
- bool findObjectSpace(object_t *obj, int16 *destx, int16 *desty);
- int16 findObject(uint16 x, uint16 y);
- void lookObject(object_t *obj);
- void storeBoundary(int x1, int x2, int y);
+ void boundaryCollision(object_t *obj);
void clearBoundary(int x1, int x2, int y);
void endGame();
+ void initStatus();
+ void readObjectImages();
void readScreenFiles(int screen);
- void setNewScreen(int screen);
- void initNewScreenDisplay();
void screenActions(int screen);
+ void setNewScreen(int screen);
void shutdown();
+ void storeBoundary(int x1, int x2, int y);
+
+ char *useBG(char *name);
+
+ int deltaX(int x1, int x2, int vx, int y);
+ int deltaY(int x1, int x2, int vy, int y);
overlay_t &getBoundaryOverlay() {
return _boundary;
@@ -229,11 +224,9 @@ public:
overlay_t &getFirstOverlay() {
return _overlay;
}
-
status_t &getGameStatus() {
return _status;
}
-
int getScore() const {
return _score;
}
@@ -253,6 +246,17 @@ public:
return _introXSize;
}
+ FileManager *_file;
+ Scheduler *_scheduler;
+ Screen *_screen;
+ MouseHandler *_mouse;
+ InventoryHandler *_inventory;
+ Parser *_parser;
+ Route *_route;
+ SoundHandler *_sound;
+ IntroHandler *_intro;
+ ObjectHandler *_object;
+
protected:
// Engine APIs
@@ -261,12 +265,13 @@ protected:
private:
int _mouseX;
int _mouseY;
- byte _paletteSize;
byte _introXSize;
status_t _status; // Game status structure
static HugoEngine *s_Engine;
+ HugoConsole *_console;
+
// The following are bit plane display overlays which mark travel boundaries,
// foreground stationary objects and baselines for those objects (used to
// determine foreground/background wrt moving objects)
@@ -274,27 +279,17 @@ private:
// Vinterstum: These shouldn't be static, but we get weird pathfinding issues (and Valgrind warnings) without.
// Needs more investigation. Alignment issues?
- static overlay_t _boundary; // Boundary overlay file
- static overlay_t _overlay; // First overlay file
- static overlay_t _ovlBase; // First overlay base file
- static overlay_t _objBound; // Boundary file marks object baselines
+ static overlay_t _boundary; // Boundary overlay file
+ static overlay_t _overlay; // First overlay file
+ static overlay_t _ovlBase; // First overlay base file
+ static overlay_t _objBound; // Boundary file marks object baselines
GameType _gameType;
Common::Platform _platform;
bool _packedFl;
- FileManager *_fileManager;
- Scheduler *_scheduler;
- Screen *_screen;
- MouseHandler *_mouseHandler;
- InventoryHandler *_inventoryHandler;
- Parser *_parser;
- Route *_route;
- SoundHandler *_soundHandler;
- IntroHandler *_introHandler;
-
- int _score; // Holds current score
- int _maxscore; // Holds maximum score
+ int _score; // Holds current score
+ int _maxscore; // Holds maximum score
char **loadTextsVariante(Common::File &in, uint16 *arraySize);
char ***loadTextsArray(Common::File &in);
@@ -305,19 +300,10 @@ private:
void initPlaylist(bool playlist[MAX_TUNES]);
void initConfig(inst_t action);
void initialize();
- int deltaX(int x1, int x2, int vx, int y);
- int deltaY(int x1, int x2, int vy, int y);
- void processMaze();
- //int y2comp (const void *a, const void *b);
- char *useBG(char *name);
- void freeObjects();
- void boundaryCollision(object_t *obj);
void calcMaxScore();
void initMachine();
void runMachine();
- static int y2comp(const void *a, const void *b);
-
};
} // End of namespace Hugo
diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp
index b818bef027..d63a979fe1 100644
--- a/engines/hugo/intro.cpp
+++ b/engines/hugo/intro.cpp
@@ -37,7 +37,7 @@
namespace Hugo {
-IntroHandler::IntroHandler(HugoEngine &vm) : _vm(vm) {
+IntroHandler::IntroHandler(HugoEngine *vm) : _vm(vm) {
}
IntroHandler::~IntroHandler() {
diff --git a/engines/hugo/intro.h b/engines/hugo/intro.h
index f8f1f95514..f1de01e609 100644
--- a/engines/hugo/intro.h
+++ b/engines/hugo/intro.h
@@ -43,7 +43,7 @@ enum seqTextIntro {
class IntroHandler {
public:
- IntroHandler(HugoEngine &vm);
+ IntroHandler(HugoEngine *vm);
virtual ~IntroHandler();
virtual void preNewGame() = 0;
@@ -51,13 +51,13 @@ public:
virtual bool introPlay() = 0;
protected:
- HugoEngine &_vm;
+ HugoEngine *_vm;
int16 introTicks; // Count calls to introPlay()
};
class intro_v1w : public IntroHandler {
public:
- intro_v1w(HugoEngine &vm);
+ intro_v1w(HugoEngine *vm);
~intro_v1w();
void preNewGame();
@@ -67,7 +67,7 @@ public:
class intro_v1d : public IntroHandler {
public:
- intro_v1d(HugoEngine &vm);
+ intro_v1d(HugoEngine *vm);
~intro_v1d();
void preNewGame();
@@ -77,7 +77,7 @@ public:
class intro_v2w : public IntroHandler {
public:
- intro_v2w(HugoEngine &vm);
+ intro_v2w(HugoEngine *vm);
~intro_v2w();
void preNewGame();
@@ -87,7 +87,7 @@ public:
class intro_v2d : public IntroHandler {
public:
- intro_v2d(HugoEngine &vm);
+ intro_v2d(HugoEngine *vm);
~intro_v2d();
void preNewGame();
@@ -97,7 +97,7 @@ public:
class intro_v3w : public IntroHandler {
public:
- intro_v3w(HugoEngine &vm);
+ intro_v3w(HugoEngine *vm);
~intro_v3w();
void preNewGame();
@@ -107,7 +107,7 @@ public:
class intro_v3d : public IntroHandler {
public:
- intro_v3d(HugoEngine &vm);
+ intro_v3d(HugoEngine *vm);
~intro_v3d();
void preNewGame();
diff --git a/engines/hugo/intro_v1d.cpp b/engines/hugo/intro_v1d.cpp
index 0e3067f0e9..61626e8172 100644
--- a/engines/hugo/intro_v1d.cpp
+++ b/engines/hugo/intro_v1d.cpp
@@ -37,7 +37,7 @@
#include "hugo/display.h"
namespace Hugo {
-intro_v1d::intro_v1d(HugoEngine &vm) : IntroHandler(vm) {
+intro_v1d::intro_v1d(HugoEngine *vm) : IntroHandler(vm) {
}
intro_v1d::~intro_v1d() {
@@ -52,116 +52,116 @@ void intro_v1d::introInit() {
bool intro_v1d::introPlay() {
static int state = 0;
- byte introSize = _vm.getIntroSize();
+ byte introSize = _vm->getIntroSize();
if (introTicks < introSize) {
switch (state++) {
case 0:
- _vm.screen().drawRectangle(true, 0, 0, 319, 199, _TMAGENTA);
- _vm.screen().drawRectangle(true, 10, 10, 309, 189, _TBLACK);
+ _vm->_screen->drawRectangle(true, 0, 0, 319, 199, _TMAGENTA);
+ _vm->_screen->drawRectangle(true, 10, 10, 309, 189, _TBLACK);
break;
case 1:
- _vm.screen().drawShape(20, 92,_TLIGHTMAGENTA,_TMAGENTA);
- _vm.screen().drawShape(250,92,_TLIGHTMAGENTA,_TMAGENTA);
+ _vm->_screen->drawShape(20, 92,_TLIGHTMAGENTA,_TMAGENTA);
+ _vm->_screen->drawShape(250,92,_TLIGHTMAGENTA,_TMAGENTA);
// HACK: use of TROMAN, size 10-5
- _vm.screen().loadFont(0);
+ _vm->_screen->loadFont(0);
char buffer[80];
if (_boot.registered)
strcpy(buffer, "Registered Version");
else
strcpy(buffer, "Shareware Version");
- _vm.screen().writeStr(CENTER, 163, buffer, _TLIGHTMAGENTA);
- _vm.screen().writeStr(CENTER, 176, COPYRIGHT, _TLIGHTMAGENTA);
+ _vm->_screen->writeStr(CENTER, 163, buffer, _TLIGHTMAGENTA);
+ _vm->_screen->writeStr(CENTER, 176, COPYRIGHT, _TLIGHTMAGENTA);
if (scumm_stricmp(_boot.distrib, "David P. Gray")) {
sprintf(buffer, "Distributed by %s.", _boot.distrib);
- _vm.screen().writeStr(CENTER, 75, buffer, _TMAGENTA);
+ _vm->_screen->writeStr(CENTER, 75, buffer, _TMAGENTA);
}
// HACK: use of SCRIPT size 24-16
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "Hugo's");
- _vm.screen().writeStr(CENTER, 20, buffer, _TMAGENTA);
+ _vm->_screen->writeStr(CENTER, 20, buffer, _TMAGENTA);
// HACK: use of TROMAN, size 30-24
strcpy(buffer, "House of Horrors !");
- _vm.screen().writeStr(CENTER, 50, buffer, _TLIGHTMAGENTA);
+ _vm->_screen->writeStr(CENTER, 50, buffer, _TLIGHTMAGENTA);
break;
case 2:
- _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK);
+ _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK);
// HACK: use of TROMAN, size 16-9
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "S t a r r i n g :");
- _vm.screen().writeStr(CENTER, 95, buffer, _TMAGENTA);
+ _vm->_screen->writeStr(CENTER, 95, buffer, _TMAGENTA);
break;
case 3:
// HACK: use of TROMAN size 20-9
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "Hugo !");
- _vm.screen().writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA);
+ _vm->_screen->writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA);
break;
case 4:
- _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK);
+ _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK);
// HACK: use of TROMAN size 16-9
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "P r o d u c e d b y :");
- _vm.screen().writeStr(CENTER, 95, buffer, _TMAGENTA);
+ _vm->_screen->writeStr(CENTER, 95, buffer, _TMAGENTA);
break;
case 5:
// HACK: use of TROMAN size 16-9
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "David P Gray !");
- _vm.screen().writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA);
+ _vm->_screen->writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA);
break;
case 6:
- _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK);
+ _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK);
// HACK: use of TROMAN size 16-9
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "D i r e c t e d b y :");
- _vm.screen().writeStr(CENTER, 95, buffer, _TMAGENTA);
+ _vm->_screen->writeStr(CENTER, 95, buffer, _TMAGENTA);
break;
case 7:
// HACK: use of TROMAN size 16-9
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "David P Gray !");
- _vm.screen().writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA);
+ _vm->_screen->writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA);
break;
case 8:
- _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK);
+ _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK);
// HACK: use of TROMAN size 16-9
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "M u s i c b y :");
- _vm.screen().writeStr(CENTER, 95, buffer, _TMAGENTA);
+ _vm->_screen->writeStr(CENTER, 95, buffer, _TMAGENTA);
break;
case 9:
// HACK: use of TROMAN size 16-9
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "David P Gray !");
- _vm.screen().writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA);
+ _vm->_screen->writeStr(CENTER, 115, buffer, _TLIGHTMAGENTA);
break;
case 10:
- _vm.screen().drawRectangle(true, 82, 92, 237, 138, _TBLACK);
+ _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK);
// HACK: use of TROMAN size 20-14
- _vm.screen().loadFont(2);
+ _vm->_screen->loadFont(2);
strcpy(buffer, "E n j o y !");
- _vm.screen().writeStr(CENTER, 100, buffer, _TLIGHTMAGENTA);
+ _vm->_screen->writeStr(CENTER, 100, buffer, _TLIGHTMAGENTA);
break;
}
- _vm.screen().displayBackground();
+ _vm->_screen->displayBackground();
g_system->updateScreen();
g_system->delayMillis(1000);
}
diff --git a/engines/hugo/intro_v1w.cpp b/engines/hugo/intro_v1w.cpp
index 38921fd3e4..bdea2837b1 100644
--- a/engines/hugo/intro_v1w.cpp
+++ b/engines/hugo/intro_v1w.cpp
@@ -39,16 +39,18 @@
namespace Hugo {
-intro_v1w::intro_v1w(HugoEngine &vm) : IntroHandler(vm) {
+intro_v1w::intro_v1w(HugoEngine *vm) : IntroHandler(vm) {
}
intro_v1w::~intro_v1w() {
}
+/**
+* Auto-start a new game
+*/
void intro_v1w::preNewGame() {
- // Auto-start a new game
- _vm.file().restoreGame(-1);
- _vm.getGameStatus().viewState = V_INTROINIT;
+ _vm->_file->restoreGame(-1);
+ _vm->getGameStatus().viewState = V_INTROINIT;
}
void intro_v1w::introInit() {
diff --git a/engines/hugo/intro_v2d.cpp b/engines/hugo/intro_v2d.cpp
index bfae11b77e..0c9f85d1ea 100644
--- a/engines/hugo/intro_v2d.cpp
+++ b/engines/hugo/intro_v2d.cpp
@@ -39,7 +39,7 @@
namespace Hugo {
-intro_v2d::intro_v2d(HugoEngine &vm) : IntroHandler(vm) {
+intro_v2d::intro_v2d(HugoEngine *vm) : IntroHandler(vm) {
}
intro_v2d::~intro_v2d() {
@@ -49,8 +49,8 @@ void intro_v2d::preNewGame() {
}
void intro_v2d::introInit() {
- _vm.screen().loadFont(0);
- _vm.file().readBackground(_vm._numScreens - 1); // display splash screen
+ _vm->_screen->loadFont(0);
+ _vm->_file->readBackground(_vm->_numScreens - 1); // display splash screen
char buffer[128];
@@ -58,14 +58,14 @@ void intro_v2d::introInit() {
sprintf(buffer, "%s Registered Version", COPYRIGHT);
else
sprintf(buffer, "%s Shareware Version", COPYRIGHT);
- _vm.screen().writeStr(CENTER, 186, buffer, _TLIGHTRED);
+ _vm->_screen->writeStr(CENTER, 186, buffer, _TLIGHTRED);
if (scumm_stricmp(_boot.distrib, "David P. Gray")) {
sprintf(buffer, "Distributed by %s.", _boot.distrib);
- _vm.screen().writeStr(CENTER, 1, buffer, _TLIGHTRED);
+ _vm->_screen->writeStr(CENTER, 1, buffer, _TLIGHTRED);
}
- _vm.screen().displayBackground();
+ _vm->_screen->displayBackground();
g_system->updateScreen();
g_system->delayMillis(5000);
}
diff --git a/engines/hugo/intro_v2w.cpp b/engines/hugo/intro_v2w.cpp
index f68761eac9..414846bfc7 100644
--- a/engines/hugo/intro_v2w.cpp
+++ b/engines/hugo/intro_v2w.cpp
@@ -38,7 +38,7 @@
namespace Hugo {
-intro_v2w::intro_v2w(HugoEngine &vm) : IntroHandler(vm) {
+intro_v2w::intro_v2w(HugoEngine *vm) : IntroHandler(vm) {
}
intro_v2w::~intro_v2w() {
diff --git a/engines/hugo/intro_v3d.cpp b/engines/hugo/intro_v3d.cpp
index 3dd2a58d8b..87dca946f5 100644
--- a/engines/hugo/intro_v3d.cpp
+++ b/engines/hugo/intro_v3d.cpp
@@ -40,7 +40,7 @@
namespace Hugo {
-intro_v3d::intro_v3d(HugoEngine &vm) : IntroHandler(vm) {
+intro_v3d::intro_v3d(HugoEngine *vm) : IntroHandler(vm) {
}
intro_v3d::~intro_v3d() {
@@ -50,8 +50,8 @@ void intro_v3d::preNewGame() {
}
void intro_v3d::introInit() {
- _vm.screen().loadFont(0);
- _vm.file().readBackground(_vm._numScreens - 1); // display splash screen
+ _vm->_screen->loadFont(0);
+ _vm->_file->readBackground(_vm->_numScreens - 1); // display splash screen
char buffer[128];
if (_boot.registered)
@@ -59,43 +59,45 @@ void intro_v3d::introInit() {
else
sprintf(buffer,"%s Shareware Version", COPYRIGHT);
- _vm.screen().writeStr(CENTER, 190, buffer, _TBROWN);
+ _vm->_screen->writeStr(CENTER, 190, buffer, _TBROWN);
if (scumm_stricmp(_boot.distrib, "David P. Gray")) {
sprintf(buffer, "Distributed by %s.", _boot.distrib);
- _vm.screen().writeStr(CENTER, 0, buffer, _TBROWN);
+ _vm->_screen->writeStr(CENTER, 0, buffer, _TBROWN);
}
- _vm.screen().displayBackground();
+ _vm->_screen->displayBackground();
g_system->updateScreen();
g_system->delayMillis(5000);
-
- _vm.file().readBackground(22); // display screen MAP_3d
- _vm.screen().displayBackground();
+
+ _vm->_file->readBackground(22); // display screen MAP_3d
+ _vm->_screen->displayBackground();
introTicks = 0;
}
+/**
+* Hugo 3 - Preamble screen before going into game. Draws path of Hugo's plane.
+* Called every tick. Returns TRUE when complete
+*/
bool intro_v3d::introPlay() {
- byte introSize = _vm.getIntroSize();
+ byte introSize = _vm->getIntroSize();
-// Hugo 3 - Preamble screen before going into game. Draws path of Hugo's plane.
-// Called every tick. Returns TRUE when complete
//TODO : Add proper check of story mode
//#if STORY
if (introTicks < introSize) {
- _vm.screen().writeStr(_vm._introX[introTicks], _vm._introY[introTicks] - DIBOFF_Y, "x", _TBRIGHTWHITE);
- _vm.screen().displayBackground();
+ _vm->_screen->writeStr(_vm->_introX[introTicks], _vm->_introY[introTicks] - DIBOFF_Y, "x", _TBRIGHTWHITE);
+ _vm->_screen->displayBackground();
// Text boxes at various times
switch (introTicks) {
case 4:
- Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro1]);
+ Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro1]);
break;
case 9:
- Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro2]);
+ Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro2]);
break;
case 35:
- Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro3]);
+ Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro3]);
break;
}
}
diff --git a/engines/hugo/intro_v3w.cpp b/engines/hugo/intro_v3w.cpp
index 924fa46805..06fe1814fe 100644
--- a/engines/hugo/intro_v3w.cpp
+++ b/engines/hugo/intro_v3w.cpp
@@ -40,7 +40,7 @@
namespace Hugo {
-intro_v3w::intro_v3w(HugoEngine &vm) : IntroHandler(vm) {
+intro_v3w::intro_v3w(HugoEngine *vm) : IntroHandler(vm) {
}
intro_v3w::~intro_v3w() {
@@ -49,39 +49,43 @@ intro_v3w::~intro_v3w() {
void intro_v3w::preNewGame() {
}
+/**
+* Hugo 3 - show map and set up for introPlay()
+*/
void intro_v3w::introInit() {
-// Hugo 3 - show map and set up for introPlay()
//#if STORY
- _vm.file().readBackground(22); // display screen MAP_3w
- _vm.screen().displayBackground();
+ _vm->_file->readBackground(22); // display screen MAP_3w
+ _vm->_screen->displayBackground();
introTicks = 0;
- _vm.screen().loadFont(0);
+ _vm->_screen->loadFont(0);
//#endif
}
+/**
+* Hugo 3 - Preamble screen before going into game. Draws path of Hugo's plane.
+* Called every tick. Returns TRUE when complete
+*/
bool intro_v3w::introPlay() {
- byte introSize = _vm.getIntroSize();
+ byte introSize = _vm->getIntroSize();
-// Hugo 3 - Preamble screen before going into game. Draws path of Hugo's plane.
-// Called every tick. Returns TRUE when complete
//TODO : Add proper check of story mode
//#if STORY
if (introTicks < introSize) {
// Scale viewport x_intro,y_intro to screen (offsetting y)
- _vm.screen().writeStr(_vm._introX[introTicks], _vm._introY[introTicks] - DIBOFF_Y, "x", _TBRIGHTWHITE);
- _vm.screen().displayBackground();
+ _vm->_screen->writeStr(_vm->_introX[introTicks], _vm->_introY[introTicks] - DIBOFF_Y, "x", _TBRIGHTWHITE);
+ _vm->_screen->displayBackground();
// Text boxes at various times
switch (introTicks) {
case 4:
- Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro1]);
+ Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro1]);
break;
case 9:
- Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro2]);
+ Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro2]);
break;
case 35:
- Utils::Box(BOX_OK, "%s", _vm._textIntro[kIntro3]);
+ Utils::Box(BOX_OK, "%s", _vm->_textIntro[kIntro3]);
break;
}
}
diff --git a/engines/hugo/inventory.cpp b/engines/hugo/inventory.cpp
index 5046d191c3..74ab32c34f 100644
--- a/engines/hugo/inventory.cpp
+++ b/engines/hugo/inventory.cpp
@@ -40,29 +40,32 @@
#include "hugo/mouse.h"
#include "hugo/inventory.h"
#include "hugo/parser.h"
+#include "hugo/object.h"
namespace Hugo {
#define MAX_DISP (XPIX / INV_DX) // Max icons displayable
-InventoryHandler::InventoryHandler(HugoEngine &vm) : _vm(vm) {
+InventoryHandler::InventoryHandler(HugoEngine *vm) : _vm(vm) {
}
-// Construct the inventory scrollbar in dib_i
-// imageTotNumb is total number of inventory icons
-// displayNumb is number requested for display
-// scrollFl is TRUE if scroll arrows required
-// firstObjId is index of first (scrolled) inventory object to display
+/**
+* Construct the inventory scrollbar in dib_i
+* imageTotNumb is total number of inventory icons
+* displayNumb is number requested for display
+* scrollFl is TRUE if scroll arrows required
+* firstObjId is index of first (scrolled) inventory object to display
+*/
void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, bool scrollFl, int16 firstObjId) {
debugC(1, kDebugInventory, "constructInventory(%d, %d, %d, %d)", imageTotNumb, displayNumb, (scrollFl) ? 0 : 1, firstObjId);
// Clear out icon buffer
- memset(_vm.screen().getIconBuffer(), 0, sizeof(_vm.screen().getIconBuffer()));
+ memset(_vm->_screen->getIconBuffer(), 0, sizeof(_vm->_screen->getIconBuffer()));
// If needed, copy arrows - reduce number of icons displayable
if (scrollFl) { // Display at first and last icon positions
- _vm.screen().moveImage(_vm.screen().getGUIBuffer(), 0, 0, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), 0, 0, XPIX);
- _vm.screen().moveImage(_vm.screen().getGUIBuffer(), INV_DX, 0, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), INV_DX *(MAX_DISP - 1), 0, XPIX);
+ _vm->_screen->moveImage(_vm->_screen->getGUIBuffer(), 0, 0, INV_DX, INV_DY, XPIX, _vm->_screen->getIconBuffer(), 0, 0, XPIX);
+ _vm->_screen->moveImage(_vm->_screen->getGUIBuffer(), INV_DX, 0, INV_DX, INV_DY, XPIX, _vm->_screen->getIconBuffer(), INV_DX *(MAX_DISP - 1), 0, XPIX);
displayNumb = MIN(displayNumb, MAX_DISP - NUM_ARROWS);
} else // No, override first index - we can show 'em all!
firstObjId = 0;
@@ -71,7 +74,7 @@ void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, b
int16 displayed = 0;
int16 carried = 0;
for (int16 i = 0; i < imageTotNumb; i++) {
- if (_vm._objects[_vm._invent[i]].carriedFl) {
+ if (_vm->_object->isCarried(_vm->_invent[i])) {
// Check still room to display and past first scroll index
if (displayed < displayNumb && carried >= firstObjId) {
// Compute source coordinates in dib_u
@@ -80,18 +83,20 @@ void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, b
// Compute dest coordinates in dib_i
int16 ix = ((scrollFl) ? displayed + 1 : displayed) * INV_DX;
- displayed++; // Count number displayed
+ displayed++; // Count number displayed
// Copy the icon
- _vm.screen().moveImage(_vm.screen().getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), ix, 0, XPIX);
+ _vm->_screen->moveImage(_vm->_screen->getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm->_screen->getIconBuffer(), ix, 0, XPIX);
}
carried++; // Count number carried
}
}
}
-// Process required action for inventory
-// Returns objId under cursor (or -1) for INV_GET
+/**
+* Process required action for inventory
+* Returns objId under cursor (or -1) for INV_GET
+*/
int16 InventoryHandler::processInventory(invact_t action, ...) {
debugC(1, kDebugInventory, "processInventory(invact_t action, ...)");
@@ -100,8 +105,8 @@ int16 InventoryHandler::processInventory(invact_t action, ...) {
int16 imageNumb; // Total number of inventory items
int displayNumb; // Total number displayed/carried
// Compute total number and number displayed, i.e. number carried
- for (imageNumb = 0, displayNumb = 0; imageNumb < _vm._maxInvent && _vm._invent[imageNumb] != -1; imageNumb++) {
- if (_vm._objects[_vm._invent[imageNumb]].carriedFl)
+ for (imageNumb = 0, displayNumb = 0; imageNumb < _vm->_maxInvent && _vm->_invent[imageNumb] != -1; imageNumb++) {
+ if (_vm->_object->isCarried(_vm->_invent[imageNumb]))
displayNumb++;
}
@@ -109,7 +114,7 @@ int16 InventoryHandler::processInventory(invact_t action, ...) {
bool scrollFl = displayNumb > MAX_DISP;
va_list marker; // Args used for D_ADD operation
int16 cursorx, cursory; // Current cursor position
- int16 objId = -1; // Return objid under cursor
+ int16 objId = -1; // Return objid under cursor
switch (action) {
case INV_INIT: // Initialize inventory display
@@ -148,8 +153,8 @@ int16 InventoryHandler::processInventory(invact_t action, ...) {
if (objId == -1 && i < displayNumb) {
// Find objid by counting # carried objects == i+1
int16 j;
- for (j = 0, i++; i > 0 && j < _vm._numObj; j++) {
- if (_vm._objects[j].carriedFl) {
+ for (j = 0, i++; i > 0 && j < _vm->_numObj; j++) {
+ if (_vm->_object->isCarried(j)) {
if (--i == 0)
objId = j;
}
@@ -158,15 +163,17 @@ int16 InventoryHandler::processInventory(invact_t action, ...) {
}
break;
}
- return objId; // For the INV_GET action
+ return objId; // For the INV_GET action
}
+/**
+* Process inventory state machine
+*/
void InventoryHandler::runInventory() {
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
debugC(1, kDebugInventory, "runInventory");
-// Process inventory state machine
switch (gameStatus.inventoryState) {
case I_OFF: // Icon bar off screen
break;
@@ -176,15 +183,15 @@ void InventoryHandler::runInventory() {
gameStatus.inventoryHeight = 0;
// Move visible portion to _frontBuffer, restore uncovered portion, display results
- _vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX);
- _vm.screen().moveImage(_vm.screen().getBackBufferBackup(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX, STEP_DY, XPIX, _vm.screen().getFrontBuffer(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX);
- _vm.screen().displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight + STEP_DY);
+ _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm->_screen->getFrontBuffer(), 0, DIBOFF_Y, XPIX);
+ _vm->_screen->moveImage(_vm->_screen->getBackBufferBackup(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX, STEP_DY, XPIX, _vm->_screen->getFrontBuffer(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX);
+ _vm->_screen->displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight + STEP_DY);
if (gameStatus.inventoryHeight == 0) { // Finished moving up?
// Yes, restore dibs and exit back to game state machine
- _vm.screen().moveImage(_vm.screen().getBackBufferBackup(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBuffer(), 0, 0, XPIX);
- _vm.screen().moveImage(_vm.screen().getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getFrontBuffer(), 0, 0, XPIX);
- _vm.updateImages(); // Add objects back into display list for restore
+ _vm->_screen->moveImage(_vm->_screen->getBackBufferBackup(), 0, 0, XPIX, YPIX, XPIX, _vm->_screen->getBackBuffer(), 0, 0, XPIX);
+ _vm->_screen->moveImage(_vm->_screen->getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm->_screen->getFrontBuffer(), 0, 0, XPIX);
+ _vm->_object->updateImages(); // Add objects back into display list for restore
gameStatus.inventoryState = I_OFF;
gameStatus.viewState = V_PLAY;
}
@@ -194,9 +201,9 @@ void InventoryHandler::runInventory() {
// and get any icon/text out of _frontBuffer
if (gameStatus.inventoryHeight == 0) {
processInventory(INV_INIT); // Initialize dib_i
- _vm.screen().displayList(D_RESTORE); // Restore _frontBuffer
- _vm.updateImages(); // Rebuild _frontBuffer without icons/text
- _vm.screen().displayList(D_DISPLAY); // Blit display list to screen
+ _vm->_screen->displayList(D_RESTORE); // Restore _frontBuffer
+ _vm->_object->updateImages(); // Rebuild _frontBuffer without icons/text
+ _vm->_screen->displayList(D_DISPLAY); // Blit display list to screen
}
gameStatus.inventoryHeight += STEP_DY; // Move the icon bar down
@@ -204,8 +211,8 @@ void InventoryHandler::runInventory() {
gameStatus.inventoryHeight = INV_DY;
// Move visible portion to _frontBuffer, display results
- _vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX);
- _vm.screen().displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight);
+ _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm->_screen->getFrontBuffer(), 0, DIBOFF_Y, XPIX);
+ _vm->_screen->displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight);
if (gameStatus.inventoryHeight == INV_DY) { // Finished moving down?
// Yes, prepare view dibs for special inventory display since
@@ -213,17 +220,17 @@ void InventoryHandler::runInventory() {
// 1. Save backing store _backBuffer in temporary dib_c
// 2. Make snapshot of _frontBuffer the new _backBuffer backing store
// 3. Reset the display list
- _vm.screen().moveImage(_vm.screen().getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBufferBackup(), 0, 0, XPIX);
- _vm.screen().moveImage(_vm.screen().getFrontBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBuffer(), 0, 0, XPIX);
- _vm.screen().displayList(D_INIT);
+ _vm->_screen->moveImage(_vm->_screen->getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm->_screen->getBackBufferBackup(), 0, 0, XPIX);
+ _vm->_screen->moveImage(_vm->_screen->getFrontBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm->_screen->getBackBuffer(), 0, 0, XPIX);
+ _vm->_screen->displayList(D_INIT);
gameStatus.inventoryState = I_ACTIVE;
}
break;
case I_ACTIVE: // Inventory active
- _vm.parser().charHandler(); // Still allow commands
- _vm.screen().displayList(D_RESTORE); // Restore previous background
- _vm.mouse().mouseHandler(); // Mouse activity - adds to display list
- _vm.screen().displayList(D_DISPLAY); // Blit the display list to screen
+ _vm->_parser->charHandler(); // Still allow commands
+ _vm->_screen->displayList(D_RESTORE); // Restore previous background
+ _vm->_mouse->mouseHandler(); // Mouse activity - adds to display list
+ _vm->_screen->displayList(D_DISPLAY); // Blit the display list to screen
break;
}
}
diff --git a/engines/hugo/inventory.h b/engines/hugo/inventory.h
index 5cc1af28c2..36fca71a43 100644
--- a/engines/hugo/inventory.h
+++ b/engines/hugo/inventory.h
@@ -40,13 +40,13 @@ namespace Hugo {
class InventoryHandler {
public:
- InventoryHandler(HugoEngine &vm);
+ InventoryHandler(HugoEngine *vm);
int16 processInventory(invact_t action, ...);
void runInventory();
private:
- HugoEngine &_vm;
+ HugoEngine *_vm;
void constructInventory(int16 imageTotNumb, int displayNumb, bool scrollFl, int16 firstObjId);
};
diff --git a/engines/hugo/module.mk b/engines/hugo/module.mk
index b646a3672d..703a70ec1f 100644
--- a/engines/hugo/module.mk
+++ b/engines/hugo/module.mk
@@ -1,11 +1,11 @@
MODULE := engines/hugo
MODULE_OBJS := \
+ console.o \
detection.o \
display.o \
display_v1d.o \
display_v1w.o \
- engine.o \
file.o \
file_v1d.o \
file_v2d.o \
@@ -21,6 +21,11 @@ MODULE_OBJS := \
intro_v3w.o \
inventory.o \
mouse.o \
+ object.o \
+ object_v1d.o \
+ object_v1w.o \
+ object_v2d.o \
+ object_v3d.o \
parser.o \
parser_v1w.o \
parser_v1d.o \
@@ -29,6 +34,8 @@ MODULE_OBJS := \
route.o \
schedule.o \
schedule_v1d.o \
+ schedule_v1w.o \
+ schedule_v2d.o \
schedule_v3d.o \
sound.o \
util.o
diff --git a/engines/hugo/mouse.cpp b/engines/hugo/mouse.cpp
index b305489568..385dce2703 100644
--- a/engines/hugo/mouse.cpp
+++ b/engines/hugo/mouse.cpp
@@ -43,6 +43,7 @@
#include "hugo/inventory.h"
#include "hugo/route.h"
#include "hugo/util.h"
+#include "hugo/object.h"
namespace Hugo {
@@ -59,34 +60,38 @@ enum seqTextMouse {
kMsExit = 1
};
-MouseHandler::MouseHandler(HugoEngine &vm) : _vm(vm) {
+MouseHandler::MouseHandler(HugoEngine *vm) : _vm(vm) {
}
-// Shadow-blit supplied string into dib_a at cx,cy and add to display list
+/**
+* Shadow-blit supplied string into dib_a at cx,cy and add to display list
+*/
void MouseHandler::cursorText(char *buffer, int16 cx, int16 cy, uif_t fontId, int16 color) {
debugC(1, kDebugMouse, "cursorText(%s, %d, %d, %d, %d)", buffer, cx, cy, fontId, color);
- _vm.screen().loadFont(fontId);
+ _vm->_screen->loadFont(fontId);
// Find bounding rect for string
- int16 sdx = _vm.screen().stringLength(buffer);
- int16 sdy = _vm.screen().fontHeight() + 1; // + 1 for shadow
+ int16 sdx = _vm->_screen->stringLength(buffer);
+ int16 sdy = _vm->_screen->fontHeight() + 1; // + 1 for shadow
int16 sx = (cx < XPIX / 2) ? cx + SX_OFF : cx - sdx - SX_OFF / 2;
int16 sy = cy + SY_OFF;
// Display the string and add rect to display list
- _vm.screen().shadowStr(sx, sy, buffer, _TBRIGHTWHITE);
- _vm.screen().displayList(D_ADD, sx, sy, sdx, sdy);
+ _vm->_screen->shadowStr(sx, sy, buffer, _TBRIGHTWHITE);
+ _vm->_screen->displayList(D_ADD, sx, sy, sdx, sdy);
}
-// Find the exit hotspot containing cx, cy.
-// Return hotspot index or -1 if not found.
+/**
+* Find the exit hotspot containing cx, cy.
+* Return hotspot index or -1 if not found.
+*/
int16 MouseHandler::findExit(int16 cx, int16 cy) {
debugC(2, kDebugMouse, "findExit(%d, %d)", cx, cy);
int i = 0;
- for (hotspot_t *hotspot = _vm._hotspots; hotspot->screenIndex >= 0; i++, hotspot++) {
- if (hotspot->screenIndex == *_vm._screen_p) {
+ for (hotspot_t *hotspot = _vm->_hotspots; hotspot->screenIndex >= 0; i++, hotspot++) {
+ if (hotspot->screenIndex == *_vm->_screen_p) {
if (cx >= hotspot->x1 && cx <= hotspot->x2 && cy >= hotspot->y1 && cy <= hotspot->y2)
return i;
}
@@ -94,13 +99,15 @@ int16 MouseHandler::findExit(int16 cx, int16 cy) {
return -1;
}
-// Process a mouse right click at coord cx, cy over object objid
+/**
+* Process a mouse right click at coord cx, cy over object objid
+*/
void MouseHandler::processRightClick(int16 objId, int16 cx, int16 cy) {
debugC(1, kDebugMouse, "Process_rclick(%d, %d, %d)", objId, cx, cy);
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
- if (gameStatus.storyModeFl || _vm._hero->pathType == QUIET) // Make sure user has control
+ if (gameStatus.storyModeFl || _vm->_hero->pathType == QUIET) // Make sure user has control
return;
bool foundFl = false; // TRUE if route found to object
@@ -111,79 +118,80 @@ void MouseHandler::processRightClick(int16 objId, int16 cx, int16 cy) {
else if (gameStatus.inventoryObjId == objId)
gameStatus.inventoryObjId = -1; // Same icon - deselect it
else
- _vm.useObject(objId); // Use status.objid on object
+ _vm->_object->useObject(objId); // Use status.objid on object
} else { // Clicked over viewport object
- object_t *obj = &_vm._objects[objId];
+ object_t *obj = &_vm->_object->_objects[objId];
int16 x, y;
switch (obj->viewx) { // Where to walk to
case -1: // Walk to object position
- if (_vm.findObjectSpace(obj, &x, &y))
- foundFl = _vm.route().startRoute(GO_GET, objId, x, y);
+ if (_vm->_object->findObjectSpace(obj, &x, &y))
+ foundFl = _vm->_route->startRoute(GO_GET, objId, x, y);
if (!foundFl) // Can't get there, try to use from here
- _vm.useObject(objId);
+ _vm->_object->useObject(objId);
break;
case 0: // Immediate use
- _vm.useObject(objId); // Pick up or use object
+ _vm->_object->useObject(objId); // Pick up or use object
break;
default: // Walk to view point if possible
- if (!_vm.route().startRoute(GO_GET, objId, obj->viewx, obj->viewy)) {
- if (_vm._hero->cycling == INVISIBLE)// If invisible do
- _vm.useObject(objId); // immediate use
+ if (!_vm->_route->startRoute(GO_GET, objId, obj->viewx, obj->viewy)) {
+ if (_vm->_hero->cycling == INVISIBLE)// If invisible do
+ _vm->_object->useObject(objId); // immediate use
else
- Utils::Box(BOX_ANY, "%s", _vm._textMouse[kMsNoWayText]); // Can't get there
+ Utils::Box(BOX_ANY, "%s", _vm->_textMouse[kMsNoWayText]); // Can't get there
}
break;
}
}
}
-// Process a left mouse click over:
-// 1. An icon - show description
-// 2. An object - walk to and show description
-// 3. An icon scroll arrow - scroll the iconbar
-// 4. Nothing - attempt to walk there
-// 5. Exit - walk to exit hotspot
+/** Process a left mouse click over:
+* 1. An icon - show description
+* 2. An object - walk to and show description
+* 3. An icon scroll arrow - scroll the iconbar
+* 4. Nothing - attempt to walk there
+* 5. Exit - walk to exit hotspot
+*/
void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) {
debugC(1, kDebugMouse, "Process_lclick(%d, %d, %d)", objId, cx, cy);
int16 i, x, y;
object_t *obj;
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
- if (gameStatus.storyModeFl || _vm._hero->pathType == QUIET) // Make sure user has control
+ if (gameStatus.storyModeFl || _vm->_hero->pathType == QUIET) // Make sure user has control
return;
switch (objId) {
case -1: // Empty space - attempt to walk there
- _vm.route().startRoute(GO_SPACE, 0, cx, cy);
+ _vm->_route->startRoute(GO_SPACE, 0, cx, cy);
break;
case LEFT_ARROW: // A scroll arrow - scroll the iconbar
case RIGHT_ARROW:
// Scroll the iconbar and display results
- _vm.inventory().processInventory((objId == LEFT_ARROW) ? INV_LEFT : INV_RIGHT);
- _vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX);
- _vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm.screen().getBackBuffer(), 0, DIBOFF_Y, XPIX);
- _vm.screen().displayList(D_ADD, 0, DIBOFF_Y, XPIX, INV_DY);
+ _vm->_inventory->processInventory((objId == LEFT_ARROW) ? INV_LEFT : INV_RIGHT);
+ _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm->_screen->getFrontBuffer(), 0, DIBOFF_Y, XPIX);
+ _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm->_screen->getBackBuffer(), 0, DIBOFF_Y, XPIX);
+ _vm->_screen->displayList(D_ADD, 0, DIBOFF_Y, XPIX, INV_DY);
break;
case EXIT_HOTSPOT: // Walk to exit hotspot
i = findExit(cx, cy);
- x = _vm._hotspots[i].viewx;
- y = _vm._hotspots[i].viewy;
+ x = _vm->_hotspots[i].viewx;
+ y = _vm->_hotspots[i].viewy;
if (x >= 0) { // Hotspot refers to an exit
// Special case of immediate exit
if (gameStatus.jumpExitFl) {
// Get rid of iconbar if necessary
if (gameStatus.inventoryState != I_OFF)
gameStatus.inventoryState = I_UP;
- _vm.scheduler().insertActionList(_vm._hotspots[i].actIndex);
+ _vm->_scheduler->insertActionList(_vm->_hotspots[i].actIndex);
} else { // Set up route to exit spot
- if (_vm._hotspots[i].direction == Common::KEYCODE_RIGHT)
+ if (_vm->_hotspots[i].direction == Common::KEYCODE_RIGHT)
x -= HERO_MAX_WIDTH;
- else if (_vm._hotspots[i].direction == Common::KEYCODE_LEFT)
+ else if (_vm->_hotspots[i].direction == Common::KEYCODE_LEFT)
x += HERO_MAX_WIDTH;
- if (!_vm.route().startRoute(GO_EXIT, i, x, y))
- Utils::Box(BOX_ANY, "%s", _vm._textMouse[kMsNoWayText]); // Can't get there
+ if (!_vm->_route->startRoute(GO_EXIT, i, x, y))
+ Utils::Box(BOX_ANY, "%s", _vm->_textMouse[kMsNoWayText]); // Can't get there
}
// Get rid of any attached icon
@@ -191,29 +199,29 @@ void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) {
}
break;
default: // Look at an icon or object
- obj = &_vm._objects[objId];
+ obj = &_vm->_object->_objects[objId];
// Over iconbar - immediate description
if (gameStatus.inventoryState == I_ACTIVE && cy < INV_DY + DIBOFF_Y)
- _vm.lookObject(obj);
+ _vm->_object->lookObject(obj);
else {
bool foundFl = false; // TRUE if route found to object
switch (obj->viewx) { // Clicked over viewport object
case -1: // Walk to object position
- if (_vm.findObjectSpace(obj, &x, &y))
- foundFl = _vm.route().startRoute(GO_LOOK, objId, x, y);
+ if (_vm->_object->findObjectSpace(obj, &x, &y))
+ foundFl = _vm->_route->startRoute(GO_LOOK, objId, x, y);
if (!foundFl) // Can't get there, immediate description
- _vm.lookObject(obj);
+ _vm->_object->lookObject(obj);
break;
case 0: // Immediate description
- _vm.lookObject(obj);
+ _vm->_object->lookObject(obj);
break;
default: // Walk to view point if possible
- if (!_vm.route().startRoute(GO_LOOK, objId, obj->viewx, obj->viewy)) {
- if (_vm._hero->cycling == INVISIBLE) // If invisible do
- _vm.lookObject(obj); // immediate decription
+ if (!_vm->_route->startRoute(GO_LOOK, objId, obj->viewx, obj->viewy)) {
+ if (_vm->_hero->cycling == INVISIBLE) // If invisible do
+ _vm->_object->lookObject(obj); // immediate decription
else
- Utils::Box(BOX_ANY, "%s", _vm._textMouse[kMsNoWayText]); // Can't get there
+ Utils::Box(BOX_ANY, "%s", _vm->_textMouse[kMsNoWayText]); // Can't get there
}
break;
}
@@ -222,14 +230,16 @@ void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) {
}
}
-// Process mouse activity
+/**
+* Process mouse activity
+*/
void MouseHandler::mouseHandler() {
debugC(2, kDebugMouse, "mouseHandler");
- int16 cx = _vm.getMouseX();
- int16 cy = _vm.getMouseY();
+ int16 cx = _vm->getMouseX();
+ int16 cy = _vm->getMouseY();
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
gameStatus.cx = cx; // Save cursor coords
gameStatus.cy = cy;
@@ -242,8 +252,8 @@ void MouseHandler::mouseHandler() {
if (gameStatus.inventoryObjId != -1) {
// Find index of icon
int16 iconId; // Find index of dragged icon
- for (iconId = 0; iconId < _vm._maxInvent; iconId++) {
- if (gameStatus.inventoryObjId == _vm._invent[iconId])
+ for (iconId = 0; iconId < _vm->_maxInvent; iconId++) {
+ if (gameStatus.inventoryObjId == _vm->_invent[iconId])
break;
}
@@ -260,20 +270,20 @@ void MouseHandler::mouseHandler() {
icony = MIN(icony, YPIX - INV_DY);
// Copy the icon and add to display list
- _vm.screen().moveImage(_vm.screen().getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm.screen().getFrontBuffer(), iconx, icony, XPIX);
- _vm.screen().displayList(D_ADD, iconx, icony, INV_DX, INV_DY);
+ _vm->_screen->moveImage(_vm->_screen->getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm->_screen->getFrontBuffer(), iconx, icony, XPIX);
+ _vm->_screen->displayList(D_ADD, iconx, icony, INV_DX, INV_DY);
}
int16 objId = -1; // Current source object
// Process cursor over an object or icon
if (gameStatus.inventoryState == I_ACTIVE) // Check inventory icon bar first
- objId = _vm.inventory().processInventory(INV_GET, cx, cy);
+ objId = _vm->_inventory->processInventory(INV_GET, cx, cy);
if (objId == -1) // No match, check rest of view
- objId = _vm.findObject(cx, cy);
+ objId = _vm->_object->findObject(cx, cy);
if (objId >= 0) { // Got a match
// Display object name next to cursor (unless CURSOR_NOCHAR)
// Note test for swapped hero name
- char *name = _vm._arrayNouns[_vm._objects[(objId == HERO) ? _vm._heroImage : objId].nounIndex][CURSOR_NAME];
+ char *name = _vm->_arrayNouns[_vm->_object->_objects[(objId == HERO) ? _vm->_heroImage : objId].nounIndex][CURSOR_NAME];
if (name[0] != CURSOR_NOCHAR)
cursorText(name, cx, cy, U_FONT8, _TBRIGHTWHITE);
@@ -285,9 +295,9 @@ void MouseHandler::mouseHandler() {
// Process cursor over an exit hotspot
if (objId == -1) {
int i = findExit(cx, cy);
- if (i != -1 && _vm._hotspots[i].viewx >= 0) {
+ if (i != -1 && _vm->_hotspots[i].viewx >= 0) {
objId = EXIT_HOTSPOT;
- cursorText(_vm._textMouse[kMsExit], cx, cy, U_FONT8, _TBRIGHTWHITE);
+ cursorText(_vm->_textMouse[kMsExit], cx, cy, U_FONT8, _TBRIGHTWHITE);
}
}
diff --git a/engines/hugo/mouse.h b/engines/hugo/mouse.h
index 3ac5f19f32..0fcb651b3a 100644
--- a/engines/hugo/mouse.h
+++ b/engines/hugo/mouse.h
@@ -36,12 +36,12 @@ namespace Hugo {
class MouseHandler {
public:
- MouseHandler(HugoEngine &vm);
+ MouseHandler(HugoEngine *vm);
void mouseHandler();
private:
- HugoEngine &_vm;
+ HugoEngine *_vm;
void cursorText(char *buffer, int16 cx, int16 cy, uif_t fontId, int16 color);
int16 findExit(int16 cx, int16 cy);
diff --git a/engines/hugo/object.cpp b/engines/hugo/object.cpp
new file mode 100644
index 0000000000..6aec9d1378
--- /dev/null
+++ b/engines/hugo/object.cpp
@@ -0,0 +1,454 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on original Hugo Trilogy source code
+ *
+ * Copyright (c) 1989-1995 David P. Gray
+ *
+ */
+
+#include "common/system.h"
+#include "common/random.h"
+
+#include "hugo/game.h"
+#include "hugo/hugo.h"
+#include "hugo/object.h"
+#include "hugo/global.h"
+#include "hugo/display.h"
+#include "hugo/file.h"
+#include "hugo/route.h"
+#include "hugo/util.h"
+#include "hugo/parser.h"
+#include "hugo/schedule.h"
+
+namespace Hugo {
+
+ObjectHandler::ObjectHandler(HugoEngine *vm) : _vm(vm), _objects(0) {
+}
+
+ObjectHandler::~ObjectHandler() {
+}
+
+/**
+* Save sequence number and image number in given object
+*/
+void ObjectHandler::saveSeq(object_t *obj) {
+ debugC(1, kDebugObject, "saveSeq");
+
+ bool found = false;
+ for (int j = 0; !found && (j < obj->seqNumb); j++) {
+ seq_t *q = obj->seqList[j].seqPtr;
+ for (int k = 0; !found && (k < obj->seqList[j].imageNbr); k++) {
+ if (obj->currImagePtr == q) {
+ found = true;
+ obj->curSeqNum = j;
+ obj->curImageNum = k;
+ } else {
+ q = q->nextSeqPtr;
+ }
+ }
+ }
+}
+
+/**
+* Set up cur_seq_p from stored sequence and image number in object
+*/
+void ObjectHandler::restoreSeq(object_t *obj) {
+ debugC(1, kDebugObject, "restoreSeq");
+
+ seq_t *q = obj->seqList[obj->curSeqNum].seqPtr;
+ for (int j = 0; j < obj->curImageNum; j++)
+ q = q->nextSeqPtr;
+ obj->currImagePtr = q;
+}
+
+/**
+* If status.objid = -1, pick up objid, else use status.objid on objid,
+* if objid can't be picked up, use it directly
+*/
+void ObjectHandler::useObject(int16 objId) {
+ debugC(1, kDebugObject, "useObject(%d)", objId);
+
+ char *verb; // Background verb to use directly
+ object_t *obj = &_objects[objId]; // Ptr to object
+ if (_vm->getGameStatus().inventoryObjId == -1) {
+ // Get or use objid directly
+ if ((obj->genericCmd & TAKE) || obj->objValue) // Get collectible item
+ sprintf(_line, "%s %s", _vm->_arrayVerbs[_vm->_take][0], _vm->_arrayNouns[obj->nounIndex][0]);
+ else if (obj->genericCmd & LOOK) // Look item
+ sprintf(_line, "%s %s", _vm->_arrayVerbs[_vm->_look][0], _vm->_arrayNouns[obj->nounIndex][0]);
+ else if (obj->genericCmd & DROP) // Drop item
+ sprintf(_line, "%s %s", _vm->_arrayVerbs[_vm->_drop][0], _vm->_arrayNouns[obj->nounIndex][0]);
+ else if (obj->cmdIndex != 0) // Use non-collectible item if able
+ sprintf(_line, "%s %s", _vm->_arrayVerbs[_vm->_cmdList[obj->cmdIndex][1].verbIndex][0], _vm->_arrayNouns[obj->nounIndex][0]);
+ else if ((verb = _vm->useBG(_vm->_arrayNouns[obj->nounIndex][0])) != 0)
+ sprintf(_line, "%s %s", verb, _vm->_arrayNouns[obj->nounIndex][0]);
+ else
+ return; // Can't use object directly
+ } else {
+ // Use status.objid on objid
+ // Default to first cmd verb
+ sprintf(_line, "%s %s %s", _vm->_arrayVerbs[_vm->_cmdList[_objects[_vm->getGameStatus().inventoryObjId].cmdIndex][1].verbIndex][0],
+ _vm->_arrayNouns[_objects[_vm->getGameStatus().inventoryObjId].nounIndex][0],
+ _vm->_arrayNouns[obj->nounIndex][0]);
+
+ // Check valid use of objects and override verb if necessary
+ for (uses_t *use = _vm->_uses; use->objId != _vm->_numObj; use++) {
+ if (_vm->getGameStatus().inventoryObjId == use->objId) {
+ // Look for secondary object, if found use matching verb
+ bool foundFl = false;
+ for (target_t *target = use->targets; _vm->_arrayNouns[target->nounIndex] != 0; target++)
+ if (_vm->_arrayNouns[target->nounIndex][0] == _vm->_arrayNouns[obj->nounIndex][0]) {
+ foundFl = true;
+ sprintf(_line, "%s %s %s", _vm->_arrayVerbs[target->verbIndex][0],
+ _vm->_arrayNouns[_objects[_vm->getGameStatus().inventoryObjId].nounIndex][0],
+ _vm->_arrayNouns[obj->nounIndex][0]);
+ }
+
+ // No valid use of objects found, print failure string
+ if (!foundFl) {
+ // Deselect dragged icon if inventory not active
+ if (_vm->getGameStatus().inventoryState != I_ACTIVE)
+ _vm->getGameStatus().inventoryObjId = -1;
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[use->dataIndex]);
+ return;
+ }
+ }
+ }
+ }
+
+ if (_vm->getGameStatus().inventoryState == I_ACTIVE) // If inventory active, remove it
+ _vm->getGameStatus().inventoryState = I_UP;
+ _vm->getGameStatus().inventoryObjId = -1; // Deselect any dragged icon
+ _vm->_parser->lineHandler(); // and process command
+}
+
+/**
+* Return object index of the topmost object under the cursor, or -1 if none
+* Objects are filtered if not "useful"
+*/
+int16 ObjectHandler::findObject(uint16 x, uint16 y) {
+ debugC(3, kDebugObject, "findObject(%d, %d)", x, y);
+
+ int16 objIndex = -1; // Index of found object
+ uint16 y2Max = 0; // Greatest y2
+ object_t *obj = _objects;
+ // Check objects on screen
+ for (int i = 0; i < _vm->_numObj; i++, obj++) {
+ // Object must be in current screen and "useful"
+ if (obj->screenIndex == *_vm->_screen_p && (obj->genericCmd || obj->objValue || obj->cmdIndex)) {
+ seq_t *curImage = obj->currImagePtr;
+ // Object must have a visible image...
+ if (curImage != 0 && obj->cycling != INVISIBLE) {
+ // If cursor inside object
+ if (x >= (uint16)obj->x && x <= obj->x + curImage->x2 && y >= (uint16)obj->y && y <= obj->y + curImage->y2) {
+ // If object is closest so far
+ if (obj->y + curImage->y2 > y2Max) {
+ y2Max = obj->y + curImage->y2;
+ objIndex = i; // Found an object!
+ }
+ }
+ } else {
+ // ...or a dummy object that has a hotspot rectangle
+ if (curImage == 0 && obj->vxPath != 0 && !obj->carriedFl) {
+ // If cursor inside special rectangle
+ if ((int16)x >= obj->oldx && (int16)x < obj->oldx + obj->vxPath && (int16)y >= obj->oldy && (int16)y < obj->oldy + obj->vyPath) {
+ // If object is closest so far
+ if (obj->oldy + obj->vyPath - 1 > (int16)y2Max) {
+ y2Max = obj->oldy + obj->vyPath - 1;
+ objIndex = i; // Found an object!
+ }
+ }
+ }
+ }
+ }
+ }
+ return objIndex;
+}
+
+/**
+* Issue "Look at <object>" command
+* Note special case of swapped hero image
+*/
+void ObjectHandler::lookObject(object_t *obj) {
+ debugC(1, kDebugObject, "lookObject");
+
+ if (obj == _vm->_hero)
+ // Hero swapped - look at other
+ obj = &_objects[_vm->_heroImage];
+
+ _vm->_parser->command("%s %s", _vm->_arrayVerbs[_vm->_look][0], _vm->_arrayNouns[obj->nounIndex][0]);
+}
+
+/**
+* Free all object images
+*/
+void ObjectHandler::freeObjects() {
+ debugC(1, kDebugObject, "freeObjects");
+
+ // Nothing to do if not allocated yet
+ if (_vm->_hero->seqList[0].seqPtr == 0)
+ return;
+
+ // Free all sequence lists and image data
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i];
+ for (int j = 0; j < obj->seqNumb; j++) { // for each sequence
+ seq_t *seq = obj->seqList[j].seqPtr; // Free image
+ if (seq == 0) // Failure during database load
+ break;
+ do {
+ free(seq->imagePtr);
+ seq = seq->nextSeqPtr;
+ } while (seq != obj->seqList[j].seqPtr);
+ free(seq); // Free sequence record
+ }
+ }
+}
+
+/**
+* Compare function for the quicksort. The sort is to order the objects in
+* increasing vertical position, using y+y2 as the baseline
+* Returns -1 if ay2 < by2 else 1 if ay2 > by2 else 0
+*/
+int ObjectHandler::y2comp(const void *a, const void *b) {
+ debugC(6, kDebugObject, "y2comp");
+
+ const object_t *p1 = &HugoEngine::get()._object->_objects[*(const byte *)a];
+ const object_t *p2 = &HugoEngine::get()._object->_objects[*(const byte *)b];
+
+ if (p1 == p2)
+ // Why does qsort try the same indexes?
+ return 0;
+
+ if (p1->priority == BACKGROUND)
+ return -1;
+
+ if (p2->priority == BACKGROUND)
+ return 1;
+
+ if (p1->priority == FOREGROUND)
+ return 1;
+
+ if (p2->priority == FOREGROUND)
+ return -1;
+
+ int ay2 = p1->y + p1->currImagePtr->y2;
+ int by2 = p2->y + p2->currImagePtr->y2;
+
+ return ay2 - by2;
+}
+
+/**
+* Return TRUE if object being carried by hero
+*/
+bool ObjectHandler::isCarrying(uint16 wordIndex) {
+ debugC(1, kDebugObject, "isCarrying(%d)", wordIndex);
+
+ for (int i = 0; i < _vm->_numObj; i++) {
+ if ((wordIndex == _objects[i].nounIndex) && _objects[i].carriedFl)
+ return true;
+ }
+ return false;
+}
+
+/**
+* Describe any takeable objects visible in this screen
+*/
+void ObjectHandler::showTakeables() {
+ debugC(1, kDebugObject, "showTakeables");
+
+ for (int j = 0; j < _vm->_numObj; j++) {
+ object_t *obj = &_objects[j];
+ if ((obj->cycling != INVISIBLE) &&
+ (obj->screenIndex == *_vm->_screen_p) &&
+ (((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) {
+ Utils::Box(BOX_ANY, "You can also see:\n%s.", _vm->_arrayNouns[obj->nounIndex][LOOK_NAME]);
+ }
+ }
+}
+
+/**
+* Find a clear space around supplied object that hero can walk to
+*/
+bool ObjectHandler::findObjectSpace(object_t *obj, int16 *destx, int16 *desty) {
+ debugC(1, kDebugObject, "findObjectSpace(obj, %d, %d)", *destx, *desty);
+
+ seq_t *curImage = obj->currImagePtr;
+ int16 y = obj->y + curImage->y2 - 1;
+
+ bool foundFl = true;
+ // Try left rear corner
+ for (int16 x = *destx = obj->x + curImage->x1; x < *destx + HERO_MAX_WIDTH; x++) {
+ if (BOUND(x, y))
+ foundFl = false;
+ }
+
+ if (!foundFl) { // Try right rear corner
+ foundFl = true;
+ for (int16 x = *destx = obj->x + curImage->x2 - HERO_MAX_WIDTH + 1; x <= obj->x + (int16)curImage->x2; x++) {
+ if (BOUND(x, y))
+ foundFl = false;
+ }
+ }
+
+ if (!foundFl) { // Try left front corner
+ foundFl = true;
+ y += 2;
+ for (int16 x = *destx = obj->x + curImage->x1; x < *destx + HERO_MAX_WIDTH; x++) {
+ if (BOUND(x, y))
+ foundFl = false;
+ }
+ }
+
+ if (!foundFl) { // Try right rear corner
+ foundFl = true;
+ for (int16 x = *destx = obj->x + curImage->x2 - HERO_MAX_WIDTH + 1; x <= obj->x + (int16)curImage->x2; x++) {
+ if (BOUND(x, y))
+ foundFl = false;
+ }
+ }
+
+ *desty = y;
+ return foundFl;
+}
+
+/**
+* Free ObjectArr (before exiting)
+*/
+void ObjectHandler::freeObjectArr() {
+ free(_objects);
+}
+
+/**
+* Load ObjectArr from Hugo.dat
+*/
+void ObjectHandler::loadObjectArr(Common::File &in) {
+ debugC(6, kDebugObject, "loadObject(&in)");
+
+// TODO: For Hugo3, if not in story mode, set _objects[2].state to 3
+ for (int varnt = 0; varnt < _vm->_numVariant; varnt++) {
+ uint16 numElem = in.readUint16BE();
+ if (varnt == _vm->_gameVariant) {
+ _objCount = numElem;
+ _objects = (object_t *)malloc(sizeof(object_t) * numElem);
+ for (int i = 0; i < numElem; i++) {
+ _objects[i].nounIndex = in.readUint16BE();
+ _objects[i].dataIndex = in.readUint16BE();
+ uint16 numSubElem = in.readUint16BE();
+ if (numSubElem == 0)
+ _objects[i].stateDataIndex = 0;
+ else
+ _objects[i].stateDataIndex = (uint16 *)malloc(sizeof(uint16) * numSubElem);
+ for (int j = 0; j < numSubElem; j++)
+ _objects[i].stateDataIndex[j] = in.readUint16BE();
+ _objects[i].pathType = (path_t) in.readSint16BE();
+ _objects[i].vxPath = in.readSint16BE();
+ _objects[i].vyPath = in.readSint16BE();
+ _objects[i].actIndex = in.readUint16BE();
+ _objects[i].seqNumb = in.readByte();
+ _objects[i].currImagePtr = 0;
+ if (_objects[i].seqNumb == 0) {
+ _objects[i].seqList[0].imageNbr = 0;
+ _objects[i].seqList[0].seqPtr = 0;
+ }
+ for (int j = 0; j < _objects[i].seqNumb; j++) {
+ _objects[i].seqList[j].imageNbr = in.readUint16BE();
+ _objects[i].seqList[j].seqPtr = 0;
+ }
+ _objects[i].cycling = (cycle_t)in.readByte();
+ _objects[i].cycleNumb = in.readByte();
+ _objects[i].frameInterval = in.readByte();
+ _objects[i].frameTimer = in.readByte();
+ _objects[i].radius = in.readByte();
+ _objects[i].screenIndex = in.readByte();
+ _objects[i].x = in.readSint16BE();
+ _objects[i].y = in.readSint16BE();
+ _objects[i].oldx = in.readSint16BE();
+ _objects[i].oldy = in.readSint16BE();
+ _objects[i].vx = in.readByte();
+ _objects[i].vy = in.readByte();
+ _objects[i].objValue = in.readByte();
+ _objects[i].genericCmd = in.readSint16BE();
+ _objects[i].cmdIndex = in.readUint16BE();
+ _objects[i].carriedFl = (in.readByte() != 0);
+ _objects[i].state = in.readByte();
+ _objects[i].verbOnlyFl = (in.readByte() != 0);
+ _objects[i].priority = in.readByte();
+ _objects[i].viewx = in.readSint16BE();
+ _objects[i].viewy = in.readSint16BE();
+ _objects[i].direction = in.readSint16BE();
+ _objects[i].curSeqNum = in.readByte();
+ _objects[i].curImageNum = in.readByte();
+ _objects[i].oldvx = in.readByte();
+ _objects[i].oldvy = in.readByte();
+ }
+ } else {
+ for (int i = 0; i < numElem; i++) {
+ in.readUint16BE();
+ in.readUint16BE();
+ uint16 numSubElem = in.readUint16BE();
+ for (int j = 0; j < numSubElem; j++)
+ in.readUint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ numSubElem = in.readByte();
+ for (int j = 0; j < numSubElem; j++)
+ in.readUint16BE();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ in.readByte();
+ }
+ }
+ }
+}
+
+} // End of namespace Hugo
diff --git a/engines/hugo/object.h b/engines/hugo/object.h
new file mode 100644
index 0000000000..72b13caa8f
--- /dev/null
+++ b/engines/hugo/object.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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on original Hugo Trilogy source code
+ *
+ * Copyright (c) 1989-1995 David P. Gray
+ *
+ */
+
+#ifndef HUGO_OBJECT_H
+#define HUGO_OBJECT_H
+
+#include "common/file.h"
+
+#define MAXOBJECTS 128 // Used in Update_images()
+#define BOUND(X, Y) ((_vm->getBoundaryOverlay()[Y * XBYTES + X / 8] & (0x80 >> X % 8)) != 0) // Boundary bit set
+
+namespace Hugo {
+
+class ObjectHandler {
+public:
+ ObjectHandler(HugoEngine *vm);
+ virtual ~ObjectHandler();
+
+ object_t *_objects;
+
+ virtual void moveObjects() = 0;
+ virtual void updateImages() = 0;
+ virtual void swapImages(int objNumb1, int objNumb2) = 0;
+
+ bool isCarrying(uint16 wordIndex);
+ bool findObjectSpace(object_t *obj, int16 *destx, int16 *desty);
+
+ int16 findObject(uint16 x, uint16 y);
+ void freeObjects();
+ void loadObjectArr(Common::File &in);
+ void freeObjectArr();
+ void lookObject(object_t *obj);
+ void restoreSeq(object_t *obj);
+ void saveSeq(object_t *obj);
+ void showTakeables();
+ void useObject(int16 objId);
+
+ static int y2comp(const void *a, const void *b);
+
+ bool isCarried(int objIndex) {
+ return _objects[objIndex].carriedFl;
+ }
+
+ void setCarry(int objIndex, bool val) {
+ _objects[objIndex].carriedFl = val;
+ }
+
+ void setVelocity(int objIndex, int8 vx, int8 vy) {
+ _objects[objIndex].vx = vx;
+ _objects[objIndex].vy = vy;
+ }
+
+ void setPath(int objIndex, path_t pathType, int16 vxPath, int16 vyPath) {
+ _objects[objIndex].pathType = pathType;
+ _objects[objIndex].vxPath = vxPath;
+ _objects[objIndex].vyPath = vyPath;
+ }
+protected:
+ HugoEngine *_vm;
+ uint16 _objCount;
+};
+
+class ObjectHandler_v1d : public ObjectHandler {
+public:
+ ObjectHandler_v1d(HugoEngine *vm);
+ virtual ~ObjectHandler_v1d();
+
+ void moveObjects();
+ void updateImages();
+ void swapImages(int objNumb1, int objNumb2);
+};
+
+class ObjectHandler_v1w : public ObjectHandler {
+public:
+ ObjectHandler_v1w(HugoEngine *vm);
+ ~ObjectHandler_v1w();
+
+ void moveObjects();
+ void updateImages();
+ void swapImages(int objNumb1, int objNumb2);
+};
+
+class ObjectHandler_v2d : public ObjectHandler_v1d {
+public:
+ ObjectHandler_v2d(HugoEngine *vm);
+ virtual ~ObjectHandler_v2d();
+
+ void moveObjects();
+ void updateImages();
+};
+
+class ObjectHandler_v3d : public ObjectHandler_v2d {
+public:
+ ObjectHandler_v3d(HugoEngine *vm);
+ ~ObjectHandler_v3d();
+
+ void moveObjects();
+ void swapImages(int objNumb1, int objNumb2);
+};
+
+} // End of namespace Hugo
+#endif //HUGO_OBJECT_H
diff --git a/engines/hugo/object_v1d.cpp b/engines/hugo/object_v1d.cpp
new file mode 100644
index 0000000000..6c929f75fd
--- /dev/null
+++ b/engines/hugo/object_v1d.cpp
@@ -0,0 +1,372 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on original Hugo Trilogy source code
+ *
+ * Copyright (c) 1989-1995 David P. Gray
+ *
+ */
+
+#include "common/system.h"
+#include "common/random.h"
+
+#include "hugo/game.h"
+#include "hugo/hugo.h"
+#include "hugo/object.h"
+#include "hugo/global.h"
+#include "hugo/display.h"
+#include "hugo/file.h"
+#include "hugo/route.h"
+#include "hugo/util.h"
+#include "hugo/parser.h"
+#include "hugo/schedule.h"
+
+namespace Hugo {
+
+ObjectHandler_v1d::ObjectHandler_v1d(HugoEngine *vm) : ObjectHandler(vm) {
+}
+
+ObjectHandler_v1d::~ObjectHandler_v1d() {
+}
+
+/**
+* Draw all objects on screen as follows:
+* 1. Sort 'FLOATING' objects in order of y2 (base of object)
+* 2. Display new object frames/positions in dib
+* Finally, cycle any animating objects to next frame
+*/
+void ObjectHandler_v1d::updateImages() {
+ debugC(5, kDebugObject, "updateImages");
+
+ // Initialise the index array to visible objects in current screen
+ int num_objs = 0;
+ byte objindex[MAXOBJECTS]; // Array of indeces to objects
+
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i];
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling >= ALMOST_INVISIBLE))
+ objindex[num_objs++] = i;
+ }
+
+ // Sort the objects into increasing y+y2 (painter's algorithm)
+ qsort(objindex, num_objs, sizeof(objindex[0]), y2comp);
+
+ // Add each visible object to display list
+ for (int i = 0; i < num_objs; i++) {
+ object_t *obj = &_objects[objindex[i]];
+ // Count down inter-frame timer
+ if (obj->frameTimer)
+ obj->frameTimer--;
+
+ if (obj->cycling > ALMOST_INVISIBLE) { // Only if visible
+ switch (obj->cycling) {
+ case NOT_CYCLING:
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, false);
+ break;
+ case CYCLE_FORWARD:
+ if (obj->frameTimer) // Not time to see next frame yet
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, false);
+ else
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, false);
+ break;
+ case CYCLE_BACKWARD: {
+ seq_t *seqPtr = obj->currImagePtr;
+ if (!obj->frameTimer) { // Show next frame
+ while (seqPtr->nextSeqPtr != obj->currImagePtr)
+ seqPtr = seqPtr->nextSeqPtr;
+ }
+ _vm->_screen->displayFrame(obj->x, obj->y, seqPtr, false);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ _vm->_scheduler->waitForRefresh();
+
+ // Cycle any animating objects
+ for (int i = 0; i < num_objs; i++) {
+ object_t *obj = &_objects[objindex[i]];
+ if (obj->cycling != INVISIBLE) {
+ // Only if it's visible
+ if (obj->cycling == ALMOST_INVISIBLE)
+ obj->cycling = INVISIBLE;
+
+ // Now Rotate to next picture in sequence
+ switch (obj->cycling) {
+ case NOT_CYCLING:
+ break;
+ case CYCLE_FORWARD:
+ if (!obj->frameTimer) {
+ // Time to step to next frame
+ obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
+ // Find out if this is last frame of sequence
+ // If so, reset frame_timer and decrement n_cycle
+ if (obj->frameInterval || obj->cycleNumb) {
+ obj->frameTimer = obj->frameInterval;
+ for (int j = 0; j < obj->seqNumb; j++) {
+ if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) {
+ if (obj->cycleNumb) { // Decr cycleNumb if Non-continous
+ if (!--obj->cycleNumb)
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case CYCLE_BACKWARD: {
+ if (!obj->frameTimer) {
+ // Time to step to prev frame
+ seq_t *seqPtr = obj->currImagePtr;
+ while (obj->currImagePtr->nextSeqPtr != seqPtr)
+ obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
+ // Find out if this is first frame of sequence
+ // If so, reset frame_timer and decrement n_cycle
+ if (obj->frameInterval || obj->cycleNumb) {
+ obj->frameTimer = obj->frameInterval;
+ for (int j = 0; j < obj->seqNumb; j++) {
+ if (obj->currImagePtr == obj->seqList[j].seqPtr) {
+ if (obj->cycleNumb){ // Decr cycleNumb if Non-continous
+ if (!--obj->cycleNumb)
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ obj->oldx = obj->x;
+ obj->oldy = obj->y;
+ }
+ }
+}
+
+/**
+* Update all object positions. Process object 'local' events
+* including boundary events and collisions
+*/
+void ObjectHandler_v1d::moveObjects() {
+ debugC(4, kDebugObject, "moveObjects");
+
+ static int dxOld, dyOld; // previous directions for CHASEing
+
+ // Added to DOS version in order to handle mouse properly
+ // If route mode enabled, do special route processing
+ if (_vm->getGameStatus().routeIndex >= 0)
+ _vm->_route->processRoute();
+
+ // Perform any adjustments to velocity based on special path types
+ // and store all (visible) object baselines into the boundary file.
+ // Don't store foreground or background objects
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ if (obj->screenIndex == *_vm->_screen_p) {
+ switch (obj->pathType) {
+ case CHASE: {
+ // Allowable motion wrt boundary
+ int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1;
+ int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1;
+ if (abs(dx) <= 1)
+ obj->vx = 0;
+ else
+ obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath);
+ if (abs(dy) <= 1)
+ obj->vy = 0;
+ else
+ obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath);
+
+ // Set first image in sequence (if multi-seq object)
+ if (obj->seqNumb == 4) {
+ if (!obj->vx) { // Got 4 directions
+ if (obj->vx != dxOld) { // vx just stopped
+ if (dy > 0)
+ obj->currImagePtr = obj->seqList[DOWN].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[_UP].seqPtr;
+ }
+ } else if (obj->vx != dxOld) {
+ if (dx > 0)
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ }
+
+ if (obj->vx || obj->vy) {
+ if (obj->seqNumb > 1)
+ obj->cycling = CYCLE_FORWARD;
+ } else {
+ obj->cycling = NOT_CYCLING;
+ _vm->boundaryCollision(obj); // Must have got hero!
+ }
+ dxOld = obj->vx;
+ dyOld = obj->vy;
+ currImage = obj->currImagePtr; // Get (new) ptr to current image
+ break;
+ }
+ case WANDER:
+ if (!_vm->_rnd->getRandomNumber(3 * NORMAL_TPS)) { // Kick on random interval
+ obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath;
+ obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath;
+
+ // Set first image in sequence (if multi-seq object)
+ if (obj->seqNumb > 1) {
+ if (!obj->vx && (obj->seqNumb > 2)) {
+ if (obj->vx != dxOld) { // vx just stopped
+ if (obj->vy > 0)
+ obj->currImagePtr = obj->seqList[DOWN].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[_UP].seqPtr;
+ }
+ } else if (obj->vx != dxOld) {
+ if (obj->vx > 0)
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+
+ if (obj->vx || obj->vy)
+ obj->cycling = CYCLE_FORWARD;
+ else
+ obj->cycling = NOT_CYCLING;
+ }
+ dxOld = obj->vx;
+ dyOld = obj->vy;
+ currImage = obj->currImagePtr; // Get (new) ptr to current image
+ }
+ break;
+ default:
+ ; // Really, nothing
+ }
+ // Store boundaries
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2);
+ }
+ }
+
+ // Move objects, allowing for boundaries
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) {
+ // Only process if it's moving
+
+ // Do object movement. Delta_x,y return allowed movement in x,y
+ // to move as close to a boundary as possible without crossing it.
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ // object coordinates
+ int x1 = obj->x + currImage->x1; // Left edge of object
+ int x2 = obj->x + currImage->x2; // Right edge
+ int y1 = obj->y + currImage->y1; // Top edge
+ int y2 = obj->y + currImage->y2; // Bottom edge
+
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(x1, x2, y2); // Clear our own boundary
+
+ // Allowable motion wrt boundary
+ int dx = _vm->deltaX(x1, x2, obj->vx, y2);
+ if (dx != obj->vx) {
+ // An object boundary collision!
+ _vm->boundaryCollision(obj);
+ obj->vx = 0;
+ }
+
+ int dy = _vm->deltaY(x1, x2, obj->vy, y2);
+ if (dy != obj->vy) {
+ // An object boundary collision!
+ _vm->boundaryCollision(obj);
+ obj->vy = 0;
+ }
+
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary
+
+ obj->x += dx; // Update object position
+ obj->y += dy;
+
+ // Don't let object go outside screen
+ if (x1 < EDGE)
+ obj->x = EDGE2;
+ if (x2 > (XPIX - EDGE))
+ obj->x = XPIX - EDGE2 - (x2 - x1);
+ if (y1 < EDGE)
+ obj->y = EDGE2;
+ if (y2 > (YPIX - EDGE))
+ obj->y = YPIX - EDGE2 - (y2 - y1);
+
+ if ((obj->vx == 0) && (obj->vy == 0))
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+
+ // Clear all object baselines from the boundary file.
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2);
+ }
+
+ // If maze mode is enabled, do special maze processing
+ if (_maze.enabledFl) {
+ seq_t *currImage = _vm->_hero->currImagePtr; // Get ptr to current image
+ // hero coordinates
+ int x1 = _vm->_hero->x + currImage->x1; // Left edge of object
+ int x2 = _vm->_hero->x + currImage->x2; // Right edge
+ int y1 = _vm->_hero->y + currImage->y1; // Top edge
+ int y2 = _vm->_hero->y + currImage->y2; // Bottom edge
+
+ _vm->_scheduler->processMaze(x1, x2, y1, y2);
+ }
+}
+
+/**
+* Swap all the images of one object with another. Set hero_image (we make
+* the assumption for now that the first obj is always the HERO) to the object
+* number of the swapped image
+*/
+void ObjectHandler_v1d::swapImages(int objNumb1, int objNumb2) {
+ debugC(1, kDebugObject, "swapImages(%d, %d)", objNumb1, objNumb2);
+
+ seqList_t tmpSeqList[MAX_SEQUENCES];
+ int seqListSize = sizeof(seqList_t) * MAX_SEQUENCES;
+
+ memcpy(tmpSeqList, _objects[objNumb1].seqList, seqListSize);
+ memcpy(_objects[objNumb1].seqList, _objects[objNumb2].seqList, seqListSize);
+ memcpy(_objects[objNumb2].seqList, tmpSeqList, seqListSize);
+ _objects[objNumb1].currImagePtr = _objects[objNumb1].seqList[0].seqPtr;
+ _objects[objNumb2].currImagePtr = _objects[objNumb2].seqList[0].seqPtr;
+ _vm->_heroImage = (_vm->_heroImage == HERO) ? objNumb2 : HERO;
+}
+
+} // End of namespace Hugo
diff --git a/engines/hugo/object_v1w.cpp b/engines/hugo/object_v1w.cpp
new file mode 100644
index 0000000000..48d921f2be
--- /dev/null
+++ b/engines/hugo/object_v1w.cpp
@@ -0,0 +1,385 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on original Hugo Trilogy source code
+ *
+ * Copyright (c) 1989-1995 David P. Gray
+ *
+ */
+
+#include "common/system.h"
+#include "common/random.h"
+
+#include "hugo/game.h"
+#include "hugo/hugo.h"
+#include "hugo/object.h"
+#include "hugo/global.h"
+#include "hugo/display.h"
+#include "hugo/file.h"
+#include "hugo/route.h"
+#include "hugo/util.h"
+#include "hugo/parser.h"
+#include "hugo/schedule.h"
+
+namespace Hugo {
+
+ObjectHandler_v1w::ObjectHandler_v1w(HugoEngine *vm) : ObjectHandler(vm) {
+}
+
+ObjectHandler_v1w::~ObjectHandler_v1w() {
+}
+
+/**
+* Draw all objects on screen as follows:
+* 1. Sort 'FLOATING' objects in order of y2 (base of object)
+* 2. Display new object frames/positions in dib
+* Finally, cycle any animating objects to next frame
+*/
+void ObjectHandler_v1w::updateImages() {
+ debugC(5, kDebugObject, "updateImages");
+
+ // Initialise the index array to visible objects in current screen
+ int num_objs = 0;
+ byte objindex[MAXOBJECTS]; // Array of indeces to objects
+
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i];
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling >= ALMOST_INVISIBLE))
+ objindex[num_objs++] = i;
+ }
+
+ // Sort the objects into increasing y+y2 (painter's algorithm)
+ qsort(objindex, num_objs, sizeof(objindex[0]), y2comp);
+
+ // Add each visible object to display list
+ for (int i = 0; i < num_objs; i++) {
+ object_t *obj = &_objects[objindex[i]];
+ // Count down inter-frame timer
+ if (obj->frameTimer)
+ obj->frameTimer--;
+
+ if (obj->cycling > ALMOST_INVISIBLE) { // Only if visible
+ switch (obj->cycling) {
+ case NOT_CYCLING:
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL);
+ break;
+ case CYCLE_FORWARD:
+ if (obj->frameTimer) // Not time to see next frame yet
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL);
+ else
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, obj->priority == OVEROVL);
+ break;
+ case CYCLE_BACKWARD: {
+ seq_t *seqPtr = obj->currImagePtr;
+ if (!obj->frameTimer) { // Show next frame
+ while (seqPtr->nextSeqPtr != obj->currImagePtr)
+ seqPtr = seqPtr->nextSeqPtr;
+ }
+ _vm->_screen->displayFrame(obj->x, obj->y, seqPtr, obj->priority == OVEROVL);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ // Cycle any animating objects
+ for (int i = 0; i < num_objs; i++) {
+ object_t *obj = &_objects[objindex[i]];
+ if (obj->cycling != INVISIBLE) {
+ // Only if it's visible
+ if (obj->cycling == ALMOST_INVISIBLE)
+ obj->cycling = INVISIBLE;
+
+ // Now Rotate to next picture in sequence
+ switch (obj->cycling) {
+ case NOT_CYCLING:
+ break;
+ case CYCLE_FORWARD:
+ if (!obj->frameTimer) {
+ // Time to step to next frame
+ obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
+ // Find out if this is last frame of sequence
+ // If so, reset frame_timer and decrement n_cycle
+ if (obj->frameInterval || obj->cycleNumb) {
+ obj->frameTimer = obj->frameInterval;
+ for (int j = 0; j < obj->seqNumb; j++) {
+ if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) {
+ if (obj->cycleNumb) { // Decr cycleNumb if Non-continous
+ if (!--obj->cycleNumb)
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case CYCLE_BACKWARD: {
+ if (!obj->frameTimer) {
+ // Time to step to prev frame
+ seq_t *seqPtr = obj->currImagePtr;
+ while (obj->currImagePtr->nextSeqPtr != seqPtr)
+ obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
+ // Find out if this is first frame of sequence
+ // If so, reset frame_timer and decrement n_cycle
+ if (obj->frameInterval || obj->cycleNumb) {
+ obj->frameTimer = obj->frameInterval;
+ for (int j = 0; j < obj->seqNumb; j++) {
+ if (obj->currImagePtr == obj->seqList[j].seqPtr) {
+ if (obj->cycleNumb){ // Decr cycleNumb if Non-continous
+ if (!--obj->cycleNumb)
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ obj->oldx = obj->x;
+ obj->oldy = obj->y;
+ }
+ }
+}
+
+/**
+* Update all object positions. Process object 'local' events
+* including boundary events and collisions
+*/
+void ObjectHandler_v1w::moveObjects() {
+ debugC(4, kDebugObject, "moveObjects");
+
+ // If route mode enabled, do special route processing
+ if (_vm->getGameStatus().routeIndex >= 0)
+ _vm->_route->processRoute();
+
+ // Perform any adjustments to velocity based on special path types
+ // and store all (visible) object baselines into the boundary file.
+ // Don't store foreground or background objects
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ if (obj->screenIndex == *_vm->_screen_p) {
+ switch (obj->pathType) {
+ case CHASE:
+ case CHASE2: {
+ int8 radius = obj->radius; // Default to object's radius
+ if (radius < 0) // If radius infinity, use closer value
+ radius = DX;
+
+ // Allowable motion wrt boundary
+ int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1;
+ int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1;
+ if (abs(dx) <= radius)
+ obj->vx = 0;
+ else
+ obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath);
+ if (abs(dy) <= radius)
+ obj->vy = 0;
+ else
+ obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath);
+
+ // Set first image in sequence (if multi-seq object)
+ switch (obj->seqNumb) {
+ case 4:
+ if (!obj->vx) { // Got 4 directions
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (dy >= 0)
+ obj->currImagePtr = obj->seqList[DOWN].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[_UP].seqPtr;
+ }
+ } else if (obj->vx != obj->oldvx) {
+ if (dx > 0)
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ break;
+ case 3:
+ case 2:
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (dx > 0) // Left & right only
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ break;
+ }
+
+ if (obj->vx || obj->vy) {
+ obj->cycling = CYCLE_FORWARD;
+ } else {
+ obj->cycling = NOT_CYCLING;
+ _vm->boundaryCollision(obj); // Must have got hero!
+ }
+ obj->oldvx = obj->vx;
+ obj->oldvy = obj->vy;
+ currImage = obj->currImagePtr; // Get (new) ptr to current image
+ break;
+ }
+ case WANDER2:
+ case WANDER:
+ if (!_vm->_rnd->getRandomNumber(3 * NORMAL_TPS)) { // Kick on random interval
+ obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath;
+ obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath;
+
+ // Set first image in sequence (if multi-seq object)
+ if (obj->seqNumb > 1) {
+ if (!obj->vx && (obj->seqNumb >= 4)) {
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (obj->vy > 0)
+ obj->currImagePtr = obj->seqList[DOWN].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[_UP].seqPtr;
+ }
+ } else if (obj->vx != obj->oldvx) {
+ if (obj->vx > 0)
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ }
+ obj->oldvx = obj->vx;
+ obj->oldvy = obj->vy;
+ currImage = obj->currImagePtr; // Get (new) ptr to current image
+ }
+ if (obj->vx || obj->vy)
+ obj->cycling = CYCLE_FORWARD;
+ break;
+ default:
+ ; // Really, nothing
+ }
+ // Store boundaries
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2);
+ }
+ }
+
+ // Move objects, allowing for boundaries
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) {
+ // Only process if it's moving
+
+ // Do object movement. Delta_x,y return allowed movement in x,y
+ // to move as close to a boundary as possible without crossing it.
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ // object coordinates
+ int x1 = obj->x + currImage->x1; // Left edge of object
+ int x2 = obj->x + currImage->x2; // Right edge
+ int y1 = obj->y + currImage->y1; // Top edge
+ int y2 = obj->y + currImage->y2; // Bottom edge
+
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(x1, x2, y2); // Clear our own boundary
+
+ // Allowable motion wrt boundary
+ int dx = _vm->deltaX(x1, x2, obj->vx, y2);
+ if (dx != obj->vx) {
+ // An object boundary collision!
+ _vm->boundaryCollision(obj);
+ obj->vx = 0;
+ }
+
+ int dy = _vm->deltaY(x1, x2, obj->vy, y2);
+ if (dy != obj->vy) {
+ // An object boundary collision!
+ _vm->boundaryCollision(obj);
+ obj->vy = 0;
+ }
+
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary
+
+ obj->x += dx; // Update object position
+ obj->y += dy;
+
+ // Don't let object go outside screen
+ if (x1 < EDGE)
+ obj->x = EDGE2;
+ if (x2 > (XPIX - EDGE))
+ obj->x = XPIX - EDGE2 - (x2 - x1);
+ if (y1 < EDGE)
+ obj->y = EDGE2;
+ if (y2 > (YPIX - EDGE))
+ obj->y = YPIX - EDGE2 - (y2 - y1);
+
+ if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != WANDER2) && (obj->pathType != CHASE2))
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+
+ // Clear all object baselines from the boundary file.
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2);
+ }
+
+ // If maze mode is enabled, do special maze processing
+ if (_maze.enabledFl) {
+ seq_t *currImage = _vm->_hero->currImagePtr; // Get ptr to current image
+ // hero coordinates
+ int x1 = _vm->_hero->x + currImage->x1; // Left edge of object
+ int x2 = _vm->_hero->x + currImage->x2; // Right edge
+ int y1 = _vm->_hero->y + currImage->y1; // Top edge
+ int y2 = _vm->_hero->y + currImage->y2; // Bottom edge
+
+ _vm->_scheduler->processMaze(x1, x2, y1, y2);
+ }
+}
+
+/**
+* Swap all the images of one object with another. Set hero_image (we make
+* the assumption for now that the first obj is always the HERO) to the object
+* number of the swapped image
+*/
+void ObjectHandler_v1w::swapImages(int objNumb1, int objNumb2) {
+ debugC(1, kDebugObject, "swapImages(%d, %d)", objNumb1, objNumb2);
+
+ saveSeq(&_objects[objNumb1]);
+
+ seqList_t tmpSeqList[MAX_SEQUENCES];
+ int seqListSize = sizeof(seqList_t) * MAX_SEQUENCES;
+
+ memcpy(tmpSeqList, _objects[objNumb1].seqList, seqListSize);
+ memcpy(_objects[objNumb1].seqList, _objects[objNumb2].seqList, seqListSize);
+ memcpy(_objects[objNumb2].seqList, tmpSeqList, seqListSize);
+ restoreSeq(&_objects[objNumb1]);
+ _objects[objNumb2].currImagePtr = _objects[objNumb2].seqList[0].seqPtr;
+ _vm->_heroImage = (_vm->_heroImage == HERO) ? objNumb2 : HERO;
+
+ // Make sure baseline stays constant
+ _objects[objNumb1].y += _objects[objNumb2].currImagePtr->y2 - _objects[objNumb1].currImagePtr->y2;
+}
+
+} // End of namespace Hugo
diff --git a/engines/hugo/object_v2d.cpp b/engines/hugo/object_v2d.cpp
new file mode 100644
index 0000000000..9d35edd882
--- /dev/null
+++ b/engines/hugo/object_v2d.cpp
@@ -0,0 +1,364 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on original Hugo Trilogy source code
+ *
+ * Copyright (c) 1989-1995 David P. Gray
+ *
+ */
+
+#include "common/system.h"
+#include "common/random.h"
+
+#include "hugo/game.h"
+#include "hugo/hugo.h"
+#include "hugo/object.h"
+#include "hugo/global.h"
+#include "hugo/display.h"
+#include "hugo/file.h"
+#include "hugo/route.h"
+#include "hugo/util.h"
+#include "hugo/parser.h"
+#include "hugo/schedule.h"
+
+namespace Hugo {
+
+ObjectHandler_v2d::ObjectHandler_v2d(HugoEngine *vm) : ObjectHandler_v1d(vm) {
+}
+
+ObjectHandler_v2d::~ObjectHandler_v2d() {
+}
+
+/**
+* Draw all objects on screen as follows:
+* 1. Sort 'FLOATING' objects in order of y2 (base of object)
+* 2. Display new object frames/positions in dib
+* Finally, cycle any animating objects to next frame
+*/
+void ObjectHandler_v2d::updateImages() {
+ debugC(5, kDebugObject, "updateImages");
+
+ // Initialise the index array to visible objects in current screen
+ int num_objs = 0;
+ byte objindex[MAXOBJECTS]; // Array of indeces to objects
+
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i];
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling >= ALMOST_INVISIBLE))
+ objindex[num_objs++] = i;
+ }
+
+ // Sort the objects into increasing y+y2 (painter's algorithm)
+ qsort(objindex, num_objs, sizeof(objindex[0]), y2comp);
+
+ // Add each visible object to display list
+ for (int i = 0; i < num_objs; i++) {
+ object_t *obj = &_objects[objindex[i]];
+ // Count down inter-frame timer
+ if (obj->frameTimer)
+ obj->frameTimer--;
+
+ if (obj->cycling > ALMOST_INVISIBLE) { // Only if visible
+ switch (obj->cycling) {
+ case NOT_CYCLING:
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL);
+ break;
+ case CYCLE_FORWARD:
+ if (obj->frameTimer) // Not time to see next frame yet
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL);
+ else
+ _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, obj->priority == OVEROVL);
+ break;
+ case CYCLE_BACKWARD: {
+ seq_t *seqPtr = obj->currImagePtr;
+ if (!obj->frameTimer) { // Show next frame
+ while (seqPtr->nextSeqPtr != obj->currImagePtr)
+ seqPtr = seqPtr->nextSeqPtr;
+ }
+ _vm->_screen->displayFrame(obj->x, obj->y, seqPtr, obj->priority == OVEROVL);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ _vm->_scheduler->waitForRefresh();
+
+ // Cycle any animating objects
+ for (int i = 0; i < num_objs; i++) {
+ object_t *obj = &_objects[objindex[i]];
+ if (obj->cycling != INVISIBLE) {
+ // Only if it's visible
+ if (obj->cycling == ALMOST_INVISIBLE)
+ obj->cycling = INVISIBLE;
+
+ // Now Rotate to next picture in sequence
+ switch (obj->cycling) {
+ case NOT_CYCLING:
+ break;
+ case CYCLE_FORWARD:
+ if (!obj->frameTimer) {
+ // Time to step to next frame
+ obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
+ // Find out if this is last frame of sequence
+ // If so, reset frame_timer and decrement n_cycle
+ if (obj->frameInterval || obj->cycleNumb) {
+ obj->frameTimer = obj->frameInterval;
+ for (int j = 0; j < obj->seqNumb; j++) {
+ if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) {
+ if (obj->cycleNumb) { // Decr cycleNumb if Non-continous
+ if (!--obj->cycleNumb)
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case CYCLE_BACKWARD: {
+ if (!obj->frameTimer) {
+ // Time to step to prev frame
+ seq_t *seqPtr = obj->currImagePtr;
+ while (obj->currImagePtr->nextSeqPtr != seqPtr)
+ obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
+ // Find out if this is first frame of sequence
+ // If so, reset frame_timer and decrement n_cycle
+ if (obj->frameInterval || obj->cycleNumb) {
+ obj->frameTimer = obj->frameInterval;
+ for (int j = 0; j < obj->seqNumb; j++) {
+ if (obj->currImagePtr == obj->seqList[j].seqPtr) {
+ if (obj->cycleNumb){ // Decr cycleNumb if Non-continous
+ if (!--obj->cycleNumb)
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ obj->oldx = obj->x;
+ obj->oldy = obj->y;
+ }
+ }
+}
+
+/**
+* Update all object positions. Process object 'local' events
+* including boundary events and collisions
+*/
+void ObjectHandler_v2d::moveObjects() {
+ debugC(4, kDebugObject, "moveObjects");
+
+ // Added to DOS version in order to handle mouse properly
+ // If route mode enabled, do special route processing
+ if (_vm->getGameStatus().routeIndex >= 0)
+ _vm->_route->processRoute();
+
+ // Perform any adjustments to velocity based on special path types
+ // and store all (visible) object baselines into the boundary file.
+ // Don't store foreground or background objects
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ if (obj->screenIndex == *_vm->_screen_p) {
+ switch (obj->pathType) {
+ case CHASE:
+ case CHASE2: {
+ int8 radius = obj->radius; // Default to object's radius
+ if (radius < 0) // If radius infinity, use closer value
+ radius = DX;
+
+ // Allowable motion wrt boundary
+ int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1;
+ int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1;
+ if (abs(dx) <= radius)
+ obj->vx = 0;
+ else
+ obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath);
+ if (abs(dy) <= radius)
+ obj->vy = 0;
+ else
+ obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath);
+
+ // Set first image in sequence (if multi-seq object)
+ switch (obj->seqNumb) {
+ case 4:
+ if (!obj->vx) { // Got 4 directions
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (dy > 0)
+ obj->currImagePtr = obj->seqList[DOWN].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[_UP].seqPtr;
+ }
+ } else if (obj->vx != obj->oldvx) {
+ if (dx > 0)
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ break;
+ case 3:
+ case 2:
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (dx > 0) // Left & right only
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ break;
+ }
+
+ if (obj->vx || obj->vy) {
+ obj->cycling = CYCLE_FORWARD;
+ } else {
+ obj->cycling = NOT_CYCLING;
+ _vm->boundaryCollision(obj); // Must have got hero!
+ }
+ obj->oldvx = obj->vx;
+ obj->oldvy = obj->vy;
+ currImage = obj->currImagePtr; // Get (new) ptr to current image
+ break;
+ }
+ case WANDER2:
+ case WANDER:
+ if (!_vm->_rnd->getRandomNumber(3 * NORMAL_TPS)) { // Kick on random interval
+ obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath;
+ obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath;
+
+ // Set first image in sequence (if multi-seq object)
+ if (obj->seqNumb > 1) {
+ if (!obj->vx && (obj->seqNumb >= 4)) {
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (obj->vy > 0)
+ obj->currImagePtr = obj->seqList[DOWN].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[_UP].seqPtr;
+ }
+ } else if (obj->vx != obj->oldvx) {
+ if (obj->vx > 0)
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ }
+ obj->oldvx = obj->vx;
+ obj->oldvy = obj->vy;
+ currImage = obj->currImagePtr; // Get (new) ptr to current image
+ }
+ if (obj->vx || obj->vy)
+ obj->cycling = CYCLE_FORWARD;
+ break;
+ default:
+ ; // Really, nothing
+ }
+ // Store boundaries
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2);
+ }
+ }
+
+ // Move objects, allowing for boundaries
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) {
+ // Only process if it's moving
+
+ // Do object movement. Delta_x,y return allowed movement in x,y
+ // to move as close to a boundary as possible without crossing it.
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ // object coordinates
+ int x1 = obj->x + currImage->x1; // Left edge of object
+ int x2 = obj->x + currImage->x2; // Right edge
+ int y1 = obj->y + currImage->y1; // Top edge
+ int y2 = obj->y + currImage->y2; // Bottom edge
+
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(x1, x2, y2); // Clear our own boundary
+
+ // Allowable motion wrt boundary
+ int dx = _vm->deltaX(x1, x2, obj->vx, y2);
+ if (dx != obj->vx) {
+ // An object boundary collision!
+ _vm->boundaryCollision(obj);
+ obj->vx = 0;
+ }
+
+ int dy = _vm->deltaY(x1, x2, obj->vy, y2);
+ if (dy != obj->vy) {
+ // An object boundary collision!
+ _vm->boundaryCollision(obj);
+ obj->vy = 0;
+ }
+
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary
+
+ obj->x += dx; // Update object position
+ obj->y += dy;
+
+ // Don't let object go outside screen
+ if (x1 < EDGE)
+ obj->x = EDGE2;
+ if (x2 > (XPIX - EDGE))
+ obj->x = XPIX - EDGE2 - (x2 - x1);
+ if (y1 < EDGE)
+ obj->y = EDGE2;
+ if (y2 > (YPIX - EDGE))
+ obj->y = YPIX - EDGE2 - (y2 - y1);
+
+ if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != WANDER2) && (obj->pathType != CHASE2))
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+
+ // Clear all object baselines from the boundary file.
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2);
+ }
+
+ // If maze mode is enabled, do special maze processing
+ if (_maze.enabledFl) {
+ seq_t *currImage = _vm->_hero->currImagePtr; // Get ptr to current image
+ // hero coordinates
+ int x1 = _vm->_hero->x + currImage->x1; // Left edge of object
+ int x2 = _vm->_hero->x + currImage->x2; // Right edge
+ int y1 = _vm->_hero->y + currImage->y1; // Top edge
+ int y2 = _vm->_hero->y + currImage->y2; // Bottom edge
+
+ _vm->_scheduler->processMaze(x1, x2, y1, y2);
+ }
+}
+
+} // End of namespace Hugo
diff --git a/engines/hugo/object_v3d.cpp b/engines/hugo/object_v3d.cpp
new file mode 100644
index 0000000000..485522bb12
--- /dev/null
+++ b/engines/hugo/object_v3d.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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on original Hugo Trilogy source code
+ *
+ * Copyright (c) 1989-1995 David P. Gray
+ *
+ */
+
+#include "common/system.h"
+#include "common/random.h"
+
+#include "hugo/game.h"
+#include "hugo/hugo.h"
+#include "hugo/object.h"
+#include "hugo/global.h"
+#include "hugo/display.h"
+#include "hugo/file.h"
+#include "hugo/route.h"
+#include "hugo/util.h"
+#include "hugo/parser.h"
+#include "hugo/schedule.h"
+
+namespace Hugo {
+
+ObjectHandler_v3d::ObjectHandler_v3d(HugoEngine *vm) : ObjectHandler_v2d(vm) {
+}
+
+ObjectHandler_v3d::~ObjectHandler_v3d() {
+}
+
+/**
+* Update all object positions. Process object 'local' events
+* including boundary events and collisions
+*/
+void ObjectHandler_v3d::moveObjects() {
+ debugC(4, kDebugObject, "moveObjects");
+
+ // Added to DOS version in order to handle mouse properly
+ // If route mode enabled, do special route processing
+ if (_vm->getGameStatus().routeIndex >= 0)
+ _vm->_route->processRoute();
+
+ // Perform any adjustments to velocity based on special path types
+ // and store all (visible) object baselines into the boundary file.
+ // Don't store foreground or background objects
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ if (obj->screenIndex == *_vm->_screen_p) {
+ switch (obj->pathType) {
+ case CHASE:
+ case CHASE2: {
+ int8 radius = obj->radius; // Default to object's radius
+ if (radius < 0) // If radius infinity, use closer value
+ radius = DX;
+
+ // Allowable motion wrt boundary
+ int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1;
+ int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1;
+ if (abs(dx) <= radius)
+ obj->vx = 0;
+ else
+ obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath);
+ if (abs(dy) <= radius)
+ obj->vy = 0;
+ else
+ obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath);
+
+ // Set first image in sequence (if multi-seq object)
+ switch (obj->seqNumb) {
+ case 4:
+ if (!obj->vx) { // Got 4 directions
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (dy >= 0)
+ obj->currImagePtr = obj->seqList[DOWN].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[_UP].seqPtr;
+ }
+ } else if (obj->vx != obj->oldvx) {
+ if (dx > 0)
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ break;
+ case 3:
+ case 2:
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (dx > 0) // Left & right only
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ break;
+ }
+
+ if (obj->vx || obj->vy) {
+ obj->cycling = CYCLE_FORWARD;
+ } else {
+ obj->cycling = NOT_CYCLING;
+ _vm->boundaryCollision(obj); // Must have got hero!
+ }
+ obj->oldvx = obj->vx;
+ obj->oldvy = obj->vy;
+ currImage = obj->currImagePtr; // Get (new) ptr to current image
+ break;
+ }
+ case WANDER2:
+ case WANDER:
+ if (!_vm->_rnd->getRandomNumber(3 * NORMAL_TPS)) { // Kick on random interval
+ obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath;
+ obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath;
+
+ // Set first image in sequence (if multi-seq object)
+ if (obj->seqNumb > 1) {
+ if (!obj->vx && (obj->seqNumb >= 4)) {
+ if (obj->vx != obj->oldvx) { // vx just stopped
+ if (obj->vy > 0)
+ obj->currImagePtr = obj->seqList[DOWN].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[_UP].seqPtr;
+ }
+ } else if (obj->vx != obj->oldvx) {
+ if (obj->vx > 0)
+ obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
+ else
+ obj->currImagePtr = obj->seqList[LEFT].seqPtr;
+ }
+ }
+ obj->oldvx = obj->vx;
+ obj->oldvy = obj->vy;
+ currImage = obj->currImagePtr; // Get (new) ptr to current image
+ }
+ if (obj->vx || obj->vy)
+ obj->cycling = CYCLE_FORWARD;
+ break;
+ default:
+ ; // Really, nothing
+ }
+ // Store boundaries
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2);
+ }
+ }
+
+ // Move objects, allowing for boundaries
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) {
+ // Only process if it's moving
+
+ // Do object movement. Delta_x,y return allowed movement in x,y
+ // to move as close to a boundary as possible without crossing it.
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ // object coordinates
+ int x1 = obj->x + currImage->x1; // Left edge of object
+ int x2 = obj->x + currImage->x2; // Right edge
+ int y1 = obj->y + currImage->y1; // Top edge
+ int y2 = obj->y + currImage->y2; // Bottom edge
+
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(x1, x2, y2); // Clear our own boundary
+
+ // Allowable motion wrt boundary
+ int dx = _vm->deltaX(x1, x2, obj->vx, y2);
+ if (dx != obj->vx) {
+ // An object boundary collision!
+ _vm->boundaryCollision(obj);
+ obj->vx = 0;
+ }
+
+ int dy = _vm->deltaY(x1, x2, obj->vy, y2);
+ if (dy != obj->vy) {
+ // An object boundary collision!
+ _vm->boundaryCollision(obj);
+ obj->vy = 0;
+ }
+
+ if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(x1, x2, y2); // Re-store our own boundary
+
+ obj->x += dx; // Update object position
+ obj->y += dy;
+
+ // Don't let object go outside screen
+ if (x1 < EDGE)
+ obj->x = EDGE2;
+ if (x2 > (XPIX - EDGE))
+ obj->x = XPIX - EDGE2 - (x2 - x1);
+ if (y1 < EDGE)
+ obj->y = EDGE2;
+ if (y2 > (YPIX - EDGE))
+ obj->y = YPIX - EDGE2 - (y2 - y1);
+
+ if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != WANDER2) && (obj->pathType != CHASE2))
+ obj->cycling = NOT_CYCLING;
+ }
+ }
+
+ // Clear all object baselines from the boundary file.
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_objects[i]; // Get pointer to object
+ seq_t *currImage = obj->currImagePtr; // Get ptr to current image
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2);
+ }
+
+ // If maze mode is enabled, do special maze processing
+ if (_maze.enabledFl) {
+ seq_t *currImage = _vm->_hero->currImagePtr;// Get ptr to current image
+ // hero coordinates
+ int x1 = _vm->_hero->x + currImage->x1; // Left edge of object
+ int x2 = _vm->_hero->x + currImage->x2; // Right edge
+ int y1 = _vm->_hero->y + currImage->y1; // Top edge
+ int y2 = _vm->_hero->y + currImage->y2; // Bottom edge
+
+ _vm->_scheduler->processMaze(x1, x2, y1, y2);
+ }
+}
+
+/**
+* Swap all the images of one object with another. Set hero_image (we make
+* the assumption for now that the first obj is always the HERO) to the object
+* number of the swapped image
+*/
+void ObjectHandler_v3d::swapImages(int objNumb1, int objNumb2) {
+ debugC(1, kDebugObject, "swapImages(%d, %d)", objNumb1, objNumb2);
+
+ saveSeq(&_objects[objNumb1]);
+
+ seqList_t tmpSeqList[MAX_SEQUENCES];
+ int seqListSize = sizeof(seqList_t) * MAX_SEQUENCES;
+
+ memcpy(tmpSeqList, _objects[objNumb1].seqList, seqListSize);
+ memcpy(_objects[objNumb1].seqList, _objects[objNumb2].seqList, seqListSize);
+ memcpy(_objects[objNumb2].seqList, tmpSeqList, seqListSize);
+ restoreSeq(&_objects[objNumb1]);
+ _objects[objNumb2].currImagePtr = _objects[objNumb2].seqList[0].seqPtr;
+ _vm->_heroImage = (_vm->_heroImage == HERO) ? objNumb2 : HERO;
+}
+
+} // End of namespace Hugo
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index 4277d6e845..22f1102b08 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -39,6 +39,7 @@
#include "hugo/route.h"
#include "hugo/util.h"
#include "hugo/sound.h"
+#include "hugo/object.h"
namespace Hugo {
@@ -46,7 +47,7 @@ namespace Hugo {
#define CX(X) LOWORD(X)
#define CY(Y) HIWORD(Y)
-Parser::Parser(HugoEngine &vm) :
+Parser::Parser(HugoEngine *vm) :
_vm(vm), _putIndex(0), _getIndex(0), _checkDoubleF1Fl(false) {
}
@@ -56,7 +57,7 @@ Parser::~Parser() {
void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
debugC(1, kDebugParser, "keyHandler(%d, %d)", nChar, nFlags);
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
bool repeatedFl = (nFlags & 0x4000); // TRUE if key is a repeat
// Process key down event - called from OnKeyDown()
@@ -74,14 +75,14 @@ void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
case Common::KEYCODE_DOWN:
if (!repeatedFl) {
gameStatus.routeIndex = -1; // Stop any automatic route
- _vm.route().setWalk(nChar); // Direction of hero travel
+ _vm->_route->setWalk(nChar); // Direction of hero travel
}
break;
case Common::KEYCODE_F1: // User Help (DOS)
if (_checkDoubleF1Fl)
- _vm.file().instructions();
+ _vm->_file->instructions();
else
- _vm.screen().userHelp();
+ _vm->_screen->userHelp();
_checkDoubleF1Fl = !_checkDoubleF1Fl;
break;
case Common::KEYCODE_F6: // Inventory
@@ -91,8 +92,8 @@ void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
_config.turboFl = !_config.turboFl;
break;
case Common::KEYCODE_F2: // Toggle sound
- _vm.sound().toggleSound();
- _vm.sound().toggleMusic();
+ _vm->_sound->toggleSound();
+ _vm->_sound->toggleMusic();
break;
case Common::KEYCODE_F3: // Repeat last line
gameStatus.recallFl = true;
@@ -105,7 +106,6 @@ void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
default: // Any other key
if (!gameStatus.storyModeFl) { // Keyboard disabled
// Add printable keys to ring buffer
-
uint16 bnext = _putIndex + 1;
if (bnext >= sizeof(_ringBuffer))
bnext = 0;
@@ -120,8 +120,10 @@ void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
_checkDoubleF1Fl = false;
}
-// Add any new chars to line buffer and display them.
-// If CR pressed, pass line to LineHandler()
+/**
+* Add any new chars to line buffer and display them.
+* If CR pressed, pass line to LineHandler()
+*/
void Parser::charHandler() {
debugC(4, kDebugParser, "charHandler");
@@ -129,7 +131,7 @@ void Parser::charHandler() {
static uint32 tick = 0; // For flashing cursor
static char cursor = '_';
static command_t cmdLine; // Build command line
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
// Check for one or more characters in ring buffer
while (_getIndex != _putIndex) {
@@ -143,7 +145,7 @@ void Parser::charHandler() {
cmdLine[--lineIndex] = '\0';
break;
case Common::KEYCODE_RETURN: // EOL, pass line to line handler
- if (lineIndex && (_vm._hero->pathType != QUIET)) {
+ if (lineIndex && (_vm->_hero->pathType != QUIET)) {
// Remove inventory bar if active
if (gameStatus.inventoryState == I_ACTIVE)
gameStatus.inventoryState = I_UP;
@@ -176,8 +178,8 @@ void Parser::charHandler() {
lineIndex = strlen(cmdLine);
}
- sprintf(_vm._statusLine, ">%s%c", cmdLine, cursor);
- sprintf(_vm._scoreLine, "F1-Help %s Score: %d of %d Sound %s", (_config.turboFl) ? "T" : " ", _vm.getScore(), _vm.getMaxScore(), (_config.soundFl) ? "On" : "Off");
+ sprintf(_vm->_statusLine, ">%s%c", cmdLine, cursor);
+ sprintf(_vm->_scoreLine, "F1-Help %s Score: %d of %d Sound %s", (_config.turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(), (_config.soundFl) ? "On" : "Off");
// See if "look" button pressed
if (gameStatus.lookFl) {
@@ -186,8 +188,10 @@ void Parser::charHandler() {
}
}
-// Perform an immediate command. Takes parameters a la sprintf
-// Assumes final string will not overrun line[] length
+/**
+* Perform an immediate command. Takes parameters a la sprintf
+* Assumes final string will not overrun line[] length
+*/
void Parser::command(const char *format, ...) {
debugC(1, kDebugParser, "Command(%s, ...)", format);
@@ -199,7 +203,9 @@ void Parser::command(const char *format, ...) {
lineHandler();
}
-// Locate any member of object name list appearing in command line
+/**
+* Locate any member of object name list appearing in command line
+*/
bool Parser::isWordPresent(char **wordArr) {
debugC(1, kDebugParser, "isWordPresent(%s)", wordArr[0]);
@@ -212,66 +218,47 @@ bool Parser::isWordPresent(char **wordArr) {
return false;
}
-// Locate word in list of nouns and return ptr to first string in noun list
+/**
+* Locate word in list of nouns and return ptr to first string in noun list
+*/
char *Parser::findNoun() {
debugC(1, kDebugParser, "findNoun()");
- for (int i = 0; _vm._arrayNouns[i]; i++) {
- for (int j = 0; strlen(_vm._arrayNouns[i][j]); j++) {
- if (strstr(_line, _vm._arrayNouns[i][j]))
- return _vm._arrayNouns[i][0];
+ for (int i = 0; _vm->_arrayNouns[i]; i++) {
+ for (int j = 0; strlen(_vm->_arrayNouns[i][j]); j++) {
+ if (strstr(_line, _vm->_arrayNouns[i][j]))
+ return _vm->_arrayNouns[i][0];
}
}
return 0;
}
-// Locate word in list of verbs and return ptr to first string in verb list
+/**
+* Locate word in list of verbs and return ptr to first string in verb list
+*/
char *Parser::findVerb() {
debugC(1, kDebugParser, "findVerb()");
- for (int i = 0; _vm._arrayVerbs[i]; i++) {
- for (int j = 0; strlen(_vm._arrayVerbs[i][j]); j++) {
- if (strstr(_line, _vm._arrayVerbs[i][j]))
- return _vm._arrayVerbs[i][0];
+ for (int i = 0; _vm->_arrayVerbs[i]; i++) {
+ for (int j = 0; strlen(_vm->_arrayVerbs[i][j]); j++) {
+ if (strstr(_line, _vm->_arrayVerbs[i][j]))
+ return _vm->_arrayVerbs[i][0];
}
}
return 0;
}
-// Describe any takeable objects visible in this screen
-void Parser::showTakeables() {
- debugC(1, kDebugParser, "showTakeables");
-
- for (int j = 0; j < _vm._numObj; j++) {
- object_t *obj = &_vm._objects[j];
- if ((obj->cycling != INVISIBLE) &&
- (obj->screenIndex == *_vm._screen_p) &&
- (((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) {
- Utils::Box(BOX_ANY, "You can also see:\n%s.", _vm._arrayNouns[obj->nounIndex][LOOK_NAME]);
- }
- }
-}
-
-// Return TRUE if object being carried by hero
-bool Parser::isCarrying(uint16 wordIndex) {
- debugC(1, kDebugParser, "isCarrying(%d)", wordIndex);
-
- for (int i = 0; i < _vm._numObj; i++) {
- if ((wordIndex == _vm._objects[i].nounIndex) && _vm._objects[i].carriedFl)
- return true;
- }
- return false;
-}
-
-// Show user all objects being carried in a variable width 2 column format
+/**
+* Show user all objects being carried in a variable width 2 column format
+*/
void Parser::showDosInventory() {
debugC(1, kDebugParser, "showDosInventory()");
static const char *blanks = " ";
uint16 index = 0, len1 = 0, len2 = 0;
- for (int i = 0; i < _vm._numObj; i++) { // Find widths of 2 columns
- if (_vm._objects[i].carriedFl) {
- uint16 len = strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]);
+ for (int i = 0; i < _vm->_numObj; i++) { // Find widths of 2 columns
+ if (_vm->_object->isCarried(i)) {
+ uint16 len = strlen(_vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][1]);
if (index++ & 1) // Right hand column
len2 = (len > len2) ? len : len2;
else
@@ -280,24 +267,24 @@ void Parser::showDosInventory() {
}
len1 += 1; // For gap between columns
- if (len1 + len2 < (uint16)strlen(_vm._textParser[kTBOutro]))
- len1 = strlen(_vm._textParser[kTBOutro]);
+ if (len1 + len2 < (uint16)strlen(_vm->_textParser[kTBOutro]))
+ len1 = strlen(_vm->_textParser[kTBOutro]);
char buffer[XBYTES *NUM_ROWS] = "\0";
- strncat(buffer, blanks, (len1 + len2 - strlen(_vm._textParser[kTBIntro])) / 2);
- strcat(strcat(buffer, _vm._textParser[kTBIntro]), "\n");
+ strncat(buffer, blanks, (len1 + len2 - strlen(_vm->_textParser[kTBIntro])) / 2);
+ strcat(strcat(buffer, _vm->_textParser[kTBIntro]), "\n");
index = 0;
- for (int i = 0; i < _vm._numObj; i++) { // Assign strings
- if (_vm._objects[i].carriedFl) {
+ for (int i = 0; i < _vm->_numObj; i++) { // Assign strings
+ if (_vm->_object->isCarried(i)) {
if (index++ & 1)
- strcat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), "\n");
+ strcat(strcat(buffer, _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][1]), "\n");
else
- strncat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), blanks, len1 - strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]));
+ strncat(strcat(buffer, _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][1]), blanks, len1 - strlen(_vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][1]));
}
}
if (index & 1)
strcat(buffer, "\n");
- strcat(buffer, _vm._textParser[kTBOutro]);
+ strcat(buffer, _vm->_textParser[kTBOutro]);
Utils::Box(BOX_ANY, "%s", buffer);
}
diff --git a/engines/hugo/parser.h b/engines/hugo/parser.h
index 5226304d51..b98813c7bc 100644
--- a/engines/hugo/parser.h
+++ b/engines/hugo/parser.h
@@ -44,7 +44,7 @@ enum seqTextParser {
class Parser {
public:
- Parser(HugoEngine &vm);
+ Parser(HugoEngine *vm);
virtual ~Parser();
bool isWordPresent(char **wordArr);
@@ -55,16 +55,12 @@ public:
virtual void lineHandler() = 0;
protected:
- HugoEngine &_vm;
+ HugoEngine *_vm;
protected:
- bool isCarrying(uint16 wordIndex);
-
char *findNoun();
char *findVerb();
- void showTakeables();
-
private:
char _ringBuffer[32]; // Ring buffer
uint16 _putIndex;
@@ -76,7 +72,7 @@ private:
class Parser_v1w : public Parser {
public:
- Parser_v1w(HugoEngine &vm);
+ Parser_v1w(HugoEngine *vm);
~Parser_v1w();
virtual void lineHandler();
@@ -95,7 +91,7 @@ private:
class Parser_v1d : public Parser {
public:
- Parser_v1d(HugoEngine &vm);
+ Parser_v1d(HugoEngine *vm);
~Parser_v1d();
virtual void lineHandler();
@@ -113,15 +109,15 @@ protected:
class Parser_v2d : public Parser_v1d {
public:
- Parser_v2d(HugoEngine &vm);
+ Parser_v2d(HugoEngine *vm);
~Parser_v2d();
void lineHandler();
};
-
+
class Parser_v3d : public Parser_v1w {
public:
- Parser_v3d(HugoEngine &vm);
+ Parser_v3d(HugoEngine *vm);
~Parser_v3d();
void lineHandler();
diff --git a/engines/hugo/parser_v1d.cpp b/engines/hugo/parser_v1d.cpp
index 9364cd9532..216ab8386c 100644
--- a/engines/hugo/parser_v1d.cpp
+++ b/engines/hugo/parser_v1d.cpp
@@ -39,72 +39,77 @@
#include "hugo/file.h"
#include "hugo/schedule.h"
#include "hugo/util.h"
+#include "hugo/object.h"
namespace Hugo {
-Parser_v1d::Parser_v1d(HugoEngine &vm) : Parser(vm) {
+Parser_v1d::Parser_v1d(HugoEngine *vm) : Parser(vm) {
}
Parser_v1d::~Parser_v1d() {
}
-// Locate word in list of nouns and return ptr to string in noun list
-// If n is NULL, start at beginning of list, else with n
+/**
+* Locate word in list of nouns and return ptr to string in noun list
+* If n is NULL, start at beginning of list, else with n
+*/
char *Parser_v1d::findNextNoun(char *noun) {
debugC(1, kDebugParser, "findNextNoun(%s)", noun);
int currNounIndex = -1;
if (noun) { // If noun not NULL, find index
- for (currNounIndex = 0; _vm._arrayNouns[currNounIndex]; currNounIndex++) {
- if (noun == _vm._arrayNouns[currNounIndex][0])
+ for (currNounIndex = 0; _vm->_arrayNouns[currNounIndex]; currNounIndex++) {
+ if (noun == _vm->_arrayNouns[currNounIndex][0])
break;
}
}
- for (int i = currNounIndex + 1; _vm._arrayNouns[i]; i++) {
- for (int j = 0; strlen(_vm._arrayNouns[i][j]); j++) {
- if (strstr(_line, _vm._arrayNouns[i][j]))
- return _vm._arrayNouns[i][0];
+ for (int i = currNounIndex + 1; _vm->_arrayNouns[i]; i++) {
+ for (int j = 0; strlen(_vm->_arrayNouns[i][j]); j++) {
+ if (strstr(_line, _vm->_arrayNouns[i][j]))
+ return _vm->_arrayNouns[i][0];
}
}
return 0;
}
-// Test whether hero is close to object. Return TRUE or FALSE
-// If no noun specified, check context flag in object before other tests.
-// If object not near, return suitable string; may be similar object closer
-// If radius is -1, treat radius as infinity
+/**
+* Test whether hero is close to object. Return TRUE or FALSE
+* If no noun specified, check context flag in object before other tests.
+* If object not near, return suitable string; may be similar object closer
+* If radius is -1, treat radius as infinity
+*/
bool Parser_v1d::isNear(char *verb, char *noun, object_t *obj, char *comment) {
debugC(1, kDebugParser, "isNear(%s, %s, obj, %s)", verb, noun, comment);
if (!noun && !obj->verbOnlyFl) { // No noun specified & object not context senesitive
return false;
- } else if (noun && (noun != _vm._arrayNouns[obj->nounIndex][0])) { // Noun specified & not same as object
+ } else if (noun && (noun != _vm->_arrayNouns[obj->nounIndex][0])) { // Noun specified & not same as object
return false;
} else if (obj->carriedFl) { // Object is being carried
return true;
- } else if (obj->screenIndex != *_vm._screen_p) { // Not in same screen
+ } else if (obj->screenIndex != *_vm->_screen_p) { // Not in same screen
if (obj->objValue)
- strcpy (comment, _vm._textParser[kCmtAny4]);
+ strcpy (comment, _vm->_textParser[kCmtAny4]);
return false;
}
if (obj->cycling == INVISIBLE) {
if (obj->seqNumb) { // There is an image
- strcpy(comment, _vm._textParser[kCmtAny5]);
+ strcpy(comment, _vm->_textParser[kCmtAny5]);
return false;
} else { // No image, assume visible
if ((obj->radius < 0) ||
- ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
- (abs(obj->y - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
+ ((abs(obj->x - _vm->_hero->x) <= obj->radius) &&
+ (abs(obj->y - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) {
return true;
} else {
// User is either not close enough (stationary, valueless objects)
// or is not carrying it (small, portable objects of value)
if (noun) { // Don't say unless object specified
- if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
- strcpy(comment, _vm._textParser[kCmtAny4]);
+ if (obj->objValue && (verb != _vm->_arrayVerbs[_vm->_take][0]))
+ strcpy(comment, _vm->_textParser[kCmtAny4]);
else
- strcpy(comment, _vm._textParser[kCmtClose]);
+ strcpy(comment, _vm->_textParser[kCmtClose]);
}
return false;
}
@@ -112,17 +117,17 @@ bool Parser_v1d::isNear(char *verb, char *noun, object_t *obj, char *comment) {
}
if ((obj->radius < 0) ||
- ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
- (abs(obj->y + obj->currImagePtr->y2 - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
+ ((abs(obj->x - _vm->_hero->x) <= obj->radius) &&
+ (abs(obj->y + obj->currImagePtr->y2 - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) {
return true;
} else {
// User is either not close enough (stationary, valueless objects)
// or is not carrying it (small, portable objects of value)
if (noun) { // Don't say unless object specified
- if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
- strcpy(comment, _vm._textParser[kCmtAny4]);
+ if (obj->objValue && (verb != _vm->_arrayVerbs[_vm->_take][0]))
+ strcpy(comment, _vm->_textParser[kCmtAny4]);
else
- strcpy(comment, _vm._textParser[kCmtClose]);
+ strcpy(comment, _vm->_textParser[kCmtClose]);
}
return false;
}
@@ -130,9 +135,11 @@ bool Parser_v1d::isNear(char *verb, char *noun, object_t *obj, char *comment) {
return true;
}
-// Test whether supplied verb is one of the common variety for this object
-// say_ok needed for special case of take/drop which may be handled not only
-// here but also in a cmd_list with a donestr string simultaneously
+/**
+* Test whether supplied verb is one of the common variety for this object
+* say_ok needed for special case of take/drop which may be handled not only
+* here but also in a cmd_list with a donestr string simultaneously
+*/
bool Parser_v1d::isGenericVerb(char *word, object_t *obj) {
debugC(1, kDebugParser, "isGenericVerb(%s, object_t *obj)", word);
@@ -140,27 +147,27 @@ bool Parser_v1d::isGenericVerb(char *word, object_t *obj) {
return false;
// Following is equivalent to switch, but couldn't do one
- if (word == _vm._arrayVerbs[_vm._look][0]) {
+ if (word == _vm->_arrayVerbs[_vm->_look][0]) {
if ((LOOK & obj->genericCmd) == LOOK)
- Utils::Box(BOX_ANY, "%s", _vm._textData[obj->dataIndex]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[obj->dataIndex]);
else
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBUnusual_1d]);
- } else if (word == _vm._arrayVerbs[_vm._take][0]) {
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBUnusual_1d]);
+ } else if (word == _vm->_arrayVerbs[_vm->_take][0]) {
if (obj->carriedFl)
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBHave]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBHave]);
else if ((TAKE & obj->genericCmd) == TAKE)
takeObject(obj);
else if (!obj->verbOnlyFl) // Make sure not taking object in context!
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoUse]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoUse]);
else
return false;
- } else if (word == _vm._arrayVerbs[_vm._drop][0]) {
+ } else if (word == _vm->_arrayVerbs[_vm->_drop][0]) {
if (!obj->carriedFl)
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBDontHave]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBDontHave]);
else if ((DROP & obj->genericCmd) == DROP)
dropObject(obj);
else
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNeed]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNeed]);
} else { // It was not a generic cmd
return false;
}
@@ -168,10 +175,12 @@ bool Parser_v1d::isGenericVerb(char *word, object_t *obj) {
return true;
}
-// Test whether supplied verb is included in the list of allowed verbs for
-// this object. If it is, then perform the tests on it from the cmd list
-// and if it passes, perform the actions in the action list. If the verb
-// is catered for, return TRUE
+/**
+* Test whether supplied verb is included in the list of allowed verbs for
+* this object. If it is, then perform the tests on it from the cmd list
+* and if it passes, perform the actions in the action list. If the verb
+* is catered for, return TRUE
+*/
bool Parser_v1d::isObjectVerb(char *word, object_t *obj) {
debugC(1, kDebugParser, "isObjectVerb(%s, object_t *obj)", word);
@@ -181,21 +190,21 @@ bool Parser_v1d::isObjectVerb(char *word, object_t *obj) {
return false;
int i;
- for (i = 0; _vm._cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd
- if (!strcmp(word, _vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex][0])) // Is this verb catered for?
+ for (i = 0; _vm->_cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd
+ if (!strcmp(word, _vm->_arrayVerbs[_vm->_cmdList[cmdIndex][i].verbIndex][0])) // Is this verb catered for?
break;
}
- if (_vm._cmdList[cmdIndex][i].verbIndex == 0) // No
+ if (_vm->_cmdList[cmdIndex][i].verbIndex == 0) // No
return false;
// Verb match found, check all required objects are being carried
- cmd *cmnd = &_vm._cmdList[cmdIndex][i]; // ptr to struct cmd
+ cmd *cmnd = &_vm->_cmdList[cmdIndex][i]; // ptr to struct cmd
if (cmnd->reqIndex) { // At least 1 thing in list
- uint16 *reqs = _vm._arrayReqs[cmnd->reqIndex]; // ptr to list of required objects
+ uint16 *reqs = _vm->_arrayReqs[cmnd->reqIndex]; // ptr to list of required objects
for (i = 0; reqs[i]; i++) { // for each obj
- if (!isCarrying(reqs[i])) {
- Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataNoCarryIndex]);
+ if (!_vm->_object->isCarrying(reqs[i])) {
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataNoCarryIndex]);
return true;
}
}
@@ -203,23 +212,25 @@ bool Parser_v1d::isObjectVerb(char *word, object_t *obj) {
// Required objects are present, now check state is correct
if ((obj->state != cmnd->reqState) && (cmnd->reqState != DONT_CARE)){
- Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataWrongIndex]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataWrongIndex]);
return true;
}
// Everything checked. Change the state and carry out any actions
if (cmnd->reqState != DONT_CARE) // Don't change new state if required state didn't care
obj->state = cmnd->newState;
- Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataDoneIndex]);
- _vm.scheduler().insertActionList(cmnd->actIndex);
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataDoneIndex]);
+ _vm->_scheduler->insertActionList(cmnd->actIndex);
// Special case if verb is Take or Drop. Assume additional generic actions
- if ((word == _vm._arrayVerbs[_vm._take][0]) || (word == _vm._arrayVerbs[_vm._drop][0]))
+ if ((word == _vm->_arrayVerbs[_vm->_take][0]) || (word == _vm->_arrayVerbs[_vm->_drop][0]))
isGenericVerb(word, obj);
return true;
}
-// Print text for possible background object. Return TRUE if match found
-// Only match if both verb and noun found. Test_ca will match verb-only
+/**
+* Print text for possible background object. Return TRUE if match found
+* Only match if both verb and noun found. Test_ca will match verb-only
+*/
bool Parser_v1d::isBackgroundWord(char *noun, char *verb, objectList_t obj) {
debugC(1, kDebugParser, "isBackgroundWord(%s, %s, object_list_t obj)", noun, verb);
@@ -227,15 +238,17 @@ bool Parser_v1d::isBackgroundWord(char *noun, char *verb, objectList_t obj) {
return false;
for (int i = 0; obj[i].verbIndex; i++) {
- if ((verb == _vm._arrayVerbs[obj[i].verbIndex][0]) && (noun == _vm._arrayNouns[obj[i].nounIndex][0])) {
- Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
+ if ((verb == _vm->_arrayVerbs[obj[i].verbIndex][0]) && (noun == _vm->_arrayNouns[obj[i].nounIndex][0])) {
+ Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(obj[i].commentIndex));
return true;
}
}
return false;
}
-// Do all things necessary to carry an object
+/**
+* Do all things necessary to carry an object
+*/
void Parser_v1d::takeObject(object_t *obj) {
debugC(1, kDebugParser, "takeObject(object_t *obj)");
@@ -243,27 +256,31 @@ void Parser_v1d::takeObject(object_t *obj) {
if (obj->seqNumb) // Don't change if no image to display
obj->cycling = ALMOST_INVISIBLE;
- _vm.adjustScore(obj->objValue);
+ _vm->adjustScore(obj->objValue);
- Utils::Box(BOX_ANY, TAKE_TEXT, _vm._arrayNouns[obj->nounIndex][TAKE_NAME]);
+ Utils::Box(BOX_ANY, TAKE_TEXT, _vm->_arrayNouns[obj->nounIndex][TAKE_NAME]);
}
-// Do all necessary things to drop an object
+/**
+* Do all necessary things to drop an object
+*/
void Parser_v1d::dropObject(object_t *obj) {
debugC(1, kDebugParser, "dropObject(object_t *obj)");
obj->carriedFl = false;
- obj->screenIndex = *_vm._screen_p;
+ obj->screenIndex = *_vm->_screen_p;
if (obj->seqNumb) // Don't change if no image to display
obj->cycling = NOT_CYCLING;
- obj->x = _vm._hero->x - 1;
- obj->y = _vm._hero->y + _vm._hero->currImagePtr->y2 - 1;
- _vm.adjustScore(-obj->objValue);
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBOk]);
+ obj->x = _vm->_hero->x - 1;
+ obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1;
+ _vm->adjustScore(-obj->objValue);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBOk]);
}
-// Print text for possible background object. Return TRUE if match found
-// If test_noun TRUE, must have a noun given
+/**
+* Print text for possible background object. Return TRUE if match found
+* If test_noun TRUE, must have a noun given
+*/
bool Parser_v1d::isCatchallVerb(bool testNounFl, char *noun, char *verb, objectList_t obj) {
debugC(1, kDebugParser, "isCatchallVerb(%d, %s, %s, object_list_t obj)", (testNounFl) ? 1 : 0, noun, verb);
@@ -271,28 +288,30 @@ bool Parser_v1d::isCatchallVerb(bool testNounFl, char *noun, char *verb, objectL
return false;
for (int i = 0; obj[i].verbIndex; i++) {
- if ((verb == _vm._arrayVerbs[obj[i].verbIndex][0]) && ((noun == _vm._arrayNouns[obj[i].nounIndex][0]) || (obj[i].nounIndex == 0))) {
- Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
+ if ((verb == _vm->_arrayVerbs[obj[i].verbIndex][0]) && ((noun == _vm->_arrayNouns[obj[i].nounIndex][0]) || (obj[i].nounIndex == 0))) {
+ Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(obj[i].commentIndex));
return true;
}
}
return false;
}
-// Parse the user's line of text input. Generate events as necessary
+/**
+* Parse the user's line of text input. Generate events as necessary
+*/
void Parser_v1d::lineHandler() {
debugC(1, kDebugParser, "lineHandler()");
object_t *obj;
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby
// Reset_prompt_line ();
Utils::strlwr(_line); // Convert to lower case
if (!strcmp("exit", _line) || strstr(_line, "quit")) {
- if (Utils::Box(BOX_YESNO, "%s", _vm._textParser[kTBExit_1d]) != 0)
- _vm.endGame();
+ if (Utils::Box(BOX_YESNO, "%s", _vm->_textParser[kTBExit_1d]) != 0)
+ _vm->endGame();
return;
}
@@ -301,13 +320,13 @@ void Parser_v1d::lineHandler() {
if (gameStatus.gameOverFl)
Utils::gameOverMsg();
else
-// _vm.file().saveOrRestore(true);
+// _vm->_file->saveOrRestore(true);
warning("STUB: saveOrRestore()");
return;
}
if (!strcmp("restore", _line)) {
-// _vm.file().saveOrRestore(false);
+// _vm->_file->saveOrRestore(false);
warning("STUB: saveOrRestore()");
return;
}
@@ -331,25 +350,25 @@ void Parser_v1d::lineHandler() {
do {
noun = findNextNoun(noun); // Find a noun in the line
// Must try at least once for objects allowing verb-context
- for (int i = 0; i < _vm._numObj; i++) {
- obj = &_vm._objects[i];
+ for (int i = 0; i < _vm->_numObj; i++) {
+ obj = &_vm->_object->_objects[i];
if (isNear(verb, noun, obj, farComment)) {
if (isObjectVerb(verb, obj) // Foreground object
|| isGenericVerb(verb, obj)) // Common action type
return;
}
}
- if ((*farComment == '\0') && isBackgroundWord(noun, verb, _vm._backgroundObjects[*_vm._screen_p]))
+ if ((*farComment == '\0') && isBackgroundWord(noun, verb, _vm->_backgroundObjects[*_vm->_screen_p]))
return;
} while (noun);
}
noun = findNextNoun(noun);
if (*farComment != '\0') // An object matched but not near enough
Utils::Box(BOX_ANY, "%s", farComment);
- else if (!isCatchallVerb(true, noun, verb, _vm._catchallList) &&
- !isCatchallVerb(false, noun, verb, _vm._backgroundObjects[*_vm._screen_p]) &&
- !isCatchallVerb(false, noun, verb, _vm._catchallList))
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh_1d]);
+ else if (!isCatchallVerb(true, noun, verb, _vm->_catchallList) &&
+ !isCatchallVerb(false, noun, verb, _vm->_backgroundObjects[*_vm->_screen_p]) &&
+ !isCatchallVerb(false, noun, verb, _vm->_catchallList))
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBEh_1d]);
}
} // End of namespace Hugo
diff --git a/engines/hugo/parser_v1w.cpp b/engines/hugo/parser_v1w.cpp
index 417b31e794..96442e4fcd 100644
--- a/engines/hugo/parser_v1w.cpp
+++ b/engines/hugo/parser_v1w.cpp
@@ -40,17 +40,20 @@
#include "hugo/schedule.h"
#include "hugo/util.h"
#include "hugo/sound.h"
+#include "hugo/object.h"
namespace Hugo {
-Parser_v1w::Parser_v1w(HugoEngine &vm) : Parser(vm) {
+Parser_v1w::Parser_v1w(HugoEngine *vm) : Parser(vm) {
}
Parser_v1w::~Parser_v1w() {
}
-// Test whether command line contains a verb allowed by this object.
-// If it does, and the object is near and passes the tests in the command
-// list then carry out the actions in the action list and return TRUE
+/**
+* Test whether command line contains a verb allowed by this object.
+* If it does, and the object is near and passes the tests in the command
+* list then carry out the actions in the action list and return TRUE
+*/
bool Parser_v1w::isObjectVerb(object_t *obj, char *comment) {
debugC(1, kDebugParser, "isObjectVerb(object_t *obj, %s)", comment);
@@ -60,26 +63,26 @@ bool Parser_v1w::isObjectVerb(object_t *obj, char *comment) {
return false;
int i;
- for (i = 0; _vm._cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd
- if (isWordPresent(_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex])) // Was this verb used?
+ for (i = 0; _vm->_cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd
+ if (isWordPresent(_vm->_arrayVerbs[_vm->_cmdList[cmdIndex][i].verbIndex])) // Was this verb used?
break;
}
- if (_vm._cmdList[cmdIndex][i].verbIndex == 0) // No verbs used.
+ if (_vm->_cmdList[cmdIndex][i].verbIndex == 0) // No verbs used.
return false;
// Verb match found. Check if object is Near
- char *verb = *_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex];
+ char *verb = *_vm->_arrayVerbs[_vm->_cmdList[cmdIndex][i].verbIndex];
if (!isNear(obj, verb, comment))
return false;
// Check all required objects are being carried
- cmd *cmnd = &_vm._cmdList[cmdIndex][i]; // ptr to struct cmd
+ cmd *cmnd = &_vm->_cmdList[cmdIndex][i]; // ptr to struct cmd
if (cmnd->reqIndex) { // At least 1 thing in list
- uint16 *reqs = _vm._arrayReqs[cmnd->reqIndex]; // ptr to list of required objects
+ uint16 *reqs = _vm->_arrayReqs[cmnd->reqIndex]; // ptr to list of required objects
for (i = 0; reqs[i]; i++) { // for each obj
- if (!isCarrying(reqs[i])) {
- Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataNoCarryIndex]);
+ if (!_vm->_object->isCarrying(reqs[i])) {
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataNoCarryIndex]);
return true;
}
}
@@ -87,23 +90,25 @@ bool Parser_v1w::isObjectVerb(object_t *obj, char *comment) {
// Required objects are present, now check state is correct
if ((obj->state != cmnd->reqState) && (cmnd->reqState != DONT_CARE)) {
- Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataWrongIndex]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataWrongIndex]);
return true;
}
// Everything checked. Change the state and carry out any actions
if (cmnd->reqState != DONT_CARE) // Don't change new state if required state didn't care
obj->state = cmnd->newState;
- Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataDoneIndex]);
- _vm.scheduler().insertActionList(cmnd->actIndex);
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[cmnd->textDataDoneIndex]);
+ _vm->_scheduler->insertActionList(cmnd->actIndex);
// See if any additional generic actions
- if ((verb == _vm._arrayVerbs[_vm._look][0]) || (verb == _vm._arrayVerbs[_vm._take][0]) || (verb == _vm._arrayVerbs[_vm._drop][0]))
+ if ((verb == _vm->_arrayVerbs[_vm->_look][0]) || (verb == _vm->_arrayVerbs[_vm->_take][0]) || (verb == _vm->_arrayVerbs[_vm->_drop][0]))
isGenericVerb(obj, comment);
return true;
}
-// Test whether command line contains one of the generic actions
+/**
+* Test whether command line contains one of the generic actions
+*/
bool Parser_v1w::isGenericVerb(object_t *obj, char *comment) {
debugC(1, kDebugParser, "isGenericVerb(object_t *obj, %s)", comment);
@@ -111,39 +116,39 @@ bool Parser_v1w::isGenericVerb(object_t *obj, char *comment) {
return false;
// Following is equivalent to switch, but couldn't do one
- if (isWordPresent(_vm._arrayVerbs[_vm._look]) && isNear(obj, _vm._arrayVerbs[_vm._look][0], comment)) {
+ if (isWordPresent(_vm->_arrayVerbs[_vm->_look]) && isNear(obj, _vm->_arrayVerbs[_vm->_look][0], comment)) {
// Test state-dependent look before general look
if ((obj->genericCmd & LOOK_S) == LOOK_S) {
- Utils::Box(BOX_ANY, "%s", _vm._textData[obj->stateDataIndex[obj->state]]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[obj->stateDataIndex[obj->state]]);
warning("isGenericVerb: use of state dependant look - To be validated");
} else {
if ((LOOK & obj->genericCmd) == LOOK) {
- if (_vm._textData[obj->dataIndex])
- Utils::Box(BOX_ANY, "%s", _vm._textData[obj->dataIndex]);
+ if (_vm->_textData[obj->dataIndex])
+ Utils::Box(BOX_ANY, "%s", _vm->_textData[obj->dataIndex]);
else
return false;
} else {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBUnusual]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBUnusual]);
}
}
- } else if (isWordPresent(_vm._arrayVerbs[_vm._take]) && isNear(obj, _vm._arrayVerbs[_vm._take][0], comment)) {
+ } else if (isWordPresent(_vm->_arrayVerbs[_vm->_take]) && isNear(obj, _vm->_arrayVerbs[_vm->_take][0], comment)) {
if (obj->carriedFl)
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBHave]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBHave]);
else if ((TAKE & obj->genericCmd) == TAKE)
takeObject(obj);
else if (obj->cmdIndex != 0) // No comment if possible commands
return false;
else if (!obj->verbOnlyFl && (TAKE & obj->genericCmd) == TAKE) // Make sure not taking object in context!
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoUse]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoUse]);
else
return false;
- } else if (isWordPresent(_vm._arrayVerbs[_vm._drop])) {
+ } else if (isWordPresent(_vm->_arrayVerbs[_vm->_drop])) {
if (!obj->carriedFl && ((DROP & obj->genericCmd) == DROP))
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBDontHave]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBDontHave]);
else if (obj->carriedFl && ((DROP & obj->genericCmd) == DROP))
dropObject(obj);
else if (obj->cmdIndex == 0)
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNeed]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNeed]);
else
return false;
} else { // It was not a generic cmd
@@ -153,63 +158,67 @@ bool Parser_v1w::isGenericVerb(object_t *obj, char *comment) {
return true;
}
-// Test whether hero is close to object. Return TRUE or FALSE
-// If object not near, return suitable comment; may be another object close
-// If radius is -1, treat radius as infinity
-// Verb is included to determine correct comment if not near
+/**
+* Test whether hero is close to object. Return TRUE or FALSE
+* If object not near, return suitable comment; may be another object close
+* If radius is -1, treat radius as infinity
+* Verb is included to determine correct comment if not near
+*/
bool Parser_v1w::isNear(object_t *obj, char *verb, char *comment) {
debugC(1, kDebugParser, "isNear(object_t *obj, %s, %s)", verb, comment);
if (obj->carriedFl) // Object is being carried
return true;
- if (obj->screenIndex != *_vm._screen_p) {
+ if (obj->screenIndex != *_vm->_screen_p) {
// Not in same screen
if (obj->objValue)
- strcpy(comment, _vm._textParser[kCmtAny1]);
+ strcpy(comment, _vm->_textParser[kCmtAny1]);
else
- strcpy(comment, _vm._textParser[kCmtAny2]);
+ strcpy(comment, _vm->_textParser[kCmtAny2]);
return false;
}
if (obj->cycling == INVISIBLE) {
if (obj->seqNumb) {
// There is an image
- strcpy(comment, _vm._textParser[kCmtAny3]);
+ strcpy(comment, _vm->_textParser[kCmtAny3]);
return false;
} else {
// No image, assume visible
if ((obj->radius < 0) ||
- ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
- (abs(obj->y - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
+ ((abs(obj->x - _vm->_hero->x) <= obj->radius) &&
+ (abs(obj->y - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) {
return true;
} else {
// User is not close enough
- if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
- strcpy(comment, _vm._textParser[kCmtAny1]);
+ if (obj->objValue && (verb != _vm->_arrayVerbs[_vm->_take][0]))
+ strcpy(comment, _vm->_textParser[kCmtAny1]);
else
- strcpy(comment, _vm._textParser[kCmtClose]);
+ strcpy(comment, _vm->_textParser[kCmtClose]);
return false;
}
}
}
if ((obj->radius < 0) ||
- ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
- (abs(obj->y + obj->currImagePtr->y2 - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
+ ((abs(obj->x - _vm->_hero->x) <= obj->radius) &&
+ (abs(obj->y + obj->currImagePtr->y2 - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) {
return true;
} else {
// User is not close enough
- if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
- strcpy(comment, _vm._textParser[kCmtAny1]);
+ if (obj->objValue && (verb != _vm->_arrayVerbs[_vm->_take][0]))
+ strcpy(comment, _vm->_textParser[kCmtAny1]);
else
- strcpy(comment, _vm._textParser[kCmtClose]);
+ strcpy(comment, _vm->_textParser[kCmtClose]);
return false;
}
return true;
}
-// Do all things necessary to carry an object
+/**
+* Do all things necessary to carry an object
+*/
void Parser_v1w::takeObject(object_t *obj) {
debugC(1, kDebugParser, "takeObject(object_t *obj)");
@@ -217,48 +226,52 @@ void Parser_v1w::takeObject(object_t *obj) {
if (obj->seqNumb) { // Don't change if no image to display
obj->cycling = INVISIBLE;
}
- _vm.adjustScore(obj->objValue);
+ _vm->adjustScore(obj->objValue);
if (obj->seqNumb > 0) // If object has an image, force walk to dropped
obj->viewx = -1; // (possibly moved) object next time taken!
- Utils::Box(BOX_ANY, TAKE_TEXT, _vm._arrayNouns[obj->nounIndex][TAKE_NAME]);
+ Utils::Box(BOX_ANY, TAKE_TEXT, _vm->_arrayNouns[obj->nounIndex][TAKE_NAME]);
}
-// Do all necessary things to drop an object
+/**
+* Do all necessary things to drop an object
+*/
void Parser_v1w::dropObject(object_t *obj) {
debugC(1, kDebugParser, "dropObject(object_t *obj)");
obj->carriedFl = false;
- obj->screenIndex = *_vm._screen_p;
+ obj->screenIndex = *_vm->_screen_p;
if ((obj->seqNumb > 1) || (obj->seqList[0].imageNbr > 1))
obj->cycling = CYCLE_FORWARD;
else
obj->cycling = NOT_CYCLING;
- obj->x = _vm._hero->x - 1;
- obj->y = _vm._hero->y + _vm._hero->currImagePtr->y2 - 1;
+ obj->x = _vm->_hero->x - 1;
+ obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1;
obj->y = (obj->y + obj->currImagePtr->y2 < YPIX) ? obj->y : YPIX - obj->currImagePtr->y2 - 10;
- _vm.adjustScore(-obj->objValue);
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBOk]);
+ _vm->adjustScore(-obj->objValue);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBOk]);
}
-// Search for matching verbs in background command list.
-// Noun is not required. Return TRUE if match found
-// Note that if the background command list has match set TRUE then do not
-// print text if there are any recognizable nouns in the command line
+/**
+* Search for matching verbs in background command list.
+* Noun is not required. Return TRUE if match found
+* Note that if the background command list has match set TRUE then do not
+* print text if there are any recognizable nouns in the command line
+*/
bool Parser_v1w::isCatchallVerb(objectList_t obj) {
debugC(1, kDebugParser, "isCatchallVerb(object_list_t obj)");
for (int i = 0; obj[i].verbIndex != 0; i++) {
- if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) && obj[i].nounIndex == 0 &&
+ if (isWordPresent(_vm->_arrayVerbs[obj[i].verbIndex]) && obj[i].nounIndex == 0 &&
(!obj[i].matchFl || !findNoun()) &&
((obj[i].roomState == DONT_CARE) ||
- (obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
- Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
- _vm.scheduler().processBonus(obj[i].bonusIndex);
+ (obj[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) {
+ Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(obj[i].commentIndex));
+ _vm->_scheduler->processBonus(obj[i].bonusIndex);
// If this is LOOK (without a noun), show any takeable objects
- if (*(_vm._arrayVerbs[obj[i].verbIndex]) == _vm._arrayVerbs[_vm._look][0])
- showTakeables();
+ if (*(_vm->_arrayVerbs[obj[i].verbIndex]) == _vm->_arrayVerbs[_vm->_look][0])
+ _vm->_object->showTakeables();
return true;
}
@@ -266,33 +279,37 @@ bool Parser_v1w::isCatchallVerb(objectList_t obj) {
return false;
}
-// Search for matching verb/noun pairs in background command list
-// Print text for possible background object. Return TRUE if match found
+/**
+* Search for matching verb/noun pairs in background command list
+* Print text for possible background object. Return TRUE if match found
+*/
bool Parser_v1w::isBackgroundWord(objectList_t obj) {
debugC(1, kDebugParser, "isBackgroundWord(object_list_t obj)");
for (int i = 0; obj[i].verbIndex != 0; i++) {
- if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) &&
- isWordPresent(_vm._arrayNouns[obj[i].nounIndex]) &&
+ if (isWordPresent(_vm->_arrayVerbs[obj[i].verbIndex]) &&
+ isWordPresent(_vm->_arrayNouns[obj[i].nounIndex]) &&
((obj[i].roomState == DONT_CARE) ||
- (obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
- Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
- _vm.scheduler().processBonus(obj[i].bonusIndex);
+ (obj[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) {
+ Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(obj[i].commentIndex));
+ _vm->_scheduler->processBonus(obj[i].bonusIndex);
return true;
}
}
return false;
}
-// Parse the user's line of text input. Generate events as necessary
+/**
+* Parse the user's line of text input. Generate events as necessary
+*/
void Parser_v1w::lineHandler() {
debugC(1, kDebugParser, "lineHandler()");
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
// Toggle God Mode
if (!strncmp(_line, "PPG", 3)) {
- _vm.sound().playSound(!_vm._soundTest, BOTH_CHANNELS, HIGH_PRI);
+ _vm->_sound->playSound(!_vm->_soundTest, BOTH_CHANNELS, HIGH_PRI);
gameStatus.godModeFl ^= 1;
return;
}
@@ -307,9 +324,9 @@ void Parser_v1w::lineHandler() {
if (gameStatus.godModeFl) {
// Special code to allow me to go straight to any screen
if (strstr(_line, "goto")) {
- for (int i = 0; i < _vm._numScreens; i++) {
- if (!strcmp(&_line[strlen("goto") + 1], _vm._screenNames[i])) {
- _vm.scheduler().newScreen(i);
+ for (int i = 0; i < _vm->_numScreens; i++) {
+ if (!strcmp(&_line[strlen("goto") + 1], _vm->_screenNames[i])) {
+ _vm->_scheduler->newScreen(i);
return;
}
}
@@ -317,17 +334,17 @@ void Parser_v1w::lineHandler() {
// Special code to allow me to get objects from anywhere
if (strstr(_line, "fetch all")) {
- for (int i = 0; i < _vm._numObj; i++) {
- if (_vm._objects[i].genericCmd & TAKE)
- takeObject(&_vm._objects[i]);
+ for (int i = 0; i < _vm->_numObj; i++) {
+ if (_vm->_object->_objects[i].genericCmd & TAKE)
+ takeObject(&_vm->_object->_objects[i]);
}
return;
}
if (strstr(_line, "fetch")) {
- for (int i = 0; i < _vm._numObj; i++) {
- if (!strcmp(&_line[strlen("fetch") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) {
- takeObject(&_vm._objects[i]);
+ for (int i = 0; i < _vm->_numObj; i++) {
+ if (!strcmp(&_line[strlen("fetch") + 1], _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][0])) {
+ takeObject(&_vm->_object->_objects[i]);
return;
}
}
@@ -335,9 +352,9 @@ void Parser_v1w::lineHandler() {
// Special code to allow me to goto objects
if (strstr(_line, "find")) {
- for (int i = 0; i < _vm._numObj; i++) {
- if (!strcmp(&_line[strlen("find") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) {
- _vm.scheduler().newScreen(_vm._objects[i].screenIndex);
+ for (int i = 0; i < _vm->_numObj; i++) {
+ if (!strcmp(&_line[strlen("find") + 1], _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][0])) {
+ _vm->_scheduler->newScreen(_vm->_object->_objects[i].screenIndex);
return;
}
}
@@ -347,19 +364,19 @@ void Parser_v1w::lineHandler() {
// Special meta commands
// EXIT/QUIT
if (!strcmp("exit", _line) || strstr(_line, "quit")) {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBExit]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBExit]);
return;
}
// SAVE/RESTORE
if (!strcmp("save", _line) && gameStatus.viewState == V_PLAY) {
- _vm.file().saveGame(gameStatus.saveSlot, "Current game");
+ _vm->_file->saveGame(gameStatus.saveSlot, "Current game");
return;
}
if (!strcmp("restore", _line) && (gameStatus.viewState == V_PLAY || gameStatus.viewState == V_IDLE)) {
- _vm.file().restoreGame(gameStatus.saveSlot);
- _vm.scheduler().restoreScreen(*_vm._screen_p);
+ _vm->_file->restoreGame(gameStatus.saveSlot);
+ _vm->_scheduler->restoreScreen(*_vm->_screen_p);
gameStatus.viewState = V_PLAY;
return;
}
@@ -379,9 +396,9 @@ void Parser_v1w::lineHandler() {
char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby
// Test for nearby objects referenced explicitly
- for (int i = 0; i < _vm._numObj; i++) {
- object_t *obj = &_vm._objects[i];
- if (isWordPresent(_vm._arrayNouns[obj->nounIndex])) {
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_vm->_object->_objects[i];
+ if (isWordPresent(_vm->_arrayNouns[obj->nounIndex])) {
if (isObjectVerb(obj, farComment) || isGenericVerb(obj, farComment))
return;
}
@@ -389,8 +406,8 @@ void Parser_v1w::lineHandler() {
// Test for nearby objects that only require a verb
// Note comment is unused if not near.
- for (int i = 0; i < _vm._numObj; i++) {
- object_t *obj = &_vm._objects[i];
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_vm->_object->_objects[i];
if (obj->verbOnlyFl) {
char contextComment[XBYTES * 5] = ""; // Unused comment for context objects
if (isObjectVerb(obj, contextComment) || isGenericVerb(obj, contextComment))
@@ -399,13 +416,13 @@ void Parser_v1w::lineHandler() {
}
// No objects match command line, try background and catchall commands
- if (isBackgroundWord(_vm._backgroundObjects[*_vm._screen_p]))
+ if (isBackgroundWord(_vm->_backgroundObjects[*_vm->_screen_p]))
return;
- if (isCatchallVerb(_vm._backgroundObjects[*_vm._screen_p]))
+ if (isCatchallVerb(_vm->_backgroundObjects[*_vm->_screen_p]))
return;
- if (isBackgroundWord(_vm._catchallList))
+ if (isBackgroundWord(_vm->_catchallList))
return;
- if (isCatchallVerb(_vm._catchallList))
+ if (isCatchallVerb(_vm->_catchallList))
return;
// If a not-near comment was generated, print it
@@ -417,17 +434,17 @@ void Parser_v1w::lineHandler() {
// Nothing matches. Report recognition success to user.
char *verb = findVerb();
char *noun = findNoun();
- if (verb == _vm._arrayVerbs[_vm._look][0] && _maze.enabledFl) {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBMaze]);
- showTakeables();
+ if (verb == _vm->_arrayVerbs[_vm->_look][0] && _maze.enabledFl) {
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBMaze]);
+ _vm->_object->showTakeables();
} else if (verb && noun) { // A combination I didn't think of
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoPoint]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoPoint]);
} else if (noun) {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoun]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoun]);
} else if (verb) {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBVerb]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBVerb]);
} else {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBEh]);
}
}
diff --git a/engines/hugo/parser_v2d.cpp b/engines/hugo/parser_v2d.cpp
index adaf5e9f9f..fc82412962 100644
--- a/engines/hugo/parser_v2d.cpp
+++ b/engines/hugo/parser_v2d.cpp
@@ -37,29 +37,32 @@
#include "hugo/hugo.h"
#include "hugo/parser.h"
#include "hugo/util.h"
+#include "hugo/object.h"
namespace Hugo {
-Parser_v2d::Parser_v2d(HugoEngine &vm) : Parser_v1d(vm) {
+Parser_v2d::Parser_v2d(HugoEngine *vm) : Parser_v1d(vm) {
}
Parser_v2d::~Parser_v2d() {
}
-// Parse the user's line of text input. Generate events as necessary
+/**
+* Parse the user's line of text input. Generate events as necessary
+*/
void Parser_v2d::lineHandler() {
debugC(1, kDebugParser, "lineHandler()");
object_t *obj;
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby
// Reset_prompt_line ();
Utils::strlwr(_line); // Convert to lower case
if (!strcmp("exit", _line) || strstr(_line, "quit")) {
- if (Utils::Box(BOX_YESNO, "%s", _vm._textParser[kTBExit_1d]) != 0)
- _vm.endGame();
+ if (Utils::Box(BOX_YESNO, "%s", _vm->_textParser[kTBExit_1d]) != 0)
+ _vm->endGame();
else
return;
}
@@ -70,14 +73,14 @@ void Parser_v2d::lineHandler() {
if (gameStatus.gameOverFl)
Utils::gameOverMsg();
else
-// _vm.file().saveOrRestore(true);
+// _vm->_file->saveOrRestore(true);
warning("STUB: saveOrRestore()");
return;
}
if (!strcmp("restore", _line)) {
_config.soundFl = false;
-// _vm.file().saveOrRestore(false);
+// _vm->_file->saveOrRestore(false);
warning("STUB: saveOrRestore()");
return;
}
@@ -101,35 +104,35 @@ void Parser_v2d::lineHandler() {
do {
noun = findNextNoun(noun); // Find a noun in the line
// Must try at least once for objects allowing verb-context
- for (int i = 0; i < _vm._numObj; i++) {
- obj = &_vm._objects[i];
+ for (int i = 0; i < _vm->_numObj; i++) {
+ obj = &_vm->_object->_objects[i];
if (isNear(verb, noun, obj, farComment)) {
if (isObjectVerb(verb, obj) // Foreground object
|| isGenericVerb(verb, obj)) // Common action type
return;
}
}
- if ((*farComment != '\0') && isBackgroundWord(noun, verb, _vm._backgroundObjects[*_vm._screen_p]))
+ if ((*farComment != '\0') && isBackgroundWord(noun, verb, _vm->_backgroundObjects[*_vm->_screen_p]))
return;
} while (noun);
}
noun = findNextNoun(noun);
- if ( !isCatchallVerb(true, noun, verb, _vm._backgroundObjects[*_vm._screen_p])
- && !isCatchallVerb(true, noun, verb, _vm._catchallList)
- && !isCatchallVerb(false, noun, verb, _vm._backgroundObjects[*_vm._screen_p])
- && !isCatchallVerb(false, noun, verb, _vm._catchallList)) {
+ if ( !isCatchallVerb(true, noun, verb, _vm->_backgroundObjects[*_vm->_screen_p])
+ && !isCatchallVerb(true, noun, verb, _vm->_catchallList)
+ && !isCatchallVerb(false, noun, verb, _vm->_backgroundObjects[*_vm->_screen_p])
+ && !isCatchallVerb(false, noun, verb, _vm->_catchallList)) {
if (*farComment != '\0') { // An object matched but not near enough
Utils::Box(BOX_ANY, "%s", farComment);
- } else if (_maze.enabledFl && (verb == _vm._arrayVerbs[_vm._look][0])) {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBMaze]);
- showTakeables();
+ } else if (_maze.enabledFl && (verb == _vm->_arrayVerbs[_vm->_look][0])) {
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBMaze]);
+ _vm->_object->showTakeables();
} else if (verb && noun) { // A combination I didn't think of
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoUse_2d]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoUse_2d]);
} else if (verb || noun) {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoun]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoun]);
} else {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh_2d]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBEh_2d]);
}
}
}
diff --git a/engines/hugo/parser_v3d.cpp b/engines/hugo/parser_v3d.cpp
index 501d8fba20..7c0b9adedf 100644
--- a/engines/hugo/parser_v3d.cpp
+++ b/engines/hugo/parser_v3d.cpp
@@ -39,24 +39,27 @@
#include "hugo/schedule.h"
#include "hugo/util.h"
#include "hugo/sound.h"
+#include "hugo/object.h"
namespace Hugo {
-Parser_v3d::Parser_v3d(HugoEngine &vm) : Parser_v1w(vm) {
+Parser_v3d::Parser_v3d(HugoEngine *vm) : Parser_v1w(vm) {
}
Parser_v3d::~Parser_v3d() {
}
-// Parse the user's line of text input. Generate events as necessary
+/**
+* Parse the user's line of text input. Generate events as necessary
+*/
void Parser_v3d::lineHandler() {
debugC(1, kDebugParser, "lineHandler()");
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
// Toggle God Mode
if (!strncmp(_line, "PPG", 3)) {
- _vm.sound().playSound(!_vm._soundTest, BOTH_CHANNELS, HIGH_PRI);
+ _vm->_sound->playSound(!_vm->_soundTest, BOTH_CHANNELS, HIGH_PRI);
gameStatus.godModeFl ^= 1;
return;
}
@@ -71,9 +74,9 @@ void Parser_v3d::lineHandler() {
if (gameStatus.godModeFl) {
// Special code to allow me to go straight to any screen
if (strstr(_line, "goto")) {
- for (int i = 0; i < _vm._numScreens; i++) {
- if (!strcmp(&_line[strlen("goto") + 1], _vm._screenNames[i])) {
- _vm.scheduler().newScreen(i);
+ for (int i = 0; i < _vm->_numScreens; i++) {
+ if (!strcmp(&_line[strlen("goto") + 1], _vm->_screenNames[i])) {
+ _vm->_scheduler->newScreen(i);
return;
}
}
@@ -81,17 +84,17 @@ void Parser_v3d::lineHandler() {
// Special code to allow me to get objects from anywhere
if (strstr(_line, "fetch all")) {
- for (int i = 0; i < _vm._numObj; i++) {
- if (_vm._objects[i].genericCmd & TAKE)
- takeObject(&_vm._objects[i]);
+ for (int i = 0; i < _vm->_numObj; i++) {
+ if (_vm->_object->_objects[i].genericCmd & TAKE)
+ takeObject(&_vm->_object->_objects[i]);
}
return;
}
if (strstr(_line, "fetch")) {
- for (int i = 0; i < _vm._numObj; i++) {
- if (!strcmp(&_line[strlen("fetch") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) {
- takeObject(&_vm._objects[i]);
+ for (int i = 0; i < _vm->_numObj; i++) {
+ if (!strcmp(&_line[strlen("fetch") + 1], _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][0])) {
+ takeObject(&_vm->_object->_objects[i]);
return;
}
}
@@ -99,9 +102,9 @@ void Parser_v3d::lineHandler() {
// Special code to allow me to goto objects
if (strstr(_line, "find")) {
- for (int i = 0; i < _vm._numObj; i++) {
- if (!strcmp(&_line[strlen("find") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) {
- _vm.scheduler().newScreen(_vm._objects[i].screenIndex);
+ for (int i = 0; i < _vm->_numObj; i++) {
+ if (!strcmp(&_line[strlen("find") + 1], _vm->_arrayNouns[_vm->_object->_objects[i].nounIndex][0])) {
+ _vm->_scheduler->newScreen(_vm->_object->_objects[i].screenIndex);
return;
}
}
@@ -111,8 +114,8 @@ void Parser_v3d::lineHandler() {
// Special meta commands
// EXIT/QUIT
if (!strcmp("exit", _line) || strstr(_line, "quit")) {
- if (Utils::Box(BOX_YESNO, "%s", _vm._textParser[kTBExit_1d]) != 0)
- _vm.endGame();
+ if (Utils::Box(BOX_YESNO, "%s", _vm->_textParser[kTBExit_1d]) != 0)
+ _vm->endGame();
else
return;
}
@@ -123,14 +126,14 @@ void Parser_v3d::lineHandler() {
if (gameStatus.gameOverFl)
Utils::gameOverMsg();
else
-// _vm.file().saveOrRestore(true);
+// _vm->_file->saveOrRestore(true);
warning("STUB: saveOrRestore()");
return;
}
if (!strcmp("restore", _line)) {
_config.soundFl = false;
-// _vm.file().saveOrRestore(false);
+// _vm->_file->saveOrRestore(false);
warning("STUB: saveOrRestore()");
return;
}
@@ -150,9 +153,9 @@ void Parser_v3d::lineHandler() {
char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby
// Test for nearby objects referenced explicitly
- for (int i = 0; i < _vm._numObj; i++) {
- object_t *obj = &_vm._objects[i];
- if (isWordPresent(_vm._arrayNouns[obj->nounIndex])) {
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_vm->_object->_objects[i];
+ if (isWordPresent(_vm->_arrayNouns[obj->nounIndex])) {
if (isObjectVerb(obj, farComment) || isGenericVerb(obj, farComment))
return;
}
@@ -160,8 +163,8 @@ void Parser_v3d::lineHandler() {
// Test for nearby objects that only require a verb
// Note comment is unused if not near.
- for (int i = 0; i < _vm._numObj; i++) {
- object_t *obj = &_vm._objects[i];
+ for (int i = 0; i < _vm->_numObj; i++) {
+ object_t *obj = &_vm->_object->_objects[i];
if (obj->verbOnlyFl) {
char contextComment[XBYTES * 5] = ""; // Unused comment for context objects
if (isObjectVerb(obj, contextComment) || isGenericVerb(obj, contextComment))
@@ -170,13 +173,13 @@ void Parser_v3d::lineHandler() {
}
// No objects match command line, try background and catchall commands
- if (isBackgroundWord(_vm._backgroundObjects[*_vm._screen_p]))
+ if (isBackgroundWord(_vm->_backgroundObjects[*_vm->_screen_p]))
return;
- if (isCatchallVerb(_vm._backgroundObjects[*_vm._screen_p]))
+ if (isCatchallVerb(_vm->_backgroundObjects[*_vm->_screen_p]))
return;
- if (isBackgroundWord(_vm._catchallList))
+ if (isBackgroundWord(_vm->_catchallList))
return;
- if (isCatchallVerb(_vm._catchallList))
+ if (isCatchallVerb(_vm->_catchallList))
return;
// If a not-near comment was generated, print it
@@ -188,15 +191,15 @@ void Parser_v3d::lineHandler() {
// Nothing matches. Report recognition success to user.
char *verb = findVerb();
char *noun = findNoun();
-
+
if (verb && noun) { // A combination I didn't think of
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoPoint]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoPoint]);
} else if (noun) {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoun]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBNoun]);
} else if (verb) {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBVerb]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBVerb]);
} else {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh]);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBEh]);
}
}
diff --git a/engines/hugo/route.cpp b/engines/hugo/route.cpp
index 2ba95fb7d7..a980dc030a 100644
--- a/engines/hugo/route.cpp
+++ b/engines/hugo/route.cpp
@@ -38,16 +38,19 @@
#include "hugo/game.h"
#include "hugo/route.h"
#include "hugo/global.h"
+#include "hugo/object.h"
namespace Hugo {
-Route::Route(HugoEngine &vm) : _vm(vm) {
+Route::Route(HugoEngine *vm) : _vm(vm) {
}
-// Face hero in new direction, based on cursor key input by user.
+/**
+* Face hero in new direction, based on cursor key input by user.
+*/
void Route::setDirection(uint16 keyCode) {
debugC(1, kDebugRoute, "setDirection(%d)", keyCode);
- object_t *obj = _vm._hero; // Pointer to hero object
+ object_t *obj = _vm->_hero; // Pointer to hero object
// Set first image in sequence
switch (keyCode) {
@@ -78,15 +81,17 @@ void Route::setDirection(uint16 keyCode) {
}
}
-// Set hero walking, based on cursor key input by user.
-// Hitting same key twice will stop hero.
+/**
+* Set hero walking, based on cursor key input by user.
+* Hitting same key twice will stop hero.
+*/
void Route::setWalk(uint16 direction) {
debugC(1, kDebugRoute, "setWalk(%d)", direction);
static uint16 oldDirection = 0; // Last direction char
- object_t *obj = _vm._hero; // Pointer to hero object
+ object_t *obj = _vm->_hero; // Pointer to hero object
- if (_vm.getGameStatus().storyModeFl || obj->pathType != USER) // Make sure user has control
+ if (_vm->getGameStatus().storyModeFl || obj->pathType != USER) // Make sure user has control
return;
if (!obj->vx && !obj->vy)
@@ -141,20 +146,22 @@ void Route::setWalk(uint16 direction) {
}
}
-// Recursive algorithm! Searches from hero to dest_x, dest_y
-// Find horizontal line segment about supplied point and recursively
-// find line segments for each point above and below that segment.
-// When destination point found in segment, start surfacing and leave
-// a trail in segment[] from destination back to hero.
-//
-// Note: there is a bug which allows a route through a 1-pixel high
-// narrow gap if between 2 segments wide enough for hero. To work
-// around this, make sure any narrow gaps are 2 or more pixels high.
-// An example of this was the blocking guard in Hugo1/Dead-End.
+/**
+* Recursive algorithm! Searches from hero to dest_x, dest_y
+* Find horizontal line segment about supplied point and recursively
+* find line segments for each point above and below that segment.
+* When destination point found in segment, start surfacing and leave
+* a trail in segment[] from destination back to hero.
+*
+* Note: there is a bug which allows a route through a 1-pixel high
+* narrow gap if between 2 segments wide enough for hero. To work
+* around this, make sure any narrow gaps are 2 or more pixels high.
+* An example of this was the blocking guard in Hugo1/Dead-End.
+*/
void Route::segment(int16 x, int16 y) {
debugC(1, kDebugRoute, "segment(%d, %d)", x, y);
-// Note use of static - can't waste stack
+ // Note: use of static - can't waste stack
static image_pt p; // Ptr to _boundaryMap[y]
static segment_t *seg_p; // Ptr to segment
@@ -195,7 +202,7 @@ void Route::segment(int16 x, int16 y) {
if (y <= 0 || y >= YPIX - 1)
return;
- if (_vm._hero->x < x1) {
+ if (_vm->_hero->x < x1) {
// Hero x not in segment, search x1..x2
// Find all segments above current
for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
@@ -208,7 +215,7 @@ void Route::segment(int16 x, int16 y) {
if (_boundaryMap[y + 1][x] == 0)
segment(x, y + 1);
}
- } else if (_vm._hero->x + HERO_MAX_WIDTH > x2) {
+ } else if (_vm->_hero->x + HERO_MAX_WIDTH > x2) {
// Hero x not in segment, search x1..x2
// Find all segments above current
for (x = x2; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x >= x1; x--) {
@@ -224,22 +231,22 @@ void Route::segment(int16 x, int16 y) {
} else {
// Organize search around hero x position - this gives
// better chance for more direct route.
- for (x = _vm._hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
+ for (x = _vm->_hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
if (_boundaryMap[y - 1][x] == 0)
segment(x, y - 1);
}
- for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm._hero->x; x++) {
+ for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm->_hero->x; x++) {
if (_boundaryMap[y - 1][x] == 0)
segment(x, y - 1);
}
- for (x = _vm._hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
+ for (x = _vm->_hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
if (_boundaryMap[y + 1][x] == 0)
segment(x, y + 1);
}
- for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm._hero->x; x++) {
+ for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm->_hero->x; x++) {
if (_boundaryMap[y + 1][x] == 0)
segment(x, y + 1);
}
@@ -261,8 +268,10 @@ void Route::segment(int16 x, int16 y) {
}
}
-// Create and return ptr to new node. Initialize with previous node.
-// Returns 0 if MAX_NODES exceeded
+/**
+* Create and return ptr to new node. Initialize with previous node.
+* Returns 0 if MAX_NODES exceeded
+*/
Point *Route::newNode() {
debugC(1, kDebugRoute, "newNode");
@@ -273,10 +282,12 @@ Point *Route::newNode() {
return &_route[_routeListIndex];
}
-// Construct route to cx, cy. Return TRUE if successful.
-// 1. Copy boundary bitmap to local byte map (include object bases)
-// 2. Construct list of segments segment[] from hero to destination
-// 3. Compress to shortest route in route[]
+/**
+* Construct route to cx, cy. Return TRUE if successful.
+* 1. Copy boundary bitmap to local byte map (include object bases)
+* 2. Construct list of segments segment[] from hero to destination
+* 3. Compress to shortest route in route[]
+*/
bool Route::findRoute(int16 cx, int16 cy) {
debugC(1, kDebugRoute, "findRoute(%d, %d)", cx, cy);
@@ -289,32 +300,32 @@ bool Route::findRoute(int16 cx, int16 cy) {
_destY = cy; // Destination coords
_destX = cx; // Destination coords
- int16 herox1 = _vm._hero->x + _vm._hero->currImagePtr->x1; // Hero baseline
- int16 herox2 = _vm._hero->x + _vm._hero->currImagePtr->x2; // Hero baseline
- int16 heroy = _vm._hero->y + _vm._hero->currImagePtr->y2; // Hero baseline
+ int16 herox1 = _vm->_hero->x + _vm->_hero->currImagePtr->x1; // Hero baseline
+ int16 herox2 = _vm->_hero->x + _vm->_hero->currImagePtr->x2; // Hero baseline
+ int16 heroy = _vm->_hero->y + _vm->_hero->currImagePtr->y2; // Hero baseline
// Store all object baselines into objbound (except hero's = [0])
object_t *obj; // Ptr to object
int i;
- for (i = 1, obj = &_vm._objects[i]; i < _vm._numObj; i++, obj++) {
- if ((obj->screenIndex == *_vm._screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING))
- _vm.storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
+ for (i = 1, obj = &_vm->_object->_objects[i]; i < _vm->_numObj; i++, obj++) {
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING))
+ _vm->storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
}
// Combine objbound and boundary bitmaps to local byte map
for (int16 y = 0; y < YPIX; y++) {
for (int16 x = 0; x < XBYTES; x++) {
for (i = 0; i < 8; i++)
- _boundaryMap[y][x * 8 + i] = ((_vm.getObjectBoundaryOverlay()[y * XBYTES + x] | _vm.getBoundaryOverlay()[y * XBYTES + x]) & (0x80 >> i)) ? kMapBound : 0;
+ _boundaryMap[y][x * 8 + i] = ((_vm->getObjectBoundaryOverlay()[y * XBYTES + x] | _vm->getBoundaryOverlay()[y * XBYTES + x]) & (0x80 >> i)) ? kMapBound : 0;
}
}
-
+
// Clear all object baselines from objbound
- for (i = 0, obj = _vm._objects; i < _vm._numObj; i++, obj++) {
- if ((obj->screenIndex == *_vm._screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING))
- _vm.clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
+ for (i = 0, obj = _vm->_object->_objects; i < _vm->_numObj; i++, obj++) {
+ if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING))
+ _vm->clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
}
-
+
// Search from hero to destination
segment(herox1, heroy);
@@ -382,60 +393,61 @@ bool Route::findRoute(int16 cx, int16 cy) {
return true;
}
-// Process hero in route mode - called from Move_objects()
+/**
+* Process hero in route mode - called from Move_objects()
+*/
void Route::processRoute() {
debugC(1, kDebugRoute, "processRoute");
static bool turnedFl = false; // Used to get extra cylce for turning
// Current hero position
- int16 herox = _vm._hero->x + _vm._hero->currImagePtr->x1;
- int16 heroy = _vm._hero->y + _vm._hero->currImagePtr->y2;
- status_t &gameStatus = _vm.getGameStatus();
+ int16 herox = _vm->_hero->x + _vm->_hero->currImagePtr->x1;
+ int16 heroy = _vm->_hero->y + _vm->_hero->currImagePtr->y2;
+ status_t &gameStatus = _vm->getGameStatus();
Point *routeNode = &_route[gameStatus.routeIndex];
// Arrived at node?
if (abs(herox - routeNode->x) < DX + 1 && abs(heroy - routeNode->y) < DY) {
// DX too low
// Close enough - position hero exactly
- _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
- _vm._hero->y = _vm._hero->oldy = routeNode->y - _vm._hero->currImagePtr->y2;
- _vm._hero->vx = _vm._hero->vy = 0;
- _vm._hero->cycling = NOT_CYCLING;
+ _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1;
+ _vm->_hero->y = _vm->_hero->oldy = routeNode->y - _vm->_hero->currImagePtr->y2;
+ _vm->_hero->vx = _vm->_hero->vy = 0;
+ _vm->_hero->cycling = NOT_CYCLING;
// Arrived at final node?
if (--gameStatus.routeIndex < 0) {
// See why we walked here
switch (gameStatus.go_for) {
case GO_EXIT: // Walked to an exit, proceed into it
- setWalk(_vm._hotspots[gameStatus.go_id].direction);
+ setWalk(_vm->_hotspots[gameStatus.go_id].direction);
break;
case GO_LOOK: // Look at an object
if (turnedFl) {
- _vm.lookObject(&_vm._objects[gameStatus.go_id]);
+ _vm->_object->lookObject(&_vm->_object->_objects[gameStatus.go_id]);
turnedFl = false;
} else {
- setDirection(_vm._objects[gameStatus.go_id].direction);
+ setDirection(_vm->_object->_objects[gameStatus.go_id].direction);
gameStatus.routeIndex++; // Come round again
turnedFl = true;
}
break;
case GO_GET: // Get (or use) an object
if (turnedFl) {
- _vm.useObject(gameStatus.go_id);
+ _vm->_object->useObject(gameStatus.go_id);
turnedFl = false;
} else {
- setDirection(_vm._objects[gameStatus.go_id].direction);
+ setDirection(_vm->_object->_objects[gameStatus.go_id].direction);
gameStatus.routeIndex++; // Come round again
turnedFl = true;
}
break;
- case GO_SPACE:
- warning("Unhandled gameStatus.go_for GO_STATUS");
+ default:
break;
}
}
- } else if (_vm._hero->vx == 0 && _vm._hero->vy == 0) {
+ } else if (_vm->_hero->vx == 0 && _vm->_hero->vy == 0) {
// Set direction of travel if at a node
// Note realignment when changing to (thinner) up/down sprite,
// otherwise hero could bump into boundaries along route.
@@ -445,25 +457,27 @@ void Route::processRoute() {
setWalk(Common::KEYCODE_LEFT);
} else if (heroy < routeNode->y) {
setWalk(Common::KEYCODE_DOWN);
- _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
+ _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1;
} else if (heroy > routeNode->y) {
setWalk(Common::KEYCODE_UP);
- _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
+ _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1;
}
}
}
-// Start a new route from hero to cx, cy
-// go_for is the purpose, id indexes the exit or object to walk to
-// Returns FALSE if route not found
+/**
+* Start a new route from hero to cx, cy
+* go_for is the purpose, id indexes the exit or object to walk to
+* Returns FALSE if route not found
+*/
bool Route::startRoute(go_t go_for, int16 id, int16 cx, int16 cy) {
debugC(1, kDebugRoute, "startRoute(%d, %d, %d, %d)", go_for, id, cx, cy);
// Don't attempt to walk if user does not have control
- if (_vm._hero->pathType != USER)
+ if (_vm->_hero->pathType != USER)
return false;
- status_t &gameStatus = _vm.getGameStatus();
+ status_t &gameStatus = _vm->getGameStatus();
// if inventory showing, make it go away
if (gameStatus.inventoryState != I_OFF)
gameStatus.inventoryState = I_UP;
@@ -478,7 +492,7 @@ bool Route::startRoute(go_t go_for, int16 id, int16 cx, int16 cy) {
bool foundFl = false; // TRUE if route found ok
if ((foundFl = findRoute(cx, cy))) { // Found a route?
gameStatus.routeIndex = _routeListIndex; // Node index
- _vm._hero->vx = _vm._hero->vy = 0; // Stop manual motion
+ _vm->_hero->vx = _vm->_hero->vy = 0; // Stop manual motion
}
return foundFl;
diff --git a/engines/hugo/route.h b/engines/hugo/route.h
index 09b4575fcd..b2185a4bb7 100644
--- a/engines/hugo/route.h
+++ b/engines/hugo/route.h
@@ -53,7 +53,7 @@ struct segment_t { // Search segment
class Route {
public:
- Route(HugoEngine &vm);
+ Route(HugoEngine *vm);
void processRoute();
bool startRoute(go_t go_for, short id, short cx, short cy);
@@ -61,7 +61,7 @@ public:
void setWalk(uint16 direction);
private:
- HugoEngine &_vm;
+ HugoEngine *_vm;
byte _boundaryMap[YPIX][XPIX]; // Boundary byte map
segment_t _segment[kMaxSeg]; // List of points in fill-path
diff --git a/engines/hugo/schedule.cpp b/engines/hugo/schedule.cpp
index 22eb99c6dd..6f88ce98bf 100644
--- a/engines/hugo/schedule.cpp
+++ b/engines/hugo/schedule.cpp
@@ -34,27 +34,23 @@
#include "common/system.h"
-#include "hugo/game.h"
#include "hugo/hugo.h"
#include "hugo/schedule.h"
-#include "hugo/global.h"
#include "hugo/file.h"
#include "hugo/display.h"
-#include "hugo/parser.h"
#include "hugo/util.h"
-#include "hugo/sound.h"
namespace Hugo {
-#define SIGN(X) ((X < 0) ? -1 : 1)
-
-Scheduler::Scheduler(HugoEngine &vm) : _vm(vm) {
+Scheduler::Scheduler(HugoEngine *vm) : _vm(vm), _actListArr(0) {
}
Scheduler::~Scheduler() {
}
-// Initialise the timer event queue
+/**
+* Initialise the timer event queue
+*/
void Scheduler::initEventQueue() {
debugC(1, kDebugSchedule, "initEventQueue");
@@ -72,7 +68,9 @@ void Scheduler::initEventQueue() {
_freeEvent = _events; // Free list is full
}
-// Return a ptr to an event structure from the free list
+/**
+* Return a ptr to an event structure from the free list
+*/
event_t *Scheduler::getQueue() {
debugC(4, kDebugSchedule, "getQueue");
@@ -84,99 +82,22 @@ event_t *Scheduler::getQueue() {
return resEvent;
}
-// Delete an event structure (i.e. return it to the free list)
-// Historical note: Originally event p was assumed to be at head of queue
-// (i.e. earliest) since all events were deleted in order when proceeding to
-// a new screen. To delete an event from the middle of the queue, the action
-// was overwritten to be ANULL. With the advent of GLOBAL events, Del_queue
-// was modified to allow deletes anywhere in the list, and the DEL_EVENT
-// action was modified to perform the actual delete.
-void Scheduler::delQueue(event_t *curEvent) {
- debugC(4, kDebugSchedule, "delQueue()");
-
- if (curEvent == _headEvent) { // If p was the head ptr
- _headEvent = curEvent->nextEvent; // then make new head_p
- } else { // Unlink p
- curEvent->prevEvent->nextEvent = curEvent->nextEvent;
- if (curEvent->nextEvent)
- curEvent->nextEvent->prevEvent = curEvent->prevEvent;
- else
- _tailEvent = curEvent->prevEvent;
- }
-
- if (_headEvent)
- _headEvent->prevEvent = 0; // Mark end of list
- else
- _tailEvent = 0; // Empty queue
-
- curEvent->nextEvent = _freeEvent; // Return p to free list
- if (_freeEvent) // Special case, if free list was empty
- _freeEvent->prevEvent = curEvent;
- _freeEvent = curEvent;
-}
-
-// Insert the action pointed to by p into the timer event queue
-// The queue goes from head (earliest) to tail (latest) timewise
-void Scheduler::insertAction(act *action) {
- debugC(1, kDebugSchedule, "insertAction() - Action type A%d", action->a0.actType);
-
- // First, get and initialise the event structure
- event_t *curEvent = getQueue();
- curEvent->action = action;
- switch (action->a0.actType) { // Assign whether local or global
- case AGSCHEDULE:
- curEvent->localActionFl = false; // Lasts over a new screen
- break;
- default:
- curEvent->localActionFl = true; // Rest are for current screen only
- break;
- }
-
- curEvent->time = action->a0.timer + getTicks(); // Convert rel to abs time
-
- // Now find the place to insert the event
- if (!_tailEvent) { // Empty queue
- _tailEvent = _headEvent = curEvent;
- curEvent->nextEvent = curEvent->prevEvent = 0;
- } else {
- event_t *wrkEvent = _tailEvent; // Search from latest time back
- bool found = false;
-
- while (wrkEvent && !found) {
- if (wrkEvent->time <= curEvent->time) { // Found if new event later
- found = true;
- if (wrkEvent == _tailEvent) // New latest in list
- _tailEvent = curEvent;
- else
- wrkEvent->nextEvent->prevEvent = curEvent;
- curEvent->nextEvent = wrkEvent->nextEvent;
- wrkEvent->nextEvent = curEvent;
- curEvent->prevEvent = wrkEvent;
- }
- wrkEvent = wrkEvent->prevEvent;
- }
-
- if (!found) { // Must be earliest in list
- _headEvent->prevEvent = curEvent; // So insert as new head
- curEvent->nextEvent = _headEvent;
- curEvent->prevEvent = 0;
- _headEvent = curEvent;
- }
- }
-}
-
+/**
+* Call Insert_action for each action in the list supplied
+*/
void Scheduler::insertActionList(uint16 actIndex) {
-// Call Insert_action for each action in the list supplied
debugC(1, kDebugSchedule, "insertActionList(%d)", actIndex);
- if (_vm._actListArr[actIndex]) {
- for (int i = 0; _vm._actListArr[actIndex][i].a0.actType != ANULL; i++)
- insertAction(&_vm._actListArr[actIndex][i]);
+ if (_actListArr[actIndex]) {
+ for (int i = 0; _actListArr[actIndex][i].a0.actType != ANULL; i++)
+ insertAction(&_actListArr[actIndex][i]);
}
}
+/**
+* Decode a string
+*/
void Scheduler::decodeString(char *line) {
-// Decode a string
debugC(1, kDebugSchedule, "decodeString(%s)", line);
static const char *cypher = getCypher();
@@ -186,360 +107,73 @@ void Scheduler::decodeString(char *line) {
debugC(1, kDebugSchedule, "result : %s", line);
}
-event_t *Scheduler::doAction(event_t *curEvent) {
-// This function performs the action in the event structure pointed to by p
-// It dequeues the event and returns it to the free list. It returns a ptr
-// to the next action in the list, except special case of NEW_SCREEN
- debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->action->a0.actType);
-
- status_t &gameStatus = _vm.getGameStatus();
- act *action = curEvent->action;
- char *response; // User's response string
- object_t *obj1;
- object_t *obj2;
- int dx, dy;
- event_t *wrkEvent; // Save ev_p->next_p for return
- event_t *saveEvent; // Used in DEL_EVENTS
-
- switch (action->a0.actType) {
- case ANULL: // Big NOP from DEL_EVENTS
- break;
- case ASCHEDULE: // act0: Schedule an action list
- insertActionList(action->a0.actIndex);
- break;
- case START_OBJ: // act1: Start an object cycling
- _vm._objects[action->a1.objNumb].cycleNumb = action->a1.cycleNumb;
- _vm._objects[action->a1.objNumb].cycling = action->a1.cycle;
- break;
- case INIT_OBJXY: // act2: Initialise an object
- _vm._objects[action->a2.objNumb].x = action->a2.x; // Coordinates
- _vm._objects[action->a2.objNumb].y = action->a2.y;
- break;
- case PROMPT: { // act3: Prompt user for key phrase
-// TODO : Add specific code for Hugo 1 DOS, which is handled differently,
- response = Utils::Box(BOX_PROMPT, "%s", _vm.file().fetchString(action->a3.promptIndex));
-
- warning("STUB: doAction(act3), expecting answer %s", response);
-
-// TODO : The answer of the player is not handled currently! Once it'll be read in the messageBox, uncomment this block
-#if 0
- bool found;
- char *tmpStr; // General purpose string ptr
-
- for (found = false, dx = 0; !found && (action->a3.responsePtr[dx] != -1); dx++) {
- tmpStr = _vm.file().Fetch_string(action->a3.responsePtr[dx]);
- if (strstr(Utils::strlwr(response) , tmpStr))
- found = true;
- }
-
- if (found)
- insertActionList(action->a3.actPassIndex);
- else
- insertActionList(action->a3.actFailIndex);
-#endif
-
- // HACK: As the answer is not read, currently it's always considered correct
- insertActionList(action->a3.actPassIndex);
- break;
- }
- case BKGD_COLOR: // act4: Set new background color
- _vm.screen().setBackgroundColor(action->a4.newBackgroundColor);
- break;
- case INIT_OBJVXY: // act5: Initialise an object
- _vm._objects[action->a5.objNumb].vx = action->a5.vx; // velocities
- _vm._objects[action->a5.objNumb].vy = action->a5.vy;
- break;
- case INIT_CARRY: // act6: Initialise an object
- _vm._objects[action->a6.objNumb].carriedFl = action->a6.carriedFl; // carried status
- break;
- case INIT_HF_COORD: // act7: Initialise an object to hero's "feet" coords
- _vm._objects[action->a7.objNumb].x = _vm._hero->x - 1;
- _vm._objects[action->a7.objNumb].y = _vm._hero->y + _vm._hero->currImagePtr->y2 - 1;
- _vm._objects[action->a7.objNumb].screenIndex = *_vm._screen_p; // Don't forget screen!
- break;
- case NEW_SCREEN: // act8: Start new screen
- newScreen(action->a8.screenIndex);
- break;
- case INIT_OBJSTATE: // act9: Initialise an object state
- _vm._objects[action->a9.objNumb].state = action->a9.newState;
- break;
- case INIT_PATH: // act10: Initialise an object path and velocity
- _vm._objects[action->a10.objNumb].pathType = (path_t) action->a10.newPathType;
- _vm._objects[action->a10.objNumb].vxPath = action->a10.vxPath;
- _vm._objects[action->a10.objNumb].vyPath = action->a10.vyPath;
- break;
- case COND_R: // act11: action lists conditional on object state
- if (_vm._objects[action->a11.objNumb].state == action->a11.stateReq)
- insertActionList(action->a11.actPassIndex);
- else
- insertActionList(action->a11.actFailIndex);
- break;
- case TEXT: // act12: Text box (CF WARN)
- Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(action->a12.stringIndex)); // Fetch string from file
- break;
- case SWAP_IMAGES: // act13: Swap 2 object images
- swapImages(action->a13.obj1, action->a13.obj2);
- break;
- case COND_SCR: // act14: Conditional on current screen
- if (_vm._objects[action->a14.objNumb].screenIndex == action->a14.screenReq)
- insertActionList(action->a14.actPassIndex);
- else
- insertActionList(action->a14.actFailIndex);
- break;
- case AUTOPILOT: // act15: Home in on a (stationary) object
- // object p1 will home in on object p2
- obj1 = &_vm._objects[action->a15.obj1];
- obj2 = &_vm._objects[action->a15.obj2];
- obj1->pathType = AUTO;
- dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1;
- dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1;
-
- if (dx == 0) // Don't EVER divide by zero!
- dx = 1;
- if (dy == 0)
- dy = 1;
-
- if (abs(dx) > abs(dy)) {
- obj1->vx = action->a15.dx * -SIGN(dx);
- obj1->vy = abs((action->a15.dy * dy) / dx) * -SIGN(dy);
- } else {
- obj1->vy = action->a15.dy * -SIGN(dy);
- obj1->vx = abs((action->a15.dx * dx) / dy) * -SIGN(dx);
- }
- break;
- case INIT_OBJ_SEQ: // act16: Set sequence number to use
- // Note: Don't set a sequence at time 0 of a new screen, it causes
- // problems clearing the boundary bits of the object! t>0 is safe
- _vm._objects[action->a16.objNumb].currImagePtr = _vm._objects[action->a16.objNumb].seqList[action->a16.seqIndex].seqPtr;
- break;
- case SET_STATE_BITS: // act17: OR mask with curr obj state
- _vm._objects[action->a17.objNumb].state |= action->a17.stateMask;
- break;
- case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state
- _vm._objects[action->a18.objNumb].state &= ~action->a18.stateMask;
- break;
- case TEST_STATE_BITS: // act19: If all bits set, do apass else afail
- if ((_vm._objects[action->a19.objNumb].state & action->a19.stateMask) == action->a19.stateMask)
- insertActionList(action->a19.actPassIndex);
- else
- insertActionList(action->a19.actFailIndex);
- break;
- case DEL_EVENTS: // act20: Remove all events of this action type
- // Note: actions are not deleted here, simply turned into NOPs!
- wrkEvent = _headEvent; // The earliest event
- while (wrkEvent) { // While events found in list
- saveEvent = wrkEvent->nextEvent;
- if (wrkEvent->action->a20.actType == action->a20.actTypeDel)
- delQueue(wrkEvent);
- wrkEvent = saveEvent;
- }
- break;
- case GAMEOVER: // act21: Game over!
- // NOTE: Must wait at least 1 tick before issuing this action if
- // any objects are to be made invisible!
- gameStatus.gameOverFl = true;
- break;
- case INIT_HH_COORD: // act22: Initialise an object to hero's actual coords
- _vm._objects[action->a22.objNumb].x = _vm._hero->x;
- _vm._objects[action->a22.objNumb].y = _vm._hero->y;
- _vm._objects[action->a22.objNumb].screenIndex = *_vm._screen_p;// Don't forget screen!
- break;
- case EXIT: // act23: Exit game back to DOS
- _vm.endGame();
- break;
- case BONUS: // act24: Get bonus score for action
- processBonus(action->a24.pointIndex);
- break;
- case COND_BOX: // act25: Conditional on bounding box
- obj1 = &_vm._objects[action->a25.objNumb];
- dx = obj1->x + obj1->currImagePtr->x1;
- dy = obj1->y + obj1->currImagePtr->y2;
- if ((dx >= action->a25.x1) && (dx <= action->a25.x2) &&
- (dy >= action->a25.y1) && (dy <= action->a25.y2))
- insertActionList(action->a25.actPassIndex);
- else
- insertActionList(action->a25.actFailIndex);
- break;
- case SOUND: // act26: Play a sound (or tune)
- if (action->a26.soundIndex < _vm._tunesNbr)
- _vm.sound().playMusic(action->a26.soundIndex);
- else
- _vm.sound().playSound(action->a26.soundIndex, BOTH_CHANNELS, MED_PRI);
- break;
- case ADD_SCORE: // act27: Add object's value to score
- _vm.adjustScore(_vm._objects[action->a27.objNumb].objValue);
- break;
- case SUB_SCORE: // act28: Subtract object's value from score
- _vm.adjustScore(-_vm._objects[action->a28.objNumb].objValue);
- break;
- case COND_CARRY: // act29: Conditional on object being carried
- if (_vm._objects[action->a29.objNumb].carriedFl)
- insertActionList(action->a29.actPassIndex);
- else
- insertActionList(action->a29.actFailIndex);
- break;
- case INIT_MAZE: // act30: Enable and init maze structure
- _maze.enabledFl = true;
- _maze.size = action->a30.mazeSize;
- _maze.x1 = action->a30.x1;
- _maze.y1 = action->a30.y1;
- _maze.x2 = action->a30.x2;
- _maze.y2 = action->a30.y2;
- _maze.x3 = action->a30.x3;
- _maze.x4 = action->a30.x4;
- _maze.firstScreenIndex = action->a30.firstScreenIndex;
- break;
- case EXIT_MAZE: // act31: Disable maze mode
- _maze.enabledFl = false;
- break;
- case INIT_PRIORITY:
- _vm._objects[action->a32.objNumb].priority = action->a32.priority;
- break;
- case INIT_SCREEN:
- _vm._objects[action->a33.objNumb].screenIndex = action->a33.screenIndex;
- break;
- case AGSCHEDULE: // act34: Schedule a (global) action list
- insertActionList(action->a34.actIndex);
- break;
- case REMAPPAL: // act35: Remap a palette color
- _vm.screen().remapPal(action->a35.oldColorIndex, action->a35.newColorIndex);
- break;
- case COND_NOUN: // act36: Conditional on noun mentioned
- if (_vm.parser().isWordPresent(_vm._arrayNouns[action->a36.nounIndex]))
- insertActionList(action->a36.actPassIndex);
- else
- insertActionList(action->a36.actFailIndex);
- break;
- case SCREEN_STATE: // act37: Set new screen state
- _vm._screenStates[action->a37.screenIndex] = action->a37.newState;
- break;
- case INIT_LIPS: // act38: Position lips on object
- _vm._objects[action->a38.lipsObjNumb].x = _vm._objects[action->a38.objNumb].x + action->a38.dxLips;
- _vm._objects[action->a38.lipsObjNumb].y = _vm._objects[action->a38.objNumb].y + action->a38.dyLips;
- _vm._objects[action->a38.lipsObjNumb].screenIndex = *_vm._screen_p; // Don't forget screen!
- _vm._objects[action->a38.lipsObjNumb].cycling = CYCLE_FORWARD;
- break;
- case INIT_STORY_MODE: // act39: Init story_mode flag
- // This is similar to the QUIET path mode, except that it is
- // independant of it and it additionally disables the ">" prompt
- gameStatus.storyModeFl = action->a39.storyModeFl;
-
- // End the game after story if this is special vendor demo mode
- if (gameStatus.demoFl && action->a39.storyModeFl == false)
- _vm.endGame();
- break;
- case WARN: // act40: Text box (CF TEXT)
- Utils::Box(BOX_OK, "%s", _vm.file().fetchString(action->a40.stringIndex));
- break;
- case COND_BONUS: // act41: Perform action if got bonus
- if (_vm._points[action->a41.BonusIndex].scoredFl)
- insertActionList(action->a41.actPassIndex);
- else
- insertActionList(action->a41.actFailIndex);
- break;
- case TEXT_TAKE: // act42: Text box with "take" message
- Utils::Box(BOX_ANY, TAKE_TEXT, _vm._arrayNouns[_vm._objects[action->a42.objNumb].nounIndex][TAKE_NAME]);
- break;
- case YESNO: // act43: Prompt user for Yes or No
- warning("doAction(act43) - Yes/No Box");
- if (Utils::Box(BOX_YESNO, "%s", _vm.file().fetchString(action->a43.promptIndex)) != 0)
- insertActionList(action->a43.actYesIndex);
- else
- insertActionList(action->a43.actNoIndex);
- break;
- case STOP_ROUTE: // act44: Stop any route in progress
- gameStatus.routeIndex = -1;
- break;
- case COND_ROUTE: // act45: Conditional on route in progress
- if (gameStatus.routeIndex >= action->a45.routeIndex)
- insertActionList(action->a45.actPassIndex);
- else
- insertActionList(action->a45.actFailIndex);
- break;
- case INIT_JUMPEXIT: // act46: Init status.jumpexit flag
- // This is to allow left click on exit to get there immediately
- // For example the plane crash in Hugo2 where hero is invisible
- // Couldn't use INVISIBLE flag since conflicts with boat in Hugo1
- gameStatus.jumpExitFl = action->a46.jumpExitFl;
- break;
- case INIT_VIEW: // act47: Init object.viewx, viewy, dir
- _vm._objects[action->a47.objNumb].viewx = action->a47.viewx;
- _vm._objects[action->a47.objNumb].viewy = action->a47.viewy;
- _vm._objects[action->a47.objNumb].direction = action->a47.direction;
- break;
- case INIT_OBJ_FRAME: // act48: Set seq,frame number to use
- // Note: Don't set a sequence at time 0 of a new screen, it causes
- // problems clearing the boundary bits of the object! t>0 is safe
- _vm._objects[action->a48.objNumb].currImagePtr = _vm._objects[action->a48.objNumb].seqList[action->a48.seqIndex].seqPtr;
- for (dx = 0; dx < action->a48.frameIndex; dx++)
- _vm._objects[action->a48.objNumb].currImagePtr = _vm._objects[action->a48.objNumb].currImagePtr->nextSeqPtr;
- break;
- case OLD_SONG:
- //TODO For Hugo 1 and Hugo2 DOS: The songs were not stored in a DAT file, but directly as
- //strings. the current play_music should be modified to use a strings instead of reading
- //the file, in those cases. This replaces, for those DOS versions, act26.
- warning("STUB: doAction(act49)");
- break;
- default:
- Utils::Error(EVNT_ERR, "%s", "doAction");
- break;
- }
+/**
+* Return system time in ticks. A tick is 1/TICKS_PER_SEC mS
+*/
+uint32 Scheduler::getWinTicks() {
+ debugC(3, kDebugSchedule, "getTicks");
- if (action->a0.actType == NEW_SCREEN) { // New_screen() deletes entire list
- return 0; // next_p = 0 since list now empty
- } else {
- wrkEvent = curEvent->nextEvent;
- delQueue(curEvent); // Return event to free list
- return wrkEvent; // Return next event ptr
- }
+ return _vm->getGameStatus().tick;
}
-// This is the scheduler which runs every tick. It examines the event queue
-// for any events whose time has come. It dequeues these events and performs
-// the action associated with the event, returning it to the free queue
-void Scheduler::runScheduler() {
- debugC(6, kDebugSchedule, "runScheduler");
+/**
+* Return system time in ticks. A tick is 1/TICKS_PER_SEC mS
+* If update FALSE, simply return last known time
+* Note that this is real time unless a processing cycle takes longer than
+* a real tick, in which case the system tick is simply incremented
+*/
+uint32 Scheduler::getDosTicks(bool updateFl) {
+ debugC(5, kDebugSchedule, "getTicks");
- status_t &gameStatus = _vm.getGameStatus();
- event_t *curEvent = _headEvent; // The earliest event
+ static uint32 tick = 0; // Current system time in ticks
+ static uint32 t_old = 0; // The previous wall time in ticks
- while (curEvent && curEvent->time <= gameStatus.tick) // While mature events found
- curEvent = doAction(curEvent); // Perform the action (returns next_p)
- gameStatus.tick++; // Accessed elsewhere via getTicks()
-}
+ uint32 t_now; // Current wall time in ticks
-uint32 Scheduler::getTicks() {
-// Return system time in ticks. A tick is 1/TICKS_PER_SEC mS
- debugC(3, kDebugSchedule, "getTicks");
+ if (!updateFl)
+ return(tick);
+
+ if (t_old == 0)
+ t_old = (uint32) floor((double) (g_system->getMillis() * TPS / 1000));
+ /* Calculate current wall time in ticks */
+ t_now = g_system->getMillis() * TPS / 1000 ;
- return _vm.getGameStatus().tick;
+ if ((t_now - t_old) > 0) {
+ t_old = t_now;
+ tick++;
+ }
+ return(tick);
}
+/**
+* Add indecated bonus to score if not added already
+*/
void Scheduler::processBonus(int bonusIndex) {
-// Add indecated bonus to score if not added already
debugC(1, kDebugSchedule, "processBonus(%d)", bonusIndex);
- if (!_vm._points[bonusIndex].scoredFl) {
- _vm.adjustScore(_vm._points[bonusIndex].score);
- _vm._points[bonusIndex].scoredFl = true;
+ if (!_vm->_points[bonusIndex].scoredFl) {
+ _vm->adjustScore(_vm->_points[bonusIndex].score);
+ _vm->_points[bonusIndex].scoredFl = true;
}
}
-// Transition to a new screen as follows:
-// 1. Clear out all non-global events from event list.
-// 2. Set the new screen (in the hero object and any carried objects)
-// 3. Read in the screen files for the new screen
-// 4. Schedule action list for new screen
-// 5. Initialise prompt line and status line
+/**
+* Transition to a new screen as follows:
+* 1. Clear out all non-global events from event list.
+* 2. Set the new screen (in the hero object and any carried objects)
+* 3. Read in the screen files for the new screen
+* 4. Schedule action list for new screen
+* 5. Initialise prompt line and status line
+*/
void Scheduler::newScreen(int screenIndex) {
debugC(1, kDebugSchedule, "newScreen(%d)", screenIndex);
// Make sure the background file exists!
- if (!_vm.isPacked()) {
+ if (!_vm->isPacked()) {
char line[32];
- if (!_vm.file().fileExists(strcat(strncat(strcpy(line, _vm._picDir), _vm._screenNames[screenIndex], NAME_LEN), BKGEXT)) &&
- !_vm.file().fileExists(strcat(strcpy(line, _vm._screenNames[screenIndex]), ".ART"))) {
- Utils::Box(BOX_ANY, "%s", _vm._textSchedule[kSsNoBackground]);
+ if (!_vm->_file->fileExists(strcat(strncat(strcpy(line, _vm->_picDir), _vm->_screenNames[screenIndex], NAME_LEN), BKGEXT)) &&
+ !_vm->_file->fileExists(strcat(strcpy(line, _vm->_screenNames[screenIndex]), ".ART"))) {
+ Utils::Box(BOX_ANY, "%s", _vm->_textSchedule[kSsNoBackground]);
return;
}
}
@@ -555,122 +189,691 @@ void Scheduler::newScreen(int screenIndex) {
}
// 2. Set the new screen in the hero object and any being carried
- _vm.setNewScreen(screenIndex);
+ _vm->setNewScreen(screenIndex);
// 3. Read in new screen files
- _vm.readScreenFiles(screenIndex);
+ _vm->readScreenFiles(screenIndex);
// 4. Schedule action list for this screen
- _vm.screenActions(screenIndex);
+ _vm->screenActions(screenIndex);
// 5. Initialise prompt line and status line
- _vm.initNewScreenDisplay();
+ _vm->_screen->initNewScreenDisplay();
}
-// Write the event queue to the file with handle f
-// Note that we convert all the event structure ptrs to indexes
-// using -1 for NULL. We can't convert the action ptrs to indexes
-// so we save address of first dummy action ptr to compare on restore.
-void Scheduler::saveEvents(Common::WriteStream *f) {
- debugC(1, kDebugSchedule, "saveEvents()");
-
- uint32 curTime = getTicks();
- event_t saveEventArr[kMaxEvents]; // Convert event ptrs to indexes
-
- // Convert event ptrs to indexes
- for (int16 i = 0; i < kMaxEvents; i++) {
- event_t *wrkEvent = &_events[i];
- saveEventArr[i] = *wrkEvent;
- saveEventArr[i].prevEvent = (wrkEvent->prevEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->prevEvent - _events);
- saveEventArr[i].nextEvent = (wrkEvent->nextEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->nextEvent - _events);
- }
+/**
+* Transition to a new screen as follows:
+* 1. Set the new screen (in the hero object and any carried objects)
+* 2. Read in the screen files for the new screen
+* 3. Initialise prompt line and status line
+*/
+void Scheduler::restoreScreen(int screenIndex) {
+ debugC(1, kDebugSchedule, "restoreScreen(%d)", screenIndex);
- int16 freeIndex = (_freeEvent == 0) ? -1 : _freeEvent - _events;
- int16 headIndex = (_headEvent == 0) ? -1 : _headEvent - _events;
- int16 tailIndex = (_tailEvent == 0) ? -1 : _tailEvent - _events;
+ // 1. Set the new screen in the hero object and any being carried
+ _vm->setNewScreen(screenIndex);
- f->write(&curTime, sizeof(curTime));
- f->write(&freeIndex, sizeof(freeIndex));
- f->write(&headIndex, sizeof(headIndex));
- f->write(&tailIndex, sizeof(tailIndex));
- f->write(saveEventArr, sizeof(saveEventArr));
-}
+ // 2. Read in new screen files
+ _vm->readScreenFiles(screenIndex);
-// Restore the event list from file with handle f
-void Scheduler::restoreEvents(Common::SeekableReadStream *f) {
- debugC(1, kDebugSchedule, "restoreEvents");
-
- uint32 saveTime;
- int16 freeIndex; // Free list index
- int16 headIndex; // Head of list index
- int16 tailIndex; // Tail of list index
- event_t savedEvents[kMaxEvents]; // Convert event ptrs to indexes
-
- f->read(&saveTime, sizeof(saveTime)); // time of save
- f->read(&freeIndex, sizeof(freeIndex));
- f->read(&headIndex, sizeof(headIndex));
- f->read(&tailIndex, sizeof(tailIndex));
- f->read(savedEvents, sizeof(savedEvents));
-
- event_t *wrkEvent;
- // Restore events indexes to pointers
- for (int i = 0; i < kMaxEvents; i++) {
- wrkEvent = &savedEvents[i];
- _events[i] = *wrkEvent;
- _events[i].prevEvent = (wrkEvent->prevEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->prevEvent ];
- _events[i].nextEvent = (wrkEvent->nextEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->nextEvent ];
- }
- _freeEvent = (freeIndex == -1) ? 0 : &_events[freeIndex];
- _headEvent = (headIndex == -1) ? 0 : &_events[headIndex];
- _tailEvent = (tailIndex == -1) ? 0 : &_events[tailIndex];
-
- // Adjust times to fit our time
- uint32 curTime = getTicks();
- wrkEvent = _headEvent; // The earliest event
- while (wrkEvent) { // While mature events found
- wrkEvent->time = wrkEvent->time - saveTime + curTime;
- wrkEvent = wrkEvent->nextEvent;
- }
+ // 3. Initialise prompt line and status line
+ _vm->_screen->initNewScreenDisplay();
}
-void Scheduler::restoreScreen(int screenIndex) {
-// Transition to a new screen as follows:
-// 1. Set the new screen (in the hero object and any carried objects)
-// 2. Read in the screen files for the new screen
-// 3. Initialise prompt line and status line
+/**
+* Wait (if necessary) for next synchronizing tick
+* Slow machines won't make it by the end of tick, so will just plod on
+* at their own speed, not waiting here, but free running.
+* Note: DOS Versions only
+*/
+void Scheduler::waitForRefresh(void) {
+ debugC(1, kDebugSchedule, "waitForRefresh()");
- debugC(1, kDebugSchedule, "restoreScreen(%d)", screenIndex);
+ static uint32 timeout = 0;
+ uint32 t;
- // 1. Set the new screen in the hero object and any being carried
- _vm.setNewScreen(screenIndex);
+ if (timeout == 0)
+ timeout = getDosTicks(true);
- // 2. Read in new screen files
- _vm.readScreenFiles(screenIndex);
+ while ((t = getDosTicks(true)) < timeout)
+ ;
+ timeout = ++t;
+}
- // 3. Initialise prompt line and status line
- _vm.initNewScreenDisplay();
+/**
+* Read kALnewscr used by maze (Hugo 2)
+*/
+void Scheduler::loadAlNewscrIndex(Common::File &in) {
+ debugC(6, kDebugSchedule, "loadAlNewscrIndex(&in)");
+
+ int numElem;
+ for (int varnt = 0; varnt < _vm->_numVariant; varnt++) {
+ numElem = in.readUint16BE();
+ if (varnt == _vm->_gameVariant)
+ _alNewscrIndex = numElem;
+ }
}
-void Scheduler::swapImages(int objNumb1, int objNumb2) {
-// Swap all the images of one object with another. Set hero_image (we make
-// the assumption for now that the first obj is always the HERO) to the object
-// number of the swapped image
- debugC(1, kDebugSchedule, "swapImages(%d, %d)", objNumb1, objNumb2);
+/**
+* Load actListArr from Hugo.dat
+*/
+void Scheduler::loadActListArr(Common::File &in) {
+ debugC(6, kDebugSchedule, "loadActListArr(&in)");
+
+ int numElem, numSubElem, numSubAct;
+ for (int varnt = 0; varnt < _vm->_numVariant; varnt++) {
+ numElem = in.readUint16BE();
+ if (varnt == _vm->_gameVariant) {
+ _actListArrSize = numElem;
+ _actListArr = (act **)malloc(sizeof(act *) * _actListArrSize);
+ for (int i = 0; i < _actListArrSize; i++) {
+ numSubElem = in.readUint16BE();
+ _actListArr[i] = (act *) malloc(sizeof(act) * (numSubElem + 1));
+ for (int j = 0; j < numSubElem; j++) {
+ _actListArr[i][j].a0.actType = (action_t) in.readByte();
+ switch (_actListArr[i][j].a0.actType) {
+ case ANULL: // -1
+ break;
+ case ASCHEDULE: // 0
+ _actListArr[i][j].a0.timer = in.readSint16BE();
+ _actListArr[i][j].a0.actIndex = in.readUint16BE();
+ break;
+ case START_OBJ: // 1
+ _actListArr[i][j].a1.timer = in.readSint16BE();
+ _actListArr[i][j].a1.objNumb = in.readSint16BE();
+ _actListArr[i][j].a1.cycleNumb = in.readSint16BE();
+ _actListArr[i][j].a1.cycle = (cycle_t) in.readByte();
+ break;
+ case INIT_OBJXY: // 2
+ _actListArr[i][j].a2.timer = in.readSint16BE();
+ _actListArr[i][j].a2.objNumb = in.readSint16BE();
+ _actListArr[i][j].a2.x = in.readSint16BE();
+ _actListArr[i][j].a2.y = in.readSint16BE();
+ break;
+ case PROMPT: // 3
+ _actListArr[i][j].a3.timer = in.readSint16BE();
+ _actListArr[i][j].a3.promptIndex = in.readSint16BE();
+ numSubAct = in.readUint16BE();
+ _actListArr[i][j].a3.responsePtr = (int *) malloc(sizeof(int) * numSubAct);
+ for (int k = 0; k < numSubAct; k++)
+ _actListArr[i][j].a3.responsePtr[k] = in.readSint16BE();
+ _actListArr[i][j].a3.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a3.actFailIndex = in.readUint16BE();
+ _actListArr[i][j].a3.encodedFl = (in.readByte() == 1) ? true : false;
+ break;
+ case BKGD_COLOR: // 4
+ _actListArr[i][j].a4.timer = in.readSint16BE();
+ _actListArr[i][j].a4.newBackgroundColor = in.readUint32BE();
+ break;
+ case INIT_OBJVXY: // 5
+ _actListArr[i][j].a5.timer = in.readSint16BE();
+ _actListArr[i][j].a5.objNumb = in.readSint16BE();
+ _actListArr[i][j].a5.vx = in.readSint16BE();
+ _actListArr[i][j].a5.vy = in.readSint16BE();
+ break;
+ case INIT_CARRY: // 6
+ _actListArr[i][j].a6.timer = in.readSint16BE();
+ _actListArr[i][j].a6.objNumb = in.readSint16BE();
+ _actListArr[i][j].a6.carriedFl = (in.readByte() == 1) ? true : false;
+ break;
+ case INIT_HF_COORD: // 7
+ _actListArr[i][j].a7.timer = in.readSint16BE();
+ _actListArr[i][j].a7.objNumb = in.readSint16BE();
+ break;
+ case NEW_SCREEN: // 8
+ _actListArr[i][j].a8.timer = in.readSint16BE();
+ _actListArr[i][j].a8.screenIndex = in.readSint16BE();
+ break;
+ case INIT_OBJSTATE: // 9
+ _actListArr[i][j].a9.timer = in.readSint16BE();
+ _actListArr[i][j].a9.objNumb = in.readSint16BE();
+ _actListArr[i][j].a9.newState = in.readByte();
+ break;
+ case INIT_PATH: // 10
+ _actListArr[i][j].a10.timer = in.readSint16BE();
+ _actListArr[i][j].a10.objNumb = in.readSint16BE();
+ _actListArr[i][j].a10.newPathType = in.readSint16BE();
+ _actListArr[i][j].a10.vxPath = in.readByte();
+ _actListArr[i][j].a10.vyPath = in.readByte();
+ break;
+ case COND_R: // 11
+ _actListArr[i][j].a11.timer = in.readSint16BE();
+ _actListArr[i][j].a11.objNumb = in.readSint16BE();
+ _actListArr[i][j].a11.stateReq = in.readByte();
+ _actListArr[i][j].a11.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a11.actFailIndex = in.readUint16BE();
+ break;
+ case TEXT: // 12
+ _actListArr[i][j].a12.timer = in.readSint16BE();
+ _actListArr[i][j].a12.stringIndex = in.readSint16BE();
+ break;
+ case SWAP_IMAGES: // 13
+ _actListArr[i][j].a13.timer = in.readSint16BE();
+ _actListArr[i][j].a13.obj1 = in.readSint16BE();
+ _actListArr[i][j].a13.obj2 = in.readSint16BE();
+ break;
+ case COND_SCR: // 14
+ _actListArr[i][j].a14.timer = in.readSint16BE();
+ _actListArr[i][j].a14.objNumb = in.readSint16BE();
+ _actListArr[i][j].a14.screenReq = in.readSint16BE();
+ _actListArr[i][j].a14.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a14.actFailIndex = in.readUint16BE();
+ break;
+ case AUTOPILOT: // 15
+ _actListArr[i][j].a15.timer = in.readSint16BE();
+ _actListArr[i][j].a15.obj1 = in.readSint16BE();
+ _actListArr[i][j].a15.obj2 = in.readSint16BE();
+ _actListArr[i][j].a15.dx = in.readByte();
+ _actListArr[i][j].a15.dy = in.readByte();
+ break;
+ case INIT_OBJ_SEQ: // 16
+ _actListArr[i][j].a16.timer = in.readSint16BE();
+ _actListArr[i][j].a16.objNumb = in.readSint16BE();
+ _actListArr[i][j].a16.seqIndex = in.readSint16BE();
+ break;
+ case SET_STATE_BITS: // 17
+ _actListArr[i][j].a17.timer = in.readSint16BE();
+ _actListArr[i][j].a17.objNumb = in.readSint16BE();
+ _actListArr[i][j].a17.stateMask = in.readSint16BE();
+ break;
+ case CLEAR_STATE_BITS: // 18
+ _actListArr[i][j].a18.timer = in.readSint16BE();
+ _actListArr[i][j].a18.objNumb = in.readSint16BE();
+ _actListArr[i][j].a18.stateMask = in.readSint16BE();
+ break;
+ case TEST_STATE_BITS: // 19
+ _actListArr[i][j].a19.timer = in.readSint16BE();
+ _actListArr[i][j].a19.objNumb = in.readSint16BE();
+ _actListArr[i][j].a19.stateMask = in.readSint16BE();
+ _actListArr[i][j].a19.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a19.actFailIndex = in.readUint16BE();
+ break;
+ case DEL_EVENTS: // 20
+ _actListArr[i][j].a20.timer = in.readSint16BE();
+ _actListArr[i][j].a20.actTypeDel = (action_t) in.readByte();
+ break;
+ case GAMEOVER: // 21
+ _actListArr[i][j].a21.timer = in.readSint16BE();
+ break;
+ case INIT_HH_COORD: // 22
+ _actListArr[i][j].a22.timer = in.readSint16BE();
+ _actListArr[i][j].a22.objNumb = in.readSint16BE();
+ break;
+ case EXIT: // 23
+ _actListArr[i][j].a23.timer = in.readSint16BE();
+ break;
+ case BONUS: // 24
+ _actListArr[i][j].a24.timer = in.readSint16BE();
+ _actListArr[i][j].a24.pointIndex = in.readSint16BE();
+ break;
+ case COND_BOX: // 25
+ _actListArr[i][j].a25.timer = in.readSint16BE();
+ _actListArr[i][j].a25.objNumb = in.readSint16BE();
+ _actListArr[i][j].a25.x1 = in.readSint16BE();
+ _actListArr[i][j].a25.y1 = in.readSint16BE();
+ _actListArr[i][j].a25.x2 = in.readSint16BE();
+ _actListArr[i][j].a25.y2 = in.readSint16BE();
+ _actListArr[i][j].a25.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a25.actFailIndex = in.readUint16BE();
+ break;
+ case SOUND: // 26
+ _actListArr[i][j].a26.timer = in.readSint16BE();
+ _actListArr[i][j].a26.soundIndex = in.readSint16BE();
+ break;
+ case ADD_SCORE: // 27
+ _actListArr[i][j].a27.timer = in.readSint16BE();
+ _actListArr[i][j].a27.objNumb = in.readSint16BE();
+ break;
+ case SUB_SCORE: // 28
+ _actListArr[i][j].a28.timer = in.readSint16BE();
+ _actListArr[i][j].a28.objNumb = in.readSint16BE();
+ break;
+ case COND_CARRY: // 29
+ _actListArr[i][j].a29.timer = in.readSint16BE();
+ _actListArr[i][j].a29.objNumb = in.readSint16BE();
+ _actListArr[i][j].a29.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a29.actFailIndex = in.readUint16BE();
+ break;
+ case INIT_MAZE: // 30
+ _actListArr[i][j].a30.timer = in.readSint16BE();
+ _actListArr[i][j].a30.mazeSize = in.readByte();
+ _actListArr[i][j].a30.x1 = in.readSint16BE();
+ _actListArr[i][j].a30.y1 = in.readSint16BE();
+ _actListArr[i][j].a30.x2 = in.readSint16BE();
+ _actListArr[i][j].a30.y2 = in.readSint16BE();
+ _actListArr[i][j].a30.x3 = in.readSint16BE();
+ _actListArr[i][j].a30.x4 = in.readSint16BE();
+ _actListArr[i][j].a30.firstScreenIndex = in.readByte();
+ break;
+ case EXIT_MAZE: // 31
+ _actListArr[i][j].a31.timer = in.readSint16BE();
+ break;
+ case INIT_PRIORITY: // 32
+ _actListArr[i][j].a32.timer = in.readSint16BE();
+ _actListArr[i][j].a32.objNumb = in.readSint16BE();
+ _actListArr[i][j].a32.priority = in.readByte();
+ break;
+ case INIT_SCREEN: // 33
+ _actListArr[i][j].a33.timer = in.readSint16BE();
+ _actListArr[i][j].a33.objNumb = in.readSint16BE();
+ _actListArr[i][j].a33.screenIndex = in.readSint16BE();
+ break;
+ case AGSCHEDULE: // 34
+ _actListArr[i][j].a34.timer = in.readSint16BE();
+ _actListArr[i][j].a34.actIndex = in.readUint16BE();
+ break;
+ case REMAPPAL: // 35
+ _actListArr[i][j].a35.timer = in.readSint16BE();
+ _actListArr[i][j].a35.oldColorIndex = in.readSint16BE();
+ _actListArr[i][j].a35.newColorIndex = in.readSint16BE();
+ break;
+ case COND_NOUN: // 36
+ _actListArr[i][j].a36.timer = in.readSint16BE();
+ _actListArr[i][j].a36.nounIndex = in.readUint16BE();
+ _actListArr[i][j].a36.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a36.actFailIndex = in.readUint16BE();
+ break;
+ case SCREEN_STATE: // 37
+ _actListArr[i][j].a37.timer = in.readSint16BE();
+ _actListArr[i][j].a37.screenIndex = in.readSint16BE();
+ _actListArr[i][j].a37.newState = in.readByte();
+ break;
+ case INIT_LIPS: // 38
+ _actListArr[i][j].a38.timer = in.readSint16BE();
+ _actListArr[i][j].a38.lipsObjNumb = in.readSint16BE();
+ _actListArr[i][j].a38.objNumb = in.readSint16BE();
+ _actListArr[i][j].a38.dxLips = in.readByte();
+ _actListArr[i][j].a38.dyLips = in.readByte();
+ break;
+ case INIT_STORY_MODE: // 39
+ _actListArr[i][j].a39.timer = in.readSint16BE();
+ _actListArr[i][j].a39.storyModeFl = (in.readByte() == 1);
+ break;
+ case WARN: // 40
+ _actListArr[i][j].a40.timer = in.readSint16BE();
+ _actListArr[i][j].a40.stringIndex = in.readSint16BE();
+ break;
+ case COND_BONUS: // 41
+ _actListArr[i][j].a41.timer = in.readSint16BE();
+ _actListArr[i][j].a41.BonusIndex = in.readSint16BE();
+ _actListArr[i][j].a41.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a41.actFailIndex = in.readUint16BE();
+ break;
+ case TEXT_TAKE: // 42
+ _actListArr[i][j].a42.timer = in.readSint16BE();
+ _actListArr[i][j].a42.objNumb = in.readSint16BE();
+ break;
+ case YESNO: // 43
+ _actListArr[i][j].a43.timer = in.readSint16BE();
+ _actListArr[i][j].a43.promptIndex = in.readSint16BE();
+ _actListArr[i][j].a43.actYesIndex = in.readUint16BE();
+ _actListArr[i][j].a43.actNoIndex = in.readUint16BE();
+ break;
+ case STOP_ROUTE: // 44
+ _actListArr[i][j].a44.timer = in.readSint16BE();
+ break;
+ case COND_ROUTE: // 45
+ _actListArr[i][j].a45.timer = in.readSint16BE();
+ _actListArr[i][j].a45.routeIndex = in.readSint16BE();
+ _actListArr[i][j].a45.actPassIndex = in.readUint16BE();
+ _actListArr[i][j].a45.actFailIndex = in.readUint16BE();
+ break;
+ case INIT_JUMPEXIT: // 46
+ _actListArr[i][j].a46.timer = in.readSint16BE();
+ _actListArr[i][j].a46.jumpExitFl = (in.readByte() == 1);
+ break;
+ case INIT_VIEW: // 47
+ _actListArr[i][j].a47.timer = in.readSint16BE();
+ _actListArr[i][j].a47.objNumb = in.readSint16BE();
+ _actListArr[i][j].a47.viewx = in.readSint16BE();
+ _actListArr[i][j].a47.viewy = in.readSint16BE();
+ _actListArr[i][j].a47.direction = in.readSint16BE();
+ break;
+ case INIT_OBJ_FRAME: // 48
+ _actListArr[i][j].a48.timer = in.readSint16BE();
+ _actListArr[i][j].a48.objNumb = in.readSint16BE();
+ _actListArr[i][j].a48.seqIndex = in.readSint16BE();
+ _actListArr[i][j].a48.frameIndex = in.readSint16BE();
+ break;
+ case OLD_SONG: //49
+ _actListArr[i][j].a49.timer = in.readSint16BE();
+ _actListArr[i][j].a49.soundIndex = in.readUint16BE();
+ break;
+ default:
+ error("Engine - Unknown action type encountered: %d", _actListArr[i][j].a0.actType);
+ }
+ }
+ _actListArr[i][numSubElem].a0.actType = ANULL;
+ }
+ } else {
+ for (int i = 0; i < numElem; i++) {
+ numSubElem = in.readUint16BE();
+ for (int j = 0; j < numSubElem; j++) {
+ numSubAct = in.readByte();
+ switch (numSubAct) {
+ case ANULL: // -1
+ break;
+ case ASCHEDULE: // 0
+ in.readSint16BE();
+ in.readUint16BE();
+ break;
+ case START_OBJ: // 1
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case INIT_OBJXY: // 2
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case PROMPT: // 3
+ in.readSint16BE();
+ in.readSint16BE();
+ numSubAct = in.readUint16BE();
+ for (int k = 0; k < numSubAct; k++)
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ in.readByte();
+ break;
+ case BKGD_COLOR: // 4
+ in.readSint16BE();
+ in.readUint32BE();
+ break;
+ case INIT_OBJVXY: // 5
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case INIT_CARRY: // 6
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case INIT_HF_COORD: // 7
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case NEW_SCREEN: // 8
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case INIT_OBJSTATE: // 9
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case INIT_PATH: // 10
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ in.readByte();
+ break;
+ case COND_R: // 11
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case TEXT: // 12
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case SWAP_IMAGES: // 13
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case COND_SCR: // 14
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case AUTOPILOT: // 15
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ in.readByte();
+ break;
+ case INIT_OBJ_SEQ: // 16
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case SET_STATE_BITS: // 17
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case CLEAR_STATE_BITS: // 18
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case TEST_STATE_BITS: // 19
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case DEL_EVENTS: // 20
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case GAMEOVER: // 21
+ in.readSint16BE();
+ break;
+ case INIT_HH_COORD: // 22
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case EXIT: // 23
+ in.readSint16BE();
+ break;
+ case BONUS: // 24
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case COND_BOX: // 25
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case SOUND: // 26
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case ADD_SCORE: // 27
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case SUB_SCORE: // 28
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case COND_CARRY: // 29
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case INIT_MAZE: // 30
+ in.readSint16BE();
+ in.readByte();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case EXIT_MAZE: // 31
+ in.readSint16BE();
+ break;
+ case INIT_PRIORITY: // 32
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case INIT_SCREEN: // 33
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case AGSCHEDULE: // 34
+ in.readSint16BE();
+ in.readUint16BE();
+ break;
+ case REMAPPAL: // 35
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case COND_NOUN: // 36
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case SCREEN_STATE: // 37
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case INIT_LIPS: // 38
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readByte();
+ in.readByte();
+ break;
+ case INIT_STORY_MODE: // 39
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case WARN: // 40
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case COND_BONUS: // 41
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case TEXT_TAKE: // 42
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case YESNO: // 43
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case STOP_ROUTE: // 44
+ in.readSint16BE();
+ break;
+ case COND_ROUTE: // 45
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readUint16BE();
+ in.readUint16BE();
+ break;
+ case INIT_JUMPEXIT: // 46
+ in.readSint16BE();
+ in.readByte();
+ break;
+ case INIT_VIEW: // 47
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case INIT_OBJ_FRAME: // 48
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ in.readSint16BE();
+ break;
+ case OLD_SONG: //49
+ in.readSint16BE();
+ in.readUint16BE();
+ break;
+ default:
+ error("Engine - Unknown action type encountered %d - variante %d pos %d.%d", numSubAct, varnt, i, j);
+ }
+ }
+ }
+ }
+ }
+}
- _vm.file().saveSeq(&_vm._objects[objNumb1]);
+void Scheduler::freeActListArr() {
+ debugC(6, kDebugSchedule, "freeActListArr()");
- seqList_t tmpSeqList[MAX_SEQUENCES];
- int seqListSize = sizeof(seqList_t) * MAX_SEQUENCES;
+ if (_actListArr) {
+ for (int i = 0; i < _actListArrSize; i++)
+ free(_actListArr[i]);
+ free(_actListArr);
+ }
+}
+
+/**
+* Maze mode is enabled. Check to see whether hero has crossed the maze
+* bounding box, if so, go to the next room
+*/
+void Scheduler::processMaze(int x1, int x2, int y1, int y2) {
+ debugC(1, kDebugSchedule, "processMaze");
- memcpy(tmpSeqList, _vm._objects[objNumb1].seqList, seqListSize);
- memcpy(_vm._objects[objNumb1].seqList, _vm._objects[objNumb2].seqList, seqListSize);
- memcpy(_vm._objects[objNumb2].seqList, tmpSeqList, seqListSize);
- _vm.file().restoreSeq(&_vm._objects[objNumb1]);
- _vm._objects[objNumb2].currImagePtr = _vm._objects[objNumb2].seqList[0].seqPtr;
- _vm._heroImage = (_vm._heroImage == HERO) ? objNumb2 : HERO;
+ status_t &gameStatus = _vm->getGameStatus();
- // Make sure baseline stays constant
- _vm._objects[objNumb1].y += _vm._objects[objNumb2].currImagePtr->y2 - _vm._objects[objNumb1].currImagePtr->y2;
+ if (x1 < _maze.x1) {
+ // Exit west
+ _actListArr[_alNewscrIndex][3].a8.screenIndex = *_vm->_screen_p - 1;
+ _actListArr[_alNewscrIndex][0].a2.x = _maze.x2 - SHIFT - (x2 - x1);
+ _actListArr[_alNewscrIndex][0].a2.y = _vm->_hero->y;
+ gameStatus.routeIndex = -1;
+ insertActionList(_alNewscrIndex);
+ } else if (x2 > _maze.x2) {
+ // Exit east
+ _actListArr[_alNewscrIndex][3].a8.screenIndex = *_vm->_screen_p + 1;
+ _actListArr[_alNewscrIndex][0].a2.x = _maze.x1 + SHIFT;
+ _actListArr[_alNewscrIndex][0].a2.y = _vm->_hero->y;
+ gameStatus.routeIndex = -1;
+ insertActionList(_alNewscrIndex);
+ } else if (y1 < _maze.y1 - SHIFT) {
+ // Exit north
+ _actListArr[_alNewscrIndex][3].a8.screenIndex = *_vm->_screen_p - _maze.size;
+ _actListArr[_alNewscrIndex][0].a2.x = _maze.x3;
+ _actListArr[_alNewscrIndex][0].a2.y = _maze.y2 - SHIFT - (y2 - y1);
+ gameStatus.routeIndex = -1;
+ insertActionList(_alNewscrIndex);
+ } else if (y2 > _maze.y2 - SHIFT / 2) {
+ // Exit south
+ _actListArr[_alNewscrIndex][3].a8.screenIndex = *_vm->_screen_p + _maze.size;
+ _actListArr[_alNewscrIndex][0].a2.x = _maze.x4;
+ _actListArr[_alNewscrIndex][0].a2.y = _maze.y1 + SHIFT;
+ gameStatus.routeIndex = -1;
+ insertActionList(_alNewscrIndex);
+ }
}
} // End of namespace Hugo
diff --git a/engines/hugo/schedule.h b/engines/hugo/schedule.h
index b77abd4302..d0824674c6 100644
--- a/engines/hugo/schedule.h
+++ b/engines/hugo/schedule.h
@@ -33,8 +33,11 @@
#ifndef HUGO_SCHEDULE_H
#define HUGO_SCHEDULE_H
+#include "common/file.h"
+
namespace Hugo {
+#define SIGN(X) ((X < 0) ? -1 : 1)
#define kMaxEvents 50 // Max events in event queue
struct event_t {
@@ -47,59 +50,103 @@ struct event_t {
class Scheduler {
public:
- Scheduler(HugoEngine &vm);
+ Scheduler(HugoEngine *vm);
virtual ~Scheduler();
+ virtual void restoreEvents(Common::SeekableReadStream *f) = 0;
+ virtual void runScheduler() = 0;
+ virtual void saveEvents(Common::WriteStream *f) = 0;
+
+ void decodeString(char *line);
+ void freeActListArr();
void initEventQueue();
- void insertAction(act *action);
void insertActionList(uint16 actIndex);
- void decodeString(char *line);
- void runScheduler();
- uint32 getTicks();
- void processBonus(int bonusIndex);
+ void loadActListArr(Common::File &in);
+ void loadAlNewscrIndex(Common::File &in);
void newScreen(int screenIndex);
- void restoreEvents(Common::SeekableReadStream *f);
- void saveEvents(Common::WriteStream *f);
+ void processBonus(int bonusIndex);
+ void processMaze(int x1, int x2, int y1, int y2);
void restoreScreen(int screenIndex);
- void swapImages(int objNumb1, int objNumb2);
+ void waitForRefresh(void);
+
+protected:
+ HugoEngine *_vm;
-private:
enum seqTextSchedule {
kSsNoBackground = 0,
kSsBadSaveGame = 1
};
- HugoEngine &_vm;
-
- event_t _events[kMaxEvents]; // Statically declare event structures
+ uint16 _actListArrSize;
+ uint16 _alNewscrIndex;
event_t *_freeEvent; // Free list of event structures
event_t *_headEvent; // Head of list (earliest time)
event_t *_tailEvent; // Tail of list (latest time)
+ event_t _events[kMaxEvents]; // Statically declare event structures
+
+ act **_actListArr;
- event_t *getQueue();
- void delQueue(event_t *curEvent);
- event_t *doAction(event_t *curEvent);
-
virtual const char *getCypher() = 0;
+ virtual event_t *doAction(event_t *curEvent) = 0;
+ virtual void delQueue(event_t *curEvent) = 0;
+ virtual void insertAction(act *action) = 0;
+
+ event_t *getQueue();
+
+ uint32 getDosTicks(bool updateFl);
+ uint32 getWinTicks();
+
};
class Scheduler_v1d : public Scheduler {
public:
- Scheduler_v1d(HugoEngine &vm);
+ Scheduler_v1d(HugoEngine *vm);
~Scheduler_v1d();
- const char *getCypher();
+ virtual const char *getCypher();
+ virtual void insertAction(act *action);
+ virtual void restoreEvents(Common::SeekableReadStream *f);
+ virtual void saveEvents(Common::WriteStream *f);
+ virtual void runScheduler();
+protected:
+ virtual void delQueue(event_t *curEvent);
+ virtual event_t *doAction(event_t *curEvent);
};
-class Scheduler_v3d : public Scheduler {
+class Scheduler_v2d : public Scheduler_v1d {
public:
- Scheduler_v3d(HugoEngine &vm);
+ Scheduler_v2d(HugoEngine *vm);
+ virtual ~Scheduler_v2d();
+
+ virtual const char *getCypher();
+ virtual void insertAction(act *action);
+protected:
+ virtual void delQueue(event_t *curEvent);
+ virtual event_t *doAction(event_t *curEvent);
+};
+
+class Scheduler_v3d : public Scheduler_v2d {
+public:
+ Scheduler_v3d(HugoEngine *vm);
~Scheduler_v3d();
const char *getCypher();
+protected:
+ virtual event_t *doAction(event_t *curEvent);
+
};
+class Scheduler_v1w : public Scheduler_v3d {
+public:
+ Scheduler_v1w(HugoEngine *vm);
+ ~Scheduler_v1w();
+
+ virtual event_t *doAction(event_t *curEvent);
+ void insertAction(act *action);
+ void restoreEvents(Common::SeekableReadStream *f);
+ void runScheduler();
+ void saveEvents(Common::WriteStream *f);
+};
} // End of namespace Hugo
-
#endif //HUGO_SCHEDULE_H
diff --git a/engines/hugo/schedule_v1d.cpp b/engines/hugo/schedule_v1d.cpp
index 81daf639f6..b7ce263a27 100644
--- a/engines/hugo/schedule_v1d.cpp
+++ b/engines/hugo/schedule_v1d.cpp
@@ -34,19 +34,384 @@
#include "common/system.h"
+#include "hugo/game.h"
#include "hugo/hugo.h"
#include "hugo/schedule.h"
+#include "hugo/file.h"
+#include "hugo/display.h"
+#include "hugo/parser.h"
+#include "hugo/util.h"
+#include "hugo/sound.h"
+#include "hugo/object.h"
namespace Hugo {
-Scheduler_v1d::Scheduler_v1d(HugoEngine &vm) : Scheduler(vm) {
+Scheduler_v1d::Scheduler_v1d(HugoEngine *vm) : Scheduler(vm) {
}
Scheduler_v1d::~Scheduler_v1d() {
}
const char *Scheduler_v1d::getCypher() {
- return "Copyright 1991, Gray Design Associates";
+ return "Copyright (c) 1990, Gray Design Associates";
+}
+
+/**
+* Delete an event structure (i.e. return it to the free list)
+* Note that event is assumed at head of queue (i.e. earliest). To delete
+* an event from the middle of the queue, merely overwrite its action type
+* to be ANULL
+*/
+void Scheduler_v1d::delQueue(event_t *curEvent) {
+ debugC(4, kDebugSchedule, "delQueue()");
+
+ if (curEvent == _headEvent) // If p was the head ptr
+ _headEvent = curEvent->nextEvent; // then make new head_p
+
+ if (_headEvent)
+ _headEvent->prevEvent = 0; // Mark end of list
+ else
+ _tailEvent = 0; // Empty queue
+
+ curEvent->nextEvent = _freeEvent; // Return p to free list
+ if (_freeEvent) // Special case, if free list was empty
+ _freeEvent->prevEvent = curEvent;
+ _freeEvent = curEvent;
+}
+
+/**
+* Insert the action pointed to by p into the timer event queue
+* The queue goes from head (earliest) to tail (latest) timewise
+*/
+void Scheduler_v1d::insertAction(act *action) {
+ debugC(1, kDebugSchedule, "insertAction() - Action type A%d", action->a0.actType);
+
+ // First, get and initialise the event structure
+ event_t *curEvent = getQueue();
+ curEvent->action = action;
+
+ curEvent->localActionFl = true; // Rest are for current screen only
+
+ curEvent->time = action->a0.timer + getDosTicks(false); // Convert rel to abs time
+
+ // Now find the place to insert the event
+ if (!_tailEvent) { // Empty queue
+ _tailEvent = _headEvent = curEvent;
+ curEvent->nextEvent = curEvent->prevEvent = 0;
+ } else {
+ event_t *wrkEvent = _tailEvent; // Search from latest time back
+ bool found = false;
+
+ while (wrkEvent && !found) {
+ if (wrkEvent->time <= curEvent->time) { // Found if new event later
+ found = true;
+ if (wrkEvent == _tailEvent) // New latest in list
+ _tailEvent = curEvent;
+ else
+ wrkEvent->nextEvent->prevEvent = curEvent;
+ curEvent->nextEvent = wrkEvent->nextEvent;
+ wrkEvent->nextEvent = curEvent;
+ curEvent->prevEvent = wrkEvent;
+ }
+ wrkEvent = wrkEvent->prevEvent;
+ }
+
+ if (!found) { // Must be earliest in list
+ _headEvent->prevEvent = curEvent; // So insert as new head
+ curEvent->nextEvent = _headEvent;
+ curEvent->prevEvent = 0;
+ _headEvent = curEvent;
+ }
+ }
+}
+
+/**
+* This function performs the action in the event structure pointed to by p
+* It dequeues the event and returns it to the free list. It returns a ptr
+* to the next action in the list, except special case of NEW_SCREEN
+*/
+event_t *Scheduler_v1d::doAction(event_t *curEvent) {
+ debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->action->a0.actType);
+
+ status_t &gameStatus = _vm->getGameStatus();
+ act *action = curEvent->action;
+ char *response; // User's response string
+ object_t *obj1;
+ object_t *obj2;
+ int dx, dy;
+ event_t *wrkEvent; // Save ev_p->next_p for return
+
+ switch (action->a0.actType) {
+ case ANULL: // Big NOP from DEL_EVENTS
+ break;
+ case ASCHEDULE: // act0: Schedule an action list
+ insertActionList(action->a0.actIndex);
+ break;
+ case START_OBJ: // act1: Start an object cycling
+ _vm->_object->_objects[action->a1.objNumb].cycleNumb = action->a1.cycleNumb;
+ _vm->_object->_objects[action->a1.objNumb].cycling = action->a1.cycle;
+ break;
+ case INIT_OBJXY: // act2: Initialise an object
+ _vm->_object->_objects[action->a2.objNumb].x = action->a2.x; // Coordinates
+ _vm->_object->_objects[action->a2.objNumb].y = action->a2.y;
+ break;
+ case PROMPT: { // act3: Prompt user for key phrase
+ response = Utils::Box(BOX_PROMPT, "%s", _vm->_file->fetchString(action->a3.promptIndex));
+ if (action->a3.encodedFl)
+ decodeString(response);
+
+ warning("STUB: doAction(act3), expecting answer %s", _vm->_file->fetchString(action->a3.responsePtr[0]));
+
+ // TODO: The answer of the player is not handled currently! Once it'll be read in the messageBox, uncomment this block
+#if 0
+ if (strstr (response, action->a3.response))
+ insertActionList(action->a3.actPassIndex);
+ else
+ insertActionList(action->a3.actFailIndex);
+#endif
+
+ // HACK: As the answer is not read, currently it's always considered correct
+ insertActionList(action->a3.actPassIndex);
+ break;
+ }
+ case BKGD_COLOR: // act4: Set new background color
+ _vm->_screen->setBackgroundColor(action->a4.newBackgroundColor);
+ break;
+ case INIT_OBJVXY: // act5: Initialise an object velocity
+ _vm->_object->setVelocity(action->a5.objNumb, action->a5.vx, action->a5.vy);
+ break;
+ case INIT_CARRY: // act6: Initialise an object
+ _vm->_object->setCarry(action->a6.objNumb, action->a6.carriedFl); // carried status
+ break;
+ case INIT_HF_COORD: // act7: Initialise an object to hero's "feet" coords
+ _vm->_object->_objects[action->a7.objNumb].x = _vm->_hero->x - 1;
+ _vm->_object->_objects[action->a7.objNumb].y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1;
+ _vm->_object->_objects[action->a7.objNumb].screenIndex = *_vm->_screen_p; // Don't forget screen!
+ break;
+ case NEW_SCREEN: // act8: Start new screen
+ newScreen(action->a8.screenIndex);
+ break;
+ case INIT_OBJSTATE: // act9: Initialise an object state
+ _vm->_object->_objects[action->a9.objNumb].state = action->a9.newState;
+ break;
+ case INIT_PATH: // act10: Initialise an object path and velocity
+ _vm->_object->setPath(action->a10.objNumb, (path_t) action->a10.newPathType, action->a10.vxPath, action->a10.vyPath);
+ break;
+ case COND_R: // act11: action lists conditional on object state
+ if (_vm->_object->_objects[action->a11.objNumb].state == action->a11.stateReq)
+ insertActionList(action->a11.actPassIndex);
+ else
+ insertActionList(action->a11.actFailIndex);
+ break;
+ case TEXT: // act12: Text box (CF WARN)
+ Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(action->a12.stringIndex)); // Fetch string from file
+ break;
+ case SWAP_IMAGES: // act13: Swap 2 object images
+ _vm->_object->swapImages(action->a13.obj1, action->a13.obj2);
+ break;
+ case COND_SCR: // act14: Conditional on current screen
+ if (_vm->_object->_objects[action->a14.objNumb].screenIndex == action->a14.screenReq)
+ insertActionList(action->a14.actPassIndex);
+ else
+ insertActionList(action->a14.actFailIndex);
+ break;
+ case AUTOPILOT: // act15: Home in on a (stationary) object
+ // object p1 will home in on object p2
+ obj1 = &_vm->_object->_objects[action->a15.obj1];
+ obj2 = &_vm->_object->_objects[action->a15.obj2];
+ obj1->pathType = AUTO;
+ dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1;
+ dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1;
+
+ if (dx == 0) // Don't EVER divide by zero!
+ dx = 1;
+ if (dy == 0)
+ dy = 1;
+
+ if (abs(dx) > abs(dy)) {
+ obj1->vx = action->a15.dx * -SIGN(dx);
+ obj1->vy = abs((action->a15.dy * dy) / dx) * -SIGN(dy);
+ } else {
+ obj1->vy = action->a15.dy * SIGN(dy);
+ obj1->vx = abs((action->a15.dx * dx) / dy) * SIGN(dx);
+ }
+ break;
+ case INIT_OBJ_SEQ: // act16: Set sequence number to use
+ // Note: Don't set a sequence at time 0 of a new screen, it causes
+ // problems clearing the boundary bits of the object! t>0 is safe
+ _vm->_object->_objects[action->a16.objNumb].currImagePtr = _vm->_object->_objects[action->a16.objNumb].seqList[action->a16.seqIndex].seqPtr;
+ break;
+ case SET_STATE_BITS: // act17: OR mask with curr obj state
+ _vm->_object->_objects[action->a17.objNumb].state |= action->a17.stateMask;
+ break;
+ case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state
+ _vm->_object->_objects[action->a18.objNumb].state &= ~action->a18.stateMask;
+ break;
+ case TEST_STATE_BITS: // act19: If all bits set, do apass else afail
+ if ((_vm->_object->_objects[action->a19.objNumb].state & action->a19.stateMask) == action->a19.stateMask)
+ insertActionList(action->a19.actPassIndex);
+ else
+ insertActionList(action->a19.actFailIndex);
+ break;
+ case DEL_EVENTS: // act20: Remove all events of this action type
+ // Note: actions are not deleted here, simply turned into NOPs!
+ wrkEvent = _headEvent; // The earliest event
+ while (wrkEvent) { // While events found in list
+ if (wrkEvent->action->a20.actType == action->a20.actTypeDel)
+ wrkEvent->action->a20.actType = ANULL;
+ wrkEvent = wrkEvent->nextEvent;
+ }
+ break;
+ case GAMEOVER: // act21: Game over!
+ // NOTE: Must wait at least 1 tick before issuing this action if
+ // any objects are to be made invisible!
+ gameStatus.gameOverFl = true;
+ break;
+ case INIT_HH_COORD: // act22: Initialise an object to hero's actual coords
+ _vm->_object->_objects[action->a22.objNumb].x = _vm->_hero->x;
+ _vm->_object->_objects[action->a22.objNumb].y = _vm->_hero->y;
+ _vm->_object->_objects[action->a22.objNumb].screenIndex = *_vm->_screen_p;// Don't forget screen!
+ break;
+ case EXIT: // act23: Exit game back to DOS
+ _vm->endGame();
+ break;
+ case BONUS: // act24: Get bonus score for action
+ processBonus(action->a24.pointIndex);
+ break;
+ case COND_BOX: // act25: Conditional on bounding box
+ obj1 = &_vm->_object->_objects[action->a25.objNumb];
+ dx = obj1->x + obj1->currImagePtr->x1;
+ dy = obj1->y + obj1->currImagePtr->y2;
+ if ((dx >= action->a25.x1) && (dx <= action->a25.x2) &&
+ (dy >= action->a25.y1) && (dy <= action->a25.y2))
+ insertActionList(action->a25.actPassIndex);
+ else
+ insertActionList(action->a25.actFailIndex);
+ break;
+// case SOUND: // act26: Play a sound (or tune)
+// if (action->a26.soundIndex < _vm->_tunesNbr)
+// _vm->_sound->playMusic(action->a26.soundIndex);
+// else
+// _vm->_sound->playSound(action->a26.soundIndex, BOTH_CHANNELS, MED_PRI);
+// break;
+ case ADD_SCORE: // act27: Add object's value to score
+ _vm->adjustScore(_vm->_object->_objects[action->a27.objNumb].objValue);
+ break;
+ case SUB_SCORE: // act28: Subtract object's value from score
+ _vm->adjustScore(-_vm->_object->_objects[action->a28.objNumb].objValue);
+ break;
+ case COND_CARRY: // act29: Conditional on object being carried
+ if (_vm->_object->isCarried(action->a29.objNumb))
+ insertActionList(action->a29.actPassIndex);
+ else
+ insertActionList(action->a29.actFailIndex);
+ break;
+ case OLD_SONG:
+ //TODO For Hugo 1 and Hugo2 DOS: The songs were not stored in a DAT file, but directly as
+ //strings. the current play_music should be modified to use a strings instead of reading
+ //the file, in those cases. This replaces, for those DOS versions, act26.
+ warning("STUB: doAction(act49)");
+ break;
+ default:
+ Utils::Error(EVNT_ERR, "%s", "doAction");
+ break;
+ }
+
+ if (action->a0.actType == NEW_SCREEN) { // New_screen() deletes entire list
+ return 0; // next_p = 0 since list now empty
+ } else {
+ wrkEvent = curEvent->nextEvent;
+ delQueue(curEvent); // Return event to free list
+ return wrkEvent; // Return next event ptr
+ }
+}
+
+/**
+* Write the event queue to the file with handle f
+* Note that we convert all the event structure ptrs to indexes
+* using -1 for NULL. We can't convert the action ptrs to indexes
+* so we save address of first dummy action ptr to compare on restore.
+*/
+void Scheduler_v1d::saveEvents(Common::WriteStream *f) {
+ debugC(1, kDebugSchedule, "saveEvents()");
+
+ uint32 curTime = getDosTicks(false);
+ event_t saveEventArr[kMaxEvents]; // Convert event ptrs to indexes
+
+ // Convert event ptrs to indexes
+ for (int16 i = 0; i < kMaxEvents; i++) {
+ event_t *wrkEvent = &_events[i];
+ saveEventArr[i] = *wrkEvent;
+ saveEventArr[i].prevEvent = (wrkEvent->prevEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->prevEvent - _events);
+ saveEventArr[i].nextEvent = (wrkEvent->nextEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->nextEvent - _events);
+ }
+
+ int16 freeIndex = (_freeEvent == 0) ? -1 : _freeEvent - _events;
+ int16 headIndex = (_headEvent == 0) ? -1 : _headEvent - _events;
+ int16 tailIndex = (_tailEvent == 0) ? -1 : _tailEvent - _events;
+
+ f->write(&curTime, sizeof(curTime));
+ f->write(&freeIndex, sizeof(freeIndex));
+ f->write(&headIndex, sizeof(headIndex));
+ f->write(&tailIndex, sizeof(tailIndex));
+ f->write(saveEventArr, sizeof(saveEventArr));
+}
+
+/**
+* Restore the event list from file with handle f
+*/
+void Scheduler_v1d::restoreEvents(Common::SeekableReadStream *f) {
+ debugC(1, kDebugSchedule, "restoreEvents");
+
+ uint32 saveTime;
+ int16 freeIndex; // Free list index
+ int16 headIndex; // Head of list index
+ int16 tailIndex; // Tail of list index
+ event_t savedEvents[kMaxEvents]; // Convert event ptrs to indexes
+
+ f->read(&saveTime, sizeof(saveTime)); // time of save
+ f->read(&freeIndex, sizeof(freeIndex));
+ f->read(&headIndex, sizeof(headIndex));
+ f->read(&tailIndex, sizeof(tailIndex));
+ f->read(savedEvents, sizeof(savedEvents));
+
+ event_t *wrkEvent;
+ // Restore events indexes to pointers
+ for (int i = 0; i < kMaxEvents; i++) {
+ wrkEvent = &savedEvents[i];
+ _events[i] = *wrkEvent;
+ _events[i].prevEvent = (wrkEvent->prevEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->prevEvent ];
+ _events[i].nextEvent = (wrkEvent->nextEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->nextEvent ];
+ }
+ _freeEvent = (freeIndex == -1) ? 0 : &_events[freeIndex];
+ _headEvent = (headIndex == -1) ? 0 : &_events[headIndex];
+ _tailEvent = (tailIndex == -1) ? 0 : &_events[tailIndex];
+
+ // Adjust times to fit our time
+ uint32 curTime = getDosTicks(false);
+ wrkEvent = _headEvent; // The earliest event
+ while (wrkEvent) { // While mature events found
+ wrkEvent->time = wrkEvent->time - saveTime + curTime;
+ wrkEvent = wrkEvent->nextEvent;
+ }
+}
+
+/**
+* This is the scheduler which runs every tick. It examines the event queue
+* for any events whose time has come. It dequeues these events and performs
+* the action associated with the event, returning it to the free queue
+*/
+void Scheduler_v1d::runScheduler() {
+ debugC(6, kDebugSchedule, "runScheduler");
+
+ uint32 ticker; // The time now, in ticks
+ event_t *curEvent; // Event ptr
+
+ ticker = getDosTicks(false);
+
+ curEvent = _headEvent; // The earliest event
+ while (curEvent && curEvent->time <= ticker) // While mature events found
+ curEvent = doAction(curEvent); // Perform the action (returns next_p)
}
} // End of namespace Hugo
diff --git a/engines/hugo/schedule_v1w.cpp b/engines/hugo/schedule_v1w.cpp
new file mode 100644
index 0000000000..128d0687a7
--- /dev/null
+++ b/engines/hugo/schedule_v1w.cpp
@@ -0,0 +1,493 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on original Hugo Trilogy source code
+ *
+ * Copyright (c) 1989-1995 David P. Gray
+ *
+ */
+
+// This module contains all the scheduling and timing stuff
+
+#include "common/system.h"
+
+#include "hugo/game.h"
+#include "hugo/hugo.h"
+#include "hugo/schedule.h"
+#include "hugo/global.h"
+#include "hugo/file.h"
+#include "hugo/display.h"
+#include "hugo/parser.h"
+#include "hugo/util.h"
+#include "hugo/sound.h"
+#include "hugo/object.h"
+
+namespace Hugo {
+
+Scheduler_v1w::Scheduler_v1w(HugoEngine *vm) : Scheduler_v3d(vm) {
+}
+
+Scheduler_v1w::~Scheduler_v1w() {
+}
+
+/**
+* This function performs the action in the event structure pointed to by p
+* It dequeues the event and returns it to the free list. It returns a ptr
+* to the next action in the list, except special case of NEW_SCREEN
+*/
+event_t *Scheduler_v1w::doAction(event_t *curEvent) {
+ debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->action->a0.actType);
+
+ status_t &gameStatus = _vm->getGameStatus();
+ act *action = curEvent->action;
+ char *response; // User's response string
+ object_t *obj1;
+ object_t *obj2;
+ int dx, dy;
+ event_t *wrkEvent; // Save ev_p->next_p for return
+ event_t *saveEvent; // Used in DEL_EVENTS
+
+ switch (action->a0.actType) {
+ case ANULL: // Big NOP from DEL_EVENTS
+ break;
+ case ASCHEDULE: // act0: Schedule an action list
+ insertActionList(action->a0.actIndex);
+ break;
+ case START_OBJ: // act1: Start an object cycling
+ _vm->_object->_objects[action->a1.objNumb].cycleNumb = action->a1.cycleNumb;
+ _vm->_object->_objects[action->a1.objNumb].cycling = action->a1.cycle;
+ break;
+ case INIT_OBJXY: // act2: Initialise an object
+ _vm->_object->_objects[action->a2.objNumb].x = action->a2.x; // Coordinates
+ _vm->_object->_objects[action->a2.objNumb].y = action->a2.y;
+ break;
+ case PROMPT: { // act3: Prompt user for key phrase
+ response = Utils::Box(BOX_PROMPT, "%s", _vm->_file->fetchString(action->a3.promptIndex));
+
+ warning("STUB: doAction(act3), expecting answer %s", _vm->_file->fetchString(action->a3.responsePtr[0]));
+
+ // TODO: The answer of the player is not handled currently! Once it'll be read in the messageBox, uncomment this block
+#if 0
+ bool found;
+ char *tmpStr; // General purpose string ptr
+
+ for (found = false, dx = 0; !found && (action->a3.responsePtr[dx] != -1); dx++) {
+ tmpStr = _vm->_file->fetchString(action->a3.responsePtr[dx]);
+ if (strstr(Utils::strlwr(response) , tmpStr))
+ found = true;
+ }
+
+ if (found)
+ insertActionList(action->a3.actPassIndex);
+ else
+ insertActionList(action->a3.actFailIndex);
+#endif
+
+ // HACK: As the answer is not read, currently it's always considered correct
+ insertActionList(action->a3.actPassIndex);
+ break;
+ }
+ case BKGD_COLOR: // act4: Set new background color
+ _vm->_screen->setBackgroundColor(action->a4.newBackgroundColor);
+ break;
+ case INIT_OBJVXY: // act5: Initialise an object velocity
+ _vm->_object->setVelocity(action->a5.objNumb, action->a5.vx, action->a5.vy);
+ break;
+ case INIT_CARRY: // act6: Initialise an object
+ _vm->_object->setCarry(action->a6.objNumb, action->a6.carriedFl); // carried status
+ break;
+ case INIT_HF_COORD: // act7: Initialise an object to hero's "feet" coords
+ _vm->_object->_objects[action->a7.objNumb].x = _vm->_hero->x - 1;
+ _vm->_object->_objects[action->a7.objNumb].y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1;
+ _vm->_object->_objects[action->a7.objNumb].screenIndex = *_vm->_screen_p; // Don't forget screen!
+ break;
+ case NEW_SCREEN: // act8: Start new screen
+ newScreen(action->a8.screenIndex);
+ break;
+ case INIT_OBJSTATE: // act9: Initialise an object state
+ _vm->_object->_objects[action->a9.objNumb].state = action->a9.newState;
+ break;
+ case INIT_PATH: // act10: Initialise an object path and velocity
+ _vm->_object->setPath(action->a10.objNumb, (path_t) action->a10.newPathType, action->a10.vxPath, action->a10.vyPath);
+ break;
+ case COND_R: // act11: action lists conditional on object state
+ if (_vm->_object->_objects[action->a11.objNumb].state == action->a11.stateReq)
+ insertActionList(action->a11.actPassIndex);
+ else
+ insertActionList(action->a11.actFailIndex);
+ break;
+ case TEXT: // act12: Text box (CF WARN)
+ Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(action->a12.stringIndex)); // Fetch string from file
+ break;
+ case SWAP_IMAGES: // act13: Swap 2 object images
+ _vm->_object->swapImages(action->a13.obj1, action->a13.obj2);
+ break;
+ case COND_SCR: // act14: Conditional on current screen
+ if (_vm->_object->_objects[action->a14.objNumb].screenIndex == action->a14.screenReq)
+ insertActionList(action->a14.actPassIndex);
+ else
+ insertActionList(action->a14.actFailIndex);
+ break;
+ case AUTOPILOT: // act15: Home in on a (stationary) object
+ // object p1 will home in on object p2
+ obj1 = &_vm->_object->_objects[action->a15.obj1];
+ obj2 = &_vm->_object->_objects[action->a15.obj2];
+ obj1->pathType = AUTO;
+ dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1;
+ dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1;
+
+ if (dx == 0) // Don't EVER divide by zero!
+ dx = 1;
+ if (dy == 0)
+ dy = 1;
+
+ if (abs(dx) > abs(dy)) {
+ obj1->vx = action->a15.dx * -SIGN(dx);
+ obj1->vy = abs((action->a15.dy * dy) / dx) * -SIGN(dy);
+ } else {
+ obj1->vy = action->a15.dy * -SIGN(dy);
+ obj1->vx = abs((action->a15.dx * dx) / dy) * -SIGN(dx);
+ }
+ break;
+ case INIT_OBJ_SEQ: // act16: Set sequence number to use
+ // Note: Don't set a sequence at time 0 of a new screen, it causes
+ // problems clearing the boundary bits of the object! t>0 is safe
+ _vm->_object->_objects[action->a16.objNumb].currImagePtr = _vm->_object->_objects[action->a16.objNumb].seqList[action->a16.seqIndex].seqPtr;
+ break;
+ case SET_STATE_BITS: // act17: OR mask with curr obj state
+ _vm->_object->_objects[action->a17.objNumb].state |= action->a17.stateMask;
+ break;
+ case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state
+ _vm->_object->_objects[action->a18.objNumb].state &= ~action->a18.stateMask;
+ break;
+ case TEST_STATE_BITS: // act19: If all bits set, do apass else afail
+ if ((_vm->_object->_objects[action->a19.objNumb].state & action->a19.stateMask) == action->a19.stateMask)
+ insertActionList(action->a19.actPassIndex);
+ else
+ insertActionList(action->a19.actFailIndex);
+ break;
+ case DEL_EVENTS: // act20: Remove all events of this action type
+ // Note: actions are not deleted here, simply turned into NOPs!
+ wrkEvent = _headEvent; // The earliest event
+ while (wrkEvent) { // While events found in list
+ saveEvent = wrkEvent->nextEvent;
+ if (wrkEvent->action->a20.actType == action->a20.actTypeDel)
+ delQueue(wrkEvent);
+ wrkEvent = saveEvent;
+ }
+ break;
+ case GAMEOVER: // act21: Game over!
+ // NOTE: Must wait at least 1 tick before issuing this action if
+ // any objects are to be made invisible!
+ gameStatus.gameOverFl = true;
+ break;
+ case INIT_HH_COORD: // act22: Initialise an object to hero's actual coords
+ _vm->_object->_objects[action->a22.objNumb].x = _vm->_hero->x;
+ _vm->_object->_objects[action->a22.objNumb].y = _vm->_hero->y;
+ _vm->_object->_objects[action->a22.objNumb].screenIndex = *_vm->_screen_p;// Don't forget screen!
+ break;
+ case EXIT: // act23: Exit game back to DOS
+ _vm->endGame();
+ break;
+ case BONUS: // act24: Get bonus score for action
+ processBonus(action->a24.pointIndex);
+ break;
+ case COND_BOX: // act25: Conditional on bounding box
+ obj1 = &_vm->_object->_objects[action->a25.objNumb];
+ dx = obj1->x + obj1->currImagePtr->x1;
+ dy = obj1->y + obj1->currImagePtr->y2;
+ if ((dx >= action->a25.x1) && (dx <= action->a25.x2) &&
+ (dy >= action->a25.y1) && (dy <= action->a25.y2))
+ insertActionList(action->a25.actPassIndex);
+ else
+ insertActionList(action->a25.actFailIndex);
+ break;
+ case SOUND: // act26: Play a sound (or tune)
+ if (action->a26.soundIndex < _vm->_tunesNbr)
+ _vm->_sound->playMusic(action->a26.soundIndex);
+ else
+ _vm->_sound->playSound(action->a26.soundIndex, BOTH_CHANNELS, MED_PRI);
+ break;
+ case ADD_SCORE: // act27: Add object's value to score
+ _vm->adjustScore(_vm->_object->_objects[action->a27.objNumb].objValue);
+ break;
+ case SUB_SCORE: // act28: Subtract object's value from score
+ _vm->adjustScore(-_vm->_object->_objects[action->a28.objNumb].objValue);
+ break;
+ case COND_CARRY: // act29: Conditional on object being carried
+ if (_vm->_object->isCarried(action->a29.objNumb))
+ insertActionList(action->a29.actPassIndex);
+ else
+ insertActionList(action->a29.actFailIndex);
+ break;
+ case INIT_MAZE: // act30: Enable and init maze structure
+ _maze.enabledFl = true;
+ _maze.size = action->a30.mazeSize;
+ _maze.x1 = action->a30.x1;
+ _maze.y1 = action->a30.y1;
+ _maze.x2 = action->a30.x2;
+ _maze.y2 = action->a30.y2;
+ _maze.x3 = action->a30.x3;
+ _maze.x4 = action->a30.x4;
+ _maze.firstScreenIndex = action->a30.firstScreenIndex;
+ break;
+ case EXIT_MAZE: // act31: Disable maze mode
+ _maze.enabledFl = false;
+ break;
+ case INIT_PRIORITY:
+ _vm->_object->_objects[action->a32.objNumb].priority = action->a32.priority;
+ break;
+ case INIT_SCREEN:
+ _vm->_object->_objects[action->a33.objNumb].screenIndex = action->a33.screenIndex;
+ break;
+ case AGSCHEDULE: // act34: Schedule a (global) action list
+ insertActionList(action->a34.actIndex);
+ break;
+ case REMAPPAL: // act35: Remap a palette color
+ _vm->_screen->remapPal(action->a35.oldColorIndex, action->a35.newColorIndex);
+ break;
+ case COND_NOUN: // act36: Conditional on noun mentioned
+ if (_vm->_parser->isWordPresent(_vm->_arrayNouns[action->a36.nounIndex]))
+ insertActionList(action->a36.actPassIndex);
+ else
+ insertActionList(action->a36.actFailIndex);
+ break;
+ case SCREEN_STATE: // act37: Set new screen state
+ _vm->_screenStates[action->a37.screenIndex] = action->a37.newState;
+ break;
+ case INIT_LIPS: // act38: Position lips on object
+ _vm->_object->_objects[action->a38.lipsObjNumb].x = _vm->_object->_objects[action->a38.objNumb].x + action->a38.dxLips;
+ _vm->_object->_objects[action->a38.lipsObjNumb].y = _vm->_object->_objects[action->a38.objNumb].y + action->a38.dyLips;
+ _vm->_object->_objects[action->a38.lipsObjNumb].screenIndex = *_vm->_screen_p; // Don't forget screen!
+ _vm->_object->_objects[action->a38.lipsObjNumb].cycling = CYCLE_FORWARD;
+ break;
+ case INIT_STORY_MODE: // act39: Init story_mode flag
+ // This is similar to the QUIET path mode, except that it is
+ // independant of it and it additionally disables the ">" prompt
+ gameStatus.storyModeFl = action->a39.storyModeFl;
+
+ // End the game after story if this is special vendor demo mode
+ if (gameStatus.demoFl && action->a39.storyModeFl == false)
+ _vm->endGame();
+ break;
+ case WARN: // act40: Text box (CF TEXT)
+ Utils::Box(BOX_OK, "%s", _vm->_file->fetchString(action->a40.stringIndex));
+ break;
+ case COND_BONUS: // act41: Perform action if got bonus
+ if (_vm->_points[action->a41.BonusIndex].scoredFl)
+ insertActionList(action->a41.actPassIndex);
+ else
+ insertActionList(action->a41.actFailIndex);
+ break;
+ case TEXT_TAKE: // act42: Text box with "take" message
+ Utils::Box(BOX_ANY, TAKE_TEXT, _vm->_arrayNouns[_vm->_object->_objects[action->a42.objNumb].nounIndex][TAKE_NAME]);
+ break;
+ case YESNO: // act43: Prompt user for Yes or No
+ warning("doAction(act43) - Yes/No Box");
+ if (Utils::Box(BOX_YESNO, "%s", _vm->_file->fetchString(action->a43.promptIndex)) != 0)
+ insertActionList(action->a43.actYesIndex);
+ else
+ insertActionList(action->a43.actNoIndex);
+ break;
+ case STOP_ROUTE: // act44: Stop any route in progress
+ gameStatus.routeIndex = -1;
+ break;
+ case COND_ROUTE: // act45: Conditional on route in progress
+ if (gameStatus.routeIndex >= action->a45.routeIndex)
+ insertActionList(action->a45.actPassIndex);
+ else
+ insertActionList(action->a45.actFailIndex);
+ break;
+ case INIT_JUMPEXIT: // act46: Init status.jumpexit flag
+ // This is to allow left click on exit to get there immediately
+ // For example the plane crash in Hugo2 where hero is invisible
+ // Couldn't use INVISIBLE flag since conflicts with boat in Hugo1
+ gameStatus.jumpExitFl = action->a46.jumpExitFl;
+ break;
+ case INIT_VIEW: // act47: Init object.viewx, viewy, dir
+ _vm->_object->_objects[action->a47.objNumb].viewx = action->a47.viewx;
+ _vm->_object->_objects[action->a47.objNumb].viewy = action->a47.viewy;
+ _vm->_object->_objects[action->a47.objNumb].direction = action->a47.direction;
+ break;
+ case INIT_OBJ_FRAME: // act48: Set seq,frame number to use
+ // Note: Don't set a sequence at time 0 of a new screen, it causes
+ // problems clearing the boundary bits of the object! t>0 is safe
+ _vm->_object->_objects[action->a48.objNumb].currImagePtr = _vm->_object->_objects[action->a48.objNumb].seqList[action->a48.seqIndex].seqPtr;
+ for (dx = 0; dx < action->a48.frameIndex; dx++)
+ _vm->_object->_objects[action->a48.objNumb].currImagePtr = _vm->_object->_objects[action->a48.objNumb].currImagePtr->nextSeqPtr;
+ break;
+ default:
+ Utils::Error(EVNT_ERR, "%s", "doAction");
+ break;
+ }
+
+ if (action->a0.actType == NEW_SCREEN) { // New_screen() deletes entire list
+ return 0; // next_p = 0 since list now empty
+ } else {
+ wrkEvent = curEvent->nextEvent;
+ delQueue(curEvent); // Return event to free list
+ return wrkEvent; // Return next event ptr
+ }
+}
+
+/**
+* Write the event queue to the file with handle f
+* Note that we convert all the event structure ptrs to indexes
+* using -1 for NULL. We can't convert the action ptrs to indexes
+* so we save address of first dummy action ptr to compare on restore.
+*/
+void Scheduler_v1w::saveEvents(Common::WriteStream *f) {
+ debugC(1, kDebugSchedule, "saveEvents()");
+
+ uint32 curTime = getWinTicks();
+ event_t saveEventArr[kMaxEvents]; // Convert event ptrs to indexes
+
+ // Convert event ptrs to indexes
+ for (int16 i = 0; i < kMaxEvents; i++) {
+ event_t *wrkEvent = &_events[i];
+ saveEventArr[i] = *wrkEvent;
+ saveEventArr[i].prevEvent = (wrkEvent->prevEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->prevEvent - _events);
+ saveEventArr[i].nextEvent = (wrkEvent->nextEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->nextEvent - _events);
+ }
+
+ int16 freeIndex = (_freeEvent == 0) ? -1 : _freeEvent - _events;
+ int16 headIndex = (_headEvent == 0) ? -1 : _headEvent - _events;
+ int16 tailIndex = (_tailEvent == 0) ? -1 : _tailEvent - _events;
+
+ f->write(&curTime, sizeof(curTime));
+ f->write(&freeIndex, sizeof(freeIndex));
+ f->write(&headIndex, sizeof(headIndex));
+ f->write(&tailIndex, sizeof(tailIndex));
+ f->write(saveEventArr, sizeof(saveEventArr));
+}
+
+/**
+* Restore the event list from file with handle f
+*/
+void Scheduler_v1w::restoreEvents(Common::SeekableReadStream *f) {
+ debugC(1, kDebugSchedule, "restoreEvents");
+
+ uint32 saveTime;
+ int16 freeIndex; // Free list index
+ int16 headIndex; // Head of list index
+ int16 tailIndex; // Tail of list index
+ event_t savedEvents[kMaxEvents]; // Convert event ptrs to indexes
+
+ f->read(&saveTime, sizeof(saveTime)); // time of save
+ f->read(&freeIndex, sizeof(freeIndex));
+ f->read(&headIndex, sizeof(headIndex));
+ f->read(&tailIndex, sizeof(tailIndex));
+ f->read(savedEvents, sizeof(savedEvents));
+
+ event_t *wrkEvent;
+ // Restore events indexes to pointers
+ for (int i = 0; i < kMaxEvents; i++) {
+ wrkEvent = &savedEvents[i];
+ _events[i] = *wrkEvent;
+ _events[i].prevEvent = (wrkEvent->prevEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->prevEvent ];
+ _events[i].nextEvent = (wrkEvent->nextEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->nextEvent ];
+ }
+ _freeEvent = (freeIndex == -1) ? 0 : &_events[freeIndex];
+ _headEvent = (headIndex == -1) ? 0 : &_events[headIndex];
+ _tailEvent = (tailIndex == -1) ? 0 : &_events[tailIndex];
+
+ // Adjust times to fit our time
+ uint32 curTime = getWinTicks();
+ wrkEvent = _headEvent; // The earliest event
+ while (wrkEvent) { // While mature events found
+ wrkEvent->time = wrkEvent->time - saveTime + curTime;
+ wrkEvent = wrkEvent->nextEvent;
+ }
+}
+
+/**
+* Insert the action pointed to by p into the timer event queue
+* The queue goes from head (earliest) to tail (latest) timewise
+*/
+void Scheduler_v1w::insertAction(act *action) {
+ debugC(1, kDebugSchedule, "insertAction() - Action type A%d", action->a0.actType);
+
+ // First, get and initialise the event structure
+ event_t *curEvent = getQueue();
+ curEvent->action = action;
+ switch (action->a0.actType) { // Assign whether local or global
+ case AGSCHEDULE:
+ curEvent->localActionFl = false; // Lasts over a new screen
+ break;
+ default:
+ curEvent->localActionFl = true; // Rest are for current screen only
+ break;
+ }
+
+ curEvent->time = action->a0.timer + getWinTicks(); // Convert rel to abs time
+
+ // Now find the place to insert the event
+ if (!_tailEvent) { // Empty queue
+ _tailEvent = _headEvent = curEvent;
+ curEvent->nextEvent = curEvent->prevEvent = 0;
+ } else {
+ event_t *wrkEvent = _tailEvent; // Search from latest time back
+ bool found = false;
+
+ while (wrkEvent && !found) {
+ if (wrkEvent->time <= curEvent->time) { // Found if new event later
+ found = true;
+ if (wrkEvent == _tailEvent) // New latest in list
+ _tailEvent = curEvent;
+ else
+ wrkEvent->nextEvent->prevEvent = curEvent;
+ curEvent->nextEvent = wrkEvent->nextEvent;
+ wrkEvent->nextEvent = curEvent;
+ curEvent->prevEvent = wrkEvent;
+ }
+ wrkEvent = wrkEvent->prevEvent;
+ }
+
+ if (!found) { // Must be earliest in list
+ _headEvent->prevEvent = curEvent; // So insert as new head
+ curEvent->nextEvent = _headEvent;
+ curEvent->prevEvent = 0;
+ _headEvent = curEvent;
+ }
+ }
+}
+
+/**
+* This is the scheduler which runs every tick. It examines the event queue
+* for any events whose time has come. It dequeues these events and performs
+* the action associated with the event, returning it to the free queue
+*/
+void Scheduler_v1w::runScheduler() {
+ debugC(6, kDebugSchedule, "runScheduler");
+
+ status_t &gameStatus = _vm->getGameStatus();
+ event_t *curEvent = _headEvent; // The earliest event
+
+ while (curEvent && curEvent->time <= gameStatus.tick) // While mature events found
+ curEvent = doAction(curEvent); // Perform the action (returns next_p)
+ gameStatus.tick++; // Accessed elsewhere via getTicks()
+}
+} // End of namespace Hugo
diff --git a/engines/hugo/schedule_v2d.cpp b/engines/hugo/schedule_v2d.cpp
new file mode 100644
index 0000000000..22a79356bf
--- /dev/null
+++ b/engines/hugo/schedule_v2d.cpp
@@ -0,0 +1,395 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on original Hugo Trilogy source code
+ *
+ * Copyright (c) 1989-1995 David P. Gray
+ *
+ */
+
+// This module contains all the scheduling and timing stuff
+
+#include "common/system.h"
+
+#include "hugo/game.h"
+#include "hugo/hugo.h"
+#include "hugo/schedule.h"
+#include "hugo/global.h"
+#include "hugo/file.h"
+#include "hugo/display.h"
+#include "hugo/parser.h"
+#include "hugo/util.h"
+#include "hugo/sound.h"
+#include "hugo/object.h"
+
+namespace Hugo {
+
+Scheduler_v2d::Scheduler_v2d(HugoEngine *vm) : Scheduler_v1d(vm) {
+}
+
+Scheduler_v2d::~Scheduler_v2d() {
+}
+
+const char *Scheduler_v2d::getCypher() {
+ return "Copyright 1991, Gray Design Associates";
+}
+
+/**
+* Delete an event structure (i.e. return it to the free list)
+* Historical note: Originally event p was assumed to be at head of queue
+* (i.e. earliest) since all events were deleted in order when proceeding to
+* a new screen. To delete an event from the middle of the queue, the action
+* was overwritten to be ANULL. With the advent of GLOBAL events, delQueue
+* was modified to allow deletes anywhere in the list, and the DEL_EVENT
+* action was modified to perform the actual delete.
+*/
+void Scheduler_v2d::delQueue(event_t *curEvent) {
+ debugC(4, kDebugSchedule, "delQueue()");
+
+ if (curEvent == _headEvent) { // If p was the head ptr
+ _headEvent = curEvent->nextEvent; // then make new head_p
+ } else { // Unlink p
+ curEvent->prevEvent->nextEvent = curEvent->nextEvent;
+ if (curEvent->nextEvent)
+ curEvent->nextEvent->prevEvent = curEvent->prevEvent;
+ else
+ _tailEvent = curEvent->prevEvent;
+ }
+
+ if (_headEvent)
+ _headEvent->prevEvent = 0; // Mark end of list
+ else
+ _tailEvent = 0; // Empty queue
+
+ curEvent->nextEvent = _freeEvent; // Return p to free list
+ if (_freeEvent) // Special case, if free list was empty
+ _freeEvent->prevEvent = curEvent;
+ _freeEvent = curEvent;
+}
+
+/**
+* Insert the action pointed to by p into the timer event queue
+* The queue goes from head (earliest) to tail (latest) timewise
+*/
+void Scheduler_v2d::insertAction(act *action) {
+ debugC(1, kDebugSchedule, "insertAction() - Action type A%d", action->a0.actType);
+
+ // First, get and initialise the event structure
+ event_t *curEvent = getQueue();
+ curEvent->action = action;
+ switch (action->a0.actType) { // Assign whether local or global
+ case AGSCHEDULE:
+ curEvent->localActionFl = false; // Lasts over a new screen
+ break;
+ default:
+ curEvent->localActionFl = true; // Rest are for current screen only
+ break;
+ }
+
+ curEvent->time = action->a0.timer + getDosTicks(false); // Convert rel to abs time
+
+ // Now find the place to insert the event
+ if (!_tailEvent) { // Empty queue
+ _tailEvent = _headEvent = curEvent;
+ curEvent->nextEvent = curEvent->prevEvent = 0;
+ } else {
+ event_t *wrkEvent = _tailEvent; // Search from latest time back
+ bool found = false;
+
+ while (wrkEvent && !found) {
+ if (wrkEvent->time <= curEvent->time) { // Found if new event later
+ found = true;
+ if (wrkEvent == _tailEvent) // New latest in list
+ _tailEvent = curEvent;
+ else
+ wrkEvent->nextEvent->prevEvent = curEvent;
+ curEvent->nextEvent = wrkEvent->nextEvent;
+ wrkEvent->nextEvent = curEvent;
+ curEvent->prevEvent = wrkEvent;
+ }
+ wrkEvent = wrkEvent->prevEvent;
+ }
+
+ if (!found) { // Must be earliest in list
+ _headEvent->prevEvent = curEvent; // So insert as new head
+ curEvent->nextEvent = _headEvent;
+ curEvent->prevEvent = 0;
+ _headEvent = curEvent;
+ }
+ }
+}
+
+/**
+* This function performs the action in the event structure pointed to by p
+* It dequeues the event and returns it to the free list. It returns a ptr
+* to the next action in the list, except special case of NEW_SCREEN
+*/
+event_t *Scheduler_v2d::doAction(event_t *curEvent) {
+ debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->action->a0.actType);
+
+ status_t &gameStatus = _vm->getGameStatus();
+ act *action = curEvent->action;
+ char *response; // User's response string
+ object_t *obj1;
+ object_t *obj2;
+ int dx, dy;
+ event_t *wrkEvent; // Save ev_p->next_p for return
+ event_t *saveEvent; // Used in DEL_EVENTS
+
+ switch (action->a0.actType) {
+ case ANULL: // Big NOP from DEL_EVENTS
+ break;
+ case ASCHEDULE: // act0: Schedule an action list
+ insertActionList(action->a0.actIndex);
+ break;
+ case START_OBJ: // act1: Start an object cycling
+ _vm->_object->_objects[action->a1.objNumb].cycleNumb = action->a1.cycleNumb;
+ _vm->_object->_objects[action->a1.objNumb].cycling = action->a1.cycle;
+ break;
+ case INIT_OBJXY: // act2: Initialise an object
+ _vm->_object->_objects[action->a2.objNumb].x = action->a2.x; // Coordinates
+ _vm->_object->_objects[action->a2.objNumb].y = action->a2.y;
+ break;
+ case PROMPT: { // act3: Prompt user for key phrase
+ response = Utils::Box(BOX_PROMPT, "%s", _vm->_file->fetchString(action->a3.promptIndex));
+
+ warning("STUB: doAction(act3), expecting answer %s", _vm->_file->fetchString(action->a3.responsePtr[0]));
+
+ // TODO: The answer of the player is not handled currently! Once it'll be read in the messageBox, uncomment this block
+#if 0
+ bool found;
+ char *tmpStr; // General purpose string ptr
+
+ for (found = false, dx = 0; !found && (action->a3.responsePtr[dx] != -1); dx++) {
+ tmpStr = _vm->_file->fetchString(action->a3.responsePtr[dx]);
+ if (strstr(Utils::strlwr(response) , tmpStr))
+ found = true;
+ }
+
+ if (found)
+ insertActionList(action->a3.actPassIndex);
+ else
+ insertActionList(action->a3.actFailIndex);
+#endif
+
+ // HACK: As the answer is not read, currently it's always considered correct
+ insertActionList(action->a3.actPassIndex);
+ break;
+ }
+ case BKGD_COLOR: // act4: Set new background color
+ _vm->_screen->setBackgroundColor(action->a4.newBackgroundColor);
+ break;
+ case INIT_OBJVXY: // act5: Initialise an object velocity
+ _vm->_object->setVelocity(action->a5.objNumb, action->a5.vx, action->a5.vy);
+ break;
+ case INIT_CARRY: // act6: Initialise an object
+ _vm->_object->setCarry(action->a6.objNumb, action->a6.carriedFl); // carried status
+ break;
+ case INIT_HF_COORD: // act7: Initialise an object to hero's "feet" coords
+ _vm->_object->_objects[action->a7.objNumb].x = _vm->_hero->x - 1;
+ _vm->_object->_objects[action->a7.objNumb].y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1;
+ _vm->_object->_objects[action->a7.objNumb].screenIndex = *_vm->_screen_p; // Don't forget screen!
+ break;
+ case NEW_SCREEN: // act8: Start new screen
+ newScreen(action->a8.screenIndex);
+ break;
+ case INIT_OBJSTATE: // act9: Initialise an object state
+ _vm->_object->_objects[action->a9.objNumb].state = action->a9.newState;
+ break;
+ case INIT_PATH: // act10: Initialise an object path and velocity
+ _vm->_object->setPath(action->a10.objNumb, (path_t) action->a10.newPathType, action->a10.vxPath, action->a10.vyPath);
+ break;
+ case COND_R: // act11: action lists conditional on object state
+ if (_vm->_object->_objects[action->a11.objNumb].state == action->a11.stateReq)
+ insertActionList(action->a11.actPassIndex);
+ else
+ insertActionList(action->a11.actFailIndex);
+ break;
+ case TEXT: // act12: Text box (CF WARN)
+ Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(action->a12.stringIndex)); // Fetch string from file
+ break;
+ case SWAP_IMAGES: // act13: Swap 2 object images
+ _vm->_object->swapImages(action->a13.obj1, action->a13.obj2);
+ break;
+ case COND_SCR: // act14: Conditional on current screen
+ if (_vm->_object->_objects[action->a14.objNumb].screenIndex == action->a14.screenReq)
+ insertActionList(action->a14.actPassIndex);
+ else
+ insertActionList(action->a14.actFailIndex);
+ break;
+ case AUTOPILOT: // act15: Home in on a (stationary) object
+ // object p1 will home in on object p2
+ obj1 = &_vm->_object->_objects[action->a15.obj1];
+ obj2 = &_vm->_object->_objects[action->a15.obj2];
+ obj1->pathType = AUTO;
+ dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1;
+ dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1;
+
+ if (dx == 0) // Don't EVER divide by zero!
+ dx = 1;
+ if (dy == 0)
+ dy = 1;
+
+ if (abs(dx) > abs(dy)) {
+ obj1->vx = action->a15.dx * -SIGN(dx);
+ obj1->vy = abs((action->a15.dy * dy) / dx) * -SIGN(dy);
+ } else {
+ obj1->vy = action->a15.dy * -SIGN(dy);
+ obj1->vx = abs((action->a15.dx * dx) / dy) * -SIGN(dx);
+ }
+ break;
+ case INIT_OBJ_SEQ: // act16: Set sequence number to use
+ // Note: Don't set a sequence at time 0 of a new screen, it causes
+ // problems clearing the boundary bits of the object! t>0 is safe
+ _vm->_object->_objects[action->a16.objNumb].currImagePtr = _vm->_object->_objects[action->a16.objNumb].seqList[action->a16.seqIndex].seqPtr;
+ break;
+ case SET_STATE_BITS: // act17: OR mask with curr obj state
+ _vm->_object->_objects[action->a17.objNumb].state |= action->a17.stateMask;
+ break;
+ case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state
+ _vm->_object->_objects[action->a18.objNumb].state &= ~action->a18.stateMask;
+ break;
+ case TEST_STATE_BITS: // act19: If all bits set, do apass else afail
+ if ((_vm->_object->_objects[action->a19.objNumb].state & action->a19.stateMask) == action->a19.stateMask)
+ insertActionList(action->a19.actPassIndex);
+ else
+ insertActionList(action->a19.actFailIndex);
+ break;
+ case DEL_EVENTS: // act20: Remove all events of this action type
+ // Note: actions are not deleted here, simply turned into NOPs!
+ wrkEvent = _headEvent; // The earliest event
+ while (wrkEvent) { // While events found in list
+ saveEvent = wrkEvent->nextEvent;
+ if (wrkEvent->action->a20.actType == action->a20.actTypeDel)
+ delQueue(wrkEvent);
+ wrkEvent = saveEvent;
+ }
+ break;
+ case GAMEOVER: // act21: Game over!
+ // NOTE: Must wait at least 1 tick before issuing this action if
+ // any objects are to be made invisible!
+ gameStatus.gameOverFl = true;
+ break;
+ case INIT_HH_COORD: // act22: Initialise an object to hero's actual coords
+ _vm->_object->_objects[action->a22.objNumb].x = _vm->_hero->x;
+ _vm->_object->_objects[action->a22.objNumb].y = _vm->_hero->y;
+ _vm->_object->_objects[action->a22.objNumb].screenIndex = *_vm->_screen_p;// Don't forget screen!
+ break;
+ case EXIT: // act23: Exit game back to DOS
+ _vm->endGame();
+ break;
+ case BONUS: // act24: Get bonus score for action
+ processBonus(action->a24.pointIndex);
+ break;
+ case COND_BOX: // act25: Conditional on bounding box
+ obj1 = &_vm->_object->_objects[action->a25.objNumb];
+ dx = obj1->x + obj1->currImagePtr->x1;
+ dy = obj1->y + obj1->currImagePtr->y2;
+ if ((dx >= action->a25.x1) && (dx <= action->a25.x2) &&
+ (dy >= action->a25.y1) && (dy <= action->a25.y2))
+ insertActionList(action->a25.actPassIndex);
+ else
+ insertActionList(action->a25.actFailIndex);
+ break;
+// case SOUND: // act26: Play a sound (or tune)
+// if (action->a26.soundIndex < _vm->_tunesNbr)
+// _vm->_sound->playMusic(action->a26.soundIndex);
+// else
+// _vm->_sound->playSound(action->a26.soundIndex, BOTH_CHANNELS, MED_PRI);
+// break;
+ case ADD_SCORE: // act27: Add object's value to score
+ _vm->adjustScore(_vm->_object->_objects[action->a27.objNumb].objValue);
+ break;
+ case SUB_SCORE: // act28: Subtract object's value from score
+ _vm->adjustScore(-_vm->_object->_objects[action->a28.objNumb].objValue);
+ break;
+ case COND_CARRY: // act29: Conditional on object being carried
+ if (_vm->_object->isCarried(action->a29.objNumb))
+ insertActionList(action->a29.actPassIndex);
+ else
+ insertActionList(action->a29.actFailIndex);
+ break;
+ case INIT_MAZE: // act30: Enable and init maze structure
+ _maze.enabledFl = true;
+ _maze.size = action->a30.mazeSize;
+ _maze.x1 = action->a30.x1;
+ _maze.y1 = action->a30.y1;
+ _maze.x2 = action->a30.x2;
+ _maze.y2 = action->a30.y2;
+ _maze.x3 = action->a30.x3;
+ _maze.x4 = action->a30.x4;
+ _maze.firstScreenIndex = action->a30.firstScreenIndex;
+ break;
+ case EXIT_MAZE: // act31: Disable maze mode
+ _maze.enabledFl = false;
+ break;
+ case INIT_PRIORITY:
+ _vm->_object->_objects[action->a32.objNumb].priority = action->a32.priority;
+ break;
+ case INIT_SCREEN:
+ _vm->_object->_objects[action->a33.objNumb].screenIndex = action->a33.screenIndex;
+ break;
+ case AGSCHEDULE: // act34: Schedule a (global) action list
+ insertActionList(action->a34.actIndex);
+ break;
+ case REMAPPAL: // act35: Remap a palette color
+ _vm->_screen->remapPal(action->a35.oldColorIndex, action->a35.newColorIndex);
+ break;
+ case COND_NOUN: // act36: Conditional on noun mentioned
+ if (_vm->_parser->isWordPresent(_vm->_arrayNouns[action->a36.nounIndex]))
+ insertActionList(action->a36.actPassIndex);
+ else
+ insertActionList(action->a36.actFailIndex);
+ break;
+ case SCREEN_STATE: // act37: Set new screen state
+ _vm->_screenStates[action->a37.screenIndex] = action->a37.newState;
+ break;
+ case INIT_LIPS: // act38: Position lips on object
+ _vm->_object->_objects[action->a38.lipsObjNumb].x = _vm->_object->_objects[action->a38.objNumb].x + action->a38.dxLips;
+ _vm->_object->_objects[action->a38.lipsObjNumb].y = _vm->_object->_objects[action->a38.objNumb].y + action->a38.dyLips;
+ _vm->_object->_objects[action->a38.lipsObjNumb].screenIndex = *_vm->_screen_p; // Don't forget screen!
+ _vm->_object->_objects[action->a38.lipsObjNumb].cycling = CYCLE_FORWARD;
+ break;
+ case OLD_SONG:
+ //TODO For Hugo 1 and Hugo2 DOS: The songs were not stored in a DAT file, but directly as
+ //strings. the current play_music should be modified to use a strings instead of reading
+ //the file, in those cases. This replaces, for those DOS versions, act26.
+ warning("STUB: doAction(act49)");
+ break;
+ default:
+ Utils::Error(EVNT_ERR, "%s", "doAction");
+ break;
+ }
+
+ if (action->a0.actType == NEW_SCREEN) { // New_screen() deletes entire list
+ return 0; // next_p = 0 since list now empty
+ } else {
+ wrkEvent = curEvent->nextEvent;
+ delQueue(curEvent); // Return event to free list
+ return wrkEvent; // Return next event ptr
+ }
+}
+} // End of namespace Hugo
diff --git a/engines/hugo/schedule_v3d.cpp b/engines/hugo/schedule_v3d.cpp
index 9421b0f5f9..fc37bd8b83 100644
--- a/engines/hugo/schedule_v3d.cpp
+++ b/engines/hugo/schedule_v3d.cpp
@@ -34,18 +34,295 @@
#include "common/system.h"
+#include "hugo/game.h"
#include "hugo/hugo.h"
#include "hugo/schedule.h"
+#include "hugo/global.h"
+#include "hugo/file.h"
+#include "hugo/display.h"
+#include "hugo/parser.h"
+#include "hugo/util.h"
+#include "hugo/sound.h"
+#include "hugo/object.h"
namespace Hugo {
-Scheduler_v3d::Scheduler_v3d(HugoEngine &vm) : Scheduler(vm) {
+Scheduler_v3d::Scheduler_v3d(HugoEngine *vm) : Scheduler_v2d(vm) {
}
Scheduler_v3d::~Scheduler_v3d() {
}
const char *Scheduler_v3d::getCypher() {
- return "Copyright 1992, Gray Design Associates";
+ return "Copyright 1992, Gray Design Associates";
+}
+
+/**
+* This function performs the action in the event structure pointed to by p
+* It dequeues the event and returns it to the free list. It returns a ptr
+* to the next action in the list, except special case of NEW_SCREEN
+*/
+event_t *Scheduler_v3d::doAction(event_t *curEvent) {
+ debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->action->a0.actType);
+
+ status_t &gameStatus = _vm->getGameStatus();
+ act *action = curEvent->action;
+ char *response; // User's response string
+ object_t *obj1;
+ object_t *obj2;
+ int dx, dy;
+ event_t *wrkEvent; // Save ev_p->next_p for return
+ event_t *saveEvent; // Used in DEL_EVENTS
+
+ switch (action->a0.actType) {
+ case ANULL: // Big NOP from DEL_EVENTS
+ break;
+ case ASCHEDULE: // act0: Schedule an action list
+ insertActionList(action->a0.actIndex);
+ break;
+ case START_OBJ: // act1: Start an object cycling
+ _vm->_object->_objects[action->a1.objNumb].cycleNumb = action->a1.cycleNumb;
+ _vm->_object->_objects[action->a1.objNumb].cycling = action->a1.cycle;
+ break;
+ case INIT_OBJXY: // act2: Initialise an object
+ _vm->_object->_objects[action->a2.objNumb].x = action->a2.x; // Coordinates
+ _vm->_object->_objects[action->a2.objNumb].y = action->a2.y;
+ break;
+ case PROMPT: { // act3: Prompt user for key phrase
+ response = Utils::Box(BOX_PROMPT, "%s", _vm->_file->fetchString(action->a3.promptIndex));
+
+ warning("STUB: doAction(act3), expecting answer %s", _vm->_file->fetchString(action->a3.responsePtr[0]));
+
+ // TODO: The answer of the player is not handled currently! Once it'll be read in the messageBox, uncomment this block
+#if 0
+ bool found;
+ char *tmpStr; // General purpose string ptr
+
+ for (found = false, dx = 0; !found && (action->a3.responsePtr[dx] != -1); dx++) {
+ tmpStr = _vm->_file->fetchString(action->a3.responsePtr[dx]);
+ if (strstr(Utils::strlwr(response) , tmpStr))
+ found = true;
+ }
+
+ if (found)
+ insertActionList(action->a3.actPassIndex);
+ else
+ insertActionList(action->a3.actFailIndex);
+#endif
+
+ // HACK: As the answer is not read, currently it's always considered correct
+ insertActionList(action->a3.actPassIndex);
+ break;
+ }
+ case BKGD_COLOR: // act4: Set new background color
+ _vm->_screen->setBackgroundColor(action->a4.newBackgroundColor);
+ break;
+ case INIT_OBJVXY: // act5: Initialise an object velocity
+ _vm->_object->setVelocity(action->a5.objNumb, action->a5.vx, action->a5.vy);
+ break;
+ case INIT_CARRY: // act6: Initialise an object
+ _vm->_object->setCarry(action->a6.objNumb, action->a6.carriedFl); // carried status
+ break;
+ case INIT_HF_COORD: // act7: Initialise an object to hero's "feet" coords
+ _vm->_object->_objects[action->a7.objNumb].x = _vm->_hero->x - 1;
+ _vm->_object->_objects[action->a7.objNumb].y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1;
+ _vm->_object->_objects[action->a7.objNumb].screenIndex = *_vm->_screen_p; // Don't forget screen!
+ break;
+ case NEW_SCREEN: // act8: Start new screen
+ newScreen(action->a8.screenIndex);
+ break;
+ case INIT_OBJSTATE: // act9: Initialise an object state
+ _vm->_object->_objects[action->a9.objNumb].state = action->a9.newState;
+ break;
+ case INIT_PATH: // act10: Initialise an object path and velocity
+ _vm->_object->setPath(action->a10.objNumb, (path_t) action->a10.newPathType, action->a10.vxPath, action->a10.vyPath);
+ break;
+ case COND_R: // act11: action lists conditional on object state
+ if (_vm->_object->_objects[action->a11.objNumb].state == action->a11.stateReq)
+ insertActionList(action->a11.actPassIndex);
+ else
+ insertActionList(action->a11.actFailIndex);
+ break;
+ case TEXT: // act12: Text box (CF WARN)
+ Utils::Box(BOX_ANY, "%s", _vm->_file->fetchString(action->a12.stringIndex)); // Fetch string from file
+ break;
+ case SWAP_IMAGES: // act13: Swap 2 object images
+ _vm->_object->swapImages(action->a13.obj1, action->a13.obj2);
+ break;
+ case COND_SCR: // act14: Conditional on current screen
+ if (_vm->_object->_objects[action->a14.objNumb].screenIndex == action->a14.screenReq)
+ insertActionList(action->a14.actPassIndex);
+ else
+ insertActionList(action->a14.actFailIndex);
+ break;
+ case AUTOPILOT: // act15: Home in on a (stationary) object
+ // object p1 will home in on object p2
+ obj1 = &_vm->_object->_objects[action->a15.obj1];
+ obj2 = &_vm->_object->_objects[action->a15.obj2];
+ obj1->pathType = AUTO;
+ dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1;
+ dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1;
+
+ if (dx == 0) // Don't EVER divide by zero!
+ dx = 1;
+ if (dy == 0)
+ dy = 1;
+
+ if (abs(dx) > abs(dy)) {
+ obj1->vx = action->a15.dx * -SIGN(dx);
+ obj1->vy = abs((action->a15.dy * dy) / dx) * -SIGN(dy);
+ } else {
+ obj1->vy = action->a15.dy * -SIGN(dy);
+ obj1->vx = abs((action->a15.dx * dx) / dy) * -SIGN(dx);
+ }
+ break;
+ case INIT_OBJ_SEQ: // act16: Set sequence number to use
+ // Note: Don't set a sequence at time 0 of a new screen, it causes
+ // problems clearing the boundary bits of the object! t>0 is safe
+ _vm->_object->_objects[action->a16.objNumb].currImagePtr = _vm->_object->_objects[action->a16.objNumb].seqList[action->a16.seqIndex].seqPtr;
+ break;
+ case SET_STATE_BITS: // act17: OR mask with curr obj state
+ _vm->_object->_objects[action->a17.objNumb].state |= action->a17.stateMask;
+ break;
+ case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state
+ _vm->_object->_objects[action->a18.objNumb].state &= ~action->a18.stateMask;
+ break;
+ case TEST_STATE_BITS: // act19: If all bits set, do apass else afail
+ if ((_vm->_object->_objects[action->a19.objNumb].state & action->a19.stateMask) == action->a19.stateMask)
+ insertActionList(action->a19.actPassIndex);
+ else
+ insertActionList(action->a19.actFailIndex);
+ break;
+ case DEL_EVENTS: // act20: Remove all events of this action type
+ // Note: actions are not deleted here, simply turned into NOPs!
+ wrkEvent = _headEvent; // The earliest event
+ while (wrkEvent) { // While events found in list
+ saveEvent = wrkEvent->nextEvent;
+ if (wrkEvent->action->a20.actType == action->a20.actTypeDel)
+ delQueue(wrkEvent);
+ wrkEvent = saveEvent;
+ }
+ break;
+ case GAMEOVER: // act21: Game over!
+ // NOTE: Must wait at least 1 tick before issuing this action if
+ // any objects are to be made invisible!
+ gameStatus.gameOverFl = true;
+ break;
+ case INIT_HH_COORD: // act22: Initialise an object to hero's actual coords
+ _vm->_object->_objects[action->a22.objNumb].x = _vm->_hero->x;
+ _vm->_object->_objects[action->a22.objNumb].y = _vm->_hero->y;
+ _vm->_object->_objects[action->a22.objNumb].screenIndex = *_vm->_screen_p;// Don't forget screen!
+ break;
+ case EXIT: // act23: Exit game back to DOS
+ _vm->endGame();
+ break;
+ case BONUS: // act24: Get bonus score for action
+ processBonus(action->a24.pointIndex);
+ break;
+ case COND_BOX: // act25: Conditional on bounding box
+ obj1 = &_vm->_object->_objects[action->a25.objNumb];
+ dx = obj1->x + obj1->currImagePtr->x1;
+ dy = obj1->y + obj1->currImagePtr->y2;
+ if ((dx >= action->a25.x1) && (dx <= action->a25.x2) &&
+ (dy >= action->a25.y1) && (dy <= action->a25.y2))
+ insertActionList(action->a25.actPassIndex);
+ else
+ insertActionList(action->a25.actFailIndex);
+ break;
+// case SOUND: // act26: Play a sound (or tune)
+// if (action->a26.soundIndex < _vm->_tunesNbr)
+// _vm->_sound->playMusic(action->a26.soundIndex);
+// else
+// _vm->_sound->playSound(action->a26.soundIndex, BOTH_CHANNELS, MED_PRI);
+// break;
+ case ADD_SCORE: // act27: Add object's value to score
+ _vm->adjustScore(_vm->_object->_objects[action->a27.objNumb].objValue);
+ break;
+ case SUB_SCORE: // act28: Subtract object's value from score
+ _vm->adjustScore(-_vm->_object->_objects[action->a28.objNumb].objValue);
+ break;
+ case COND_CARRY: // act29: Conditional on object being carried
+ if (_vm->_object->isCarried(action->a29.objNumb))
+ insertActionList(action->a29.actPassIndex);
+ else
+ insertActionList(action->a29.actFailIndex);
+ break;
+ case INIT_MAZE: // act30: Enable and init maze structure
+ _maze.enabledFl = true;
+ _maze.size = action->a30.mazeSize;
+ _maze.x1 = action->a30.x1;
+ _maze.y1 = action->a30.y1;
+ _maze.x2 = action->a30.x2;
+ _maze.y2 = action->a30.y2;
+ _maze.x3 = action->a30.x3;
+ _maze.x4 = action->a30.x4;
+ _maze.firstScreenIndex = action->a30.firstScreenIndex;
+ break;
+ case EXIT_MAZE: // act31: Disable maze mode
+ _maze.enabledFl = false;
+ break;
+ case INIT_PRIORITY:
+ _vm->_object->_objects[action->a32.objNumb].priority = action->a32.priority;
+ break;
+ case INIT_SCREEN:
+ _vm->_object->_objects[action->a33.objNumb].screenIndex = action->a33.screenIndex;
+ break;
+ case AGSCHEDULE: // act34: Schedule a (global) action list
+ insertActionList(action->a34.actIndex);
+ break;
+ case REMAPPAL: // act35: Remap a palette color
+ _vm->_screen->remapPal(action->a35.oldColorIndex, action->a35.newColorIndex);
+ break;
+ case COND_NOUN: // act36: Conditional on noun mentioned
+ if (_vm->_parser->isWordPresent(_vm->_arrayNouns[action->a36.nounIndex]))
+ insertActionList(action->a36.actPassIndex);
+ else
+ insertActionList(action->a36.actFailIndex);
+ break;
+ case SCREEN_STATE: // act37: Set new screen state
+ _vm->_screenStates[action->a37.screenIndex] = action->a37.newState;
+ break;
+ case INIT_LIPS: // act38: Position lips on object
+ _vm->_object->_objects[action->a38.lipsObjNumb].x = _vm->_object->_objects[action->a38.objNumb].x + action->a38.dxLips;
+ _vm->_object->_objects[action->a38.lipsObjNumb].y = _vm->_object->_objects[action->a38.objNumb].y + action->a38.dyLips;
+ _vm->_object->_objects[action->a38.lipsObjNumb].screenIndex = *_vm->_screen_p; // Don't forget screen!
+ _vm->_object->_objects[action->a38.lipsObjNumb].cycling = CYCLE_FORWARD;
+ break;
+ case INIT_STORY_MODE: // act39: Init story_mode flag
+ // This is similar to the QUIET path mode, except that it is
+ // independant of it and it additionally disables the ">" prompt
+ gameStatus.storyModeFl = action->a39.storyModeFl;
+
+ // End the game after story if this is special vendor demo mode
+ if (gameStatus.demoFl && action->a39.storyModeFl == false)
+ _vm->endGame();
+ break;
+ case WARN: // act40: Text box (CF TEXT)
+ Utils::Box(BOX_OK, "%s", _vm->_file->fetchString(action->a40.stringIndex));
+ break;
+ case COND_BONUS: // act41: Perform action if got bonus
+ if (_vm->_points[action->a41.BonusIndex].scoredFl)
+ insertActionList(action->a41.actPassIndex);
+ else
+ insertActionList(action->a41.actFailIndex);
+ break;
+ case OLD_SONG:
+ //TODO For Hugo 1 and Hugo2 DOS: The songs were not stored in a DAT file, but directly as
+ //strings. the current play_music should be modified to use a strings instead of reading
+ //the file, in those cases. This replaces, for those DOS versions, act26.
+ warning("STUB: doAction(act49)");
+ break;
+ default:
+ Utils::Error(EVNT_ERR, "%s", "doAction");
+ break;
+ }
+
+ if (action->a0.actType == NEW_SCREEN) { // New_screen() deletes entire list
+ return 0; // next_p = 0 since list now empty
+ } else {
+ wrkEvent = curEvent->nextEvent;
+ delQueue(curEvent); // Return event to free list
+ return wrkEvent; // Return next event ptr
+ }
}
} // End of namespace Hugo
diff --git a/engines/hugo/sound.cpp b/engines/hugo/sound.cpp
index e5f55afcc8..b8a5a3297e 100644
--- a/engines/hugo/sound.cpp
+++ b/engines/hugo/sound.cpp
@@ -239,7 +239,7 @@ void MidiPlayer::timerCallback(void *p) {
player->updateTimer();
}
-SoundHandler::SoundHandler(HugoEngine &vm) : _vm(vm) {
+SoundHandler::SoundHandler(HugoEngine *vm) : _vm(vm) {
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
MidiDriver *driver = MidiDriver::createMidi(dev);
@@ -248,13 +248,13 @@ SoundHandler::SoundHandler(HugoEngine &vm) : _vm(vm) {
void SoundHandler::setMusicVolume() {
/* Set the FM music volume from config.mvolume (0..100%) */
-
+
_midiPlayer->setVolume(_config.musicVolume * 255 / 100);
}
void SoundHandler::stopSound() {
/* Stop any sound that might be playing */
- _vm._mixer->stopAll();
+ _vm->_mixer->stopAll();
}
void SoundHandler::stopMusic() {
@@ -265,7 +265,7 @@ void SoundHandler::stopMusic() {
void SoundHandler::toggleMusic() {
// Turn music on and off
_config.musicFl = !_config.musicFl;
-
+
_midiPlayer->pause(_config.musicFl);
}
@@ -285,8 +285,8 @@ void SoundHandler::playMusic(int16 tune) {
uint16 size; // Size of sequence data
if (_config.musicFl) {
- _vm.getGameStatus().song = tune;
- seqPtr = _vm.file().getSound(tune, &size);
+ _vm->getGameStatus().song = tune;
+ seqPtr = _vm->_file->getSound(tune, &size);
playMIDI(seqPtr, size);
}
}
@@ -302,7 +302,7 @@ void SoundHandler::playSound(int16 sound, stereo_t channel, byte priority) {
static byte curPriority = 0; // Priority of currently playing sound
//
/* Sound disabled */
- if (!_config.soundFl || !_vm._mixer->isReady())
+ if (!_config.soundFl || !_vm->_mixer->isReady())
return;
//
// // See if last wave still playing - if so, check priority
@@ -314,11 +314,11 @@ void SoundHandler::playSound(int16 sound, stereo_t channel, byte priority) {
curPriority = priority;
//
/* Get sound data */
- if ((sound_p = _vm.file().getSound(sound, &size)) == 0)
+ if ((sound_p = _vm->_file->getSound(sound, &size)) == 0)
return;
Audio::AudioStream *stream = Audio::makeRawStream(sound_p, size, 11025, Audio::FLAG_UNSIGNED);
- _vm._mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle, stream);
+ _vm->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle, stream);
}
diff --git a/engines/hugo/sound.h b/engines/hugo/sound.h
index 53a5912a92..ff38a7f70a 100644
--- a/engines/hugo/sound.h
+++ b/engines/hugo/sound.h
@@ -38,10 +38,10 @@
namespace Hugo {
class MidiPlayer;
-
+
class SoundHandler {
public:
- SoundHandler(HugoEngine &vm);
+ SoundHandler(HugoEngine *vm);
void toggleMusic();
void toggleSound();
@@ -51,7 +51,7 @@ public:
void initSound();
private:
- HugoEngine &_vm;
+ HugoEngine *_vm;
Audio::SoundHandle _soundHandle;
MidiPlayer *_midiPlayer;
diff --git a/engines/hugo/util.cpp b/engines/hugo/util.cpp
index 8cca4b7d84..a3e778e228 100644
--- a/engines/hugo/util.cpp
+++ b/engines/hugo/util.cpp
@@ -40,8 +40,10 @@
namespace Hugo {
+/**
+ * Returns index (0 to 7) of first 1 in supplied byte, or 8 if not found
+ */
int Utils::firstBit(byte data) {
-// Returns index (0 to 7) of first 1 in supplied byte, or 8 if not found
if (!data)
return 8;
@@ -54,8 +56,10 @@ int Utils::firstBit(byte data) {
return i;
}
+/**
+ * Returns index (0 to 7) of last 1 in supplied byte, or 8 if not found
+ */
int Utils::lastBit(byte data) {
-// Returns index (0 to 7) of last 1 in supplied byte, or 8 if not found
if (!data)
return 8;
@@ -68,8 +72,10 @@ int Utils::lastBit(byte data) {
return i;
}
+/**
+ * Reverse the bit order in supplied byte
+ */
void Utils::reverseByte(byte *data) {
-// Reverse the bit order in supplied byte
byte maskIn = 0x80;
byte maskOut = 0x01;
byte result = 0;
@@ -78,21 +84,21 @@ void Utils::reverseByte(byte *data) {
if (*data & maskIn)
result |= maskOut;
}
-
+
*data = result;
}
char *Utils::Box(box_t dismiss, const char *s, ...) {
static char buffer[MAX_STRLEN + 1]; // Format text into this
- if (!s)
+ if (!s)
return 0; // NULL strings catered for
if (s[0] == '\0')
return 0;
if (strlen(s) > MAX_STRLEN - 100) { // Test length
- Warn("String too big:\n%s", s);
+ warning("String too big: '%s'", s);
return 0;
}
@@ -129,20 +135,11 @@ char *Utils::Box(box_t dismiss, const char *s, ...) {
return buffer;
}
-void Utils::Warn(const char *format, ...) {
-// Warning handler. Print supplied message and continue
-// Arguments are same as printf
- char buffer[WARNLEN];
- va_list marker;
- va_start(marker, format);
- vsnprintf(buffer, WARNLEN, format, marker);
- va_end(marker);
- warning("Hugo warning: %s", buffer);
-}
-
+/**
+ * Fatal error handler. Reset environment, print error and exit
+ * Arguments are same as printf
+ */
void Utils::Error(int error_type, const char *format, ...) {
-// Fatal error handler. Reset environment, print error and exit
-// Arguments are same as printf
char buffer[ERRLEN + 1];
bool fatal = true; // Fatal error, else continue
@@ -183,8 +180,10 @@ void Utils::Error(int error_type, const char *format, ...) {
exit(1);
}
+/**
+ * Print options for user when dead
+ */
void Utils::gameOverMsg(void) {
- // Print options for user when dead
//MessageBox(hwnd, gameoverstring, "Be more careful next time!", MB_OK | MB_ICONINFORMATION);
warning("STUB: Gameover_msg(): %s", HugoEngine::get()._textUtil[kGameOver]);
}
@@ -201,5 +200,4 @@ char *Utils::strlwr(char *buffer) {
return result;
}
-
} // End of namespace Hugo
diff --git a/engines/hugo/util.h b/engines/hugo/util.h
index 69428fb3bb..a3e206dba9 100644
--- a/engines/hugo/util.h
+++ b/engines/hugo/util.h
@@ -55,7 +55,6 @@ int lastBit(byte data);
void gameOverMsg();
void reverseByte(byte *data);
void Error(int code, const char *format, ...) GCC_PRINTF(2, 3);
-void Warn(const char *format, ...) GCC_PRINTF(1, 2);
char *Box(box_t, const char *, ...) GCC_PRINTF(2, 3);
char *strlwr(char *buffer);
diff --git a/engines/kyra/animator_v2.cpp b/engines/kyra/animator_v2.cpp
index 6c4fafa674..b06dffd36f 100644
--- a/engines/kyra/animator_v2.cpp
+++ b/engines/kyra/animator_v2.cpp
@@ -141,7 +141,7 @@ void KyraEngine_v2::flagAnimObjsSpecialRefresh() {
}
void KyraEngine_v2::addItemToAnimList(int item) {
- assert(item < _itemListSize);
+ assert(item >= 0 && item < _itemListSize);
restorePage3();
diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp
index fc509700d7..d58494303c 100644
--- a/engines/kyra/debugger.cpp
+++ b/engines/kyra/debugger.cpp
@@ -53,6 +53,16 @@ Debugger::Debugger(KyraEngine_v1 *vm)
DCmd_Register("settimercountdown", WRAP_METHOD(Debugger, cmd_setTimerCountdown));
}
+void Debugger::preEnter() {
+ _vm->pauseEngine(true);
+ ::GUI::Debugger::preEnter();
+}
+
+void Debugger::postEnter() {
+ ::GUI::Debugger::postEnter();
+ _vm->pauseEngine(false);
+}
+
bool Debugger::cmd_setScreenDebug(int argc, const char **argv) {
if (argc > 1) {
if (scumm_stricmp(argv[1], "enable") == 0)
@@ -201,14 +211,6 @@ Debugger_LoK::Debugger_LoK(KyraEngine_LoK *vm)
DCmd_Register("birthstones", WRAP_METHOD(Debugger_LoK, cmd_listBirthstones));
}
-void Debugger_LoK::preEnter() {
- //_vm->midi.pause(1);
-}
-
-void Debugger_LoK::postEnter() {
- //_vm->midi.pause(0);
-}
-
bool Debugger_LoK::cmd_enterRoom(int argc, const char **argv) {
uint direction = 0;
if (argc > 1) {
@@ -331,7 +333,7 @@ bool Debugger_v2::cmd_enterScene(int argc, const char **argv) {
return false;
}
- DebugPrintf("Syntax: %d <scenenum> <direction>\n", argv[0]);
+ DebugPrintf("Syntax: %s <scenenum> <direction>\n", argv[0]);
return true;
}
diff --git a/engines/kyra/debugger.h b/engines/kyra/debugger.h
index c9cf6dba2a..dfc2a26aa2 100644
--- a/engines/kyra/debugger.h
+++ b/engines/kyra/debugger.h
@@ -41,6 +41,9 @@ public:
virtual ~Debugger() {} // we need this for __SYMBIAN32__ archaic gcc/UIQ
protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
KyraEngine_v1 *_vm;
bool cmd_setScreenDebug(int argc, const char **argv);
@@ -62,9 +65,6 @@ public:
protected:
KyraEngine_LoK *_vm;
- virtual void preEnter();
- virtual void postEnter();
-
bool cmd_enterRoom(int argc, const char **argv);
bool cmd_listScenes(int argc, const char **argv);
bool cmd_giveItem(int argc, const char **argv);
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 875b49b62d..6c111a6601 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -50,7 +50,7 @@ const char * const directoryGlobs[] = {
0
};
-const ADParams detectionParams = {
+static const ADParams detectionParams = {
// Pointer to ADGameDescription or its superset structure
(const byte *)adGameDescs,
// Size of that superset structure
diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index 84e0f343a7..5c97df8895 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -1146,6 +1146,23 @@ const KYRAGameDescription adGameDescs[] = {
"lol",
"Extracted",
{
+ { "GENERAL.PAK", 0, "d119e3b57f8e5edcbb90980ca6f4215a", -1 },
+ { "CHAPTER7.PAK", 0, "71a3d3cb1554294646a389e5c345cf28", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NOSPEECH | Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIGM | Common::GUIO_MIDIPCSPK
+ },
+ LOL_FLOPPY_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "Extracted",
+ {
{ "GENERAL.PAK", 0, "996e66e81054d36249907a1d8158da3d", -1 },
{ "CHAPTER7.PAK", 0, "cabee57f00d6d84b65a732b6868a4959", -1 },
{ 0, 0, 0, 0 }
diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp
index 621b3199c5..56971e563c 100644
--- a/engines/kyra/gui_hof.cpp
+++ b/engines/kyra/gui_hof.cpp
@@ -122,9 +122,9 @@ int KyraEngine_HoF::buttonInventory(Button *button) {
int inventorySlot = button->index - 6;
- uint16 item = _mainCharacter.inventory[inventorySlot];
- if (_itemInHand == -1) {
- if (item == 0xFFFF)
+ Item item = _mainCharacter.inventory[inventorySlot];
+ if (_itemInHand == kItemNone) {
+ if (item == kItemNone)
return 0;
_screen->hideMouse();
clearInventorySlot(inventorySlot, 0);
@@ -134,9 +134,9 @@ int KyraEngine_HoF::buttonInventory(Button *button) {
updateCommandLineEx(item+54, string, 0xD6);
_itemInHand = (int16)item;
_screen->showMouse();
- _mainCharacter.inventory[inventorySlot] = 0xFFFF;
+ _mainCharacter.inventory[inventorySlot] = kItemNone;
} else {
- if (_mainCharacter.inventory[inventorySlot] != 0xFFFF) {
+ if (_mainCharacter.inventory[inventorySlot] != kItemNone) {
if (checkInventoryItemExchange(_itemInHand, inventorySlot))
return 0;
@@ -160,7 +160,7 @@ int KyraEngine_HoF::buttonInventory(Button *button) {
updateCommandLineEx(_itemInHand+54, string, 0xD6);
_screen->showMouse();
_mainCharacter.inventory[inventorySlot] = _itemInHand;
- _itemInHand = -1;
+ _itemInHand = kItemNone;
}
}
@@ -168,15 +168,15 @@ int KyraEngine_HoF::buttonInventory(Button *button) {
}
int KyraEngine_HoF::scrollInventory(Button *button) {
- uint16 *src = _mainCharacter.inventory;
- uint16 *dst = &_mainCharacter.inventory[10];
- uint16 temp[5];
-
- memcpy(temp, src, sizeof(uint16)*5);
- memcpy(src, src+5, sizeof(uint16)*5);
- memcpy(src+5, dst, sizeof(uint16)*5);
- memcpy(dst, dst+5, sizeof(uint16)*5);
- memcpy(dst+5, temp, sizeof(uint16)*5);
+ Item *src = _mainCharacter.inventory;
+ Item *dst = &_mainCharacter.inventory[10];
+ Item temp[5];
+
+ memcpy(temp, src, sizeof(Item)*5);
+ memcpy(src, src+5, sizeof(Item)*5);
+ memcpy(src+5, dst, sizeof(Item)*5);
+ memcpy(dst, dst+5, sizeof(Item)*5);
+ memcpy(dst+5, temp, sizeof(Item)*5);
_screen->hideMouse();
_screen->copyRegion(0x46, 0x90, 0x46, 0x90, 0x71, 0x2E, 0, 2);
_screen->showMouse();
@@ -185,7 +185,7 @@ int KyraEngine_HoF::scrollInventory(Button *button) {
return 0;
}
-int KyraEngine_HoF::getInventoryItemSlot(uint16 item) {
+int KyraEngine_HoF::getInventoryItemSlot(Item item) {
for (int i = 0; i < 20; ++i) {
if (_mainCharacter.inventory[i] == item)
return i;
@@ -195,14 +195,14 @@ int KyraEngine_HoF::getInventoryItemSlot(uint16 item) {
int KyraEngine_HoF::findFreeVisibleInventorySlot() {
for (int i = 0; i < 10; ++i) {
- if (_mainCharacter.inventory[i] == 0xFFFF)
+ if (_mainCharacter.inventory[i] == kItemNone)
return i;
}
return -1;
}
void KyraEngine_HoF::removeSlotFromInventory(int slot) {
- _mainCharacter.inventory[slot] = 0xFFFF;
+ _mainCharacter.inventory[slot] = kItemNone;
if (slot < 10) {
_screen->hideMouse();
clearInventorySlot(slot, 0);
@@ -210,21 +210,21 @@ void KyraEngine_HoF::removeSlotFromInventory(int slot) {
}
}
-bool KyraEngine_HoF::checkInventoryItemExchange(uint16 handItem, int slot) {
+bool KyraEngine_HoF::checkInventoryItemExchange(Item handItem, int slot) {
bool removeItem = false;
- uint16 newItem = 0xFFFF;
+ Item newItem = kItemNone;
- uint16 invItem = _mainCharacter.inventory[slot];
+ Item invItem = _mainCharacter.inventory[slot];
for (const uint16 *table = _itemMagicTable; *table != 0xFFFF; table += 4) {
- if (table[0] != handItem || table[1] != invItem)
+ if (table[0] != handItem || table[1] != (uint16)invItem)
continue;
if (table[3] == 0xFFFF)
continue;
removeItem = (table[3] == 1);
- newItem = table[2];
+ newItem = (Item)table[2];
snd_playSoundEffect(0x68);
_mainCharacter.inventory[slot] = newItem;
@@ -246,7 +246,7 @@ bool KyraEngine_HoF::checkInventoryItemExchange(uint16 handItem, int slot) {
return false;
}
-void KyraEngine_HoF::drawInventoryShape(int page, uint16 item, int slot) {
+void KyraEngine_HoF::drawInventoryShape(int page, Item item, int slot) {
_screen->drawShape(page, getShapePtr(item+64), _inventoryX[slot], _inventoryY[slot], 0, 0);
_screen->updateScreen();
}
@@ -260,11 +260,11 @@ void KyraEngine_HoF::redrawInventory(int page) {
int pageBackUp = _screen->_curPage;
_screen->_curPage = page;
- const uint16 *inventory = _mainCharacter.inventory;
+ const Item *inventory = _mainCharacter.inventory;
_screen->hideMouse();
for (int i = 0; i < 10; ++i) {
clearInventorySlot(i, page);
- if (inventory[i] != 0xFFFF) {
+ if (inventory[i] != kItemNone) {
_screen->drawShape(page, getShapePtr(inventory[i]+64), _inventoryX[i], _inventoryY[i], 0, 0);
drawInventoryShape(page, inventory[i], i);
}
@@ -734,7 +734,7 @@ int GUI_HoF::optionsButton(Button *button) {
if (_loadedSave) {
if (_restartGame)
- _vm->_itemInHand = -1;
+ _vm->_itemInHand = kItemNone;
} else {
restorePage1(_vm->_screenBuffer);
restorePalette();
@@ -820,7 +820,7 @@ void GUI_HoF::resetState(int item) {
_vm->setNextIdleAnimTimer();
_isDeathMenu = false;
if (!_loadedSave) {
- _vm->_itemInHand = -1;
+ _vm->_itemInHand = kItemNone;
_vm->setHandItem(item);
} else {
_vm->setHandItem(_vm->_itemInHand);
@@ -998,7 +998,7 @@ int GUI_HoF::gameOptionsTalkie(Button *caller) {
Graphics::Surface thumb;
createScreenThumbnail(thumb);
- _vm->saveGameState(999, "Autosave", &thumb);
+ _vm->saveGameStateIntern(999, "Autosave", &thumb);
thumb.free();
_vm->_lastAutosave = _vm->_system->getMillis();
diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp
index 9a1d750391..b7952eb81e 100644
--- a/engines/kyra/gui_lok.cpp
+++ b/engines/kyra/gui_lok.cpp
@@ -32,6 +32,7 @@
#include "kyra/gui_lok.h"
#include "kyra/timer.h"
#include "kyra/util.h"
+#include "kyra/item.h"
#include "common/config-manager.h"
#include "common/savefile.h"
@@ -49,9 +50,9 @@ void KyraEngine_LoK::initMainButtonList() {
int KyraEngine_LoK::buttonInventoryCallback(Button *caller) {
int itemOffset = caller->index - 2;
- uint8 inventoryItem = _currentCharacter->inventoryItems[itemOffset];
- if (_itemInHand == -1) {
- if (inventoryItem == 0xFF) {
+ Item inventoryItem = (int8)_currentCharacter->inventoryItems[itemOffset];
+ if (_itemInHand == kItemNone) {
+ if (inventoryItem == kItemNone) {
snd_playSoundEffect(0x36);
return 0;
} else {
@@ -62,10 +63,10 @@ int KyraEngine_LoK::buttonInventoryCallback(Button *caller) {
updateSentenceCommand(_itemList[getItemListIndex(inventoryItem)], _takenList[0], 179);
_itemInHand = inventoryItem;
_screen->showMouse();
- _currentCharacter->inventoryItems[itemOffset] = 0xFF;
+ _currentCharacter->inventoryItems[itemOffset] = kItemNone;
}
} else {
- if (inventoryItem != 0xFF) {
+ if (inventoryItem != kItemNone) {
snd_playSoundEffect(0x35);
_screen->hideMouse();
_screen->fillRect(_itemPosX[itemOffset], _itemPosY[itemOffset], _itemPosX[itemOffset] + 15, _itemPosY[itemOffset] + 15, _flags.platform == Common::kPlatformAmiga ? 19 : 12);
@@ -87,7 +88,7 @@ int KyraEngine_LoK::buttonInventoryCallback(Button *caller) {
updateSentenceCommand(_itemList[getItemListIndex(_itemInHand)], _placedList[0], 179);
_screen->showMouse();
_currentCharacter->inventoryItems[itemOffset] = _itemInHand;
- _itemInHand = -1;
+ _itemInHand = kItemNone;
}
}
_screen->updateScreen();
@@ -104,7 +105,7 @@ int KyraEngine_LoK::buttonAmuletCallback(Button *caller) {
}
if (!queryGameFlag(0x2D))
return 1;
- if (_itemInHand != -1) {
+ if (_itemInHand != kItemNone) {
assert(_putDownFirst);
characterSays(2000, _putDownFirst[0], 0, -2);
return 1;
@@ -777,7 +778,7 @@ int GUI_LoK::saveGame(Button *button) {
Graphics::Surface thumb;
createScreenThumbnail(thumb);
- _vm->saveGameState(_vm->_gameToLoad, _savegameName, &thumb);
+ _vm->saveGameStateIntern(_vm->_gameToLoad, _savegameName, &thumb);
thumb.free();
}
}
diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp
index 2c86073892..07fbf1664d 100644
--- a/engines/kyra/gui_lol.cpp
+++ b/engines/kyra/gui_lol.cpp
@@ -2906,7 +2906,7 @@ int GUI_LoL::clickedSavenameMenu(Button *button) {
int slot = _menuResult == -2 ? getNextSavegameSlot() : _menuResult - 1;
Graphics::Surface thumb;
createScreenThumbnail(thumb);
- _vm->saveGameState(slot, _saveDescription, &thumb);
+ _vm->saveGameStateIntern(slot, _saveDescription, &thumb);
thumb.free();
_displayMenu = false;
diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp
index bcc74f5a07..a04ec49324 100644
--- a/engines/kyra/gui_mr.cpp
+++ b/engines/kyra/gui_mr.cpp
@@ -130,7 +130,7 @@ void KyraEngine_MR::showMessageFromCCode(int string, uint8 c0, int) {
showMessage((const char *)getTableEntry(_cCodeFile, string), c0, 0xF0);
}
-void KyraEngine_MR::updateItemCommand(int item, int str, uint8 c0) {
+void KyraEngine_MR::updateItemCommand(Item item, int str, uint8 c0) {
char buffer[100];
char *src = (char *)getTableEntry(_itemFile, item);
@@ -449,7 +449,7 @@ void KyraEngine_MR::redrawInventory(int page) {
for (int i = 0; i < 10; ++i) {
clearInventorySlot(i, page);
- if (_mainCharacter.inventory[i] != 0xFFFF) {
+ if (_mainCharacter.inventory[i] != kItemNone) {
_screen->drawShape(page, getShapePtr(_mainCharacter.inventory[i]+248), _inventoryX[i], _inventoryY[i] + yOffset, 0, 0);
drawInventorySlot(page, _mainCharacter.inventory[i], i);
}
@@ -472,7 +472,7 @@ void KyraEngine_MR::clearInventorySlot(int slot, int page) {
_screen->drawShape(page, getShapePtr(slot+422), _inventoryX[slot], _inventoryY[slot] + yOffset, 0, 0);
}
-void KyraEngine_MR::drawInventorySlot(int page, int item, int slot) {
+void KyraEngine_MR::drawInventorySlot(int page, Item item, int slot) {
int yOffset = 0;
if (page == 30) {
page = 2;
@@ -488,9 +488,9 @@ int KyraEngine_MR::buttonInventory(Button *button) {
return 0;
const int slot = button->index - 5;
- const int16 slotItem = (int16)_mainCharacter.inventory[slot];
- if (_itemInHand == -1) {
- if (slotItem == -1)
+ const Item slotItem = _mainCharacter.inventory[slot];
+ if (_itemInHand == kItemNone) {
+ if (slotItem == kItemNone)
return 0;
_screen->hideMouse();
@@ -499,7 +499,7 @@ int KyraEngine_MR::buttonInventory(Button *button) {
setMouseCursor(slotItem);
updateItemCommand(slotItem, (_lang == 1) ? getItemCommandStringPickUp(slotItem) : 0, 0xFF);
_itemInHand = slotItem;
- _mainCharacter.inventory[slot] = 0xFFFF;
+ _mainCharacter.inventory[slot] = kItemNone;
_screen->showMouse();
} else if (_itemInHand == 27) {
if (_chatText)
@@ -528,7 +528,7 @@ int KyraEngine_MR::buttonInventory(Button *button) {
updateItemCommand(_itemInHand, (_lang == 1) ? getItemCommandStringInv(_itemInHand) : 2, 0xFF);
_screen->showMouse();
_mainCharacter.inventory[slot] = _itemInHand;
- _itemInHand = -1;
+ _itemInHand = kItemNone;
}
}
@@ -635,7 +635,7 @@ int KyraEngine_MR::buttonJesterStaff(Button *button) {
updateItemCommand(27, 2, 0xFF);
setGameFlag(0x97);
_screen->showMouse();
- } else if (_itemInHand == -1) {
+ } else if (_itemInHand == kItemNone) {
if (queryGameFlag(0x97)) {
_screen->hideMouse();
snd_playSoundEffect(0x0B, 0xC8);
@@ -1141,7 +1141,7 @@ void GUI_MR::resetState(int item) {
_vm->setNextIdleAnimTimer();
_isDeathMenu = false;
if (!_loadedSave) {
- _vm->_itemInHand = -1;
+ _vm->_itemInHand = kItemNone;
_vm->setHandItem(item);
} else {
_vm->setHandItem(_vm->_itemInHand);
@@ -1239,7 +1239,7 @@ int GUI_MR::optionsButton(Button *button) {
if (_loadedSave) {
if (_restartGame)
- _vm->_itemInHand = -1;
+ _vm->_itemInHand = kItemNone;
} else {
restorePage1(_vm->_screenBuffer);
}
@@ -1380,7 +1380,7 @@ int GUI_MR::gameOptions(Button *caller) {
Graphics::Surface thumb;
createScreenThumbnail(thumb);
- _vm->saveGameState(999, "Autosave", &thumb);
+ _vm->saveGameStateIntern(999, "Autosave", &thumb);
thumb.free();
_vm->_lastAutosave = _vm->_system->getMillis();
diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp
index fe4b54d09b..2247a0ca2e 100644
--- a/engines/kyra/gui_v2.cpp
+++ b/engines/kyra/gui_v2.cpp
@@ -625,7 +625,7 @@ int GUI_v2::saveMenu(Button *caller) {
Graphics::Surface thumb;
createScreenThumbnail(thumb);
Util::convertDOSToISO(_saveDescription);
- _vm->saveGameState(_saveSlot, _saveDescription, &thumb);
+ _vm->saveGameStateIntern(_saveSlot, _saveDescription, &thumb);
thumb.free();
_displayMenu = false;
diff --git a/backends/platform/sdl/amigaos/amigaos.h b/engines/kyra/item.h
index 92232ec98a..2088f4bd8b 100644
--- a/backends/platform/sdl/amigaos/amigaos.h
+++ b/engines/kyra/item.h
@@ -23,17 +23,23 @@
*
*/
-#ifndef PLATFORM_SDL_AMIGAOS_H
-#define PLATFORM_SDL_AMIGAOS_H
+#ifndef KYRA_ITEM_H
+#define KYRA_ITEM_H
-#include "backends/platform/sdl/sdl.h"
+#include "common/scummsys.h"
-class OSystem_AmigaOS : public OSystem_SDL {
-public:
- OSystem_AmigaOS() {}
- virtual ~OSystem_AmigaOS() {}
+namespace Kyra {
- virtual void init();
+typedef int16 Item;
+
+enum {
+ /**
+ * Constant for invalid item.
+ */
+ kItemNone = -1
};
+} // End of namespace Kyra
+
#endif
+
diff --git a/engines/kyra/items_hof.cpp b/engines/kyra/items_hof.cpp
index 876db58716..6a78a77c23 100644
--- a/engines/kyra/items_hof.cpp
+++ b/engines/kyra/items_hof.cpp
@@ -31,9 +31,9 @@ int KyraEngine_HoF::checkItemCollision(int x, int y) {
int itemPos = -1, yPos = -1;
for (int i = 0; i < 30; ++i) {
- const Item &curItem = _itemList[i];
+ const ItemDefinition &curItem = _itemList[i];
- if (curItem.id == 0xFFFF || curItem.sceneId != _mainCharacter.sceneId)
+ if (curItem.id == kItemNone || curItem.sceneId != _mainCharacter.sceneId)
continue;
int itemX1 = curItem.x - 8 - 3;
@@ -79,7 +79,7 @@ void KyraEngine_HoF::updateWaterFlasks() {
}
}
-bool KyraEngine_HoF::dropItem(int unk1, uint16 item, int x, int y, int unk2) {
+bool KyraEngine_HoF::dropItem(int unk1, Item item, int x, int y, int unk2) {
if (_mouseState <= -1)
return false;
@@ -93,7 +93,7 @@ bool KyraEngine_HoF::dropItem(int unk1, uint16 item, int x, int y, int unk2) {
return success;
}
-bool KyraEngine_HoF::processItemDrop(uint16 sceneId, uint16 item, int x, int y, int unk1, int unk2) {
+bool KyraEngine_HoF::processItemDrop(uint16 sceneId, Item item, int x, int y, int unk1, int unk2) {
int itemPos = checkItemCollision(x, y);
if (unk1)
@@ -108,7 +108,7 @@ bool KyraEngine_HoF::processItemDrop(uint16 sceneId, uint16 item, int x, int y,
if (unk1 != 3) {
for (int i = 0; i < 30; ++i) {
- if (_itemList[i].id == 0xFFFF) {
+ if (_itemList[i].id == kItemNone) {
freeItemSlot = i;
break;
}
@@ -200,7 +200,7 @@ bool KyraEngine_HoF::processItemDrop(uint16 sceneId, uint16 item, int x, int y,
return true;
}
-void KyraEngine_HoF::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, uint16 item) {
+void KyraEngine_HoF::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, Item item) {
uint8 *itemShape = getShapePtr(item + 64);
if (startX == dstX && startY == dstY) {
@@ -335,7 +335,7 @@ bool KyraEngine_HoF::pickUpItem(int x, int y) {
_screen->hideMouse();
deleteItemAnimEntry(itemPos);
int itemId = _itemList[itemPos].id;
- _itemList[itemPos].id = 0xFFFF;
+ _itemList[itemPos].id = kItemNone;
snd_playSoundEffect(0x0b);
setMouseCursor(itemId);
int str2 = 7;
@@ -368,8 +368,8 @@ bool KyraEngine_HoF::isDropable(int x, int y) {
return true;
}
-int KyraEngine_HoF::getItemCommandStringDrop(uint16 item) {
- assert(item < _itemStringMapSize);
+int KyraEngine_HoF::getItemCommandStringDrop(Item item) {
+ assert(item >= 0 && item < _itemStringMapSize);
int stringId = _itemStringMap[item];
static const int dropStringIds[] = {
@@ -380,8 +380,8 @@ int KyraEngine_HoF::getItemCommandStringDrop(uint16 item) {
return dropStringIds[stringId];
}
-int KyraEngine_HoF::getItemCommandStringPickUp(uint16 item) {
- assert(item < _itemStringMapSize);
+int KyraEngine_HoF::getItemCommandStringPickUp(Item item) {
+ assert(item >= 0 && item < _itemStringMapSize);
int stringId = _itemStringMap[item];
static const int pickUpStringIds[] = {
@@ -392,8 +392,8 @@ int KyraEngine_HoF::getItemCommandStringPickUp(uint16 item) {
return pickUpStringIds[stringId];
}
-int KyraEngine_HoF::getItemCommandStringInv(uint16 item) {
- assert(item < _itemStringMapSize);
+int KyraEngine_HoF::getItemCommandStringInv(Item item) {
+ assert(item >= 0 && item < _itemStringMapSize);
int stringId = _itemStringMap[item];
static const int pickUpStringIds[] = {
@@ -404,8 +404,8 @@ int KyraEngine_HoF::getItemCommandStringInv(uint16 item) {
return pickUpStringIds[stringId];
}
-bool KyraEngine_HoF::itemIsFlask(int item) {
- for (int i = 0; _flaskTable[i] != -1; ++i) {
+bool KyraEngine_HoF::itemIsFlask(Item item) {
+ for (int i = 0; _flaskTable[i] != kItemNone; ++i) {
if (_flaskTable[i] == item)
return true;
}
@@ -413,12 +413,12 @@ bool KyraEngine_HoF::itemIsFlask(int item) {
return false;
}
-void KyraEngine_HoF::setMouseCursor(uint16 item) {
+void KyraEngine_HoF::setMouseCursor(Item item) {
int shape = 0;
int hotX = 1;
int hotY = 1;
- if (item != 0xFFFF) {
+ if (item != kItemNone) {
hotX = 8;
hotY = 15;
shape = item+64;
diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp
index df46dfa4cd..322314e3ad 100644
--- a/engines/kyra/items_lok.cpp
+++ b/engines/kyra/items_lok.cpp
@@ -74,29 +74,31 @@ void KyraEngine_LoK::clearNoDropRects() {
byte KyraEngine_LoK::findFreeItemInScene(int scene) {
assert(scene < _roomTableSize);
Room *room = &_roomTable[scene];
+
for (int i = 0; i < 12; ++i) {
- if (room->itemsTable[i] == 0xFF)
+ if (room->itemsTable[i] == kItemNone)
return i;
}
+
return 0xFF;
}
byte KyraEngine_LoK::findItemAtPos(int x, int y) {
assert(_currentCharacter->sceneId < _roomTableSize);
- const uint8 *itemsTable = _roomTable[_currentCharacter->sceneId].itemsTable;
+ const int8 *itemsTable = _roomTable[_currentCharacter->sceneId].itemsTable;
const uint16 *xposOffset = _roomTable[_currentCharacter->sceneId].itemsXPos;
const uint8 *yposOffset = _roomTable[_currentCharacter->sceneId].itemsYPos;
int highestYPos = -1;
- byte returnValue = 0xFF;
+ Item returnValue = kItemNone;
for (int i = 0; i < 12; ++i) {
- if (*itemsTable != 0xFF) {
+ if (*itemsTable != kItemNone) {
int xpos = *xposOffset - 11;
int xpos2 = *xposOffset + 10;
if (x > xpos && x < xpos2) {
- assert(*itemsTable < ARRAYSIZE(_itemTable));
- int itemHeight = _itemTable[*itemsTable].height;
+ assert(*itemsTable >= 0);
+ int itemHeight = _itemHtDat[*itemsTable];
int ypos = *yposOffset + 3;
int ypos2 = ypos - itemHeight - 3;
@@ -108,6 +110,7 @@ byte KyraEngine_LoK::findItemAtPos(int x, int y) {
}
}
}
+
++xposOffset;
++yposOffset;
++itemsTable;
@@ -170,7 +173,7 @@ void KyraEngine_LoK::placeItemInGenericMapScene(int item, int index) {
}
}
-void KyraEngine_LoK::setHandItem(uint16 item) {
+void KyraEngine_LoK::setHandItem(Item item) {
_screen->hideMouse();
setMouseItem(item);
_itemInHand = item;
@@ -180,20 +183,21 @@ void KyraEngine_LoK::setHandItem(uint16 item) {
void KyraEngine_LoK::removeHandItem() {
_screen->hideMouse();
_screen->setMouseCursor(1, 1, _shapes[0]);
- _itemInHand = -1;
+ _itemInHand = kItemNone;
_screen->showMouse();
}
-void KyraEngine_LoK::setMouseItem(uint16 item) {
- if (item == 0xFFFF)
+void KyraEngine_LoK::setMouseItem(Item item) {
+ if (item == kItemNone)
_screen->setMouseCursor(1, 1, _shapes[6]);
else
_screen->setMouseCursor(8, 15, _shapes[216+item]);
}
void KyraEngine_LoK::wipeDownMouseItem(int xpos, int ypos) {
- if (_itemInHand == -1)
+ if (_itemInHand == kItemNone)
return;
+
xpos -= 8;
ypos -= 15;
_screen->hideMouse();
@@ -261,7 +265,7 @@ int KyraEngine_LoK::countItemsInScene(uint16 sceneId) {
int items = 0;
for (int i = 0; i < 12; ++i) {
- if (currentRoom->itemsTable[i] != 0xFF)
+ if (currentRoom->itemsTable[i] != kItemNone)
++items;
}
@@ -284,7 +288,7 @@ int KyraEngine_LoK::processItemDrop(uint16 sceneId, uint8 item, int x, int y, in
if (unk1 != 3) {
for (int i = 0; i < 12; ++i) {
- if (currentRoom->itemsTable[i] == 0xFF) {
+ if (currentRoom->itemsTable[i] == kItemNone) {
freeItem = i;
break;
}
@@ -301,13 +305,14 @@ int KyraEngine_LoK::processItemDrop(uint16 sceneId, uint8 item, int x, int y, in
return 1;
}
- int itemHeight = _itemTable[item].height;
+ int itemHeight = _itemHtDat[item];
_lastProcessedItemHeight = itemHeight;
- if (x == -1 && x == -1) {
+ if (x == -1)
x = _rnd.getRandomNumberRng(16, 304);
+
+ if (y == -1)
y = _rnd.getRandomNumberRng(_northExitHeight & 0xFF, 135);
- }
int xpos = x;
int ypos = y;
@@ -618,7 +623,7 @@ void KyraEngine_LoK::itemSpecialFX1(int x, int y, int item) {
void KyraEngine_LoK::itemSpecialFX2(int x, int y, int item) {
x -= 8;
y -= 15;
- int yAdd = (int8)(((16 - _itemTable[item].height) >> 1) & 0xFF);
+ int yAdd = (int8)(((16 - _itemHtDat[item]) >> 1) & 0xFF);
backUpItemRect0(x, y);
if (item >= 80 && item <= 89)
snd_playSoundEffect(55);
@@ -646,7 +651,8 @@ void KyraEngine_LoK::magicOutMouseItem(int animIndex, int itemPos) {
int videoPageBackUp = _screen->_curPage;
_screen->_curPage = 0;
int x = 0, y = 0;
- if (itemPos == -1) {
+
+ if (itemPos == kItemNone) {
Common::Point mouse = getMousePos();
x = mouse.x - 12;
y = mouse.y - 18;
@@ -655,7 +661,7 @@ void KyraEngine_LoK::magicOutMouseItem(int animIndex, int itemPos) {
y = _itemPosY[itemPos] - 3;
}
- if (_itemInHand == -1 && itemPos == -1)
+ if (_itemInHand == kItemNone && itemPos == -1)
return;
int tableIndex = 0, loopStart = 0, maxLoops = 0;
@@ -712,15 +718,17 @@ void KyraEngine_LoK::magicOutMouseItem(int animIndex, int itemPos) {
delayUntil(nextTime);
}
restoreItemRect1(x, y);
+
if (itemPos == -1) {
_screen->setMouseCursor(1, 1, _shapes[0]);
- _itemInHand = -1;
+ _itemInHand = kItemNone;
} else {
- _characterList[0].inventoryItems[itemPos] = 0xFF;
+ _characterList[0].inventoryItems[itemPos] = kItemNone;
_screen->hideMouse();
_screen->fillRect(_itemPosX[itemPos], _itemPosY[itemPos], _itemPosX[itemPos] + 15, _itemPosY[itemPos] + 15, _flags.platform == Common::kPlatformAmiga ? 19 : 12, 0);
_screen->showMouse();
}
+
_screen->showMouse();
_screen->_curPage = videoPageBackUp;
}
@@ -883,7 +891,8 @@ void KyraEngine_LoK::redrawInventory(int page) {
_screen->hideMouse();
for (int i = 0; i < 10; ++i) {
_screen->fillRect(_itemPosX[i], _itemPosY[i], _itemPosX[i] + 15, _itemPosY[i] + 15, _flags.platform == Common::kPlatformAmiga ? 19 : 12, page);
- if (_currentCharacter->inventoryItems[i] != 0xFF) {
+
+ if (_currentCharacter->inventoryItems[i] != kItemNone) {
uint8 item = _currentCharacter->inventoryItems[i];
_screen->drawShape(page, _shapes[216+item], _itemPosX[i], _itemPosY[i], 0, 0);
}
@@ -913,12 +922,12 @@ void KyraEngine_LoK::restoreItemRect1(int xpos, int ypos) {
_screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 4<<3, 32, _itemBkgBackUp[1]);
}
-int KyraEngine_LoK::getItemListIndex(uint16 item) {
+int KyraEngine_LoK::getItemListIndex(Item item) {
if (_flags.platform != Common::kPlatformAmiga)
return item;
// "Unknown item" is at 81.
- if (item == 0xFFFF || item == 0xFF)
+ if (item == kItemNone)
return 81;
// The first item names are mapped directly
else if (item <= 28)
diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp
index 5b566d51db..e99f3bf701 100644
--- a/engines/kyra/items_lol.cpp
+++ b/engines/kyra/items_lol.cpp
@@ -110,10 +110,10 @@ void LoLEngine::takeCredits(int credits, int redraw) {
}
}
-int LoLEngine::makeItem(int itemType, int curFrame, int flags) {
+Item LoLEngine::makeItem(int itemType, int curFrame, int flags) {
int cnt = 0;
int r = 0;
- int i = 1;
+ Item i = 1;
for (; i < 400; i++) {
if (_itemsInPlay[i].shpCurFrame_flg & 0x8000) {
@@ -130,7 +130,7 @@ int LoLEngine::makeItem(int itemType, int curFrame, int flags) {
continue;
bool t = false;
- int ii = i;
+ Item ii = i;
while (ii && !t) {
t = testUnkItemFlags(ii);
if (t)
@@ -145,7 +145,7 @@ int LoLEngine::makeItem(int itemType, int curFrame, int flags) {
}
}
- int slot = i;
+ Item slot = i;
if (cnt) {
slot = r;
if (testUnkItemFlags(r)) {
@@ -154,7 +154,7 @@ int LoLEngine::makeItem(int itemType, int curFrame, int flags) {
deleteItem(r);
slot = r;
} else {
- int ii = _itemsInPlay[slot].nextAssignedObject;
+ uint16 ii = _itemsInPlay[slot].nextAssignedObject;
while (ii) {
if (testUnkItemFlags(ii)) {
_itemsInPlay[slot].nextAssignedObject = _itemsInPlay[ii].nextAssignedObject;
@@ -178,7 +178,7 @@ int LoLEngine::makeItem(int itemType, int curFrame, int flags) {
return slot;
}
-void LoLEngine::placeMoveLevelItem(int itemIndex, int level, int block, int xOffs, int yOffs, int flyingHeight) {
+void LoLEngine::placeMoveLevelItem(Item itemIndex, int level, int block, int xOffs, int yOffs, int flyingHeight) {
calcCoordinates(_itemsInPlay[itemIndex].x, _itemsInPlay[itemIndex].y, block, xOffs, yOffs);
if (_itemsInPlay[itemIndex].block)
@@ -194,7 +194,7 @@ void LoLEngine::placeMoveLevelItem(int itemIndex, int level, int block, int xOff
}
}
-bool LoLEngine::addItemToInventory(int itemIndex) {
+bool LoLEngine::addItemToInventory(Item itemIndex) {
int pos = 0;
int i = 0;
@@ -222,7 +222,7 @@ bool LoLEngine::addItemToInventory(int itemIndex) {
return true;
}
-bool LoLEngine::testUnkItemFlags(int itemIndex) {
+bool LoLEngine::testUnkItemFlags(Item itemIndex) {
if (!(_itemsInPlay[itemIndex].shpCurFrame_flg & 0x4000))
return false;
@@ -233,7 +233,7 @@ bool LoLEngine::testUnkItemFlags(int itemIndex) {
}
-void LoLEngine::deleteItem(int itemIndex) {
+void LoLEngine::deleteItem(Item itemIndex) {
memset(&_itemsInPlay[itemIndex], 0, sizeof(ItemInPlay));
_itemsInPlay[itemIndex].shpCurFrame_flg |= 0x8000;
}
@@ -245,7 +245,7 @@ ItemInPlay *LoLEngine::findObject(uint16 index) {
return &_itemsInPlay[index];
}
-void LoLEngine::runItemScript(int charNum, int item, int flags, int next, int reg4) {
+void LoLEngine::runItemScript(int charNum, Item item, int flags, int next, int reg4) {
EMCState scriptState;
memset(&scriptState, 0, sizeof(EMCState));
@@ -270,7 +270,7 @@ void LoLEngine::runItemScript(int charNum, int item, int flags, int next, int re
}
}
-void LoLEngine::setHandItem(uint16 itemIndex) {
+void LoLEngine::setHandItem(Item itemIndex) {
if (itemIndex && _itemProperties[_itemsInPlay[itemIndex].itemPropertyIndex].flags & 0x80) {
runItemScript(-1, itemIndex, 0x400, 0, 0);
if (_itemsInPlay[itemIndex].shpCurFrame_flg & 0x8000)
@@ -307,7 +307,7 @@ bool LoLEngine::itemEquipped(int charNum, uint16 itemType) {
return false;
}
-void LoLEngine::setItemPosition(int item, uint16 x, uint16 y, int flyingHeight, int b) {
+void LoLEngine::setItemPosition(Item item, uint16 x, uint16 y, int flyingHeight, int b) {
if (!flyingHeight) {
x = (x & 0xffc0) | 0x40;
y = (y & 0xffc0) | 0x40;
@@ -334,7 +334,7 @@ void LoLEngine::setItemPosition(int item, uint16 x, uint16 y, int flyingHeight,
checkSceneUpdateNeed(block);
}
-void LoLEngine::removeLevelItem(int item, int block) {
+void LoLEngine::removeLevelItem(Item item, int block) {
removeAssignedObjectFromBlock(&_levelBlockProperties[block], item);
removeDrawObjectFromBlock(&_levelBlockProperties[block], item);
runLevelScriptCustom(block, 0x100, -1, item, 0, 0);
@@ -342,7 +342,7 @@ void LoLEngine::removeLevelItem(int item, int block) {
_itemsInPlay[item].level = 0;
}
-bool LoLEngine::launchObject(int objectType, int item, int startX, int startY, int flyingHeight, int direction, int, int attackerId, int c) {
+bool LoLEngine::launchObject(int objectType, Item item, int startX, int startY, int flyingHeight, int direction, int, int attackerId, int c) {
int sp = checkDrawObjectSpace(_partyPosX, _partyPosY, startX, startY);
FlyingObject *t = _flyingObjects;
int slot = -1;
diff --git a/engines/kyra/items_mr.cpp b/engines/kyra/items_mr.cpp
index 256753cc69..2bc268ace3 100644
--- a/engines/kyra/items_mr.cpp
+++ b/engines/kyra/items_mr.cpp
@@ -29,7 +29,7 @@
namespace Kyra {
void KyraEngine_MR::removeTrashItems() {
- for (int i = 0; _trashItemList[i] != 0xFF; ++i) {
+ for (int i = 0; _trashItemList[i] != kItemNone; ++i) {
for (int item = findItem(_trashItemList[i]); item != -1; item = findItem(_trashItemList[i])) {
if (_itemList[item].sceneId != _mainCharacter.sceneId)
resetItem(item);
@@ -41,7 +41,7 @@ void KyraEngine_MR::removeTrashItems() {
int KyraEngine_MR::findFreeInventorySlot() {
for (int i = 0; i < 10; ++i) {
- if (_mainCharacter.inventory[i] == 0xFFFF)
+ if (_mainCharacter.inventory[i] == kItemNone)
return i;
}
return -1;
@@ -52,7 +52,7 @@ int KyraEngine_MR::checkItemCollision(int x, int y) {
int maxItemY = -1;
for (int i = 0; i < 50; ++i) {
- if (_itemList[i].id == 0xFFFF || _itemList[i].sceneId != _mainCharacter.sceneId)
+ if (_itemList[i].id == kItemNone || _itemList[i].sceneId != _mainCharacter.sceneId)
continue;
const int x1 = _itemList[i].x - 11;
@@ -76,12 +76,12 @@ int KyraEngine_MR::checkItemCollision(int x, int y) {
return itemIndex;
}
-void KyraEngine_MR::setMouseCursor(uint16 item) {
+void KyraEngine_MR::setMouseCursor(Item item) {
int shape = 0;
int hotX = 1;
int hotY = 1;
- if (item != 0xFFFF) {
+ if (item != kItemNone) {
hotX = 12;
hotY = 19;
shape = item+248;
@@ -94,13 +94,13 @@ void KyraEngine_MR::setMouseCursor(uint16 item) {
void KyraEngine_MR::setItemMouseCursor() {
_mouseState = _itemInHand;
- if (_itemInHand == -1)
+ if (_itemInHand == kItemNone)
_screen->setMouseCursor(0, 0, _gameShapes[0]);
else
_screen->setMouseCursor(12, 19, _gameShapes[_itemInHand+248]);
}
-bool KyraEngine_MR::dropItem(int unk1, uint16 item, int x, int y, int unk2) {
+bool KyraEngine_MR::dropItem(int unk1, Item item, int x, int y, int unk2) {
if (_mouseState <= -1)
return false;
@@ -123,7 +123,7 @@ bool KyraEngine_MR::dropItem(int unk1, uint16 item, int x, int y, int unk2) {
return false;
}
-bool KyraEngine_MR::processItemDrop(uint16 sceneId, uint16 item, int x, int y, int unk1, int unk2) {
+bool KyraEngine_MR::processItemDrop(uint16 sceneId, Item item, int x, int y, int unk1, int unk2) {
int itemPos = checkItemCollision(x, y);
if (unk1)
@@ -138,7 +138,7 @@ bool KyraEngine_MR::processItemDrop(uint16 sceneId, uint16 item, int x, int y, i
if (unk2 != 3) {
for (int i = 0; i < 50; ++i) {
- if (_itemList[i].id == 0xFFFF) {
+ if (_itemList[i].id == kItemNone) {
freeItemSlot = i;
break;
}
@@ -227,7 +227,7 @@ bool KyraEngine_MR::processItemDrop(uint16 sceneId, uint16 item, int x, int y, i
return true;
}
-void KyraEngine_MR::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, uint16 item, int remove) {
+void KyraEngine_MR::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, Item item, int remove) {
if (startX == dstX && startY == dstY) {
_itemList[itemSlot].x = dstX;
_itemList[itemSlot].y = dstY;
@@ -323,7 +323,7 @@ void KyraEngine_MR::exchangeMouseItem(int itemPos, int runScript) {
_screen->hideMouse();
deleteItemAnimEntry(itemPos);
- int itemId = _itemList[itemPos].id;
+ Item itemId = _itemList[itemPos].id;
_itemList[itemPos].id = _itemInHand;
_itemInHand = itemId;
@@ -353,8 +353,8 @@ bool KyraEngine_MR::pickUpItem(int x, int y, int runScript) {
} else {
_screen->hideMouse();
deleteItemAnimEntry(itemPos);
- int itemId = _itemList[itemPos].id;
- _itemList[itemPos].id = 0xFFFF;
+ Item itemId = _itemList[itemPos].id;
+ _itemList[itemPos].id = kItemNone;
snd_playSoundEffect(0x0B, 0xC8);
setMouseCursor(itemId);
int itemString = 0;
@@ -387,8 +387,9 @@ bool KyraEngine_MR::isDropable(int x, int y) {
return true;
}
-bool KyraEngine_MR::itemListMagic(int handItem, int itemSlot) {
- uint16 item = _itemList[itemSlot].id;
+bool KyraEngine_MR::itemListMagic(Item handItem, int itemSlot) {
+ Item item = _itemList[itemSlot].id;
+
if (_currentChapter == 1 && handItem == 3 && item == 3 && queryGameFlag(0x76)) {
eelScript();
return true;
@@ -410,7 +411,7 @@ bool KyraEngine_MR::itemListMagic(int handItem, int itemSlot) {
}
deleteItemAnimEntry(itemSlot);
- _itemList[itemSlot].id = 0xFFFF;
+ _itemList[itemSlot].id = kItemNone;
_screen->showMouse();
return true;
}
@@ -430,7 +431,7 @@ bool KyraEngine_MR::itemListMagic(int handItem, int itemSlot) {
}
for (int i = 0; _itemMagicTable[i] != 0xFF; i += 4) {
- if (_itemMagicTable[i+0] != handItem || _itemMagicTable[i+1] != item)
+ if (_itemMagicTable[i+0] != handItem || (int8)_itemMagicTable[i+1] != item)
continue;
uint8 resItem = _itemMagicTable[i+2];
@@ -438,7 +439,7 @@ bool KyraEngine_MR::itemListMagic(int handItem, int itemSlot) {
snd_playSoundEffect(0x0F, 0xC8);
- _itemList[itemSlot].id = (resItem == 0xFF) ? 0xFFFF : resItem;
+ _itemList[itemSlot].id = (int8)resItem;
_screen->hideMouse();
deleteItemAnimEntry(itemSlot);
@@ -465,8 +466,9 @@ bool KyraEngine_MR::itemListMagic(int handItem, int itemSlot) {
return false;
}
-bool KyraEngine_MR::itemInventoryMagic(int handItem, int invSlot) {
- uint16 item = _mainCharacter.inventory[invSlot];
+bool KyraEngine_MR::itemInventoryMagic(Item handItem, int invSlot) {
+ Item item = _mainCharacter.inventory[invSlot];
+
if (_currentChapter == 1 && handItem == 3 && item == 3 && queryGameFlag(0x76)) {
eelScript();
return true;
@@ -482,7 +484,7 @@ bool KyraEngine_MR::itemInventoryMagic(int handItem, int invSlot) {
delay(1*_tickLength, true);
}
- _mainCharacter.inventory[invSlot] = 0xFFFF;
+ _mainCharacter.inventory[invSlot] = kItemNone;
clearInventorySlot(invSlot, 0);
_screen->showMouse();
return true;
@@ -497,7 +499,7 @@ bool KyraEngine_MR::itemInventoryMagic(int handItem, int invSlot) {
snd_playSoundEffect(0x0F, 0xC8);
- _mainCharacter.inventory[invSlot] = (resItem == 0xFF) ? 0xFFFF : resItem;
+ _mainCharacter.inventory[invSlot] = (int8)resItem;
_screen->hideMouse();
clearInventorySlot(invSlot, 0);
diff --git a/engines/kyra/items_v2.cpp b/engines/kyra/items_v2.cpp
index 29901b2ddb..90b6194f0d 100644
--- a/engines/kyra/items_v2.cpp
+++ b/engines/kyra/items_v2.cpp
@@ -31,9 +31,9 @@ namespace Kyra {
void KyraEngine_v2::initItemList(int size) {
delete[] _itemList;
- _itemList = new Item[size];
+ _itemList = new ItemDefinition[size];
assert(_itemList);
- memset(_itemList, 0, sizeof(Item)*size);
+ memset(_itemList, 0, sizeof(ItemDefinition)*size);
_itemListSize = size;
resetItemList();
@@ -41,7 +41,7 @@ void KyraEngine_v2::initItemList(int size) {
int KyraEngine_v2::findFreeItem() {
for (int i = 0; i < _itemListSize; ++i) {
- if (_itemList[i].id == 0xFFFF)
+ if (_itemList[i].id == kItemNone)
return i;
}
return -1;
@@ -50,13 +50,13 @@ int KyraEngine_v2::findFreeItem() {
int KyraEngine_v2::countAllItems() {
int num = 0;
for (int i = 0; i < _itemListSize; ++i) {
- if (_itemList[i].id != 0xFFFF)
+ if (_itemList[i].id != kItemNone)
++num;
}
return num;
}
-int KyraEngine_v2::findItem(uint16 sceneId, uint16 id) {
+int KyraEngine_v2::findItem(uint16 sceneId, Item id) {
for (int i = 0; i < _itemListSize; ++i) {
if (_itemList[i].id == id && _itemList[i].sceneId == sceneId)
return i;
@@ -64,7 +64,7 @@ int KyraEngine_v2::findItem(uint16 sceneId, uint16 id) {
return -1;
}
-int KyraEngine_v2::findItem(uint16 item) {
+int KyraEngine_v2::findItem(Item item) {
for (int i = 0; i < _itemListSize; ++i) {
if (_itemList[i].id == item)
return i;
@@ -78,17 +78,17 @@ void KyraEngine_v2::resetItemList() {
}
void KyraEngine_v2::resetItem(int index) {
- _itemList[index].id = 0xFFFF;
+ _itemList[index].id = kItemNone;
_itemList[index].sceneId = 0xFFFF;
_itemList[index].x = 0;
_itemList[index].y = 0;
}
-void KyraEngine_v2::setHandItem(uint16 item) {
+void KyraEngine_v2::setHandItem(Item item) {
Screen *scr = screen();
scr->hideMouse();
- if (item == 0xFFFF) {
+ if (item == kItemNone) {
removeHandItem();
} else {
setMouseCursor(item);
@@ -102,8 +102,8 @@ void KyraEngine_v2::removeHandItem() {
Screen *scr = screen();
scr->hideMouse();
scr->setMouseCursor(0, 0, getShapePtr(0));
- _itemInHand = -1;
- _mouseState = -1;
+ _itemInHand = kItemNone;
+ _mouseState = kItemNone;
scr->showMouse();
}
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 0fafaa15ce..5c471a8c8b 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -74,7 +74,7 @@ KyraEngine_HoF::KyraEngine_HoF(OSystem *system, const GameFlags &flags) : KyraEn
_mainCharX = _mainCharY = -1;
_drawNoShapeFlag = false;
_charPalEntry = 0;
- _itemInHand = -1;
+ _itemInHand = kItemNone;
_unkSceneScreenFlag1 = false;
_noScriptEnter = true;
_currentChapter = 0;
@@ -441,7 +441,7 @@ void KyraEngine_HoF::startup() {
if (_gameToLoad == -1) {
snd_playWanderScoreViaMap(52, 1);
enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1);
- saveGameState(0, "New Game", 0);
+ saveGameStateIntern(0, "New Game", 0);
} else {
loadGameStateCheck(_gameToLoad);
}
@@ -507,7 +507,7 @@ void KyraEngine_HoF::runLoop() {
update();
if (inputFlag == 198 || inputFlag == 199) {
- _unk3 = _mouseState;
+ _savedMouseState = _mouseState;
handleInput(_mouseX, _mouseY);
}
@@ -528,7 +528,7 @@ void KyraEngine_HoF::handleInput(int x, int y) {
if (!_screen->isMouseVisible())
return;
- if (_unk3 == -2) {
+ if (_savedMouseState == -2) {
snd_playSoundEffect(13);
return;
}
@@ -537,8 +537,8 @@ void KyraEngine_HoF::handleInput(int x, int y) {
if (x <= 6 || x >= 312 || y <= 6 || y >= 135) {
bool exitOk = false;
- assert(_unk3 + 6 >= 0);
- switch (_unk3 + 6) {
+ assert(_savedMouseState + 6 >= 0);
+ switch (_savedMouseState + 6) {
case 0:
if (_sceneExit1 != 0xFFFF)
exitOk = true;
@@ -569,7 +569,7 @@ void KyraEngine_HoF::handleInput(int x, int y) {
}
}
- if (checkCharCollision(x, y) && _unk3 >= -1) {
+ if (checkCharCollision(x, y) && _savedMouseState >= -1) {
runSceneScript2();
return;
} else if (pickUpItem(x, y)) {
@@ -609,7 +609,7 @@ void KyraEngine_HoF::handleInput(int x, int y) {
dropItem(0, _itemInHand, x, y, 1);
} else {
- if (_unk3 == -2 || y > 135)
+ if (_savedMouseState == -2 || y > 135)
return;
if (!_unk5) {
@@ -790,7 +790,7 @@ void KyraEngine_HoF::updateMouse() {
if ((mouse.y > 145) || (mouse.x > 6 && mouse.x < 312 && mouse.y > 6 && mouse.y < 135)) {
_mouseState = _itemInHand;
_screen->hideMouse();
- if (_itemInHand == -1)
+ if (_itemInHand == kItemNone)
_screen->setMouseCursor(0, 0, getShapePtr(0));
else
_screen->setMouseCursor(8, 15, getShapePtr(_itemInHand+64));
@@ -1169,25 +1169,25 @@ int KyraEngine_HoF::inputSceneChange(int x, int y, int unk1, int unk2) {
_pathfinderFlag = 15;
if (!_unkHandleSceneChangeFlag) {
- if (_unk3 == -3) {
+ if (_savedMouseState == -3) {
if (_sceneList[curScene].exit4 != 0xFFFF) {
x = 4;
y = _sceneEnterY4;
_pathfinderFlag = 7;
}
- } else if (_unk3 == -5) {
+ } else if (_savedMouseState == -5) {
if (_sceneList[curScene].exit2 != 0xFFFF) {
x = 316;
y = _sceneEnterY2;
_pathfinderFlag = 7;
}
- } else if (_unk3 == -6) {
+ } else if (_savedMouseState == -6) {
if (_sceneList[curScene].exit1 != 0xFFFF) {
x = _sceneEnterX1;
y = _sceneEnterY1 - 2;
_pathfinderFlag = 14;
}
- } else if (_unk3 == -4) {
+ } else if (_savedMouseState == -4) {
if (_sceneList[curScene].exit3 != 0xFFFF) {
x = _sceneEnterX3;
y = 147;
@@ -1200,13 +1200,13 @@ int KyraEngine_HoF::inputSceneChange(int x, int y, int unk1, int unk2) {
int vocH = _flags.isTalkie ? 131 : -1;
if (_pathfinderFlag) {
- if (findItem(curScene, 13) >= 0 && _unk3 <= -3) {
+ if (findItem(curScene, 13) >= 0 && _savedMouseState <= -3) {
strId = 252;
} else if (_itemInHand == 72) {
strId = 257;
- } else if (findItem(curScene, 72) >= 0 && _unk3 <= -3) {
+ } else if (findItem(curScene, 72) >= 0 && _savedMouseState <= -3) {
strId = 256;
- } else if (getInventoryItemSlot(72) != -1 && _unk3 <= -3) {
+ } else if (getInventoryItemSlot(72) != -1 && _savedMouseState <= -3) {
strId = 257;
}
}
diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h
index 05d04fe993..576232740b 100644
--- a/engines/kyra/kyra_hof.h
+++ b/engines/kyra/kyra_hof.h
@@ -443,16 +443,16 @@ protected:
bool lineIsPassable(int x, int y);
// item
- void setMouseCursor(uint16 item);
+ void setMouseCursor(Item item);
uint8 _itemHtDat[176];
int checkItemCollision(int x, int y);
void updateWaterFlasks();
- bool dropItem(int unk1, uint16 item, int x, int y, int unk2);
- bool processItemDrop(uint16 sceneId, uint16 item, int x, int y, int unk1, int unk2);
- void itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, uint16 item);
+ bool dropItem(int unk1, Item item, int x, int y, int unk2);
+ bool processItemDrop(uint16 sceneId, Item item, int x, int y, int unk1, int unk2);
+ void itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, Item item);
void exchangeMouseItem(int itemPos);
bool pickUpItem(int x, int y);
@@ -461,18 +461,18 @@ protected:
static const byte _itemStringMap[];
static const int _itemStringMapSize;
- static const int16 _flaskTable[];
- bool itemIsFlask(int item);
+ static const Item _flaskTable[];
+ bool itemIsFlask(Item item);
// inventory
static const int _inventoryX[];
static const int _inventoryY[];
static const uint16 _itemMagicTable[];
- int getInventoryItemSlot(uint16 item);
+ int getInventoryItemSlot(Item item);
void removeSlotFromInventory(int slot);
- bool checkInventoryItemExchange(uint16 item, int slot);
- void drawInventoryShape(int page, uint16 item, int slot);
+ bool checkInventoryItemExchange(Item item, int slot);
+ void drawInventoryShape(int page, Item item, int slot);
void clearInventorySlot(int slot, int page);
void redrawInventory(int page);
void scrollInventoryWheel();
@@ -561,9 +561,9 @@ protected:
void changeFileExtension(char *buffer);
// - Just used in French version
- int getItemCommandStringDrop(uint16 item);
- int getItemCommandStringPickUp(uint16 item);
- int getItemCommandStringInv(uint16 item);
+ int getItemCommandStringDrop(Item item);
+ int getItemCommandStringPickUp(Item item);
+ int getItemCommandStringInv(Item item);
// -
char _internStringBuf[200];
@@ -915,7 +915,7 @@ protected:
int _dbgPass;
// save/load specific
- Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail);
+ Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail);
Common::Error loadGameState(int slot);
};
diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp
index 159230e928..d46fc2d502 100644
--- a/engines/kyra/kyra_lok.cpp
+++ b/engines/kyra/kyra_lok.cpp
@@ -247,7 +247,7 @@ Common::Error KyraEngine_LoK::init() {
_brandonPosX = _brandonPosY = -1;
_poisonDeathCounter = 0;
- memset(_itemTable, 0, sizeof(_itemTable));
+ memset(_itemHtDat, 0, sizeof(_itemHtDat));
memset(_exitList, 0xFFFF, sizeof(_exitList));
_exitListPtr = 0;
_pathfinderFlag = _pathfinderFlag2 = 0;
@@ -260,7 +260,7 @@ Common::Error KyraEngine_LoK::init() {
_marbleVaseItem = -1;
memset(_foyerItemTable, -1, sizeof(_foyerItemTable));
- _itemInHand = -1;
+ _itemInHand = kItemNone;
_currentRoom = 0xFFFF;
_scenePhasingFlag = 0;
@@ -373,7 +373,7 @@ void KyraEngine_LoK::startup() {
for (int i = 0; i < _roomTableSize; ++i) {
for (int item = 0; item < 12; ++item) {
- _roomTable[i].itemsTable[item] = 0xFF;
+ _roomTable[i].itemsTable[item] = kItemNone;
_roomTable[i].itemsXPos[item] = 0xFFFF;
_roomTable[i].itemsYPos[item] = 0xFF;
_roomTable[i].needInit[item] = 0;
@@ -420,7 +420,7 @@ void KyraEngine_LoK::startup() {
_gui->buttonMenuCallback(0);
_menuDirectlyToLoad = false;
} else if (!shouldQuit()) {
- saveGameState(0, "New game", 0);
+ saveGameStateIntern(0, "New game", 0);
}
} else {
_screen->setFont(_flags.lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
@@ -672,12 +672,13 @@ void KyraEngine_LoK::processInput(int xpos, int ypos) {
runNpcScript(script);
return;
}
- if (_itemInHand != -1) {
+ if (_itemInHand != kItemNone) {
if (ypos < 155) {
if (hasClickedOnExit(xpos, ypos)) {
handleSceneChange(xpos, ypos, 1, 1);
return;
}
+
dropItem(0, _itemInHand, xpos, ypos, 1);
}
} else {
@@ -691,14 +692,14 @@ void KyraEngine_LoK::processInput(int xpos, int ypos) {
int KyraEngine_LoK::processInputHelper(int xpos, int ypos) {
uint8 item = findItemAtPos(xpos, ypos);
if (item != 0xFF) {
- if (_itemInHand == -1) {
+ if (_itemInHand == kItemNone) {
_screen->hideMouse();
_animator->animRemoveGameItem(item);
snd_playSoundEffect(53);
assert(_currentCharacter->sceneId < _roomTableSize);
Room *currentRoom = &_roomTable[_currentCharacter->sceneId];
int item2 = currentRoom->itemsTable[item];
- currentRoom->itemsTable[item] = 0xFF;
+ currentRoom->itemsTable[item] = kItemNone;
setMouseItem(item2);
assert(_itemList && _takenList);
updateSentenceCommand(_itemList[getItemListIndex(item2)], _takenList[0], 179);
@@ -830,7 +831,7 @@ void KyraEngine_LoK::updateMousePointer(bool forceUpdate) {
if (mouse.y > 158 || (mouse.x >= 12 && mouse.x < 308 && mouse.y < 136 && mouse.y >= 12) || forceUpdate) {
_mouseState = _itemInHand;
_screen->hideMouse();
- if (_itemInHand == -1)
+ if (_itemInHand == kItemNone)
_screen->setMouseCursor(1, 1, _shapes[0]);
else
_screen->setMouseCursor(8, 15, _shapes[216+_itemInHand]);
diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h
index 50f36d7b71..dfbf5bddd8 100644
--- a/engines/kyra/kyra_lok.h
+++ b/engines/kyra/kyra_lok.h
@@ -30,6 +30,7 @@
#include "kyra/script.h"
#include "kyra/screen_lok.h"
#include "kyra/gui_lok.h"
+#include "kyra/item.h"
namespace Kyra {
@@ -46,7 +47,7 @@ struct Character {
uint8 height;
uint8 facing;
uint16 currentAnimFrame;
- uint8 inventoryItems[10];
+ int8 inventoryItems[10];
int16 x1, y1, x2, y2;
};
@@ -62,19 +63,12 @@ struct Room {
uint16 eastExit;
uint16 southExit;
uint16 westExit;
- uint8 itemsTable[12];
+ int8 itemsTable[12];
uint16 itemsXPos[12];
uint8 itemsYPos[12];
uint8 needInit[12];
};
-struct Item {
- uint8 unk1;
- uint8 height;
- uint8 unk2;
- uint8 unk3;
-};
-
struct SeqLoop {
const uint8 *ptr;
uint16 count;
@@ -218,7 +212,7 @@ public:
protected:
int32 _speechPlayTime;
- Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail);
+ Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail);
Common::Error loadGameState(int slot);
protected:
// input
@@ -288,11 +282,11 @@ protected:
void placeItemInGenericMapScene(int item, int index);
// -> mouse item
- void setHandItem(uint16 item);
+ void setHandItem(Item item);
void removeHandItem();
- void setMouseItem(uint16 item);
+ void setMouseItem(Item item);
- int getItemListIndex(uint16 item);
+ int getItemListIndex(Item item);
// -> graphics effects
void wipeDownMouseItem(int xpos, int ypos);
@@ -402,7 +396,7 @@ protected:
bool _menuDirectlyToLoad;
uint8 *_itemBkgBackUp[2];
uint8 *_shapes[373];
- int8 _itemInHand;
+ Item _itemInHand;
bool _changedScene;
int _unkScreenVar1, _unkScreenVar2, _unkScreenVar3;
int _beadStateVar;
@@ -455,7 +449,7 @@ protected:
int8 *_sceneAnimTable[50];
- Item _itemTable[145];
+ uint8 _itemHtDat[145];
int _lastProcessedItem;
int _lastProcessedItemHeight;
diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp
index c224a76385..5ac6da9f2b 100644
--- a/engines/kyra/kyra_mr.cpp
+++ b/engines/kyra/kyra_mr.cpp
@@ -99,8 +99,8 @@ KyraEngine_MR::KyraEngine_MR(OSystem *system, const GameFlags &flags) : KyraEngi
_unk5 = 0;
_unkSceneScreenFlag1 = false;
_noScriptEnter = true;
- _itemInHand = _mouseState = -1;
- _unk3 = -1;
+ _itemInHand = _mouseState = kItemNone;
+ _savedMouseState = -1;
_unk4 = 0;
_loadingState = false;
_noStartupChat = false;
@@ -653,7 +653,7 @@ void KyraEngine_MR::startup() {
assert(_invWsa);
_invWsa->open("MOODOMTR.WSA", 1, 0);
_invWsaFrame = 6;
- saveGameState(0, "New Game", 0);
+ saveGameStateIntern(0, "New Game", 0);
if (_gameToLoad == -1)
enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1);
else
@@ -966,7 +966,7 @@ void KyraEngine_MR::runLoop() {
_timer->update();
if (inputFlag == 198 || inputFlag == 199) {
- _unk3 = _mouseState;
+ _savedMouseState = _mouseState;
Common::Point mouse = getMousePos();
handleInput(mouse.x, mouse.y);
}
@@ -988,7 +988,7 @@ void KyraEngine_MR::handleInput(int x, int y) {
if (!_screen->isMouseVisible())
return;
- if (_unk3 == -3) {
+ if (_savedMouseState == -3) {
snd_playSoundEffect(0x0D, 0x80);
return;
}
@@ -997,7 +997,7 @@ void KyraEngine_MR::handleInput(int x, int y) {
int skip = 0;
- if (checkCharCollision(x, y) && _unk3 >= -1 && runSceneScript2()) {
+ if (checkCharCollision(x, y) && _savedMouseState >= -1 && runSceneScript2()) {
return;
} else if (_itemInHand != 27 && pickUpItem(x, y, 1)) {
return;
@@ -1023,7 +1023,7 @@ void KyraEngine_MR::handleInput(int x, int y) {
if (checkCharCollision(x, y)) {
if (runSceneScript2())
return;
- } else if (_itemInHand >= 0 && _unk3 >= 0) {
+ } else if (_itemInHand >= 0 && _savedMouseState >= 0) {
if (_itemInHand == 27) {
makeCharFacingMouse();
} else if (y <= 187) {
@@ -1033,10 +1033,10 @@ void KyraEngine_MR::handleInput(int x, int y) {
dropItem(0, _itemInHand, x, y, 1);
}
return;
- } else if (_unk3 == -3) {
+ } else if (_savedMouseState == -3) {
return;
} else {
- if (y > 187 && _unk3 > -4)
+ if (y > 187 && _savedMouseState > -4)
return;
if (_unk5) {
_unk5 = 0;
@@ -1052,25 +1052,25 @@ int KyraEngine_MR::inputSceneChange(int x, int y, int unk1, int unk2) {
_pathfinderFlag = 15;
if (!_unkHandleSceneChangeFlag) {
- if (_unk3 == -4) {
+ if (_savedMouseState == -4) {
if (_sceneList[curScene].exit4 != 0xFFFF) {
x = 4;
y = _sceneEnterY4;
_pathfinderFlag = 7;
}
- } else if (_unk3 == -6) {
+ } else if (_savedMouseState == -6) {
if (_sceneList[curScene].exit2 != 0xFFFF) {
x = 316;
y = _sceneEnterY2;
_pathfinderFlag = 7;
}
- } else if (_unk3 == -7) {
+ } else if (_savedMouseState == -7) {
if (_sceneList[curScene].exit1 != 0xFFFF) {
x = _sceneEnterX1;
y = _sceneEnterY1 - 2;
_pathfinderFlag = 14;
}
- } else if (_unk3 == -5) {
+ } else if (_savedMouseState == -5) {
if (_sceneList[curScene].exit3 != 0xFFFF) {
x = _sceneEnterX3;
y = 191;
@@ -1167,8 +1167,8 @@ void KyraEngine_MR::updateMouse() {
}
if (hasItemCollision && _mouseState < -1 && _itemInHand < 0) {
- _mouseState = -1;
- _itemInHand = -1;
+ _mouseState = kItemNone;
+ _itemInHand = kItemNone;
_screen->setMouseCursor(0, 0, _gameShapes[0]);
}
diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h
index 36b937f2a8..e6f75742f4 100644
--- a/engines/kyra/kyra_mr.h
+++ b/engines/kyra/kyra_mr.h
@@ -235,7 +235,7 @@ private:
void showMessage(const char *string, uint8 c0, uint8 c1);
void showMessageFromCCode(int string, uint8 c0, int);
- void updateItemCommand(int item, int str, uint8 c0);
+ void updateItemCommand(Item item, int str, uint8 c0);
void updateCommandLine();
void restoreCommandLine();
@@ -262,7 +262,7 @@ private:
static const uint8 _inventoryY[];
void redrawInventory(int page);
void clearInventorySlot(int slot, int page);
- void drawInventorySlot(int page, int item, int slot);
+ void drawInventorySlot(int page, Item item, int slot);
WSAMovie_v2 *_invWsa;
int _invWsaFrame;
@@ -284,24 +284,24 @@ private:
int8 *_itemBuffer1;
int8 *_itemBuffer2;
- static const uint8 _trashItemList[];
+ static const Item _trashItemList[];
void removeTrashItems();
void initItems();
int checkItemCollision(int x, int y);
- bool dropItem(int unk1, uint16 item, int x, int y, int unk2);
- bool processItemDrop(uint16 sceneId, uint16 item, int x, int y, int unk1, int unk2);
- void itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, uint16 item, int remove);
+ bool dropItem(int unk1, Item item, int x, int y, int unk2);
+ bool processItemDrop(uint16 sceneId, Item item, int x, int y, int unk1, int unk2);
+ void itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, Item item, int remove);
void exchangeMouseItem(int itemPos, int runScript);
bool pickUpItem(int x, int y, int runScript);
bool isDropable(int x, int y);
const uint8 *_itemMagicTable;
- bool itemListMagic(int handItem, int itemSlot);
- bool itemInventoryMagic(int handItem, int invSlot);
+ bool itemListMagic(Item handItem, int itemSlot);
+ bool itemInventoryMagic(Item handItem, int invSlot);
const uint8 *_itemStringMap;
int _itemStringMapSize;
@@ -315,7 +315,7 @@ private:
// -> hand item
void setItemMouseCursor();
- void setMouseCursor(uint16 item);
+ void setMouseCursor(Item item);
// shapes
void initMouseShapes();
@@ -585,7 +585,7 @@ private:
int albumClose(Button *caller);
// save/load
- Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail);
+ Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail);
Common::Error loadGameState(int slot);
// opcodes
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index 4d0248b1e4..26c4001578 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -103,11 +103,14 @@ Common::Error KyraEngine_v1::init() {
syncSoundSettings();
if (!_flags.useDigSound) {
- // We prefer AdLib over MIDI in Kyra 1, since it offers MT-32 support only, most users don't have a real
- // MT-32/LAPC1/CM32L/CM64 device and AdLib sounds better than our incomplete MT-32 emulator and also better than
- // MT-32/GM mapping. For Kyra 2 and LoL which have real GM tracks which sound better than AdLib tracks we prefer GM
- // since most users have a GM compatible device.
- MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB | ((_flags.gameID == GI_KYRA2 || _flags.gameID == GI_LOL) ? MDT_PREFER_GM : 0));
+ // In Kyra 1 users who have specified a default MT-32 device in the launcher settings
+ // will get MT-32 music, otherwise AdLib. In Kyra 2 and LoL users who have specified a
+ // default GM device in the launcher will get GM music, otherwise AdLib. Users who want
+ // MT-32 music in Kyra2 or LoL have to select this individually (since we assume that
+ // most users rather have a GM device than a MT-32 device).
+ // Users who want PC speaker sound always have to select this individually for all
+ // Kyra games.
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB | ((_flags.gameID == GI_KYRA2 || _flags.gameID == GI_LOL) ? MDT_PREFER_GM : MDT_PREFER_MT32));
if (_flags.platform == Common::kPlatformFMTowns) {
if (_flags.gameID == GI_KYRA1)
@@ -275,7 +278,7 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag)
} else {
char savegameName[14];
sprintf(savegameName, "Quicksave %d", event.kbd.keycode - Common::KEYCODE_0);
- saveGameState(saveLoadSlot, savegameName, 0);
+ saveGameStateIntern(saveLoadSlot, savegameName, 0);
}
} else if (event.kbd.hasFlags(Common::KBD_CTRL)) {
if (event.kbd.keycode == Common::KEYCODE_d) {
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index d077d3a3b0..31c07336a6 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -37,6 +37,7 @@
#include "sound/mixer.h"
#include "kyra/script.h"
+#include "kyra/item.h"
namespace Common {
class SeekableReadStream;
@@ -93,7 +94,7 @@ class KyraMetaEngine;
* is pretty minor priority though, since the benefit would be mostly nicer code). The biggest
* task left is the kyra.dat handling, which is currently being revised by LordHoto.
*
- * Supported games:
+ * Games using this engine:
* - The Legend of Kyrandia (fully supported, except for Macintosh port, which lacks sound)
* - (The) Hand of Fate (fully supported)
* - Malcolm's Revenge (fully supported)
@@ -339,7 +340,7 @@ protected:
// items
int _mouseState;
- virtual void setHandItem(uint16 item) = 0;
+ virtual void setHandItem(Item item) = 0;
virtual void removeHandItem() = 0;
// game flags
@@ -414,8 +415,8 @@ protected:
void loadGameStateCheck(int slot);
virtual Common::Error loadGameState(int slot) = 0;
- Common::Error saveGameState(int slot, const char *saveName) { return saveGameState(slot, saveName, 0); }
- virtual Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail) = 0;
+ Common::Error saveGameState(int slot, const char *saveName) { return saveGameStateIntern(slot, saveName, 0); }
+ virtual Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) = 0;
Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header);
Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const;
diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h
index 6414040344..39c9f0875e 100644
--- a/engines/kyra/kyra_v2.h
+++ b/engines/kyra/kyra_v2.h
@@ -29,6 +29,7 @@
#include "kyra/kyra_v1.h"
#include "kyra/gui.h"
#include "kyra/wsamovie.h"
+#include "kyra/item.h"
#include "common/list.h"
#include "common/hashmap.h"
@@ -41,7 +42,7 @@ struct FrameControl {
};
struct ItemAnimData_v2 {
- int16 itemIndex;
+ Item itemIndex;
uint8 numFrames;
const FrameControl *frames;
};
@@ -69,7 +70,7 @@ public:
int animScriptFrameAdd;
// Item specific
- int maxItemId;
+ Item maxItemId;
};
KyraEngine_v2(OSystem *system, const GameFlags &flags, const EngineDesc &desc);
@@ -286,8 +287,8 @@ protected:
int _pathfinderPositionIndexTable[200];
// items
- struct Item {
- uint16 id;
+ struct ItemDefinition {
+ Item id;
uint16 sceneId;
int16 x;
uint8 y;
@@ -295,25 +296,26 @@ protected:
void initItemList(int size);
- uint16 _hiddenItems[100];
+ Item _hiddenItems[100];
- Item *_itemList;
+ ItemDefinition *_itemList;
int _itemListSize;
int _itemInHand;
+ int _savedMouseState;
int findFreeItem();
int countAllItems();
- int findItem(uint16 sceneId, uint16 id);
- int findItem(uint16 item);
+ int findItem(uint16 sceneId, Item id);
+ int findItem(Item item);
void resetItemList();
void resetItem(int index);
- virtual void setMouseCursor(uint16 item) = 0;
+ virtual void setMouseCursor(Item item) = 0;
- void setHandItem(uint16 item);
+ void setHandItem(Item item);
void removeHandItem();
// character
@@ -324,7 +326,7 @@ protected:
uint8 facing;
uint16 animFrame;
byte walkspeed;
- uint16 inventory[20];
+ Item inventory[20];
int16 x1, y1;
int16 x2, y2;
int16 x3, y3;
@@ -360,7 +362,7 @@ protected:
virtual void randomSceneChat() = 0;
// unknown
- int _unk3, _unk4, _unk5;
+ int _unk4, _unk5;
bool _unkSceneScreenFlag1;
bool _unkHandleSceneChangeFlag;
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index 03d52ec4ac..f6ac8a1a73 100644
--- a/engines/kyra/lol.cpp
+++ b/engines/kyra/lol.cpp
@@ -1930,11 +1930,11 @@ int LoLEngine::playCharacterScriptChat(int charId, int mode, int restorePortrait
return 1;
}
-void LoLEngine::giveItemToMonster(MonsterInPlay *monster, uint16 item) {
+void LoLEngine::giveItemToMonster(MonsterInPlay *monster, Item item) {
uint16 *c = &monster->assignedItems;
while (*c)
c = &_itemsInPlay[*c].nextAssignedObject;
- *c = item;
+ *c = (uint16)item;
_itemsInPlay[item].nextAssignedObject = 0;
}
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
index 57c127a94f..f2c93f83fc 100644
--- a/engines/kyra/lol.h
+++ b/engines/kyra/lol.h
@@ -225,7 +225,7 @@ struct FlyingObject {
uint8 enable;
uint8 objectType;
uint16 attackerId;
- uint16 item;
+ Item item;
uint16 x;
uint16 y;
uint8 flyingHeight;
@@ -1202,19 +1202,19 @@ private:
// items
void giveCredits(int credits, int redraw);
void takeCredits(int credits, int redraw);
- int makeItem(int itemType, int curFrame, int flags);
- void placeMoveLevelItem(int itemIndex, int level, int block, int xOffs, int yOffs, int flyingHeight);
- bool addItemToInventory(int itemIndex);
- bool testUnkItemFlags(int itemIndex);
- void deleteItem(int itemIndex);
+ Item makeItem(int itemType, int curFrame, int flags);
+ void placeMoveLevelItem(Item itemIndex, int level, int block, int xOffs, int yOffs, int flyingHeight);
+ bool addItemToInventory(Item itemIndex);
+ bool testUnkItemFlags(Item itemIndex);
+ void deleteItem(Item itemIndex);
ItemInPlay *findObject(uint16 index);
- void runItemScript(int charNum, int item, int flags, int next, int reg4);
- void setHandItem(uint16 itemIndex);
+ void runItemScript(int charNum, Item item, int flags, int next, int reg4);
+ void setHandItem(Item itemIndex);
bool itemEquipped(int charNum, uint16 itemType);
- void setItemPosition(int item, uint16 x, uint16 y, int flyingHeight, int b);
- void removeLevelItem(int item, int block);
- bool launchObject(int objectType, int item, int startX, int startY, int flyingHeight, int direction, int, int attackerId, int c);
+ void setItemPosition(Item item, uint16 x, uint16 y, int flyingHeight, int b);
+ void removeLevelItem(Item item, int block);
+ bool launchObject(int objectType, Item item, int startX, int startY, int flyingHeight, int direction, int, int attackerId, int c);
void endObjectFlight(FlyingObject *t, int x, int y, int objectOnNextBlock);
void processObjectFlight(FlyingObject *t, int x, int y);
void updateObjectFlightPosition(FlyingObject *t);
@@ -1231,9 +1231,9 @@ private:
ItemInPlay *_itemsInPlay;
ItemProperty *_itemProperties;
- int _itemInHand;
- uint16 _inventory[48];
- int _inventoryCurItem;
+ Item _itemInHand;
+ Item _inventory[48];
+ Item _inventoryCurItem;
int _currentControlMode;
int _specialSceneFlag;
int _lastCharInventory;
@@ -1269,10 +1269,10 @@ private:
int calcMonsterDirection(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
void setMonsterDirection(MonsterInPlay *monster, int dir);
void monsterDropItems(MonsterInPlay *monster);
- void removeAssignedObjectFromBlock(LevelBlockProperty *l, int id);
- void removeDrawObjectFromBlock(LevelBlockProperty *l, int id);
- void assignMonsterToBlock(uint16 *assignedBlockObjects, int id);
- void giveItemToMonster(MonsterInPlay *monster, uint16 item);
+ void removeAssignedObjectFromBlock(LevelBlockProperty *l, uint16 id);
+ void removeDrawObjectFromBlock(LevelBlockProperty *l, uint16 id);
+ void assignMonsterToBlock(uint16 *assignedBlockObjects, uint16 id);
+ void giveItemToMonster(MonsterInPlay *monster, Item item);
int checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 objectWidth, uint16 testFlag, uint16 wallFlag);
int checkBlockForWallsAndSufficientSpace(int block, int x, int y, int objectWidth, int testFlag, int wallFlag);
int calcMonsterSkillLevel(int id, int a);
@@ -1488,7 +1488,7 @@ private:
// save
Common::Error loadGameState(int slot);
- Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail);
+ Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail);
Graphics::Surface *generateSaveThumbnail() const;
diff --git a/engines/kyra/resource_intern.cpp b/engines/kyra/resource_intern.cpp
index 445ea579a0..dff8759d55 100644
--- a/engines/kyra/resource_intern.cpp
+++ b/engines/kyra/resource_intern.cpp
@@ -102,7 +102,7 @@ int TlkArchive::listMembers(Common::ArchiveMemberList &list) {
uint count = 0;
for (; count < _entryCount; ++count) {
- const Common::String name = Common::String::printf("%08u.AUD", _fileEntries[count * 2 + 0]);
+ const Common::String name = Common::String::format("%08u.AUD", _fileEntries[count * 2 + 0]);
list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(name, this)));
}
diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp
index 3ad7093046..c5658c0445 100644
--- a/engines/kyra/saveload.cpp
+++ b/engines/kyra/saveload.cpp
@@ -230,7 +230,7 @@ const char *KyraEngine_v1::getSavegameFilename(int num) {
Common::String KyraEngine_v1::getSavegameFilename(const Common::String &target, int num) {
assert(num >= 0 && num <= 999);
- return target + Common::String::printf(".%03d", num);
+ return target + Common::String::format(".%03d", num);
}
bool KyraEngine_v1::saveFileLoadable(int slot) {
@@ -250,7 +250,7 @@ bool KyraEngine_v1::saveFileLoadable(int slot) {
void KyraEngine_v1::checkAutosave() {
if (shouldPerformAutoSave(_lastAutosave)) {
- saveGameState(999, "Autosave", 0);
+ saveGameStateIntern(999, "Autosave", 0);
_lastAutosave = _system->getMillis();
}
}
diff --git a/engines/kyra/saveload_hof.cpp b/engines/kyra/saveload_hof.cpp
index 2d276cc6a4..e957718f95 100644
--- a/engines/kyra/saveload_hof.cpp
+++ b/engines/kyra/saveload_hof.cpp
@@ -35,7 +35,7 @@
namespace Kyra {
-Common::Error KyraEngine_HoF::saveGameState(int slot, const char *saveName, const Graphics::Surface *thumb) {
+Common::Error KyraEngine_HoF::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumb) {
const char *fileName = getSavegameFilename(slot);
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);
@@ -64,7 +64,7 @@ Common::Error KyraEngine_HoF::saveGameState(int slot, const char *saveName, cons
for (int i = 0; i < 25; ++i)
out->writeSint16BE(_cauldronTable[i]);
for (int i = 0; i < 20; ++i)
- out->writeUint16BE(_hiddenItems[i]);
+ out->writeSint16BE(_hiddenItems[i]);
for (int i = 0; i < 19; ++i)
out->write(_conversationState[i], 14);
out->write(_newSceneDlgState, 32);
@@ -83,7 +83,7 @@ Common::Error KyraEngine_HoF::saveGameState(int slot, const char *saveName, cons
out->writeSint16BE(_mainCharacter.y2);
for (int i = 0; i < 30; ++i) {
- out->writeUint16BE(_itemList[i].id);
+ out->writeSint16BE(_itemList[i].id);
out->writeUint16BE(_itemList[i].sceneId);
out->writeSint16BE(_itemList[i].x);
out->writeByte(_itemList[i].y);
@@ -183,7 +183,7 @@ Common::Error KyraEngine_HoF::loadGameState(int slot) {
for (int i = 0; i < 25; ++i)
_cauldronTable[i] = in.readSint16();
for (int i = 0; i < 20; ++i)
- _hiddenItems[i] = in.readUint16();
+ _hiddenItems[i] = in.readSint16();
if (header.originalSave) {
assert(sizeof(_flagsTable) >= 0x41);
@@ -222,7 +222,7 @@ Common::Error KyraEngine_HoF::loadGameState(int slot) {
_mainCharacter.y2 = in.readSint16();
for (int i = 0; i < 30; ++i) {
- _itemList[i].id = in.readUint16();
+ _itemList[i].id = in.readSint16();
_itemList[i].sceneId = in.readUint16();
_itemList[i].x = in.readSint16();
_itemList[i].y = in.readByte();
diff --git a/engines/kyra/saveload_lok.cpp b/engines/kyra/saveload_lok.cpp
index 1a61f9a962..3e11d3dad3 100644
--- a/engines/kyra/saveload_lok.cpp
+++ b/engines/kyra/saveload_lok.cpp
@@ -80,7 +80,7 @@ Common::Error KyraEngine_LoK::loadGameState(int slot) {
}
_marbleVaseItem = in->readSint16BE();
- _itemInHand = in->readByte();
+ _itemInHand = (int8)in->readByte();
for (int i = 0; i < 4; ++i)
_birthstoneGemTable[i] = in->readByte();
@@ -109,7 +109,7 @@ Common::Error KyraEngine_LoK::loadGameState(int slot) {
for (int i = 0; i < _roomTableSize; ++i) {
for (int item = 0; item < 12; ++item) {
- _roomTable[i].itemsTable[item] = 0xFF;
+ _roomTable[i].itemsTable[item] = kItemNone;
_roomTable[i].itemsXPos[item] = 0xFFFF;
_roomTable[i].itemsYPos[item] = 0xFF;
_roomTable[i].needInit[item] = 0;
@@ -241,7 +241,7 @@ Common::Error KyraEngine_LoK::loadGameState(int slot) {
return Common::kNoError;
}
-Common::Error KyraEngine_LoK::saveGameState(int slot, const char *saveName, const Graphics::Surface *thumb) {
+Common::Error KyraEngine_LoK::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumb) {
const char *fileName = getSavegameFilename(slot);
if (shouldQuit())
diff --git a/engines/kyra/saveload_lol.cpp b/engines/kyra/saveload_lol.cpp
index 480714e5c9..aee24957a0 100644
--- a/engines/kyra/saveload_lol.cpp
+++ b/engines/kyra/saveload_lol.cpp
@@ -117,7 +117,7 @@ Common::Error LoLEngine::loadGameState(int slot) {
_selectedCharacter = in.readSByte();
_currentLevel = in.readByte();
for (int i = 0; i < 48; i++)
- _inventory[i] = in.readUint16BE();
+ _inventory[i] = in.readSint16BE();
_inventoryCurItem = in.readSint16BE();
_itemInHand = in.readSint16BE();
_lastMouseRegion = in.readSint16BE();
@@ -243,7 +243,7 @@ Common::Error LoLEngine::loadGameState(int slot) {
m->enable = in.readByte();
m->objectType = in.readByte();
m->attackerId = in.readUint16BE();
- m->item = in.readUint16BE();
+ m->item = in.readSint16BE();
m->x = in.readUint16BE();
m->y = in.readUint16BE();
m->flyingHeight = in.readByte();
@@ -274,7 +274,7 @@ Common::Error LoLEngine::loadGameState(int slot) {
return Common::kNoError;
}
-Common::Error LoLEngine::saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail) {
+Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) {
const char *fileName = getSavegameFilename(slot);
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumbnail);
@@ -340,7 +340,7 @@ Common::Error LoLEngine::saveGameState(int slot, const char *saveName, const Gra
out->writeSByte(_selectedCharacter);
out->writeByte(_currentLevel);
for (int i = 0; i < 48; i++)
- out->writeUint16BE(_inventory[i]);
+ out->writeSint16BE(_inventory[i]);
out->writeSint16BE(_inventoryCurItem);
out->writeSint16BE(_itemInHand);
out->writeSint16BE(_lastMouseRegion);
@@ -423,7 +423,7 @@ Common::Error LoLEngine::saveGameState(int slot, const char *saveName, const Gra
out->writeByte(m->enable);
out->writeByte(m->objectType);
out->writeUint16BE(m->attackerId);
- out->writeUint16BE(m->item);
+ out->writeSint16BE(m->item);
out->writeUint16BE(m->x);
out->writeUint16BE(m->y);
out->writeByte(m->flyingHeight);
diff --git a/engines/kyra/saveload_mr.cpp b/engines/kyra/saveload_mr.cpp
index 737c83c33d..80c9b2b83c 100644
--- a/engines/kyra/saveload_mr.cpp
+++ b/engines/kyra/saveload_mr.cpp
@@ -32,7 +32,7 @@
namespace Kyra {
-Common::Error KyraEngine_MR::saveGameState(int slot, const char *saveName, const Graphics::Surface *thumb) {
+Common::Error KyraEngine_MR::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumb) {
const char *fileName = getSavegameFilename(slot);
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);
@@ -55,7 +55,7 @@ Common::Error KyraEngine_MR::saveGameState(int slot, const char *saveName, const
out->write(_conversationState[i], 30);
out->write(_newSceneDlgState, 40);
for (int i = 0; i < 100; ++i)
- out->writeUint16BE(_hiddenItems[i]);
+ out->writeSint16BE(_hiddenItems[i]);
out->write(_scoreFlagTable, 26);
out->writeUint16BE(_mainCharacter.sceneId);
@@ -74,7 +74,7 @@ Common::Error KyraEngine_MR::saveGameState(int slot, const char *saveName, const
out->writeSint16BE(_mainCharacter.y3);
for (int i = 0; i < 50; ++i) {
- out->writeUint16BE(_itemList[i].id);
+ out->writeSint16BE(_itemList[i].id);
out->writeUint16BE(_itemList[i].sceneId);
out->writeSint16BE(_itemList[i].x);
out->writeSint16BE(_itemList[i].y);
@@ -189,7 +189,7 @@ Common::Error KyraEngine_MR::loadGameState(int slot) {
}
for (int i = 0; i < 100; ++i)
- _hiddenItems[i] = in.readUint16();
+ _hiddenItems[i] = in.readSint16();
if (header.originalSave)
in.read(_flagsTable, 69);
@@ -216,7 +216,7 @@ Common::Error KyraEngine_MR::loadGameState(int slot) {
_mainCharacter.y3 = in.readSint16();
for (int i = 0; i < 50; ++i) {
- _itemList[i].id = in.readUint16();
+ _itemList[i].id = in.readSint16();
_itemList[i].sceneId = in.readUint16();
_itemList[i].x = in.readSint16();
_itemList[i].y = in.readSint16();
diff --git a/engines/kyra/scene_hof.cpp b/engines/kyra/scene_hof.cpp
index 4559554d77..79827361a3 100644
--- a/engines/kyra/scene_hof.cpp
+++ b/engines/kyra/scene_hof.cpp
@@ -241,7 +241,7 @@ void KyraEngine_HoF::enterNewSceneUnk1(int facing, int unk1, int unk2) {
}
void KyraEngine_HoF::enterNewSceneUnk2(int unk1) {
- _unk3 = -1;
+ _savedMouseState = -1;
if (_flags.isTalkie) {
if (_mainCharX == -1 && _mainCharY == -1 && _mainCharacter.sceneId != 61 &&
@@ -265,7 +265,7 @@ void KyraEngine_HoF::enterNewSceneUnk2(int unk1) {
}
_unk4 = 0;
- _unk3 = -1;
+ _savedMouseState = -1;
}
int KyraEngine_HoF::trySceneChange(int *moveTable, int unk1, int updateChar) {
@@ -339,16 +339,16 @@ int KyraEngine_HoF::checkSceneChange() {
int facing = 0;
int process = 0;
- if (_screen->getLayer(charX, charY) == 1 && _unk3 == -6) {
+ if (_screen->getLayer(charX, charY) == 1 && _savedMouseState == -6) {
facing = 0;
process = 1;
- } else if (charX >= 316 && _unk3 == -5) {
+ } else if (charX >= 316 && _savedMouseState == -5) {
facing = 2;
process = 1;
- } else if (charY >= 142 && _unk3 == -4) {
+ } else if (charY >= 142 && _savedMouseState == -4) {
facing = 4;
process = 1;
- } else if (charX <= 4 && _unk3 == -3) {
+ } else if (charX <= 4 && _savedMouseState == -3) {
facing = 6;
process = 1;
}
diff --git a/engines/kyra/scene_lok.cpp b/engines/kyra/scene_lok.cpp
index f71c3bd756..f7ada5d623 100644
--- a/engines/kyra/scene_lok.cpp
+++ b/engines/kyra/scene_lok.cpp
@@ -824,13 +824,14 @@ void KyraEngine_LoK::initSceneScreen(int brandonAlive) {
_emc->run(&_scriptClick);
setTextFadeTimerCountdown(-1);
+
if (_currentCharacter->sceneId == 210) {
- if (_itemInHand != -1)
+ if (_itemInHand != kItemNone)
magicOutMouseItem(2, -1);
_screen->hideMouse();
for (int i = 0; i < 10; ++i) {
- if (_currentCharacter->inventoryItems[i] != 0xFF)
+ if (_currentCharacter->inventoryItems[i] != kItemNone)
magicOutMouseItem(2, i);
}
_screen->showMouse();
diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp
index bf3320486a..e070b91a44 100644
--- a/engines/kyra/scene_lol.cpp
+++ b/engines/kyra/scene_lol.cpp
@@ -1618,7 +1618,7 @@ void LoLEngine::generateBlockDrawingBuffer() {
_sceneDrawVarLeft = _dscBlockMap[_currentDirection + 8];
/*******************************************
- * _visibleBlocks map *
+ * _visibleBlocks map *
* *
* | | | | | | *
* 00 | 01 | 02 | 03 | 04 | 05 | 06 *
diff --git a/engines/kyra/scene_mr.cpp b/engines/kyra/scene_mr.cpp
index bd0a1fe544..f1ea79f49b 100644
--- a/engines/kyra/scene_mr.cpp
+++ b/engines/kyra/scene_mr.cpp
@@ -176,8 +176,8 @@ void KyraEngine_MR::enterNewScene(uint16 sceneId, int facing, int unk1, int unk2
setNextIdleAnimTimer();
if (_itemInHand < 0) {
- _itemInHand = -1;
- _mouseState = -1;
+ _itemInHand = kItemNone;
+ _mouseState = kItemNone;
_screen->setMouseCursor(0, 0, _gameShapes[0]);
}
@@ -287,7 +287,7 @@ void KyraEngine_MR::enterNewSceneUnk1(int facing, int unk1, int unk2) {
}
void KyraEngine_MR::enterNewSceneUnk2(int unk1) {
- _unk3 = -1;
+ _savedMouseState = -1;
if (_mainCharX == -1 && _mainCharY == -1 && !unk1) {
_mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
updateCharacterAnim(0);
@@ -300,7 +300,7 @@ void KyraEngine_MR::enterNewSceneUnk2(int unk1) {
}
_unk4 = 0;
- _unk3 = -1;
+ _savedMouseState = -1;
}
void KyraEngine_MR::unloadScene() {
@@ -556,8 +556,8 @@ void KyraEngine_MR::initSceneAnims(int unk1) {
for (int i = 0; i < 50; ++i) {
obj = &_animObjects[i+17];
- const Item &item = _itemList[i];
- if (item.id != 0xFFFF && item.sceneId == _mainCharacter.sceneId) {
+ const ItemDefinition &item = _itemList[i];
+ if (item.id != kItemNone && item.sceneId == _mainCharacter.sceneId) {
obj->xPos1 = item.x;
obj->yPos1 = item.y;
animSetupPaletteEntry(obj);
@@ -696,16 +696,16 @@ int KyraEngine_MR::checkSceneChange() {
int facing = 0;
int process = 0;
- if (_screen->getLayer(charX, charY) == 1 && _unk3 == -7) {
+ if (_screen->getLayer(charX, charY) == 1 && _savedMouseState == -7) {
facing = 0;
process = 1;
- } else if (charX >= 316 && _unk3 == -6) {
+ } else if (charX >= 316 && _savedMouseState == -6) {
facing = 2;
process = 1;
- } else if (charY >= 186 && _unk3 == -5) {
+ } else if (charY >= 186 && _savedMouseState == -5) {
facing = 4;
process = 1;
- } else if (charX <= 4 && _unk3 == -4) {
+ } else if (charX <= 4 && _savedMouseState == -4) {
facing = 6;
process = 1;
}
@@ -742,7 +742,7 @@ int KyraEngine_MR::checkSceneChange() {
return 1;
}
int KyraEngine_MR::runSceneScript1(int x, int y) {
- if (y > 187 && _unk3 > -4)
+ if (y > 187 && _savedMouseState > -4)
return 0;
if (_deathHandler >= 0)
return 0;
diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp
index b7e01f31aa..8b0a87f0c8 100644
--- a/engines/kyra/screen.cpp
+++ b/engines/kyra/screen.cpp
@@ -3313,7 +3313,7 @@ SJISFont::SJISFont(Screen *s, Graphics::FontSJIS *font, const uint8 invisColor,
: _colorMap(0), _font(font), _invisColor(invisColor), _is16Color(is16Color), _screen(s) {
assert(_font);
- _font->enableOutline(outlineSize);
+ _font->setDrawingMode(outlineSize ? Graphics::FontSJIS::kOutlineMode : Graphics::FontSJIS::kDefaultMode);
_sjisWidth = _font->getMaxFontWidth() >> 1;
_fontHeight = _font->getFontHeight() >> 1;
@@ -3345,9 +3345,9 @@ void SJISFont::setColorMap(const uint8 *src) {
if (!_is16Color) {
if (_colorMap[0] == _invisColor)
- _font->enableOutline(false);
+ _font->setDrawingMode(Graphics::FontSJIS::kDefaultMode);
else
- _font->enableOutline(true);
+ _font->setDrawingMode(Graphics::FontSJIS::kOutlineMode);
}
}
diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h
index 654b7da6b7..e35b9b37b2 100644
--- a/engines/kyra/screen.h
+++ b/engines/kyra/screen.h
@@ -423,6 +423,7 @@ public:
virtual void setScreenDim(int dim) = 0;
virtual const ScreenDim *getScreenDim(int dim) = 0;
+ virtual int screenDimTableCount() const = 0;
const ScreenDim *_curDim;
diff --git a/engines/kyra/screen_hof.h b/engines/kyra/screen_hof.h
index 1c17a424b3..5117716ac0 100644
--- a/engines/kyra/screen_hof.h
+++ b/engines/kyra/screen_hof.h
@@ -39,6 +39,7 @@ public:
void setScreenDim(int dim);
const ScreenDim *getScreenDim(int dim);
+ int screenDimTableCount() const { return _screenDimTableCount; }
// sequence player
void generateGrayOverlay(const Palette &pal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag);
diff --git a/engines/kyra/screen_lok.h b/engines/kyra/screen_lok.h
index 2a5ef7e12e..0d30c35bfd 100644
--- a/engines/kyra/screen_lok.h
+++ b/engines/kyra/screen_lok.h
@@ -43,6 +43,7 @@ public:
void setScreenDim(int dim);
const ScreenDim *getScreenDim(int dim);
+ int screenDimTableCount() const { return _screenDimTableCount; }
void setTextColorMap(const uint8 *cmap);
diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h
index 52e66df1ec..9f4d751d0c 100644
--- a/engines/kyra/screen_lol.h
+++ b/engines/kyra/screen_lol.h
@@ -43,8 +43,9 @@ public:
void setScreenDim(int dim);
const ScreenDim *getScreenDim(int dim);
- int curDimIndex() { return _curDimIndex; }
+ int curDimIndex() const { return _curDimIndex; }
void modifyScreenDim(int dim, int x, int y, int w, int h);
+ int screenDimTableCount() const { return _screenDimTableCount; }
void fprintString(const char *format, int x, int y, uint8 col1, uint8 col2, uint16 flags, ...) GCC_PRINTF(2, 8);
void fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...) GCC_PRINTF(2, 9);
diff --git a/engines/kyra/screen_mr.h b/engines/kyra/screen_mr.h
index 4107003b12..c02fc4bfb2 100644
--- a/engines/kyra/screen_mr.h
+++ b/engines/kyra/screen_mr.h
@@ -39,6 +39,7 @@ public:
void setScreenDim(int dim);
const ScreenDim *getScreenDim(int dim);
+ int screenDimTableCount() const { return _screenDimTableCount; }
int getLayer(int x, int y);
diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp
index 4d90bf2bab..9c224d1562 100644
--- a/engines/kyra/screen_v2.cpp
+++ b/engines/kyra/screen_v2.cpp
@@ -187,16 +187,22 @@ uint8 *Screen_v2::getPtrToShape(uint8 *shpFile, int shape) {
}
int Screen_v2::getShapeScaledWidth(const uint8 *shpFile, int scale) {
+ if (!shpFile)
+ return 0;
int width = READ_LE_UINT16(shpFile+3);
return (width * scale) >> 8;
}
int Screen_v2::getShapeScaledHeight(const uint8 *shpFile, int scale) {
+ if (!shpFile)
+ return 0;
int height = shpFile[2];
return (height * scale) >> 8;
}
uint16 Screen_v2::getShapeSize(const uint8 *shp) {
+ if (!shp)
+ return 0;
return READ_LE_UINT16(shp+6);
}
diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp
index f30f5787e7..d57bb7efc5 100644
--- a/engines/kyra/script_hof.cpp
+++ b/engines/kyra/script_hof.cpp
@@ -410,7 +410,7 @@ int KyraEngine_HoF::o2_countItemsInScene(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_countItemsInScene(%p) (%d)", (const void *)script, stackPos(0));
int count = 0;
for (int i = 0; i < 30; ++i) {
- if (_itemList[i].sceneId == stackPos(0) && _itemList[i].id != 0xFFFF)
+ if (_itemList[i].sceneId == stackPos(0) && _itemList[i].id != kItemNone)
++count;
}
return count;
@@ -1039,7 +1039,7 @@ int KyraEngine_HoF::o2_setColorCodeValue(EMCState *script) {
int KyraEngine_HoF::o2_countItemInstances(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_countItemInstances(%p) (%d)", (const void *)script, stackPos(0));
- uint16 item = stackPos(0);
+ Item item = stackPos(0);
int count = 0;
for (int i = 0; i < 20; ++i) {
@@ -1047,7 +1047,7 @@ int KyraEngine_HoF::o2_countItemInstances(EMCState *script) {
++count;
}
- if (_itemInHand == int16(item))
+ if (_itemInHand == item)
++count;
for (int i = 0; i < 30; ++i) {
@@ -1075,7 +1075,7 @@ int KyraEngine_HoF::o2_removeItemFromScene(EMCState *script) {
const uint16 item = stackPos(1);
for (int i = 0; i < 30; ++i) {
if (_itemList[i].sceneId == scene && _itemList[i].id == item)
- _itemList[i].id = 0xFFFF;
+ _itemList[i].id = kItemNone;
}
return 0;
}
diff --git a/engines/kyra/script_lok.cpp b/engines/kyra/script_lok.cpp
index 1b4a11f793..a2bad8035e 100644
--- a/engines/kyra/script_lok.cpp
+++ b/engines/kyra/script_lok.cpp
@@ -37,6 +37,7 @@
#include "kyra/sound.h"
namespace Kyra {
+
int KyraEngine_LoK::o1_magicInMouseItem(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_magicInMouseItem(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
magicInMouseItem(stackPos(0), stackPos(1), -1);
@@ -203,9 +204,7 @@ int KyraEngine_LoK::o1_getElapsedSeconds(EMCState *script) {
int KyraEngine_LoK::o1_mouseIsPointer(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_mouseIsPointer(%p) ()", (const void *)script);
- if (_itemInHand == -1)
- return 1;
- return 0;
+ return (_itemInHand == kItemNone);
}
int KyraEngine_LoK::o1_runSceneAnimUntilDone(EMCState *script) {
diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp
index 1034e86d4e..33fa16a22c 100644
--- a/engines/kyra/script_lol.cpp
+++ b/engines/kyra/script_lol.cpp
@@ -267,6 +267,12 @@ int LoLEngine::olol_setItemProperty(EMCState *script) {
tmp->nameStringId = stackPos(1);
tmp->shpIndex = stackPos(2);
tmp->type = stackPos(3);
+
+ // WORKAROUND for unpatched early floppy versions.
+ // The Vaelan's cube should not be able to be equipped in a weapon slot.
+ if (stackPos(0) == 264 && tmp->type == 5)
+ tmp->type = 0;
+
tmp->itemScriptFunc = stackPos(4);
tmp->might = stackPos(5);
tmp->skill = stackPos(6);
@@ -1065,6 +1071,7 @@ int LoLEngine::olol_createHandItem(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_createHandItem(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
if (_itemInHand)
return 0;
+
setHandItem(makeItem(stackPos(0), stackPos(1), stackPos(2)));
return 1;
}
diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp
index ae125b5b99..a9637a6378 100644
--- a/engines/kyra/script_mr.cpp
+++ b/engines/kyra/script_mr.cpp
@@ -216,7 +216,7 @@ int KyraEngine_MR::o3_removeInventoryItemInstances(EMCState *script) {
const int item = stackPos(0);
for (int i = 0; i < 10; ++i) {
if (_mainCharacter.inventory[i] == item)
- _mainCharacter.inventory[i] = 0xFFFF;
+ _mainCharacter.inventory[i] = kItemNone;
}
return 0;
}
@@ -293,7 +293,7 @@ int KyraEngine_MR::o3_updateScore(EMCState *script) {
int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script);
- saveGameState(999, "Autosave", 0);
+ saveGameStateIntern(999, "Autosave", 0);
return 0;
}
@@ -594,7 +594,7 @@ int KyraEngine_MR::o3_updateConversations(EMCState *script) {
int KyraEngine_MR::o3_removeItemSlot(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeItemSlot(%p) (%d)", (const void *)script, stackPos(0));
deleteItemAnimEntry(stackPos(0));
- _itemList[stackPos(0)].id = 0xFFFF;
+ _itemList[stackPos(0)].id = kItemNone;
return 1;
}
@@ -642,7 +642,7 @@ int KyraEngine_MR::o3_removeItemInstances(EMCState *script) {
for (int i = 0; i < 10; ++i) {
if (_mainCharacter.inventory[i] == item) {
- _mainCharacter.inventory[i] = 0xFFFF;
+ _mainCharacter.inventory[i] = kItemNone;
++deleted;
}
}
@@ -654,7 +654,7 @@ int KyraEngine_MR::o3_removeItemInstances(EMCState *script) {
for (int i = 0; i < 50; ++i) {
if (_itemList[i].id == item) {
- _itemList[i].id = 0xFFFF;
+ _itemList[i].id = kItemNone;
++deleted;
}
}
diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp
index 61916b92c0..30291c67db 100644
--- a/engines/kyra/script_tim.cpp
+++ b/engines/kyra/script_tim.cpp
@@ -946,7 +946,7 @@ int TIMInterpreter_LoL::initAnimStruct(int index, const char *filename, int x, i
}
}
- if (wsaFlags & 7)
+ if (wsa && (wsaFlags & 7))
wsa->displayFrame(0, 0, x, y, 0, 0, 0);
if (wsaFlags & 3) {
diff --git a/engines/kyra/script_v2.cpp b/engines/kyra/script_v2.cpp
index 01f058c383..17e882398e 100644
--- a/engines/kyra/script_v2.cpp
+++ b/engines/kyra/script_v2.cpp
@@ -69,7 +69,7 @@ int KyraEngine_v2::o2_trySceneChange(EMCState *script) {
if (success) {
_emc->init(script, script->dataPtr);
_unk4 = 0;
- _unk3 = -1;
+ _savedMouseState = -1;
_unk5 = 1;
return 0;
} else {
diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index 0a3e13bb26..e92866490b 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -2002,7 +2002,7 @@ void KyraEngine_HoF::seq_processText() {
outputStr[linePos] = *srcStr;
srcStr++;
}
- outputStr[linePos] = 0;
+ outputStr[linePos] = 0;
if (*srcStr == 0x0d)
srcStr++;
@@ -2130,7 +2130,7 @@ void KyraEngine_HoF::seq_cmpFadeFrame(const char *cmpFile) {
_screen->cmpFadeFrameStep(4, 320, 200, 0, 0, 2, 320, 200, 0, 0, 320, 200, 6);
_screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
_screen->updateScreen();
- delayUntil(endtime);
+ delayUntil(endtime);
}
_screen->copyPage(4, 0);
diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp
index ac9148e607..e8ea7a9dcb 100644
--- a/engines/kyra/sequences_lol.cpp
+++ b/engines/kyra/sequences_lol.cpp
@@ -1435,7 +1435,7 @@ void LoLEngine::processCredits(char *t, int dimState, int page, int delayTime) {
if (monsterAnimFrame >= 8)
_screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 22) ? 0 : 1);
- _screen->drawShape(page, monsterShape, monsterX, monsterY, 0, 0x104 | ((!isRightMonster | (monsterAnimFrame < 20)) ? 0 : 1), _outroShapeTable, 1, _outroMonsterScaleTableX[monsterAnimFrame], _outroMonsterScaleTableY[monsterAnimFrame]);
+ _screen->drawShape(page, monsterShape, monsterX, monsterY, 0, 0x104 | ((!isRightMonster || monsterAnimFrame < 20) ? 0 : 1), _outroShapeTable, 1, _outroMonsterScaleTableX[monsterAnimFrame], _outroMonsterScaleTableY[monsterAnimFrame]);
if (monsterAnimFrame < 8)
_screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 22) ? 0 : 1);
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index 3b0fbbed0a..8b83796d46 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -94,7 +94,7 @@ public:
* @param track track number
* @return true if available, false otherwise
*/
- virtual bool hasSoundFile(uint file) { return (fileListEntry(file) != 0); }
+ virtual bool hasSoundFile(uint file) const { return (fileListEntry(file) != 0); }
/**
* Load a specifc sound file for use of
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index 8458d751de..a45972ece7 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -2304,7 +2304,7 @@ void SoundAdLibPC::haltTrack() {
//_vm->_system->delayMillis(3 * 60);
}
-bool SoundAdLibPC::isPlaying() {
+bool SoundAdLibPC::isPlaying() const {
return _driver->callback(7, int(0)) != 0;
}
diff --git a/engines/kyra/sound_adlib.h b/engines/kyra/sound_adlib.h
index 0607e1dd7a..aaca1b9138 100644
--- a/engines/kyra/sound_adlib.h
+++ b/engines/kyra/sound_adlib.h
@@ -76,7 +76,7 @@ public:
void playTrack(uint8 track);
void haltTrack();
- bool isPlaying();
+ bool isPlaying() const;
void playSoundEffect(uint8 track);
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index f8738bc791..bc1c2be1e2 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -68,7 +68,7 @@ public:
void playTrack(uint8 track);
void haltTrack();
- bool isPlaying();
+ bool isPlaying() const;
void playSoundEffect(uint8 track);
void stopAllSoundEffects();
diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp
index c24ce5a95b..8982c1cca4 100644
--- a/engines/kyra/sound_midi.cpp
+++ b/engines/kyra/sound_midi.cpp
@@ -683,7 +683,7 @@ void SoundMidiPC::haltTrack() {
_output->deinitSource(0);
}
-bool SoundMidiPC::isPlaying() {
+bool SoundMidiPC::isPlaying() const {
Common::StackLock lock(_mutex);
return _music->isPlaying();
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 86a1eb228e..487f5e8128 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -85,8 +85,8 @@ void SoundTowns::playTrack(uint8 track) {
const int32 *const tTable = (const int32 *const)cdaData();
int tTableIndex = 3 * track;
- int trackNum = (int) READ_LE_UINT32(&tTable[tTableIndex + 2]);
- int32 loop = (int32) READ_LE_UINT32(&tTable[tTableIndex + 1]);
+ int trackNum = (int)READ_LE_UINT32(&tTable[tTableIndex + 2]);
+ int32 loop = (int32)READ_LE_UINT32(&tTable[tTableIndex + 1]);
if (track == _lastTrack && _musicEnabled)
return;
diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp
index 3b63618d6d..6245ecdd1f 100644
--- a/engines/kyra/sprites_lol.cpp
+++ b/engines/kyra/sprites_lol.cpp
@@ -350,7 +350,7 @@ void LoLEngine::monsterDropItems(MonsterInPlay *monster) {
}
}
-void LoLEngine::removeAssignedObjectFromBlock(LevelBlockProperty *l, int id) {
+void LoLEngine::removeAssignedObjectFromBlock(LevelBlockProperty *l, uint16 id) {
uint16 *blockItemIndex = &l->assignedObjects;
ItemInPlay *i = 0;
@@ -367,7 +367,7 @@ void LoLEngine::removeAssignedObjectFromBlock(LevelBlockProperty *l, int id) {
}
}
-void LoLEngine::removeDrawObjectFromBlock(LevelBlockProperty *l, int id) {
+void LoLEngine::removeDrawObjectFromBlock(LevelBlockProperty *l, uint16 id) {
uint16 *blockItemIndex = &l->drawObjects;
ItemInPlay *i = 0;
@@ -384,7 +384,7 @@ void LoLEngine::removeDrawObjectFromBlock(LevelBlockProperty *l, int id) {
}
}
-void LoLEngine::assignMonsterToBlock(uint16 *assignedBlockObjects, int id) {
+void LoLEngine::assignMonsterToBlock(uint16 *assignedBlockObjects, uint16 id) {
ItemInPlay *t = findObject(id);
t->nextAssignedObject = *assignedBlockObjects;
*assignedBlockObjects = id;
@@ -901,6 +901,9 @@ void LoLEngine::calcSpriteRelPosition(uint16 x1, uint16 y1, int &x2, int &y2, ui
}
void LoLEngine::drawDoor(uint8 *shape, uint8 *doorPalette, int index, int unk2, int w, int h, int flags) {
+ if (!shape)
+ return;
+
uint8 c = _dscDoor1[(_currentDirection << 5) + unk2];
int r = (c / 5) + 5 * _dscDimMap[index];
uint16 d = _dscShapeOvlIndex[r];
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index a06b488c86..fe4bd2ad71 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -42,7 +42,7 @@
namespace Kyra {
-#define RESFILE_VERSION 72
+#define RESFILE_VERSION 73
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
@@ -57,7 +57,7 @@ bool checkKyraDat(Common::SeekableReadStream *file) {
uint8 digestCalc[16];
file->seek(0, SEEK_SET);
- if (!Common::md5_file(*file, digestCalc, size))
+ if (!Common::computeStreamMD5(*file, digestCalc, size))
return false;
for (int i = 0; i < 16; ++i)
@@ -209,7 +209,7 @@ bool StaticResource::tryKyraDatLoad() {
return false;
// load the ID map for our game
- const Common::String filenamePattern = Common::String::printf("0%01X%01X%01X000%01X", game, platform, special, lang);
+ const Common::String filenamePattern = Common::String::format("0%01X%01X%01X000%01X", game, platform, special, lang);
Common::SeekableReadStream *idMap = _vm->resource()->createReadStream(filenamePattern);
if (!idMap)
return false;
@@ -328,7 +328,7 @@ bool StaticResource::prefetchId(int id) {
ResData data;
data.id = id;
data.type = dDesc->_value.type;
- Common::SeekableReadStream *fileStream = _vm->resource()->createReadStream(Common::String::printf("%08X", dDesc->_value.filename));
+ Common::SeekableReadStream *fileStream = _vm->resource()->createReadStream(Common::String::format("%08X", dDesc->_value.filename));
if (!fileStream)
return false;
@@ -912,16 +912,7 @@ void KyraEngine_LoK::loadItems() {
_shapes[216 + i] = _screen->encodeShape( (i % 20) * 16, i/20 * 16, 16, 16, 0);
}
- uint32 size;
- uint8 *fileData = _res->fileData("_ITEM_HT.DAT", &size);
- assert(fileData);
-
- for (int i = 0; i < 107; i++) {
- _itemTable[i].height = fileData[i];
- _itemTable[i].unk1 = _itemTable[i].unk2 = 0;
- }
-
- delete[] fileData;
+ _res->loadFileToBuf("_ITEM_HT.DAT", &_itemHtDat, sizeof(_itemHtDat));
}
void KyraEngine_LoK::loadButtonShapes() {
@@ -1866,9 +1857,9 @@ const uint8 KyraEngine_HoF::_cauldronStateTable[] = {
3, 3, 3, 3, 3, 3, 3
};
-const int16 KyraEngine_HoF::_flaskTable[] = {
+const Item KyraEngine_HoF::_flaskTable[] = {
0x19, 0x14, 0x15, 0x16, 0x17, 0x18, 0x34,
- 0x1B, 0x39, 0x1A, 0x3A, 0x4D, 0x72, -1
+ 0x1B, 0x39, 0x1A, 0x3A, 0x4D, 0x72, kItemNone
};
const uint8 KyraEngine_HoF::_rainbowRoomData[] = {
@@ -1964,10 +1955,10 @@ const uint8 KyraEngine_MR::_inventoryY[] = {
0xB2, 0xB2, 0xB2, 0xB2, 0xB2
};
-const uint8 KyraEngine_MR::_trashItemList[] = {
+const Item KyraEngine_MR::_trashItemList[] = {
0x1E, 0x1D, 0x1C, 0x1F, 0x0F, 0x05, 0x04, 0x00,
0x03, 0x22, 0x0B, 0x20, 0x21, 0x10, 0x11, 0x3A,
- 0x39, 0x40, 0x3E, 0x3D, 0x3C, 0x3F, 0xFF
+ 0x39, 0x40, 0x3E, 0x3D, 0x3C, 0x3F, kItemNone
};
const uint8 KyraEngine_MR::_itemStringPickUp[] = {
diff --git a/engines/kyra/text_lol.cpp b/engines/kyra/text_lol.cpp
index 7f9531507c..9f98586303 100644
--- a/engines/kyra/text_lol.cpp
+++ b/engines/kyra/text_lol.cpp
@@ -46,7 +46,9 @@ TextDisplayer_LoL::TextDisplayer_LoL(LoLEngine *vm, Screen_LoL *screen) : _vm(vm
_currentLine = new char[85];
memset(_currentLine, 0, 85);
- for (int i = 0; i < 14; i++){
+ _textDimData = new TextDimData[_screen->screenDimTableCount()];
+
+ for (int i = 0; i < _screen->screenDimTableCount(); i++){
const ScreenDim *d = _screen->getScreenDim(i);
_textDimData[i].color1 = d->unk8;
_textDimData[i].color2 = d->unkA;
@@ -59,6 +61,7 @@ TextDisplayer_LoL::~TextDisplayer_LoL() {
delete[] _buffer;
delete[] _dialogueBuffer;
delete[] _currentLine;
+ delete[] _textDimData;
}
void TextDisplayer_LoL::setupField(bool mode) {
@@ -185,6 +188,7 @@ void TextDisplayer_LoL::printDialogueText(int dim, char *str, EMCState *script,
} else {
oldDim = _screen->curDimIndex();
_screen->setScreenDim(dim);
+ _lineCount = 0;
_textDimData[dim].color1 = isPc98 ? 0x33 : 254;
_textDimData[dim].color2 = _screen->_curDim->unkA;
}
@@ -197,6 +201,7 @@ void TextDisplayer_LoL::printDialogueText(int dim, char *str, EMCState *script,
displayText(_dialogueBuffer);
_screen->setScreenDim(oldDim);
+ _lineCount = 0;
_screen->setCurPage(cp);
_screen->setFont(of);
@@ -243,6 +248,7 @@ void TextDisplayer_LoL::printMessage(uint16 type, const char *str, ...) {
displayText(_buffer);
_screen->setScreenDim(od);
+ _lineCount = 0;
if (!(type & 0x8000)) {
if (soundEffect[type])
@@ -373,7 +379,6 @@ void TextDisplayer_LoL::displayText(char *str, ...) {
_tempString2 = 0;
_currentLine[0] = 0;
-
memset(_ctrl, 0, 3);
char c = parseCommand();
@@ -591,13 +596,13 @@ void TextDisplayer_LoL::printLine(char *str) {
int n2 = 0;
int n1 = (w / 4) - 1;
- do {
+ while (n2 < n1 && n2 < s) {
c = str[n2];
uint8 cu = (uint8) c;
if (cu >= 0xE0 || (cu > 0x80 && cu < 0xA0))
n2++;
n2++;
- } while (n2 < n1 && n2 < s);
+ }
s = n2;
}
} else {
diff --git a/engines/kyra/text_lol.h b/engines/kyra/text_lol.h
index 488be17cff..1e5bc8884e 100644
--- a/engines/kyra/text_lol.h
+++ b/engines/kyra/text_lol.h
@@ -90,7 +90,7 @@ private:
uint8 line;
};
- TextDimData _textDimData[14];
+ TextDimData *_textDimData;
};
} // End of namespace Kyra
diff --git a/engines/kyra/timer_mr.cpp b/engines/kyra/timer_mr.cpp
index 48fa55519c..0d89decf5a 100644
--- a/engines/kyra/timer_mr.cpp
+++ b/engines/kyra/timer_mr.cpp
@@ -60,7 +60,7 @@ void KyraEngine_MR::timerRunSceneScript7(int arg) {
void KyraEngine_MR::timerFleaDeath(int arg) {
_timer->setCountdown(4, 5400);
- saveGameState(999, "Autosave", 0);
+ saveGameStateIntern(999, "Autosave", 0);
_screen->hideMouse();
_timer->disable(4);
runAnimationScript("FLEADTH1.EMC", 0, 0, 1, 1);
diff --git a/engines/lastexpress/data/animation.cpp b/engines/lastexpress/data/animation.cpp
new file mode 100644
index 0000000000..88973c4b0b
--- /dev/null
+++ b/engines/lastexpress/data/animation.cpp
@@ -0,0 +1,300 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based on Deniz Oezmen's code: http://oezmen.eu/
+
+#include "lastexpress/data/animation.h"
+
+#include "lastexpress/data/sequence.h"
+#include "lastexpress/data/snd.h"
+
+#include "lastexpress/debug.h"
+
+#include "common/events.h"
+#include "engines/engine.h"
+
+namespace LastExpress {
+
+Animation::Animation() : _stream(NULL), _currentChunk(NULL), _overlay(NULL), _background1(NULL), _background2(NULL), _backgroundCurrent(0), _audio(NULL), _startTime(0), _changed(false), _flag(0) {
+}
+
+Animation::~Animation() {
+ reset();
+}
+
+void Animation::reset() {
+ delete _overlay;
+ _overlay = NULL;
+ delete _background1;
+ _background1 = NULL;
+ delete _background2;
+ _background2 = NULL;
+ delete _audio;
+ _audio = NULL;
+
+ _backgroundCurrent = 0;
+ _chunks.clear();
+
+ _currentChunk = NULL;
+
+ delete _stream;
+}
+
+bool Animation::load(Common::SeekableReadStream *stream, int flag) {
+ if (!stream)
+ return false;
+
+ reset();
+
+ // Keep stream for later decoding of animation
+ _stream = stream;
+
+ // Read header to get the number of chunks
+ uint32 numChunks = _stream->readUint32LE();
+ debugC(3, kLastExpressDebugGraphics, "Number of chunks in NIS file: %d", numChunks);
+
+ // Check if there is enough data
+ if (_stream->size() - _stream->pos() < (signed)(numChunks * sizeof(Chunk))) {
+ debugC(2, kLastExpressDebugGraphics, "NIS file seems to be corrupted!");
+ return false;
+ }
+
+ // Read all the chunks
+ for (uint32 i = 0; i < numChunks; ++i) {
+ Chunk chunk;
+ chunk.type = (ChunkType)_stream->readUint16LE();
+ chunk.frame = _stream->readUint16LE();
+ chunk.size = _stream->readUint32LE();
+
+ _chunks.push_back(chunk);
+
+ debugC(9, kLastExpressDebugGraphics, "Chunk Entry: type 0x%.4x, frame=%d, size=%d", chunk.type, chunk.frame, chunk.size);
+ }
+ _currentChunk = _chunks.begin();
+ _changed = false;
+ _startTime = g_engine->_system->getMillis();
+
+ return true;
+}
+
+bool Animation::process() {
+ if (!_currentChunk)
+ error("Animation::process - internal error: the current chunk iterator is invalid!");
+
+ if (_stream == NULL || _chunks.size() == 0)
+ error("Trying to show an animation before loading data");
+
+ // TODO: substract the time paused by the GUI
+ uint32 currentFrame = (uint32)(((float)(g_engine->_system->getMillis() - _startTime)) / 33.33f);
+
+ // Process all chunks until the current frame
+ while (!_changed && currentFrame > _currentChunk->frame && !hasEnded()) {
+ switch(_currentChunk->type) {
+ //TODO: some info chunks are probably subtitle/sync related
+ case kChunkTypeUnknown1:
+ case kChunkTypeUnknown2:
+ case kChunkTypeUnknown5:
+ debugC(9, kLastExpressDebugGraphics | kLastExpressDebugUnknown, " info chunk: type 0x%.4x (size %d)", _currentChunk->type, _currentChunk->size);
+ assert (_currentChunk->frame == 0);
+ //TODO: _currentChunk->size?
+ break;
+
+ case kChunkTypeAudioInfo:
+ debugC(9, kLastExpressDebugGraphics, " audio info: %d blocks", _currentChunk->size);
+ assert (_currentChunk->frame == 0);
+ //TODO: save the size?
+ _audio = new AppendableSound();
+ break;
+
+ case kChunkTypeUnknown4:
+ debugC(9, kLastExpressDebugGraphics | kLastExpressDebugUnknown, " info block 4");
+ assert (_currentChunk->frame == 0 && _currentChunk->size == 0);
+ //TODO unknown type of chunk
+ break;
+
+ case kChunkTypeBackground1:
+ debugC(9, kLastExpressDebugGraphics, " background frame 1 (%d bytes, frame %d)", _currentChunk->size, _currentChunk->frame);
+ delete _background1;
+ _background1 = processChunkFrame(_stream, *_currentChunk);
+ break;
+
+ case kChunkTypeSelectBackground1:
+ debugC(9, kLastExpressDebugGraphics, " select background 1");
+ assert (_currentChunk->frame == 0 && _currentChunk->size == 0);
+ _backgroundCurrent = 1;
+ break;
+
+ case kChunkTypeBackground2:
+ debugC(9, kLastExpressDebugGraphics, " background frame 2 (%d bytes, frame %d)", _currentChunk->size, _currentChunk->frame);
+ delete _background2;
+ _background2 = processChunkFrame(_stream, *_currentChunk);
+ break;
+
+ case kChunkTypeSelectBackground2:
+ debugC(9, kLastExpressDebugGraphics, " select background 2");
+ assert (_currentChunk->frame == 0 && _currentChunk->size == 0);
+ _backgroundCurrent = 2;
+ break;
+
+ case kChunkTypeOverlay:
+ debugC(9, kLastExpressDebugGraphics, " overlay frame (%d bytes, frame %d)", _currentChunk->size, _currentChunk->frame);
+ delete _overlay;
+ _overlay = processChunkFrame(_stream, *_currentChunk);
+ break;
+
+ case kChunkTypeUpdate:
+ case kChunkTypeUpdateTransition:
+ debugC(9, kLastExpressDebugGraphics, " update%s: frame %d", _currentChunk->type == 15 ? "" : " with transition", _currentChunk->frame);
+ assert (_currentChunk->size == 0);
+ _changed = true;
+ break;
+
+ case kChunkTypeAudioData:
+ debugC(9, kLastExpressDebugGraphics, " audio (%d blocks, %d bytes, frame %d)", _currentChunk->size / _soundBlockSize, _currentChunk->size, _currentChunk->frame);
+ processChunkAudio(_stream, *_currentChunk);
+
+ // Synchronize the audio by resetting the start time
+ if (_currentChunk->frame == 0)
+ _startTime = g_engine->_system->getMillis();
+ break;
+
+ case kChunkTypeAudioEnd:
+ debugC(9, kLastExpressDebugGraphics, " audio end: %d blocks", _currentChunk->frame);
+ assert (_currentChunk->size == 0);
+ _audio->finish();
+ //TODO: we need to start the linked sound (.LNK) after the audio from the animation ends
+ break;
+
+ default:
+ error(" UNKNOWN chunk type=%x frame=%d size=%d", _currentChunk->type, _currentChunk->frame, _currentChunk->size);
+ break;
+ }
+ _currentChunk++;
+ }
+
+ return true;
+}
+
+bool Animation::hasEnded() {
+ return _currentChunk == _chunks.end();
+}
+
+Common::Rect Animation::draw(Graphics::Surface *surface) {
+ if (!_overlay)
+ error("Animation::draw - internal error: the current overlay animation frame is invalid!");
+
+ // Paint the background
+ if (_backgroundCurrent == 1 && _background1)
+ _background1->draw(surface);
+ else if (_backgroundCurrent == 2 && _background2)
+ _background2->draw(surface);
+
+ // Paint the overlay
+ _overlay->draw(surface);
+
+ //TODO
+ return Common::Rect();
+}
+
+AnimFrame *Animation::processChunkFrame(Common::SeekableReadStream *in, const Chunk &c) const {
+ assert (c.frame == 0);
+
+ // Create a temporary chunk buffer
+ Common::MemoryReadStream *str = in->readStream(c.size);
+
+ // Read the frame information
+ FrameInfo i;
+ i.read(str, false);
+
+ // Decode the frame
+ AnimFrame *f = new AnimFrame(str, i);
+
+ // Delete the temporary chunk buffer
+ delete str;
+
+ return f;
+}
+
+void Animation::processChunkAudio(Common::SeekableReadStream *in, const Chunk &c) {
+ if (!_audio)
+ error("Animation::processChunkAudio - internal error: the audio stream is invalid!");
+
+ // Skip the Snd header, to queue just the audio blocks
+ uint32 size = c.size;
+ if ((c.size % 739) != 0) {
+ // Read Snd header
+ uint32 header1 = in->readUint32LE();
+ uint16 header2 = in->readUint16LE();
+ warning("Start ADPCM: %d, %d", header1, header2);
+ size -= 6;
+ }
+
+ // Append the current chunk to the Snd
+ _audio->queueBuffer(in->readStream(size));
+}
+
+// TODO: this method will probably go away and be integrated in the main loop
+void Animation::play() {
+ while (!hasEnded() && !g_engine->getEventManager()->shouldQuit() && !g_engine->getEventManager()->shouldRTL()) {
+ process();
+
+ if (_changed) {
+ // Create a temporary surface to merge the overlay with the background
+ Graphics::Surface *s = new Graphics::Surface;
+ s->create(640, 480, 2);
+
+ draw(s);
+
+ // XXX: Update the screen
+ g_system->copyRectToScreen((byte *)s->pixels, s->pitch, 0, 0, s->w, s->h);
+
+ // Free the temporary surface
+ s->free();
+ delete s;
+
+ _changed = false;
+ }
+
+ g_system->updateScreen();
+
+ //FIXME: implement subtitles
+ g_engine->_system->delayMillis(20);
+
+ // Handle right-click to interrupt animations
+ Common::Event ev;
+ while (g_engine->getEventManager()->pollEvent(ev)) {
+ if (ev.type == Common::EVENT_RBUTTONUP) {
+ // Stop audio
+ if (_audio)
+ _audio->finish();
+
+ // TODO start LNK file sound?
+ return;
+ }
+ }
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/animation.h b/engines/lastexpress/data/animation.h
new file mode 100644
index 0000000000..ca1f7c6fa0
--- /dev/null
+++ b/engines/lastexpress/data/animation.h
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ANIMATION_H
+#define LASTEXPRESS_ANIMATION_H
+
+/*
+ Animation format (.NIS)
+
+ uint32 {4} - Number of chunks
+
+ // for each chunk
+ uint16 {2} - Type
+ uint16 {2} - Tag
+ uint32 {4} - Size of chunk
+ byte {x} - Data (for "data" chunks: backgrounds, overlay & audio data)
+*/
+
+#include "lastexpress/drawable.h"
+
+#include "common/array.h"
+#include "common/stream.h"
+
+namespace LastExpress {
+
+class AnimFrame;
+class AppendableSound;
+
+class Animation : public Drawable {
+public:
+ enum FlagType {
+ kFlagDefault = 16384,
+ kFlagProcess = 49152
+ };
+
+ Animation();
+ ~Animation();
+
+ bool load(Common::SeekableReadStream *stream, int flag = kFlagDefault);
+ bool process();
+ bool hasEnded();
+ Common::Rect draw(Graphics::Surface *surface);
+ void play();
+
+private:
+ static const uint32 _soundBlockSize = 739;
+
+ // despite their size field, info chunks don't have a payload
+ enum ChunkType {
+ kChunkTypeUnknown1 = 1,
+ kChunkTypeUnknown2 = 2,
+ kChunkTypeAudioInfo = 3,
+ kChunkTypeUnknown4 = 4,
+ kChunkTypeUnknown5 = 5,
+ kChunkTypeBackground1 = 10,
+ kChunkTypeSelectBackground1 = 11,
+ kChunkTypeBackground2 = 12,
+ kChunkTypeSelectBackground2 = 13,
+ kChunkTypeOverlay = 20,
+ kChunkTypeUpdate = 21,
+ kChunkTypeUpdateTransition = 22,
+ kChunkTypeSound1 = 30,
+ kChunkTypeSound2 = 31,
+ kChunkTypeAudioData = 32,
+ kChunkTypeAudioEnd = 99
+ };
+
+ struct Chunk {
+ ChunkType type;
+ uint16 frame;
+ uint32 size;
+ };
+
+ void reset();
+ AnimFrame *processChunkFrame(Common::SeekableReadStream *in, const Chunk &c) const;
+ void processChunkAudio(Common::SeekableReadStream *in, const Chunk &c);
+
+ Common::SeekableReadStream *_stream;
+ Common::Array<Chunk> _chunks;
+ Common::Array<Chunk>::iterator _currentChunk;
+ AnimFrame *_overlay, *_background1, *_background2;
+ byte _backgroundCurrent;
+ AppendableSound *_audio;
+
+ uint32 _startTime;
+ bool _changed;
+ int _flag;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ANIMATION_H
diff --git a/engines/lastexpress/data/archive.cpp b/engines/lastexpress/data/archive.cpp
new file mode 100644
index 0000000000..1a5b6905a3
--- /dev/null
+++ b/engines/lastexpress/data/archive.cpp
@@ -0,0 +1,115 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based on the Xentax Wiki documentation:
+// http://wiki.xentax.com/index.php/The_Last_Express_SND
+
+#include "lastexpress/data/archive.h"
+
+#include "lastexpress/debug.h"
+
+#include "common/debug.h"
+#include "common/file.h"
+
+namespace LastExpress {
+
+HPFArchive::HPFArchive(const Common::String &path) {
+ _filename = path;
+
+ // Open a stream to the archive
+ Common::SeekableReadStream *archive = SearchMan.createReadStreamForMember(_filename);
+ if (!archive) {
+ debugC(2, kLastExpressDebugResource, "Error opening file: %s", path.c_str());
+ return;
+ }
+
+ debugC(2, kLastExpressDebugResource, "Opened archive: %s", path.c_str());
+
+ // Read header to get the number of files
+ uint32 numFiles = archive->readUint32LE();
+ debugC(3, kLastExpressDebugResource, "Number of files in archive: %d", numFiles);
+
+ // Read the list of files
+ for (unsigned int i = 0; i < numFiles; ++i) {
+ char name[13];
+ HPFEntry entry;
+
+ archive->read(&name, sizeof(char) * _archiveNameSize);
+ entry.offset = archive->readUint32LE();
+ entry.size = archive->readUint32LE();
+ entry.isOnHD = archive->readUint16LE();
+
+ // Terminate string
+ name[12] = '\0';
+
+ Common::String filename(name);
+ filename.toLowercase();
+
+ _files[filename] = entry;
+
+ //debugC(9, kLastExpressDebugResource, "File entry: %s (offset:%d - Size: %d - HD: %u)", &name, entry.offset, entry.size, entry.isOnHD);
+ }
+
+ // Close stream
+ delete archive;
+}
+
+bool HPFArchive::hasFile(const Common::String &name) {
+ return (_files.find(name) != _files.end());
+}
+
+int HPFArchive::listMembers(Common::ArchiveMemberList &list) {
+ int numMembers = 0;
+
+ for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) {
+ list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(i->_key, this)));
+ numMembers++;
+ }
+
+ return numMembers;
+}
+
+Common::ArchiveMemberPtr HPFArchive::getMember(const Common::String &name) {
+ if (!hasFile(name))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *HPFArchive::createReadStreamForMember(const Common::String &name) const {
+ FileMap::const_iterator fDesc = _files.find(name);
+ if (fDesc == _files.end())
+ return NULL;
+
+ Common::File *archive = new Common::File();
+ if (!archive->open(_filename)) {
+ delete archive;
+ return NULL;
+ }
+
+ return new Common::SeekableSubReadStream(archive, fDesc->_value.offset * _archiveSectorSize, fDesc->_value.offset * _archiveSectorSize + fDesc->_value.size * _archiveSectorSize, DisposeAfterUse::YES);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/archive.h b/engines/lastexpress/data/archive.h
new file mode 100644
index 0000000000..3860245bc5
--- /dev/null
+++ b/engines/lastexpress/data/archive.h
@@ -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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_HPFARCHIVE_H
+#define LASTEXPRESS_HPFARCHIVE_H
+
+/*
+ Archive file format (.HPF)
+
+ uint32 {4} - number of files
+
+ // for each file
+ char {12} - name (zero-terminated)
+ uint32 {4} - offset (expressed in sectors of 2048 bytes)
+ uint32 {4} - size (expressed in sectors of 2048 bytes)
+ byte {2} - file status: 1 = on disk (ie. in HD.HPF), 0 = on CD
+*/
+
+#include "common/archive.h"
+
+namespace LastExpress {
+
+class HPFArchive : public Common::Archive {
+public:
+ HPFArchive(const Common::String &path);
+
+ bool hasFile(const Common::String &name);
+ int listMembers(Common::ArchiveMemberList &list);
+ Common::ArchiveMemberPtr getMember(const Common::String &name);
+ Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+
+ int count() { return _files.size(); }
+
+private:
+ static const unsigned int _archiveNameSize = 12;
+ static const unsigned int _archiveSectorSize = 2048;
+
+ // File entry
+ struct HPFEntry {
+ uint32 offset; ///< Offset (in sectors of 2048 bytes)
+ uint32 size; ///< Size (in sectors of 2048 bytes)
+ uint16 isOnHD; ///< File location (1: on HD; 0: on CD)
+ };
+
+ typedef Common::HashMap<Common::String, HPFEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
+
+ FileMap _files; ///< List of files
+ Common::String _filename; ///< Filename of the archive
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_HPFARCHIVE_H
diff --git a/engines/lastexpress/data/background.cpp b/engines/lastexpress/data/background.cpp
new file mode 100644
index 0000000000..94d7fb16c3
--- /dev/null
+++ b/engines/lastexpress/data/background.cpp
@@ -0,0 +1,141 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based on Deniz Oezmen's code and Xentax Wiki documentation
+// http://oezmen.eu/
+// http://wiki.xentax.com/index.php/The_Last_Express_BG
+
+#include "lastexpress/data/background.h"
+
+#include "lastexpress/debug.h"
+
+namespace LastExpress {
+
+Background::Background() : _data(NULL) {
+ memset(&_header, 0, sizeof(BackgroundHeader));
+}
+
+Background::~Background() {
+ delete[] _data;
+}
+
+bool Background::load(Common::SeekableReadStream *stream) {
+ if (!stream)
+ return false;
+
+ // Reset data
+ delete[] _data;
+
+ // Load Background header
+ _header.posX = stream->readUint32LE();
+ _header.posY = stream->readUint32LE();
+ _header.width = stream->readUint32LE();
+ _header.height = stream->readUint32LE();
+ _header.redSize = stream->readUint32LE();
+ _header.blueSize = stream->readUint32LE();
+ _header.greenSize = stream->readUint32LE();
+
+ debugC(3, kLastExpressDebugGraphics, "Background Info: (%d, %d) - (%d x %d) - (%d, %d, %d)",
+ _header.posX, _header.posY, _header.width, _header.height,
+ _header.redSize, _header.blueSize, _header.greenSize);
+
+ // Load and decompress Background channel data
+ uint32 numPix = _header.width * _header.height;
+ byte *dataR = decodeComponent(stream, _header.redSize, numPix);
+ byte *dataB = decodeComponent(stream, _header.blueSize, numPix);
+ byte *dataG = decodeComponent(stream, _header.greenSize, numPix);
+
+ // Save to pixel buffer
+ // FIXME handle big-endian case
+ _data = new uint16[_header.width * _header.height];
+ for (uint i = 0; i < _header.width * _header.height; i++)
+ _data[i] = (uint16)((dataR[i] << 10) + (dataG[i] << 5) + dataB[i]);
+
+ // Cleanup buffers
+ delete[] dataR;
+ delete[] dataG;
+ delete[] dataB;
+
+ delete stream;
+
+ return true;
+}
+
+Common::Rect Background::draw(Graphics::Surface *surface) {
+ if (!_data) {
+ debugC(2, kLastExpressDebugGraphics, "Trying to show a background before loading data!");
+ return Common::Rect();
+ }
+
+ int i = 0;
+ for (uint16 y = 0; y < _header.height; y++) {
+ for (uint16 x = 0; x < _header.width; x++) {
+ surface->fillRect(Common::Rect((int16)(_header.posX + x), (int16)(_header.posY + y), (int16)(_header.posX + x + 1), (int16)(_header.posY + y + 1)), _data[i]);
+ i ++;
+ }
+ }
+
+ return Common::Rect((int16)_header.posX, (int16)_header.posY, (int16)(_header.posX + _header.width), (int16)(_header.posY + _header.height));
+}
+
+byte *Background::decodeComponent(Common::SeekableReadStream *in, uint32 inSize, uint32 outSize) const {
+ // Create the destination array
+ byte *out = new byte[outSize];
+ if (!out)
+ return NULL;
+
+ // Initialize the decoding
+ uint32 inPos = 0;
+ uint32 outPos = 0;
+
+ // Decode
+ while (inPos < inSize) {
+ byte inByte = in->readByte();
+ inPos++;
+
+ if (inByte < 0x80) {
+ // Direct decompression (RLE)
+ byte len = (inByte >> 5) + 1;
+ byte data = inByte & 0x1f;
+ for (int i = 0; i < len && outPos < outSize; i++)
+ out[outPos++] = data;
+ } else {
+ // Buffer back reference, 4096 byte window
+ // Take inByte and the following value as a big endian
+ // OfsLen while zeroing the first bit
+ uint16 ofsLen = ((inByte & 0x7F) << 8) | in->readByte();
+ inPos++;
+
+ int32 len = (ofsLen >> 12) + 3;
+ int32 hisPos = (int32)(outPos + (ofsLen & 0x0FFF) - 4096);
+ for (int i = 0; i < len && outPos < outSize; i++)
+ out[outPos++] = out[hisPos++];
+ }
+ }
+
+ return out;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/background.h b/engines/lastexpress/data/background.h
new file mode 100644
index 0000000000..fc1cc26fa4
--- /dev/null
+++ b/engines/lastexpress/data/background.h
@@ -0,0 +1,81 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_BACKGROUND_H
+#define LASTEXPRESS_BACKGROUND_H
+
+/*
+ Background file format (.BG)
+
+ header:
+ uint32 {4} - position X on screen
+ uint32 {4} - position Y on screen
+ uint32 {4} - image width
+ uint32 {4} - image height
+ uint32 {4} - red colour channel data size
+ uint32 {4} - blue colour channel data size
+ uint32 {4} - green colour channel data size
+
+ data:
+ byte {x} - red colour channel data
+ byte {x} - blue colour channel data
+ byte {x} - green colour channel data
+*/
+
+#include "lastexpress/drawable.h"
+
+#include "common/stream.h"
+
+namespace LastExpress {
+
+class Background : public Drawable {
+public:
+ Background();
+ ~Background();
+
+ bool load(Common::SeekableReadStream *stream);
+
+ Common::Rect draw(Graphics::Surface *surface);
+
+private:
+ struct BackgroundHeader {
+ uint32 posX; ///< position X on screen
+ uint32 posY; ///< position Y on screen
+ uint32 width; ///< image width
+ uint32 height; ///< image height
+ uint32 redSize; ///< red color channel data size
+ uint32 blueSize; ///< blue color channel data size
+ uint32 greenSize; ///< green color channel data size
+ };
+
+ BackgroundHeader _header;
+ uint16 *_data; ///< decoded background data
+
+ byte *decodeComponent(Common::SeekableReadStream *in, uint32 inSize, uint32 outSize) const;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_BACKGROUND_H
diff --git a/engines/lastexpress/data/cursor.cpp b/engines/lastexpress/data/cursor.cpp
new file mode 100644
index 0000000000..4e7003578a
--- /dev/null
+++ b/engines/lastexpress/data/cursor.cpp
@@ -0,0 +1,144 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/data/cursor.h"
+
+#include "lastexpress/lastexpress.h"
+
+#include "common/system.h"
+#include "graphics/cursorman.h"
+
+namespace LastExpress {
+
+Cursor::Cursor() : _current(kCursorMAX) {
+ memset(&_cursors, 0, sizeof(_cursors));
+}
+
+bool Cursor::load(Common::SeekableReadStream *stream) {
+ if (!stream)
+ return false;
+
+ // Load the whole file to memory
+ Common::MemoryReadStream *data = stream->readStream((uint32) stream->size());
+ delete stream;
+ if (!data)
+ return false;
+
+ // Read the hotspot data
+ for (int i = 0; i < kCursorMAX; i++) {
+ _cursors[i].hotspotX = data->readUint16LE();
+ _cursors[i].hotspotY = data->readUint16LE();
+ debugC(15, kLastExpressDebugCursor | kLastExpressDebugAll,
+ "Cursor %d hotspot x: %d, hotspot y: %d",
+ i, _cursors[i].hotspotX, _cursors[i].hotspotY);
+ }
+
+ // Read the pixel data
+ for (int i = 0; i < kCursorMAX; i++)
+ for (int pix = 0; pix < 32 * 32; pix++)
+ _cursors[i].image[pix] = data->readUint16LE();
+
+ delete data;
+ return true;
+}
+
+void Cursor::show(bool visible) const {
+ CursorMan.showMouse(visible);
+}
+
+bool Cursor::checkStyle(CursorStyle style) const {
+ if (style >= kCursorMAX) {
+ debugC(2, kLastExpressDebugGraphics, "Trying to use an invalid cursor style: was %d, max %d", (int)style, kCursorMAX);
+ return false;
+ }
+
+ return true;
+}
+
+void Cursor::setStyle(CursorStyle style) {
+ if (!checkStyle(style))
+ return;
+
+ if (style == _current)
+ return;
+
+ debugC(10, kLastExpressDebugCursor | kLastExpressDebugAll, "Cursor: setting style: %d", style);
+
+ // Save the new cursor
+ _current = style;
+
+ // Reuse the screen pixel format
+ Graphics::PixelFormat pf = g_system->getScreenFormat();
+ CursorMan.replaceCursor((const byte *)getCursorImage(style),
+ 32, 32, _cursors[style].hotspotX, _cursors[style].hotspotY,
+ 0, 1, &pf);
+}
+
+const uint16 *Cursor::getCursorImage(CursorStyle style) const {
+ if (!checkStyle(style))
+ return NULL;
+
+ return _cursors[style].image;
+}
+
+
+Icon::Icon(CursorStyle style) : _style(style), _x(0), _y(0), _brightness(100) {}
+
+void Icon::setPosition(int16 x, int16 y) {
+ _x = x;
+ _y = y;
+}
+
+void Icon::setBrightness(uint brightness) {
+ assert(brightness <= 100);
+
+ _brightness = (uint8)brightness;
+}
+
+Common::Rect Icon::draw(Graphics::Surface *surface) {
+ const uint16 *image = ((LastExpressEngine *)g_engine)->getCursor()->getCursorImage((CursorStyle)_style);
+ if (!image)
+ return Common::Rect();
+
+ // TODO adjust brightness. The original game seems to be using a table for that (at least in the highlighting case)
+ for (int j = 0; j < 32; j++) {
+ uint16 *s = (uint16 *)surface->getBasePtr(_x, _y + j);
+ for (int i = 0; i < 32; i++) {
+ if (_brightness == 100)
+ *s = *image;
+ else
+ // HACK change color to show highlight
+ *s = (*image & 0x739C) >> 1;
+
+ // Update the image and surface pointers
+ image++;
+ s++;
+ }
+ }
+
+ return Common::Rect(_x, _y, _x + 32, _y + 32);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/cursor.h b/engines/lastexpress/data/cursor.h
new file mode 100644
index 0000000000..992266569f
--- /dev/null
+++ b/engines/lastexpress/data/cursor.h
@@ -0,0 +1,93 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_CURSOR_H
+#define LASTEXPRESS_CURSOR_H
+
+/*
+ Cursor format (CURSORS.TBM)
+
+ style table:
+ (for each cursor)
+ uint16 {2} - hotspot X
+ uint16 {2} - hotspot Y
+
+ data:
+ (for each cursor)
+ uint16 {32*32} - cursor data
+*/
+
+#include "lastexpress/drawable.h"
+
+#include "lastexpress/shared.h"
+
+#include "common/stream.h"
+
+namespace LastExpress {
+
+class Icon : public Drawable {
+public:
+ Icon(CursorStyle style);
+
+ void setPosition(int16 x, int16 y);
+ void setBrightness(uint brightness);
+ Common::Rect draw(Graphics::Surface *surface);
+
+private:
+ CursorStyle _style;
+ int16 _x, _y;
+ uint8 _brightness;
+};
+
+class Cursor {
+public:
+ Cursor();
+
+ bool load(Common::SeekableReadStream *stream);
+ void show(bool visible) const;
+
+ void setStyle(CursorStyle style);
+ CursorStyle getStyle() const { return _current; }
+
+private:
+ // Style
+ CursorStyle _current;
+
+ // Cursors data
+ struct {
+ uint16 image[32 * 32];
+ uint16 hotspotX, hotspotY;
+ } _cursors[kCursorMAX];
+
+ bool checkStyle(CursorStyle style) const;
+ const uint16 *getCursorImage(CursorStyle style) const;
+
+ // Only allow full access for drawing (needed for getCursorImage)
+ friend Common::Rect Icon::draw(Graphics::Surface *surface);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_CURSOR_H
diff --git a/engines/lastexpress/data/font.cpp b/engines/lastexpress/data/font.cpp
new file mode 100644
index 0000000000..5f4b3b40b8
--- /dev/null
+++ b/engines/lastexpress/data/font.cpp
@@ -0,0 +1,205 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/data/font.h"
+
+#include "common/system.h"
+
+namespace LastExpress {
+
+Font::Font() : _numGlyphs(0), _glyphs(NULL), _glyphWidths(0) {
+ memset(&_palette, 0, sizeof(_palette));
+ memset(&_charMap, 0, sizeof(_charMap));
+}
+
+Font::~Font() {
+ reset();
+}
+
+void Font::reset() {
+ delete[] _glyphs;
+ delete[] _glyphWidths;
+}
+
+bool Font::load(Common::SeekableReadStream *stream) {
+ if (!stream)
+ return false;
+
+ // Reset data
+ reset();
+
+ // Read the palette
+ for (uint i = 0; i < _paletteSize; i++) {
+ _palette[i] = stream->readUint16LE();
+ }
+
+ // Read the character map
+ stream->read(_charMap, _charMapSize);
+
+ // Read the glyphs
+ _numGlyphs = stream->readUint16LE();
+ _glyphs = new byte[_numGlyphs * 18 * 8];
+ stream->read(_glyphs, _numGlyphs * 18 * 8);
+
+ // TODO: Read something else?
+ //uint16 unknown = fontFile->readByte();
+ //warning("unknown = %d", unknown);
+ //warning("pos = %d", fontFile->pos());
+ //warning("left = %d", fontFile->size() - fontFile->pos());
+
+ //while (!fontFile->eos()) {
+ //unknown = fontFile->readByte();
+ //warning("val = %d", unknown);
+ //}
+
+ // Precalculate glyph widths
+ _glyphWidths = new byte[_numGlyphs];
+ for (uint16 i = 0; i < _numGlyphs; i++) {
+ _glyphWidths[i] = getGlyphWidth(i);
+ }
+
+ delete stream;
+
+ return true;
+}
+
+
+uint16 Font::getCharGlyph(uint16 c) const {
+ //warning("%c", c);
+ if (c >= 0x200)
+ error("Express::Font: Invalid character %d", c);
+
+ return _charMap[c];
+}
+
+byte *Font::getGlyphImg(uint16 g) {
+ if (!_glyphs)
+ error("Express::getGlyphImg: Invalid glyphs!");
+
+ if (g >= _numGlyphs)
+ error("Express::getGlyphImg: Invalid glyph %d (%d available)", g, _numGlyphs);
+
+ return _glyphs + g * 18 * 8;
+}
+
+uint8 Font::getGlyphWidth(uint16 g) {
+ byte *p = getGlyphImg(g);
+
+ uint8 maxLineWidth = 0;
+ for (int j = 0; j < 18; j++) {
+ uint8 currentLineWidth = 0;
+ for (uint8 i = 0; i < 16; i++) {
+ byte index;
+ if (i % 2)
+ index = *p & 0xf;
+ else
+ index = *p >> 4;
+ uint16 color = _palette[index];
+ if (color != 0x1f)
+ currentLineWidth = i;
+ if (i % 2)
+ p++;
+ }
+ if (currentLineWidth > maxLineWidth)
+ maxLineWidth = currentLineWidth;
+ }
+
+ return maxLineWidth;
+}
+
+byte *Font::getCharImg(uint16 c) {
+ return getGlyphImg(getCharGlyph(c));
+}
+
+uint8 Font::getCharWidth(uint16 c) const{
+ if (c == 0x20) {
+ // Space is a special case
+ // TODO: this is an arbitrary value
+ return 10;
+ } else {
+ if (!_glyphWidths)
+ error("Express::getCharWidth: Invalid glyphs widths!");
+
+ return _glyphWidths[getCharGlyph(c)];
+ }
+}
+
+uint16 Font::getStringWidth(Common::String str) const {
+ uint16 width = 0;
+ for (uint i = 0; i < str.size(); i++)
+ width += getCharWidth((unsigned) (int)str[i]);
+
+ return width;
+}
+
+uint16 Font::getStringWidth(const uint16 *str, uint16 length) const {
+ uint16 width = 0;
+ for (uint i = 0; i < length; i++)
+ width += getCharWidth(str[i]);
+
+ return width;
+}
+
+void Font::drawChar(Graphics::Surface *surface, int16 x, int16 y, uint16 c) {
+ byte *p = getCharImg(c);
+
+ for (int16 j = 0; j < 18; j++) {
+ for (int16 i = 0; i < 16; i++) {
+ byte index;
+ if (i % 2)
+ index = *p & 0xf;
+ else
+ index = *p >> 4;
+ uint16 color = _palette[index];
+ if (color != 0x1f) {
+ surface->fillRect(Common::Rect(x+i, y+j, x+i+1, y+j+1), color);
+ }
+ if (i % 2)
+ p++;
+ }
+ }
+}
+
+Common::Rect Font::drawString(Graphics::Surface *surface, int16 x, int16 y, Common::String str) {
+ int16 currentX = x;
+ for (uint i = 0; i < str.size(); i++) {
+ drawChar(surface, currentX, y, (unsigned) (int)str[i]);
+ currentX += getCharWidth((unsigned) (int)str[i]);
+ }
+
+ return Common::Rect(x, y, x + currentX, y + (int16)_charHeight);
+}
+
+Common::Rect Font::drawString(Graphics::Surface *surface, int16 x, int16 y, const uint16 *str, uint16 length) {
+ int16 currentX = x;
+ for (uint i = 0; i < length; i++) {
+ drawChar(surface, currentX, y, str[i]);
+ currentX += getCharWidth(str[i]);
+ }
+
+ return Common::Rect(x, y, x + currentX, y + (int16)_charHeight);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/font.h b/engines/lastexpress/data/font.h
new file mode 100644
index 0000000000..457c0c3432
--- /dev/null
+++ b/engines/lastexpress/data/font.h
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_FONT_H
+#define LASTEXPRESS_FONT_H
+
+/*
+ Font format (FONT.DAT)
+
+ uint16 {40} - Palette data
+ byte {200} - Character map
+ uint16 {2} - Number of glyphs
+
+ // For each glyph
+ byte {18*8} - Glyph data
+
+ byte {x} - Unknown data (probably just garbage)
+*/
+
+#include "common/stream.h"
+#include "graphics/surface.h"
+
+namespace LastExpress {
+
+class Font {
+public:
+ Font();
+ ~Font();
+
+ bool load(Common::SeekableReadStream *stream);
+ Common::Rect drawString(Graphics::Surface *surface, int16 x, int16 y, Common::String str);
+ Common::Rect drawString(Graphics::Surface *surface, int16 x, int16 y, const uint16 *str, uint16 length);
+
+private:
+ static const uint32 _paletteSize = 0x10;
+ static const uint32 _charMapSize = 0x200;
+ static const uint32 _charHeight = 16;
+
+ void reset();
+
+ uint16 getCharGlyph(uint16 c) const;
+ byte *getGlyphImg(uint16 g);
+ uint8 getGlyphWidth(uint16 g);
+ byte *getCharImg(uint16 c);
+ uint8 getCharWidth(uint16 c) const;
+ uint16 getStringWidth(Common::String str) const;
+ uint16 getStringWidth(const uint16 *str, uint16 length) const;
+ void drawChar(Graphics::Surface *surface, int16 x, int16 y, uint16 c);
+
+ // Font data
+ uint16 _palette[_paletteSize];
+ uint8 _charMap[_charMapSize];
+ uint16 _numGlyphs;
+ byte *_glyphs;
+ uint8 *_glyphWidths;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FONT_H
diff --git a/engines/lastexpress/data/scene.cpp b/engines/lastexpress/data/scene.cpp
new file mode 100644
index 0000000000..8e90d93828
--- /dev/null
+++ b/engines/lastexpress/data/scene.cpp
@@ -0,0 +1,292 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/data/scene.h"
+
+#include "lastexpress/data/background.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+SceneHotspot *SceneHotspot::load(Common::SeekableReadStream *stream) {
+ SceneHotspot *hs = new SceneHotspot();
+
+ // Rect
+ hs->rect.left = (int16)stream->readUint16LE();
+ hs->rect.right = (int16)stream->readUint16LE();
+ hs->rect.top = (int16)stream->readUint16LE();
+ hs->rect.bottom = (int16)stream->readUint16LE();
+
+ hs->coordsOffset = stream->readUint32LE();
+ hs->scene = (SceneIndex)stream->readUint16LE();
+ hs->location = stream->readByte();
+ hs->action = (Action)stream->readByte();
+ hs->param1 = stream->readByte();
+ hs->param2 = stream->readByte();
+ hs->param3 = stream->readByte();
+ hs->cursor = stream->readByte();
+ hs->next = stream->readUint32LE();
+
+ debugC(10, kLastExpressDebugScenes, "\thotspot: scene=%d location=%02d action=%d param1=%02d param2=%02d param3=%02d cursor=%02d rect=(%d, %d)x(%d, %d)",
+ hs->scene, hs->location, hs->action, hs->param1, hs->param2, hs->param3, hs->cursor, hs->rect.left, hs->rect.top, hs->rect.right, hs->rect.bottom);
+ debugC(10, kLastExpressDebugScenes, "\t coords=%d next=%d ", hs->coordsOffset, hs->next);
+
+ // Read all coords data
+ uint32 offset = hs->coordsOffset;
+ while (offset != 0) {
+
+ SceneCoord *sceneCoord = new SceneCoord;
+
+ stream->seek(offset, SEEK_SET);
+
+ sceneCoord->field_0 = stream->readSint32LE();
+ sceneCoord->field_4 = stream->readSint32LE();
+ sceneCoord->field_8 = stream->readByte();
+ sceneCoord->next = stream->readUint32LE();
+
+ hs->_coords.push_back(sceneCoord);
+
+ offset = sceneCoord->next;
+ }
+
+ return hs;
+}
+
+Common::String SceneHotspot::toString() const {
+ Common::String output = "";
+
+ output += Common::String::format(" hotspot: scene=%d location=%02d action=%d param1=%02d param2=%02d param3=%02d cursor=%02d rect=(%d, %d)x(%d, %d)",
+ scene, location, action, param1, param2, param3, cursor, rect.left, rect.top, rect.right, rect.bottom);
+
+ return output;
+}
+
+bool SceneHotspot::isInside(const Common::Point &point) {
+
+ bool contains = rect.contains(point);
+
+ if (_coords.empty() || !contains)
+ return contains;
+
+ // Checks extended coordinates
+ for (uint i = 0; i < _coords.size(); i++) {
+
+ SceneCoord *sCoord = _coords[i];
+
+ bool cont;
+ if (sCoord->field_8)
+ cont = (sCoord->field_4 + point.x * sCoord->field_0 + 1000 * point.y) >= 0;
+ else
+ cont = (sCoord->field_4 + point.x * sCoord->field_0 + 1000 * point.y) <= 0;
+
+ if (!cont)
+ return false;
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Scene
+Scene::~Scene() {
+ // Free the hotspots
+ for (int i = 0; i < (int)_hotspots.size(); i++)
+ delete _hotspots[i];
+}
+
+Scene *Scene::load(Common::SeekableReadStream *stream) {
+ Scene *scene = new Scene();
+
+ stream->read(&scene->_name, sizeof(scene->_name));
+ scene->_sig = stream->readByte();
+ scene->entityPosition = (EntityPosition)stream->readUint16LE();
+ scene->location = (Location)stream->readUint16LE();
+ scene->car = (CarIndex)stream->readUint16LE();
+ scene->position = stream->readByte();
+ scene->type = (Type)stream->readByte();
+ scene->param1 = stream->readByte();
+ scene->param2 = stream->readByte();
+ scene->param3 = stream->readByte();
+ scene->_hotspot = stream->readUint32LE();
+
+ return scene;
+}
+
+void Scene::loadHotspots(Common::SeekableReadStream *stream) {
+ if (!_hotspots.empty())
+ return;
+
+ debugC(10, kLastExpressDebugScenes, "Scene: name=%s, sig=%02d, entityPosition=%d, location=%d", _name, _sig, entityPosition, location);
+ debugC(10, kLastExpressDebugScenes, "\tcar=%02d, position=%02d, type=%02d, param1=%02d", car, position, type, param1);
+ debugC(10, kLastExpressDebugScenes, "\tparam2=%02d, param3=%02d, hotspot=%d\n", param2, param3, _hotspot);
+
+ // Read all hotspots
+ if (_hotspot != 0) {
+ stream->seek((int32)_hotspot, SEEK_SET);
+ SceneHotspot *hotspot = SceneHotspot::load(stream);
+ while (hotspot) {
+ _hotspots.push_back(hotspot);
+
+ if (hotspot->next == 0)
+ break;
+
+ stream->seek((int32)hotspot->next, SEEK_SET);
+ hotspot = SceneHotspot::load(stream);
+ }
+ }
+}
+
+bool Scene::checkHotSpot(const Common::Point &coord, SceneHotspot **hotspot) {
+ bool found = false;
+ int _location = 0;
+
+ for (int i = 0; i < (int)_hotspots.size(); i++) {
+ if (_hotspots[i]->isInside(coord)) {
+ if (_location <= _hotspots[i]->location) {
+ _location = _hotspots[i]->location;
+ *hotspot = _hotspots[i];
+ found = true;
+ }
+ }
+ }
+
+ return found;
+}
+
+SceneHotspot *Scene::getHotspot(uint index) {
+ if (_hotspots.empty())
+ error("Scene::getHotspot: scene does not have any hotspots!");
+
+ if (index >= _hotspots.size())
+ error("Scene::getHotspot: invalid index (was: %d, max: %d)", index, _hotspots.size() - 1);
+
+ return _hotspots[index];
+}
+
+Common::Rect Scene::draw(Graphics::Surface *surface) {
+ // Safety checks
+ Common::Rect rect;
+
+ Common::String sceneName(_name);
+ sceneName.trim();
+ if (sceneName.empty())
+ error("Scene::draw: This scene is not a valid drawing scene!");
+
+ // Load background
+ Background *background = ((LastExpressEngine *)g_engine)->getResourceManager()->loadBackground(sceneName);
+ if (background) {
+ rect = background->draw(surface);
+ delete background;
+ }
+
+ return rect;
+}
+
+Common::String Scene::toString() {
+ Common::String output = "";
+
+ output += Common::String::format("Scene: name=%s, sig=%02d, entityPosition=%d, location=%d\n", _name, _sig, entityPosition, location);
+ output += Common::String::format(" car=%02d, position=%02d, type=%02d, param1=%02d\n", car, position, type, param1);
+ output += Common::String::format(" param2=%02d, param3=%02d, hotspot=%d\n", param2, param3, _hotspot);
+
+ // Hotspots
+ if (_hotspots.size() != 0) {
+ output += "\nHotspots:\n";
+ for (int i = 0; i < (int)_hotspots.size(); i++)
+ output += _hotspots[i]->toString() + "\n";
+ }
+
+ return output;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// SceneLoader
+SceneLoader::SceneLoader() : _stream(NULL) {}
+
+SceneLoader::~SceneLoader() {
+ clear();
+}
+
+void SceneLoader::clear() {
+ // Remove all scenes
+ for (int i = 0; i < (int)_scenes.size(); i++)
+ delete _scenes[i];
+
+ _scenes.clear();
+
+ delete _stream;
+}
+
+bool SceneLoader::load(Common::SeekableReadStream *stream) {
+ if (!stream)
+ return false;
+
+ clear();
+
+ _stream = stream;
+
+ // Read the default scene to get the total number of scenes
+ Scene *header = Scene::load(_stream);
+ if (!header)
+ error("SceneLoader::load: Invalid data file!");
+
+ debugC(2, kLastExpressDebugScenes, " found %d entries", header->entityPosition); /* Header entityPosition is the scene count */
+
+ if (header->entityPosition > 2500) {
+ delete header;
+
+ return false;
+ }
+
+ _scenes.push_back(header);
+
+ // Read all the chunks
+ for (uint i = 0; i < (uint)header->entityPosition; ++i) {
+ Scene *scene = Scene::load(_stream);
+ if (!scene)
+ break;
+
+ _scenes.push_back(scene);
+ }
+
+ return true;
+}
+
+Scene *SceneLoader::get(SceneIndex index) {
+ if (_scenes.empty())
+ return NULL;
+
+ if (index > _scenes.size())
+ return NULL;
+
+ // Load the hotspots if needed
+ _scenes[(int)index]->loadHotspots(_stream);
+
+ return _scenes[(int)index];
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/scene.h b/engines/lastexpress/data/scene.h
new file mode 100644
index 0000000000..c4a34e127b
--- /dev/null
+++ b/engines/lastexpress/data/scene.h
@@ -0,0 +1,245 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SCENE_H
+#define LASTEXPRESS_SCENE_H
+
+/*
+ Scene format (CDTRAIN.DAT)
+
+ (text:00484750)
+ header (24 bytes)
+ char {8} - entry name (null terminated)
+ byte {1} - 0xCD
+ uint16 {2} - number of scenes (for first entry - always 0 after?)
+ uint16 {2} - 11 ??
+ uint16 {2} - car
+ byte {1} - camera position (used to get the proper sequences to show)
+ byte {1} - type
+ byte {1} - param1
+ byte {1} - param2
+ byte {1} - param3
+ uint32 {4} - Offset to hotspot info struct
+
+ probably contains cursor type too / scene index : 0 - 2500 (max)
+
+ hotspot info (24 bytes)
+ uint16 {2} - left
+ uint16 {2} - right
+ uint16 {2} - top
+ uint16 {2} - bottom
+ uint32 {4} - scene coords data
+ uint16 {2} - scene
+ byte {1} - location;
+ byte {1} - action;
+ byte {1} - param1;
+ byte {1} - param2;
+ byte {1} - param3
+ byte {1} - cursor
+ uint32{4} - offset to next hotpost
+
+ coords data (9 bytes)
+ uint32 {4} - ??
+ uint32 {4} - ??
+ byte {1} - ??
+ uint32 {4} - offset to next coords data structure
+
+*/
+
+#include "lastexpress/drawable.h"
+#include "lastexpress/shared.h"
+
+#include "common/array.h"
+#include "common/stream.h"
+
+namespace LastExpress {
+
+class Scene;
+
+class SceneHotspot {
+public:
+ enum Action {
+ kActionInventory = 1,
+ kActionSavePoint = 2,
+ kActionPlaySound = 3,
+ kActionPlayMusic = 4,
+ kActionKnockOnDoor = 5,
+ kActionCompartment = 6,
+ kActionPlaySounds = 7,
+ kActionPlayAnimation = 8,
+ kActionOpenCloseObject = 9,
+ kActionObjectUpdateLocation2 = 10,
+ kActionSetItemLocation = 11,
+ kAction12 = 12,
+ kActionPickItem = 13,
+ kActionDropItem = 14,
+ kAction15 = 15,
+ kActionEnterCompartment = 16,
+ kActionGetOutsideTrain = 18,
+ kActionSlip = 19,
+ kActionGetInsideTrain = 20,
+ kActionClimbUpTrain = 21,
+ kActionClimbDownTrain = 22,
+ kActionJumpUpDownTrain = 23,
+ kActionUnbound = 24,
+ kAction25 = 25,
+ kAction26 = 26,
+ kAction27 = 27,
+ kActionConcertSitCough = 28,
+ kAction29 = 29,
+ kActionCatchBeetle = 30,
+ kActionExitCompartment = 31,
+ kAction32 = 32,
+ KActionUseWhistle = 33,
+ kActionOpenMatchBox = 34,
+ kActionOpenBed = 35,
+ kActionDialog = 37,
+ kActionEggBox = 38,
+ kAction39 = 39,
+ kActionBed = 40,
+ kAction41 = 41,
+ kAction42 = 42,
+ kActionSwitchChapter = 43,
+ kAction44 = 44
+ };
+
+ struct SceneCoord {
+ int32 field_0;
+ int32 field_4;
+ byte field_8;
+ uint32 next;
+
+ SceneCoord() {
+ field_0 = 0;
+ field_4 = 0;
+ field_8 = 0;
+ next = 0;
+ }
+ };
+
+ Common::Rect rect;
+ uint32 coordsOffset;
+ SceneIndex scene;
+ byte location;
+ Action action;
+ byte param1;
+ byte param2;
+ byte param3;
+ byte cursor;
+ uint32 next;
+
+ SceneHotspot() {}
+ static SceneHotspot *load(Common::SeekableReadStream *stream);
+
+ bool isInside(const Common::Point &point);
+
+ Common::String toString() const;
+
+private:
+ Common::Array<SceneCoord *> _coords;
+};
+
+class SceneLoader {
+public:
+ SceneLoader();
+ ~SceneLoader();
+
+ bool load(Common::SeekableReadStream *stream);
+ Scene *get(SceneIndex index);
+
+ uint32 count() const { return _scenes.size() - 1; }
+
+private:
+ Common::SeekableReadStream *_stream;
+ Common::Array<Scene *> _scenes;
+
+ void clear();
+};
+
+class Scene : public Drawable {
+public:
+ // Enumerations
+ enum Type {
+ // PreProcess
+ kTypeObject = 1,
+ kTypeItem = 2,
+ kTypeItem2 = 3,
+ kTypeObjectItem = 4,
+ kTypeItem3 = 5,
+ kTypeObjectLocation2 = 6,
+ kTypeCompartments = 7,
+ kTypeCompartmentsItem = 8,
+
+ // PostProcess
+ kTypeList = 128,
+ kTypeSavePointChapter = 129,
+ kTypeLoadBeetleSequences = 130,
+ kTypeGameOver = 131,
+ kTypeReadText = 132,
+ kType133 = 133
+ };
+
+ // Data
+ EntityPosition entityPosition;
+ Location location;
+ CarIndex car;
+ Position position;
+ Type type;
+ byte param1;
+ byte param2;
+ byte param3;
+
+ ~Scene();
+
+ Common::Rect draw(Graphics::Surface *surface);
+
+ // Hotspots
+ Common::Array<SceneHotspot *> *getHotspots() { return &_hotspots; }
+ bool checkHotSpot(const Common::Point &coord, SceneHotspot **hotspot);
+ SceneHotspot *getHotspot(uint index = 0);
+
+ Common::String toString();
+
+private:
+ char _name[8];
+ byte _sig;
+ uint32 _hotspot;
+
+ Scene() {}
+ Common::Array<SceneHotspot *> _hotspots;
+
+ static Scene *load(Common::SeekableReadStream *stream);
+ void loadHotspots(Common::SeekableReadStream *stream);
+
+ void clear();
+
+ // Only allow full access for loading the scene and the hotspots
+ friend bool SceneLoader::load(Common::SeekableReadStream *stream);
+ friend Scene *SceneLoader::get(SceneIndex index);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SCENE_H
diff --git a/engines/lastexpress/data/sequence.cpp b/engines/lastexpress/data/sequence.cpp
new file mode 100644
index 0000000000..cf71bd6a61
--- /dev/null
+++ b/engines/lastexpress/data/sequence.cpp
@@ -0,0 +1,482 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based on Deniz Oezmen's code: http://oezmen.eu/
+
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/debug.h"
+
+namespace LastExpress {
+
+void FrameInfo::read(Common::SeekableReadStream *in, bool isSequence) {
+ // Save the current position
+ int32 basePos = in->pos();
+
+ dataOffset = in->readUint32LE();
+ unknown = in->readUint32LE();
+ paletteOffset = in->readUint32LE();
+ xPos1 = in->readUint32LE();
+ yPos1 = in->readUint32LE();
+ xPos2 = in->readUint32LE();
+ yPos2 = in->readUint32LE();
+ initialSkip = in->readUint32LE();
+ decompressedEndOffset = in->readUint32LE();
+
+ // Read the compression type for NIS files
+ if (!isSequence) {
+ in->seek(basePos + 0x124);
+ } else {
+ hotspot.left = (int16)in->readUint16LE();
+ hotspot.right = (int16)in->readUint16LE();
+ hotspot.top = (int16)in->readUint16LE();
+ hotspot.bottom = (int16)in->readUint16LE();
+ }
+
+ compressionType = in->readByte();
+ subType = (FrameSubType)in->readByte();
+
+ // Sequence information
+ field_2E = in->readByte();
+ keepPreviousFrame = in->readByte();
+ field_30 = in->readByte();
+ field_31 = in->readByte();
+ soundAction = in->readByte();
+ field_33 = in->readByte();
+ position = in->readByte();
+ field_35 = in->readByte();
+ field_36 = in->readUint16LE();
+ field_38 = in->readUint32LE();
+ entityPosition = (EntityPosition)in->readUint16LE();
+ location = in->readUint16LE();
+ next = in->readUint32LE();
+}
+
+
+// AnimFrame
+
+AnimFrame::AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f) : _palette(NULL) {
+ _palSize = 1;
+ // TODO: use just the needed rectangle
+ _image.create(640, 480, 1);
+
+ //debugC(6, kLastExpressDebugGraphics, " Offsets: data=%d, unknown=%d, palette=%d", f.dataOffset, f.unknown, f.paletteOffset);
+ //debugC(6, kLastExpressDebugGraphics, " Position: (%d, %d) - (%d, %d)", f.xPos1, f.yPos1, f.xPos2, f.yPos2);
+ //debugC(6, kLastExpressDebugGraphics, " Initial Skip: %d", f.initialSkip);
+ //debugC(6, kLastExpressDebugGraphics, " Decompressed end offset: %d", f.decompressedEndOffset);
+ //debugC(6, kLastExpressDebugGraphics, " Hotspot: (%d, %d) x (%d, %d)\n", f.hotspot.left, f.hotspot.top, f.hotspot.right, f.hotspot.bottom);
+ //debugC(6, kLastExpressDebugGraphics, " Compression type: %u / %u", f.compressionType, f.subType);
+ //debugC(6, kLastExpressDebugGraphics, " Unknown: %u - %u - %u - %u - %u - %u - %u - %d", f.field_2E, f.field_2F, f.field_30, f.field_31, f.field_33, f.field_35, f.field_36, f.field_38);
+ //debugC(6, kLastExpressDebugGraphics, " Sound action: %u", f.soundAction);
+ //debugC(6, kLastExpressDebugGraphics, " Position: %d", f.position);
+ //debugC(6, kLastExpressDebugGraphics, " Entity Position: %d", f.entityPosition);
+ //debugC(6, kLastExpressDebugGraphics, " Location: %d", f.location);
+ //debugC(6, kLastExpressDebugGraphics, " next: %d", f.next);
+
+ switch (f.compressionType) {
+ case 0:
+ // Empty frame
+ break;
+ case 3:
+ decomp3(in, f);
+ break;
+ case 4:
+ decomp4(in, f);
+ break;
+ case 5:
+ decomp5(in, f);
+ break;
+ case 7:
+ decomp7(in, f);
+ break;
+ case 255:
+ decompFF(in, f);
+ break;
+ default:
+ error("Unknown frame compression: %d", f.compressionType);
+ }
+
+ readPalette(in, f);
+ _rect = Common::Rect((int16)f.xPos1, (int16)f.yPos1, (int16)f.xPos2, (int16)f.yPos2);
+ //_rect.debugPrint(0, "Frame rect:");
+}
+
+AnimFrame::~AnimFrame() {
+ _image.free();
+ delete[] _palette;
+}
+
+Common::Rect AnimFrame::draw(Graphics::Surface *s) {
+ byte *inp = (byte *)_image.pixels;
+ uint16 *outp = (uint16 *)s->pixels;
+ for (int i = 0; i < 640 * 480; i++, inp++, outp++) {
+ if (*inp)
+ *outp = _palette[*inp];
+ }
+ return _rect;
+}
+
+void AnimFrame::readPalette(Common::SeekableReadStream *in, const FrameInfo &f) {
+ // Read the palette
+ in->seek((int)f.paletteOffset);
+ _palette = new uint16[_palSize];
+ for (uint32 i = 0; i < _palSize; i++) {
+ _palette[i] = in->readUint16LE();
+ }
+}
+
+void AnimFrame::decomp3(Common::SeekableReadStream *in, const FrameInfo &f) {
+ decomp34(in, f, 0x7, 3);
+}
+
+void AnimFrame::decomp4(Common::SeekableReadStream *in, const FrameInfo &f) {
+ decomp34(in, f, 0xf, 4);
+}
+
+void AnimFrame::decomp34(Common::SeekableReadStream *in, const FrameInfo &f, byte mask, byte shift) {
+ byte *p = (byte *)_image.getBasePtr(0, 0);
+
+ uint32 skip = f.initialSkip / 2;
+ uint32 size = f.decompressedEndOffset / 2;
+ //warning("skip: %d, %d", skip % 640, skip / 640);
+ //warning("size: %d, %d", size % 640, size / 640);
+ //assert (f.yPos1 == skip / 640);
+ //assert (f.yPos2 == size / 640);
+
+ uint32 numBlanks = 640 - (f.xPos2 - f.xPos1);
+
+ in->seek((int)f.dataOffset);
+ for (uint32 out = skip; out < size; ) {
+ uint16 opcode = in->readByte();
+
+ if (opcode & 0x80) {
+ if (opcode & 0x40) {
+ opcode &= 0x3f;
+ out += numBlanks + opcode + 1;
+ } else {
+ opcode &= 0x3f;
+ if (opcode & 0x20) {
+ opcode = ((opcode & 0x1f) << 8) + in->readByte();
+ if (opcode & 0x1000) {
+ out += opcode & 0xfff;
+ continue;
+ }
+ }
+ out += opcode + 2;
+ }
+ } else {
+ byte value = opcode & mask;
+ opcode >>= shift;
+ if (_palSize <= value)
+ _palSize = value + 1;
+ if (!opcode)
+ opcode = in->readByte();
+ for (int i = 0; i < opcode; i++, out++) {
+ p[out] = value;
+ }
+ }
+ }
+}
+
+void AnimFrame::decomp5(Common::SeekableReadStream *in, const FrameInfo &f) {
+ byte *p = (byte *)_image.getBasePtr(0, 0);
+
+ uint32 skip = f.initialSkip / 2;
+ uint32 size = f.decompressedEndOffset / 2;
+ //warning("skip: %d, %d", skip % 640, skip / 640);
+ //warning("size: %d, %d", size % 640, size / 640);
+ //assert (f.yPos1 == skip / 640);
+ //assert (f.yPos2 == size / 640);
+
+ in->seek((int)f.dataOffset);
+ for (uint32 out = skip; out < size; ) {
+ uint16 opcode = in->readByte();
+ if (!(opcode & 0x1f)) {
+ opcode = (uint16)((opcode << 3) + in->readByte());
+ if (opcode & 0x400) {
+ // skip these 10 bits
+ out += (opcode & 0x3ff);
+ } else {
+ out += opcode + 2;
+ }
+ } else {
+ byte value = opcode & 0x1f;
+ opcode >>= 5;
+ if (_palSize <= value)
+ _palSize = value + 1;
+ if (!opcode)
+ opcode = in->readByte();
+ for (int i = 0; i < opcode; i++, out++) {
+ p[out] = value;
+ }
+ }
+ }
+}
+
+void AnimFrame::decomp7(Common::SeekableReadStream *in, const FrameInfo &f) {
+ byte *p = (byte *)_image.getBasePtr(0, 0);
+
+ uint32 skip = f.initialSkip / 2;
+ uint32 size = f.decompressedEndOffset / 2;
+ //warning("skip: %d, %d", skip % 640, skip / 640);
+ //warning("size: %d, %d", size % 640, size / 640);
+ //assert (f.yPos1 == skip / 640);
+ //assert (f.yPos2 == size / 640);
+
+ uint32 numBlanks = 640 - (f.xPos2 - f.xPos1);
+
+ in->seek((int)f.dataOffset);
+ for (uint32 out = skip; out < size; ) {
+ uint16 opcode = in->readByte();
+ if (opcode & 0x80) {
+ if (opcode & 0x40) {
+ if (opcode & 0x20) {
+ opcode &= 0x1f;
+ out += numBlanks + opcode + 1;
+ } else {
+ opcode &= 0x1f;
+ if (opcode & 0x10) {
+ opcode = ((opcode & 0xf) << 8) + in->readByte();
+ if (opcode & 0x800) {
+ // skip these 11 bits
+ out += (opcode & 0x7ff);
+ continue;
+ }
+ }
+
+ // skip these 4 bits
+ out += opcode + 2;
+ }
+ } else {
+ opcode &= 0x3f;
+ byte value = in->readByte();
+ if (_palSize <= value)
+ _palSize = value + 1;
+ for (int i = 0; i < opcode; i++, out++) {
+ p[out] = value;
+ }
+ }
+ } else {
+ if (_palSize <= opcode)
+ _palSize = opcode + 1;
+ // set the given value
+ p[out] = (byte)opcode;
+ out++;
+ }
+ }
+}
+
+void AnimFrame::decompFF(Common::SeekableReadStream *in, const FrameInfo &f) {
+ byte *p = (byte *)_image.getBasePtr(0, 0);
+
+ uint32 skip = f.initialSkip / 2;
+ uint32 size = f.decompressedEndOffset / 2;
+
+ in->seek((int)f.dataOffset);
+ for (uint32 out = skip; out < size; ) {
+ uint16 opcode = in->readByte();
+
+ if (opcode < 0x80) {
+ if (_palSize <= opcode)
+ _palSize = opcode + 1;
+ // set the given value
+ p[out] = (byte)opcode;
+ out++;
+ } else {
+ if (opcode < 0xf0) {
+ if (opcode < 0xe0) {
+ // copy old part
+ uint32 old = out + ((opcode & 0x7) << 8) + in->readByte() - 2048;
+ opcode = ((opcode >> 3) & 0xf) + 3;
+ for (int i = 0; i < opcode; i++, out++, old++) {
+ p[out] = p[old];
+ }
+ } else {
+ opcode = (opcode & 0xf) + 1;
+ byte value = in->readByte();
+ if (_palSize <= value)
+ _palSize = value + 1;
+ for (int i = 0; i < opcode; i++, out++) {
+ p[out] = value;
+ }
+ }
+ } else {
+ out += ((opcode & 0xf) << 8) + in->readByte();
+ }
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// SEQUENCE
+//////////////////////////////////////////////////////////////////////////
+
+Sequence::~Sequence() {
+ reset();
+}
+
+void Sequence::reset() {
+ _frames.clear();
+ delete _stream;
+ _stream = NULL;
+}
+
+Sequence *Sequence::load(Common::String name, Common::SeekableReadStream *stream, byte field30) {
+ Sequence *sequence = new Sequence(name);
+
+ if (!sequence->load(stream, field30)) {
+ delete sequence;
+ return NULL;
+ }
+
+ return sequence;
+}
+
+bool Sequence::load(Common::SeekableReadStream *stream, byte field30) {
+ if (!stream)
+ return false;
+
+ // Reset data
+ reset();
+
+ _field30 = field30;
+
+ // Keep stream for later decoding of sequence
+ _stream = stream;
+
+ // Read header to get the number of frames
+ _stream->seek(0);
+ uint32 numframes = _stream->readUint32LE();
+ uint32 unknown = _stream->readUint32LE();
+ debugC(3, kLastExpressDebugGraphics, "Number of frames in sequence: %d / unknown=0x%x", numframes, unknown);
+
+ // Store frames information
+ for (uint i = 0; i < numframes; i++) {
+
+ // Move stream to start of frame
+ _stream->seek((int32)(_sequenceHeaderSize + i * _sequenceFrameSize), SEEK_SET);
+ if (_stream->eos())
+ error("Couldn't seek to the current frame data");
+
+ // Check if there is enough data
+ if ((unsigned)(_stream->size() - _stream->pos()) < _sequenceFrameSize)
+ error("The sequence frame does not have a valid header");
+
+ FrameInfo info;
+ info.read(_stream, true);
+ _frames.push_back(info);
+ }
+
+ _isLoaded = true;
+
+ return true;
+}
+
+FrameInfo *Sequence::getFrameInfo(uint16 index) {
+ if (_frames.size() == 0)
+ error("Trying to decode a sequence before loading its data");
+
+ if (index > _frames.size() - 1)
+ error("Invalid sequence frame requested: %d, max %d", index, _frames.size() - 1);
+
+ return &_frames[index];
+}
+
+AnimFrame *Sequence::getFrame(uint16 index) {
+
+ FrameInfo *frame = getFrameInfo(index);
+
+ if (!frame)
+ return NULL;
+
+ // Skip "invalid" frames
+ if (frame->compressionType == 0)
+ return NULL;
+
+ debugC(9, kLastExpressDebugGraphics, "Decoding sequence %s: frame %d / %d", _name.c_str(), index, _frames.size() - 1);
+
+ return new AnimFrame(_stream, *frame);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// SequenceFrame
+SequenceFrame::~SequenceFrame() {
+ if (_dispose && _sequence) {
+ delete _sequence;
+ }
+
+ _sequence = NULL;
+}
+
+Common::Rect SequenceFrame::draw(Graphics::Surface *surface) {
+ if (!_sequence || _frame >= _sequence->count())
+ return Common::Rect();
+
+ AnimFrame *f = _sequence->getFrame(_frame);
+ if (!f)
+ return Common::Rect();
+
+ Common::Rect rect = f->draw(surface);
+
+ delete f;
+
+ return rect;
+}
+
+bool SequenceFrame::setFrame(uint16 frame) {
+ if (!_sequence)
+ return false;
+
+ if (frame < _sequence->count()) {
+ _frame = frame;
+ return true;
+ } else
+ return false;
+}
+
+bool SequenceFrame::nextFrame() {
+ return setFrame(_frame + 1);
+}
+
+FrameInfo *SequenceFrame::getInfo() {
+ if (!_sequence)
+ error("SequenceFrame::getFrameInfo: Invalid sequence!");
+
+ return _sequence->getFrameInfo(_frame);
+}
+
+Common::String SequenceFrame::getName() {
+ if (!_sequence)
+ error("SequenceFrame::getName: Invalid sequence!");
+
+ return _sequence->getName();
+}
+
+bool SequenceFrame::equal(const SequenceFrame *other) const {
+ return _sequence->getName() == other->_sequence->getName() && _frame == other->_frame;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/sequence.h b/engines/lastexpress/data/sequence.h
new file mode 100644
index 0000000000..25170993df
--- /dev/null
+++ b/engines/lastexpress/data/sequence.h
@@ -0,0 +1,205 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SEQUENCE_H
+#define LASTEXPRESS_SEQUENCE_H
+
+/*
+ Sequence format (.SEQ / .NIS (frame header & data only))
+
+ uint32 {4} - Number of frames in sequence
+ uint32 {4} - Unknown
+
+ frames headers (68 bytes):
+ // for each frame
+ uint32 {4} - Data offset (from beginning of file)
+ uint32 {4} - Unknown
+ uint32 {4} - Palette offset (from beginning of file)
+ uint32 {4} - Top-left X coordinate
+ uint32 {4} - Top-left Y coordinate
+ uint32 {4} - Bottom-right X coordinate
+ uint32 {4} - Bottom-right Y coordinate
+ uint32 {4} - Initial offset of decompressed data (doubled, since each pixel occupies one color word)
+ uint32 {4} - End of data after decompression
+
+ (for SEQ files only)
+ uint16 {2} - Hotspot left
+ uint16 {2} - Hotspot right
+ uint16 {2} - Hotspot top
+ uint16 {2} - Hotspot bottom
+ byte {1} - Compression type
+ byte {1} - Subtype (determines which set of decompression functions will be called) => 0, 1, 2, 3
+ byte {1} - Unknown
+ byte {1} - Unknown
+ uint16 {2} - Unknown
+ byte {1} - Sound action
+ byte {1} - Unknown
+ uint32 {4} - positionId
+ uint32 {4} - Unknown
+ uint16 {2} - Entity Position
+ uint16 {2} - Location (~z-order)
+ uint32 {4} - Next sequence in the linked list
+
+ (for NIS files: found at 0x124)
+ byte {1} - Compression type
+
+ palette data:
+ uint16 {x} - palette data (max size: 256)
+
+ data
+ byte {x} - compressed image data
+*/
+
+#include "lastexpress/drawable.h"
+
+#include "lastexpress/shared.h"
+
+#include "common/array.h"
+#include "common/stream.h"
+
+namespace LastExpress {
+
+enum FrameSubType {
+ kFrameTypeNone = 0,
+ kFrameType1 = 1,
+ kFrameType2 = 2,
+ kFrameType3 = 3
+};
+
+struct FrameInfo {
+ void read(Common::SeekableReadStream *in, bool isSequence);
+
+ uint32 dataOffset; ///< Data offset (from beginning of file)
+ uint32 unknown; ///< FIXME: unknown data
+ uint32 paletteOffset; ///< Palette offset (from beginning of file)
+ uint32 xPos1; ///< Top-left X coordinate
+ uint32 yPos1; ///< Top-left Y coordinate
+ uint32 xPos2; ///< Bottom-right X coordinate
+ uint32 yPos2; ///< Bottom-right Y coordinate
+ uint32 initialSkip; ///< Initial on-screen offset of decompressed data (doubled, since each pixel occupies one color word)
+ uint32 decompressedEndOffset; ///< End of data after decompression
+
+ // NIS frame headers end here. SEQ frame headers have additional 32 bytes of
+ // data, notably the compression type at the position outlined above in
+ // CompPos_SEQ
+
+ Common::Rect hotspot;
+
+ byte compressionType; ///< Type of frame compression (0x03, 0x04, 0x05, 0x07, 0xFF)
+ FrameSubType subType; ///< Subtype (byte)
+
+ byte field_2E;
+ byte keepPreviousFrame;
+ byte field_30;
+ byte field_31;
+ byte soundAction;
+ byte field_33;
+ Position position;
+ byte field_35;
+ int16 field_36;
+ uint32 field_38;
+ EntityPosition entityPosition;
+ uint16 location;
+ uint32 next;
+};
+
+class AnimFrame : public Drawable {
+public:
+ AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f);
+ ~AnimFrame();
+ Common::Rect draw(Graphics::Surface *s);
+
+private:
+ void decomp3(Common::SeekableReadStream *in, const FrameInfo &f);
+ void decomp4(Common::SeekableReadStream *in, const FrameInfo &f);
+ void decomp34(Common::SeekableReadStream *in, const FrameInfo &f, byte mask, byte shift);
+ void decomp5(Common::SeekableReadStream *in, const FrameInfo &f);
+ void decomp7(Common::SeekableReadStream *in, const FrameInfo &f);
+ void decompFF(Common::SeekableReadStream *in, const FrameInfo &f);
+ void readPalette(Common::SeekableReadStream *in, const FrameInfo &f);
+
+ Graphics::Surface _image;
+ uint16 _palSize;
+ uint16 *_palette;
+ Common::Rect _rect;
+};
+
+class Sequence {
+public:
+ Sequence(Common::String name) : _stream(NULL), _isLoaded(false), _name(name), _field30(15) {}
+ ~Sequence();
+
+ static Sequence *load(Common::String name, Common::SeekableReadStream *stream = NULL, byte field30 = 15);
+
+ bool load(Common::SeekableReadStream *stream, byte field30 = 15);
+
+ uint16 count() const { return (uint16)_frames.size(); }
+ AnimFrame *getFrame(uint16 index = 0);
+ FrameInfo *getFrameInfo(uint16 index = 0);
+
+ Common::String getName() { return _name; }
+ byte getField30() { return _field30; }
+
+ bool isLoaded() { return _isLoaded; }
+
+private:
+ static const uint32 _sequenceHeaderSize = 8;
+ static const uint32 _sequenceFrameSize = 68;
+
+ void reset();
+
+ Common::Array<FrameInfo> _frames;
+ Common::SeekableReadStream *_stream;
+ bool _isLoaded;
+
+ Common::String _name;
+ byte _field30; // used when copying sequences
+};
+
+class SequenceFrame : public Drawable {
+public:
+ SequenceFrame(Sequence *sequence, uint16 frame = 0, bool dispose = false) : _sequence(sequence), _frame(frame), _dispose(dispose) {}
+ ~SequenceFrame();
+
+ Common::Rect draw(Graphics::Surface *surface);
+
+ bool setFrame(uint16 frame);
+ uint32 getFrame() { return _frame; }
+ bool nextFrame();
+
+ Common::String getName();
+ FrameInfo *getInfo();
+
+ bool equal(const SequenceFrame *other) const;
+
+private:
+ Sequence *_sequence;
+ uint16 _frame;
+ bool _dispose;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SEQUENCE_H
diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp
new file mode 100644
index 0000000000..496bd58772
--- /dev/null
+++ b/engines/lastexpress/data/snd.cpp
@@ -0,0 +1,141 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based on the Xentax Wiki documentation:
+// http://wiki.xentax.com/index.php/The_Last_Express_SND
+
+#include "lastexpress/data/snd.h"
+
+#include "lastexpress/debug.h"
+
+#include "sound/decoders/adpcm.h"
+#include "sound/audiostream.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// Sound
+//////////////////////////////////////////////////////////////////////////
+SimpleSound::SimpleSound() : _size(0), _blocks(0), _blockSize(0) {}
+
+SimpleSound::~SimpleSound() {
+ stop();
+}
+
+// Stop the sound
+void SimpleSound::stop() const {
+ g_system->getMixer()->stopHandle(_handle);
+}
+
+void SimpleSound::loadHeader(Common::SeekableReadStream *in) {
+ _size = in->readUint32LE();
+ _blocks = in->readUint16LE();
+ debugC(5, kLastExpressDebugSound, " sound header data: size=\"%d\", %d blocks", _size, _blocks);
+
+ assert (_size % _blocks == 0);
+ _blockSize = _size / _blocks;
+}
+
+Audio::AudioStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size) const {
+ return Audio::makeADPCMStream(in, DisposeAfterUse::YES, size, Audio::kADPCMMSImaLastExpress, 44100, 1, _blockSize);
+}
+
+void SimpleSound::play(Audio::AudioStream *as) {
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, as);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// StreamedSound
+//////////////////////////////////////////////////////////////////////////
+StreamedSound::StreamedSound() {}
+StreamedSound::~StreamedSound() {}
+
+bool StreamedSound::load(Common::SeekableReadStream *stream) {
+ if (!stream)
+ return false;
+
+ g_system->getMixer()->stopHandle(_handle);
+
+ loadHeader(stream);
+
+ // Start decoding the input stream
+ Audio::AudioStream *as = makeDecoder(stream, _size);
+
+ // Start playing the decoded audio stream
+ play(as);
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// StreamedSound
+//////////////////////////////////////////////////////////////////////////
+AppendableSound::AppendableSound() : SimpleSound() {
+ // Create an audio stream where the decoded chunks will be appended
+ _as = Audio::makeQueuingAudioStream(44100, false);
+ _finished = false;
+
+ // Start playing the decoded audio stream
+ play(_as);
+
+ // Initialize the block size
+ // TODO: get it as an argument?
+ _blockSize = 739;
+}
+
+AppendableSound::~AppendableSound() {
+ finish();
+
+ _as = NULL;
+}
+
+void AppendableSound::queueBuffer(const byte *data, uint32 size) {
+ Common::MemoryReadStream *buffer = new Common::MemoryReadStream(data, size);
+ queueBuffer(buffer);
+}
+
+void AppendableSound::queueBuffer(Common::SeekableReadStream *bufferIn) {
+ if (!_as)
+ error("AppendableSound::queueBuffer - internal error: the audio stream is invalid!");
+
+ // Setup the ADPCM decoder
+ uint32 sizeIn = (uint32)bufferIn->size();
+ Audio::AudioStream *adpcm = makeDecoder(bufferIn, sizeIn);
+
+ // Queue the stream
+ _as->queueAudioStream(adpcm);
+}
+
+void AppendableSound::finish() {
+ if (!_as)
+ error("AppendableSound::queueBuffer - internal error: the audio stream is invalid!");
+
+ if (!_finished)
+ _as->finish();
+
+ _finished = true;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/snd.h b/engines/lastexpress/data/snd.h
new file mode 100644
index 0000000000..2e0bc8c1b0
--- /dev/null
+++ b/engines/lastexpress/data/snd.h
@@ -0,0 +1,97 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SND_H
+#define LASTEXPRESS_SND_H
+
+/*
+ Sound format (.SND / .LNK)
+
+ uint32 {4} - data size
+ uint16 {2} - number of blocks
+
+ // for each block
+ int16 {2} - initial sample
+ byte {1} - initial index
+ byte {1} - unused (00)
+ byte {x} - IMA ADPCM sample codes
+*/
+
+#include "common/stream.h"
+#include "sound/mixer.h"
+
+namespace Audio {
+ class AudioStream;
+ class QueuingAudioStream;
+}
+
+namespace LastExpress {
+
+class SimpleSound {
+public:
+ SimpleSound();
+ virtual ~SimpleSound();
+
+ void stop() const;
+
+protected:
+ void loadHeader(Common::SeekableReadStream *in);
+ Audio::AudioStream *makeDecoder(Common::SeekableReadStream *in, uint32 size) const;
+ void play(Audio::AudioStream *as);
+
+ uint32 _size; ///< data size
+ ///< - NIS: size of all blocks, including those located in the matching LNK file
+ ///< - LNK: size of the LNK file itself, including the header
+ ///< - SND: size of all blocks
+ uint16 _blocks; ///< number of blocks
+ uint32 _blockSize;
+ Audio::SoundHandle _handle;
+};
+
+class StreamedSound : public SimpleSound {
+public:
+ StreamedSound();
+ ~StreamedSound();
+
+ bool load(Common::SeekableReadStream *stream);
+};
+
+class AppendableSound : public SimpleSound {
+public:
+ AppendableSound();
+ ~AppendableSound();
+
+ void queueBuffer(const byte *data, uint32 size);
+ void queueBuffer(Common::SeekableReadStream *bufferIn);
+ void finish();
+
+private:
+ Audio::QueuingAudioStream *_as;
+ bool _finished;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SND_H
diff --git a/engines/lastexpress/data/subtitle.cpp b/engines/lastexpress/data/subtitle.cpp
new file mode 100644
index 0000000000..67d6445ab9
--- /dev/null
+++ b/engines/lastexpress/data/subtitle.cpp
@@ -0,0 +1,244 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based on the Xentax Wiki documentation:
+// http://wiki.xentax.com/index.php/The_Last_Express_SBE
+
+#include "lastexpress/data/subtitle.h"
+
+#include "lastexpress/data/font.h"
+
+#include "lastexpress/debug.h"
+
+#include "common/debug.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// Subtitle
+//////////////////////////////////////////////////////////////////////////
+class Subtitle {
+public:
+ Subtitle() : _timeStart(0), _timeStop(0), _topLength(0), _topText(NULL),
+ _bottomLength(0), _bottomText(NULL) {}
+ ~Subtitle() { reset(); }
+
+ bool load(Common::SeekableReadStream *in);
+ Common::Rect draw(Graphics::Surface *surface, Font *font);
+
+ uint16 getTimeStart() const { return _timeStart; }
+ uint16 getTimeStop() const { return _timeStop; }
+
+private:
+ uint16 _timeStart; ///< display start time
+ uint16 _timeStop; ///< display stop time
+
+ uint16 _topLength; ///< top line length
+ uint16 *_topText; ///< bottom line length
+
+ uint16 _bottomLength; ///< top line (UTF-16 string)
+ uint16 *_bottomText; ///< bottom line (UTF-16 string)
+
+ void reset();
+};
+
+void Subtitle::reset() {
+ delete[] _topText;
+ delete[] _bottomText;
+ _topText = NULL;
+ _bottomText = NULL;
+}
+
+template<typename T>
+T *newArray(size_t n) {
+ if (n <= (size_t)-1 / sizeof(T))
+ return new T[n];
+
+ // n is too large
+ return NULL;
+}
+
+bool Subtitle::load(Common::SeekableReadStream *in) {
+ reset();
+
+ if (!in)
+ return false;
+
+ // Read the display times
+ _timeStart = in->readUint16LE();
+ _timeStop = in->readUint16LE();
+
+ // Read the text lengths
+ _topLength = in->readUint16LE();
+ _bottomLength = in->readUint16LE();
+
+ // Create the buffers
+ if (_topLength) {
+ _topText = newArray<uint16>(_topLength + 1);
+ if (!_topText)
+ return false;
+
+ _topText[_topLength] = 0;
+ }
+ if (_bottomLength) {
+ _bottomText = newArray<uint16>(_bottomLength + 1);
+ if (!_bottomText)
+ return false;
+
+ _bottomText[_bottomLength] = 0;
+ }
+
+ // Read the texts
+ for (int i = 0; i < _topLength; i++)
+ _topText[i] = in->readUint16LE();
+ for (int i = 0; i < _bottomLength; i++)
+ _bottomText[i] = in->readUint16LE();
+
+ debugC(9, kLastExpressDebugSubtitle, " %d -> %d:", _timeStart, _timeStop);
+ if (_topLength)
+ debugC(9, kLastExpressDebugSubtitle, "\t%ls", (wchar_t *)_topText);
+ if (_bottomLength)
+ debugC(9, kLastExpressDebugSubtitle, "\t%ls", (wchar_t *)_bottomText);
+
+ return true;
+}
+
+Common::Rect Subtitle::draw(Graphics::Surface *surface, Font *font) {
+ Common::Rect rectTop, rectBottom;
+
+ //FIXME find out proper subtitles coordinates (and hope it's hardcoded and not stored in the sequence or animation)
+ rectTop = font->drawString(surface, 100, 100, _topText, _topLength);
+ rectBottom = font->drawString(surface, 100, 300, _bottomText, _bottomLength);
+
+ rectTop.extend(rectBottom);
+
+ return rectTop;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// SubtitleManager
+//////////////////////////////////////////////////////////////////////////
+SubtitleManager::SubtitleManager(Font *font) : _font(font), _maxTime(0), _currentIndex(-1), _lastIndex(-1) {}
+
+SubtitleManager::~SubtitleManager() {
+ reset();
+
+ // Zero passed pointers
+ _font = NULL;
+}
+
+void SubtitleManager::reset() {
+ for (int i = 0; i < (int)_subtitles.size(); i++)
+ delete _subtitles[i];
+
+ _subtitles.clear();
+ _currentIndex = -1;
+ _lastIndex = -1;
+}
+
+bool SubtitleManager::load(Common::SeekableReadStream *stream) {
+ if (!stream)
+ return false;
+
+ reset();
+
+ // Read header to get the number of subtitles
+ uint32 numSubtitles = stream->readUint16LE();
+ if (stream->eos())
+ error("Cannot read from subtitle file");
+
+ debugC(3, kLastExpressDebugSubtitle, "Number of subtitles in file: %d", numSubtitles);
+
+ // TODO: Check that stream contain enough data
+ //if (stream->size() < (signed)(numSubtitles * sizeof(SubtitleData))) {
+ //debugC(2, kLastExpressDebugSubtitle, "Subtitle file does not contain valid data!");
+ //return false;
+ //}
+
+ // Read the list of subtitles
+ _maxTime = 0;
+ for (uint i = 0; i < numSubtitles; i++) {
+ Subtitle *subtitle = new Subtitle();
+ if (!subtitle->load(stream)) {
+ // Failed to read this line
+ reset();
+
+ delete subtitle;
+
+ return false;
+ }
+
+ // Update the max time
+ if (subtitle->getTimeStop() > _maxTime)
+ _maxTime = subtitle->getTimeStop();
+
+ _subtitles.push_back(subtitle);
+ }
+
+ delete stream;
+
+ return true;
+}
+
+uint16 SubtitleManager::getMaxTime() const {
+ return _maxTime;
+}
+
+void SubtitleManager::setTime(uint16 time) {
+ _currentIndex = -1;
+
+ // Find the appropriate line to show
+ for (int16 i = 0; i < (int16)_subtitles.size(); i++) {
+ if ((time >= _subtitles[i]->getTimeStart()) && (time <= _subtitles[i]->getTimeStop())) {
+ // Keep the index of the line to show
+ _currentIndex = i;
+ return;
+ }
+ }
+}
+
+bool SubtitleManager::hasChanged() const {
+ // TODO: mark the old line rect as dirty
+ if (_currentIndex != _lastIndex)
+ return true;
+ else
+ return false;
+}
+
+Common::Rect SubtitleManager::draw(Graphics::Surface *surface) {
+ // Update the last drawn index
+ _lastIndex = _currentIndex;
+
+ // Return if we don't have to draw any line
+ if (_currentIndex == -1)
+ return Common::Rect();
+
+ // Draw the current line
+ assert(_currentIndex >= 0 && _currentIndex < (int16)_subtitles.size());
+ return _subtitles[_currentIndex]->draw(surface, _font);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/subtitle.h b/engines/lastexpress/data/subtitle.h
new file mode 100644
index 0000000000..9acb7068f1
--- /dev/null
+++ b/engines/lastexpress/data/subtitle.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SUBTITLE_H
+#define LASTEXPRESS_SUBTITLE_H
+
+/*
+ Subtitle format (.SBE)
+
+ uint16 {2} - number of subtitles
+
+ // for each subtitle
+ uint16 {2} - display start time
+ uint16 {2} - display stop time
+ uint16 {2} - top line length
+ uint16 {2} - bottom line length
+ byte {x} - top line (UTF-16 string)
+ byte {x} - bottom line (UTF-16 string)
+
+ Subtitles seem to be drawn on screen at (80, 420) x (560, 458)
+*/
+
+#include "lastexpress/drawable.h"
+
+#include "common/array.h"
+#include "common/stream.h"
+
+namespace LastExpress {
+
+class Font;
+class Subtitle;
+
+class SubtitleManager : public Drawable {
+public:
+ SubtitleManager(Font *font);
+ ~SubtitleManager();
+
+ bool load(Common::SeekableReadStream *stream);
+ uint16 getMaxTime() const;
+ void setTime(uint16 time);
+ bool hasChanged() const;
+ Common::Rect draw(Graphics::Surface *surface);
+
+private:
+ Common::Array<Subtitle *> _subtitles;
+ Font *_font;
+ uint16 _maxTime;
+
+ int16 _currentIndex;
+ int16 _lastIndex;
+
+ void reset();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SUBTITLE_H
diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp
new file mode 100644
index 0000000000..66949c3d34
--- /dev/null
+++ b/engines/lastexpress/debug.cpp
@@ -0,0 +1,1177 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/debug.h"
+
+// Data
+#include "lastexpress/data/animation.h"
+#include "lastexpress/data/background.h"
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/scene.h"
+#include "lastexpress/data/sequence.h"
+#include "lastexpress/data/snd.h"
+#include "lastexpress/data/subtitle.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/beetle.h"
+#include "lastexpress/game/fight.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savegame.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+#include "common/debug-channels.h"
+#include "common/events.h"
+#include "common/md5.h"
+
+namespace LastExpress {
+
+Debugger::Debugger(LastExpressEngine *engine) : _engine(engine), _command(NULL), _numParams(0), _commandParams(NULL) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Register the debugger commands
+
+ // General
+ DCmd_Register("help", WRAP_METHOD(Debugger, cmdHelp));
+
+ // Data
+ DCmd_Register("ls", WRAP_METHOD(Debugger, cmdListFiles));
+ DCmd_Register("dump", WRAP_METHOD(Debugger, cmdDumpFiles));
+
+ DCmd_Register("showframe", WRAP_METHOD(Debugger, cmdShowFrame));
+ DCmd_Register("showbg", WRAP_METHOD(Debugger, cmdShowBg));
+ DCmd_Register("playseq", WRAP_METHOD(Debugger, cmdPlaySeq));
+ DCmd_Register("playsnd", WRAP_METHOD(Debugger, cmdPlaySnd));
+ DCmd_Register("playsbe", WRAP_METHOD(Debugger, cmdPlaySbe));
+ DCmd_Register("playnis", WRAP_METHOD(Debugger, cmdPlayNis));
+
+ // Scene & interaction
+ DCmd_Register("loadscene", WRAP_METHOD(Debugger, cmdLoadScene));
+ DCmd_Register("fight", WRAP_METHOD(Debugger, cmdFight));
+ DCmd_Register("beetle", WRAP_METHOD(Debugger, cmdBeetle));
+
+ // Game
+ DCmd_Register("delta", WRAP_METHOD(Debugger, cmdTimeDelta));
+ DCmd_Register("time", WRAP_METHOD(Debugger, cmdTime));
+ DCmd_Register("show", WRAP_METHOD(Debugger, cmdShow));
+ DCmd_Register("entity", WRAP_METHOD(Debugger, cmdEntity));
+
+ // Misc
+ DCmd_Register("loadgame", WRAP_METHOD(Debugger, cmdLoadGame));
+ DCmd_Register("chapter", WRAP_METHOD(Debugger, cmdSwitchChapter));
+ DCmd_Register("clear", WRAP_METHOD(Debugger, cmdClear));
+
+ resetCommand();
+
+ _soundStream = new StreamedSound();
+}
+
+Debugger::~Debugger() {
+ DebugMan.clearAllDebugChannels();
+
+ delete _soundStream;
+ resetCommand();
+
+ _command = NULL;
+ _commandParams = NULL;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Helper functions
+//////////////////////////////////////////////////////////////////////////
+bool Debugger::hasCommand() const {
+ return (_numParams != 0);
+}
+
+void Debugger::resetCommand() {
+ SAFE_DELETE(_command);
+
+ if (_commandParams)
+ for (int i = 0; i < _numParams; i++)
+ free(_commandParams[i]);
+
+ free(_commandParams);
+ _commandParams = NULL;
+ _numParams = 0;
+}
+
+int Debugger::getNumber(const char *arg) const {
+ return strtol(arg, (char **)NULL, 0);
+}
+
+void Debugger::copyCommand(int argc, const char **argv) {
+ _commandParams = (char **)malloc(sizeof(char *) * (uint)argc);
+ if (!_commandParams)
+ return;
+
+ _numParams = argc;
+
+ for (int i = 0; i < _numParams; i++) {
+ _commandParams[i] = (char *)malloc(strlen(argv[i]) + 1);
+ memset(_commandParams[i], 0, strlen(argv[i]) + 1);
+ strcpy(_commandParams[i], argv[i]);
+ }
+
+ // Exit the debugger!
+ Cmd_Exit(0, 0);
+}
+
+void Debugger::callCommand() {
+ if (_command)
+ (*_command)(_numParams, const_cast<const char **>(_commandParams));
+}
+
+void Debugger::loadArchive(ArchiveIndex index) const {
+ _engine->getResourceManager()->loadArchive(index);
+ getScenes()->loadSceneDataFile(index);
+}
+
+// Restore loaded archive
+void Debugger::restoreArchive() const {
+
+ ArchiveIndex index = kArchiveCd1;
+
+ switch (getProgress().chapter) {
+ default:
+ case kChapter1:
+ index = kArchiveCd1;
+ break;
+
+ case kChapter2:
+ case kChapter3:
+ index = kArchiveCd2;
+ break;
+
+ case kChapter4:
+ case kChapter5:
+ index = kArchiveCd3;
+ break;
+ }
+
+ _engine->getResourceManager()->loadArchive(index);
+ getScenes()->loadSceneDataFile(index);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Debugger commands
+//////////////////////////////////////////////////////////////////////////
+bool Debugger::cmdHelp(int, const char **) {
+ DebugPrintf("Debug flags\n");
+ DebugPrintf("-----------\n");
+ DebugPrintf(" debugflag_list - Lists the available debug flags and their status\n");
+ DebugPrintf(" debugflag_enable - Enables a debug flag\n");
+ DebugPrintf(" debugflag_disable - Disables a debug flag\n");
+ DebugPrintf("\n");
+ DebugPrintf("Commands\n");
+ DebugPrintf("--------\n");
+ DebugPrintf(" ls - list files in the archive\n");
+ DebugPrintf(" dump - dump a list of files in all archives\n");
+ DebugPrintf("\n");
+ DebugPrintf(" showframe - show a frame from a sequence\n");
+ DebugPrintf(" showbg - show a background\n");
+ DebugPrintf(" playseq - play a sequence\n");
+ DebugPrintf(" playsnd - play a sound\n");
+ DebugPrintf(" playsbe - play a subtitle\n");
+ DebugPrintf(" playnis - play an animation\n");
+ DebugPrintf("\n");
+ DebugPrintf(" loadscene - load a scene\n");
+ DebugPrintf(" fight - start a fight\n");
+ DebugPrintf(" beetle - start the beetle game\n");
+ DebugPrintf("\n");
+ DebugPrintf(" delta - Adjust the time delta\n");
+ DebugPrintf(" show - show game data\n");
+ DebugPrintf(" entity - show entity data\n");
+ DebugPrintf("\n");
+ DebugPrintf(" loadgame - load a saved game\n");
+ DebugPrintf(" chapter - switch to a specific chapter\n");
+ DebugPrintf(" clear - clear the screen\n");
+ DebugPrintf("\n");
+ return true;
+}
+
+/**
+ * Command: list files in archive
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdListFiles(int argc, const char **argv) {
+ if (argc == 2 || argc == 3) {
+ Common::String filter(const_cast<char *>(argv[1]));
+
+ // Load the proper archive
+ if (argc == 3)
+ loadArchive((ArchiveIndex)getNumber(argv[2]));
+
+ Common::ArchiveMemberList list;
+ int count = _engine->getResourceManager()->listMatchingMembers(list, filter);
+
+ DebugPrintf("Number of matches: %d\n", count);
+ for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it)
+ DebugPrintf(" %s\n", (*it)->getName().c_str());
+
+ // Restore archive
+ if (argc == 3)
+ restoreArchive();
+ } else {
+ DebugPrintf("Syntax: ls <filter> (use * for all) (<cd number>)\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: Dump the list of files in the archive
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdDumpFiles(int argc, const char **) {
+#define OUTPUT_ARCHIVE_FILES(name, filename) { \
+ _engine->getResourceManager()->reset(); \
+ _engine->getResourceManager()->loadArchive(filename); \
+ Common::ArchiveMemberList list; \
+ int count = _engine->getResourceManager()->listMatchingMembers(list, "*"); \
+ debugC(1, kLastExpressDebugResource, "\n\n--------------------------------------------------------------------\n"); \
+ debugC(1, kLastExpressDebugResource, "-- " #name " (%d files)\n", count); \
+ debugC(1, kLastExpressDebugResource, "--------------------------------------------------------------------\n\n"); \
+ debugC(1, kLastExpressDebugResource, "Filename,Size,MD5\n"); \
+ for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) { \
+ Common::SeekableReadStream *stream = getArchive((*it)->getName()); \
+ if (!stream) { \
+ DebugPrintf("ERROR: Cannot create stream for file: %s\n", (*it)->getName().c_str()); \
+ restoreArchive(); \
+ return true; \
+ } \
+ Common::String md5str = Common::computeStreamMD5AsString(*stream); \
+ debugC(1, kLastExpressDebugResource, "%s, %d, %s", (*it)->getName().c_str(), stream->size(), md5str.c_str()); \
+ delete stream; \
+ } \
+}
+
+ if (argc == 1) {
+ // For each archive file, dump the list of files
+ if (_engine->isDemo()) {
+ OUTPUT_ARCHIVE_FILES("DEMO", "DEMO.HPF");
+ } else {
+ OUTPUT_ARCHIVE_FILES("HD", "HD.HPF");
+ OUTPUT_ARCHIVE_FILES("CD 1", "CD1.HPF");
+ OUTPUT_ARCHIVE_FILES("CD 2", "CD2.HPF");
+ OUTPUT_ARCHIVE_FILES("CD 3", "CD3.HPF");
+ }
+
+ // Restore current loaded archive
+ restoreArchive();
+ } else {
+ DebugPrintf("Syntax: dump");
+ }
+
+ return true;
+}
+
+/**
+ * Command: Shows a frame
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdShowFrame(int argc, const char **argv) {
+ if (argc == 3 || argc == 4) {
+ Common::String filename(const_cast<char *>(argv[1]));
+ filename += ".seq";
+
+ if (argc == 4)
+ loadArchive((ArchiveIndex)getNumber(argv[3]));
+
+ if (!_engine->getResourceManager()->hasFile(filename)) {
+ DebugPrintf("Cannot find file: %s\n", filename.c_str());
+ return true;
+ }
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdShowFrame);
+ copyCommand(argc, argv);
+
+ return Cmd_Exit(0, 0);
+ } else {
+ Sequence sequence(filename);
+ if (sequence.load(getArchive(filename))) {
+ _engine->getCursor()->show(false);
+ clearBg(GraphicsManager::kBackgroundOverlay);
+
+ AnimFrame *frame = sequence.getFrame((uint16)getNumber(argv[2]));
+ if (!frame) {
+ DebugPrintf("Invalid frame index '%s'\n", argv[2]);
+ resetCommand();
+ return true;
+ }
+
+ _engine->getGraphicsManager()->draw(frame, GraphicsManager::kBackgroundOverlay);
+ delete frame;
+
+ askForRedraw();
+ redrawScreen();
+
+ _engine->_system->delayMillis(1000);
+ _engine->getCursor()->show(true);
+ }
+
+ resetCommand();
+
+ if (argc == 4)
+ restoreArchive();
+ }
+ } else {
+ DebugPrintf("Syntax: cmd_showframe <seqname> <index> (<cd number>)\n");
+ }
+ return true;
+}
+
+/**
+ * Command: shows a background
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdShowBg(int argc, const char **argv) {
+ if (argc == 2 || argc == 3) {
+ Common::String filename(const_cast<char *>(argv[1]));
+
+ if (argc == 3)
+ loadArchive((ArchiveIndex)getNumber(argv[2]));
+
+ if (!_engine->getResourceManager()->hasFile(filename + ".BG")) {
+ DebugPrintf("Cannot find file: %s\n", (filename + ".BG").c_str());
+ return true;
+ }
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdShowBg);
+ copyCommand(argc, argv);
+
+ return Cmd_Exit(0, 0);
+ } else {
+ clearBg(GraphicsManager::kBackgroundC);
+
+ Background *background = _engine->getResourceManager()->loadBackground(filename);
+ if (background) {
+ _engine->getGraphicsManager()->draw(background, GraphicsManager::kBackgroundC);
+ delete background;
+ askForRedraw();
+ }
+
+ redrawScreen();
+
+ if (argc == 3)
+ restoreArchive();
+
+ // Pause for a second to be able to see the background
+ _engine->_system->delayMillis(1000);
+
+ resetCommand();
+ }
+ } else {
+ DebugPrintf("Syntax: showbg <bgname> (<cd number>)\n");
+ }
+ return true;
+}
+
+/**
+ * Command: plays a sequence.
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdPlaySeq(int argc, const char **argv) {
+ if (argc == 2 || argc == 3) {
+ Common::String filename(const_cast<char *>(argv[1]));
+ filename += ".seq";
+
+ if (argc == 3)
+ loadArchive((ArchiveIndex)getNumber(argv[2]));
+
+ if (!_engine->getResourceManager()->hasFile(filename)) {
+ DebugPrintf("Cannot find file: %s\n", filename.c_str());
+ return true;
+ }
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdPlaySeq);
+ copyCommand(argc, argv);
+
+ return Cmd_Exit(0, 0);
+ } else {
+ Sequence *sequence = new Sequence(filename);
+ if (sequence->load(getArchive(filename))) {
+
+ // Check that we have at least a frame to show
+ if (sequence->count() == 0) {
+ delete sequence;
+ return false;
+ }
+
+ _engine->getCursor()->show(false);
+
+ SequenceFrame player(sequence, 0, true);
+ do {
+ // Clear screen
+ clearBg(GraphicsManager::kBackgroundA);
+
+ _engine->getGraphicsManager()->draw(&player, GraphicsManager::kBackgroundA);
+
+ askForRedraw();
+ redrawScreen();
+
+ // Handle right-click to interrupt sequence
+ Common::Event ev;
+ _engine->getEventManager()->pollEvent(ev);
+ if (ev.type == Common::EVENT_RBUTTONUP)
+ break;
+
+ _engine->_system->delayMillis(175);
+
+ // go to the next frame
+ } while (player.nextFrame());
+ _engine->getCursor()->show(true);
+ } else {
+ // Sequence player is deleting his reference to the sequence, but we need to take care of it if the
+ // sequence could not be loaded
+ delete sequence;
+ }
+
+ resetCommand();
+
+ if (argc == 3)
+ restoreArchive();
+ }
+ } else {
+ DebugPrintf("Syntax: playseq <seqname> (<cd number>)\n");
+ }
+ return true;
+}
+
+/**
+ * Command: plays a sound
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdPlaySnd(int argc, const char **argv) {
+ if (argc == 2 || argc == 3) {
+
+ if (argc == 3)
+ loadArchive((ArchiveIndex)getNumber(argv[2]));
+
+ // Add .SND at the end of the filename if needed
+ Common::String name(const_cast<char *>(argv[1]));
+ if (!name.contains('.'))
+ name += ".SND";
+
+ if (!_engine->getResourceManager()->hasFile(name)) {
+ DebugPrintf("Cannot find file: %s\n", name.c_str());
+ return true;
+ }
+
+ _engine->_system->getMixer()->stopAll();
+
+ _soundStream->load(getArchive(name));
+
+ if (argc == 3)
+ restoreArchive();
+ } else {
+ DebugPrintf("Syntax: playsnd <sndname> (<cd number>)\n");
+ }
+ return true;
+}
+
+/**
+ * Command: plays subtitles
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdPlaySbe(int argc, const char **argv) {
+ if (argc == 2 || argc == 3) {
+ Common::String filename(const_cast<char *>(argv[1]));
+
+ if (argc == 3)
+ loadArchive((ArchiveIndex)getNumber(argv[2]));
+
+ filename += ".sbe";
+
+ if (!_engine->getResourceManager()->hasFile(filename)) {
+ DebugPrintf("Cannot find file: %s\n", filename.c_str());
+ return true;
+ }
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdPlaySbe);
+ copyCommand(argc, argv);
+
+ return Cmd_Exit(0, 0);
+ } else {
+ SubtitleManager subtitle(_engine->getFont());
+ if (subtitle.load(getArchive(filename))) {
+ _engine->getCursor()->show(false);
+ for (uint16 i = 0; i < subtitle.getMaxTime(); i += 25) {
+ clearBg(GraphicsManager::kBackgroundAll);
+
+ subtitle.setTime(i);
+ _engine->getGraphicsManager()->draw(&subtitle, GraphicsManager::kBackgroundOverlay);
+
+ askForRedraw();
+ redrawScreen();
+
+ // Handle right-click to interrupt sequence
+ Common::Event ev;
+ _engine->getEventManager()->pollEvent(ev);
+ if (ev.type == Common::EVENT_RBUTTONUP)
+ break;
+
+ _engine->_system->delayMillis(500);
+ }
+ _engine->getCursor()->show(true);
+ }
+
+ if (argc == 3)
+ restoreArchive();
+
+ resetCommand();
+ }
+ } else {
+ DebugPrintf("Syntax: playsbe <sbename> (<cd number>)\n");
+ }
+ return true;
+}
+
+/**
+ * Command: plays a NIS animation sequence.
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdPlayNis(int argc, const char **argv) {
+ if (argc == 2 || argc == 3) {
+ Common::String name(const_cast<char *>(argv[1]));
+
+ if (argc == 3)
+ loadArchive((ArchiveIndex)getNumber(argv[2]));
+
+ // If we got a nis filename, check that the file exists
+ if (name.contains('.') && _engine->getResourceManager()->hasFile(name)) {
+ DebugPrintf("Cannot find file: %s\n", name.c_str());
+ return true;
+ }
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdPlayNis);
+ copyCommand(argc, argv);
+
+ return Cmd_Exit(0, 0);
+ } else {
+ // Make sure we are not called in a loop
+ _numParams = 0;
+
+
+ // Check if we got a nis filename or an animation index
+ if (name.contains('.')) {
+ Animation animation;
+ if (animation.load(getArchive(name))) {
+ _engine->getCursor()->show(false);
+ animation.play();
+ _engine->getCursor()->show(true);
+ }
+ } else {
+ getAction()->playAnimation((EventIndex)atoi(name.c_str()), true);
+ }
+
+ if (argc == 3)
+ restoreArchive();
+
+ resetCommand();
+ }
+ } else {
+ DebugPrintf("Syntax: playnis <nisname.nis or animation index> (<cd number>)\n");
+ }
+ return true;
+}
+
+/**
+ * Command: loads a scene
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdLoadScene(int argc, const char **argv) {
+ if (argc == 2 || argc == 3) {
+ int cd = 1;
+ SceneIndex index = (SceneIndex)getNumber(argv[1]);
+
+ // Check args
+ if (argc == 3)
+ loadArchive((ArchiveIndex)getNumber(argv[2]));
+
+ if (index > 2500) {
+ DebugPrintf("Error: invalid index value (0-2500)");
+ return true;
+ }
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdLoadScene);
+ copyCommand(argc, argv);
+
+ return Cmd_Exit(0, 0);
+ } else {
+
+ clearBg(GraphicsManager::kBackgroundAll);
+
+ /************ DEBUG *************************/
+ // Use to find scenes with certain values
+
+ //for (int i = index; i < 2500; i++) {
+ // loadSceneObject(scene, i);
+
+ // if (scene.getHeader() && scene.getHeader()->car == 5 && scene.getHeader()->position == 81) {
+ // DebugPrintf("Found scene: %d", i);
+
+ // // Draw scene found
+ // _engine->getGraphicsManager()->draw(&scene, GraphicsManager::kBackgroundC);
+
+ // askForRedraw();
+ // redrawScreen();
+ // _engine->_system->delayMillis(500);
+
+ // break;
+ // }
+ //}
+
+ //delete _sceneLoader;
+ //resetCommand();
+ //return true;
+
+ /*********************************************/
+ Scene *scene = getScenes()->get(index);
+ if (!scene) {
+ DebugPrintf("Cannot load scene %i from CD %i", index, cd);
+ resetCommand();
+
+ return true;
+ }
+
+ _engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC);
+
+ askForRedraw();
+ redrawScreen();
+
+ // Pause for a second to be able to see the scene
+ _engine->_system->delayMillis(500);
+
+ if (argc == 3)
+ restoreArchive();
+
+ resetCommand();
+ }
+ } else {
+ DebugPrintf("Syntax: loadscene <scene index> (<cd number>)\n");
+ }
+ return true;
+}
+
+/**
+ * Command: starts a fight sequence
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdFight(int argc, const char **argv) {
+ if (argc == 2) {
+ FightType type = (FightType)getNumber(argv[1]);
+
+ // Load proper data file
+ ArchiveIndex index = kArchiveCd1;
+ switch (type) {
+ default:
+ goto error;
+
+ case kFightMilos:
+ index = kArchiveCd1;
+ break;
+
+ case kFightAnna:
+ index = kArchiveCd2;
+ break;
+
+ case kFightIvo:
+ case kFightSalko:
+ case kFightVesna:
+ index = kArchiveCd3;
+ break;
+ }
+
+ loadArchive(index);
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdFight);
+ copyCommand(argc, argv);
+
+ return false;
+ } else {
+ // Make sure we are not called in a loop
+ _numParams = 0;
+
+ clearBg(GraphicsManager::kBackgroundAll);
+ askForRedraw();
+ redrawScreen();
+
+ SceneIndex lastScene = getState()->scene;
+
+ getFight()->setup(type) ? DebugPrintf("Lost fight!\n") : DebugPrintf("Won fight!\n");
+
+ // Pause for a second to be able to see the final scene
+ _engine->_system->delayMillis(1000);
+
+ // Restore loaded archive
+ restoreArchive();
+
+ // Stop audio and restore scene
+ getSound()->stopAllSound();
+
+ clearBg(GraphicsManager::kBackgroundAll);
+
+ Scene *scene = getScenes()->get(lastScene);
+ _engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC);
+
+ askForRedraw();
+ redrawScreen();
+
+ resetCommand();
+ }
+ } else {
+error:
+ DebugPrintf("Syntax: fight <id> (id=2001-2005)\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: starts the beetle sequence
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdBeetle(int argc, const char **argv) {
+ if (argc == 1) {
+ // Load proper data file (beetle game in in Cd2)
+ loadArchive(kArchiveCd2);
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdBeetle);
+ copyCommand(argc, argv);
+
+ return false;
+ } else {
+ clearBg(GraphicsManager::kBackgroundAll);
+ askForRedraw();
+ redrawScreen();
+
+ // Save current state
+ SceneIndex previousScene = getState()->scene;
+ ObjectLocation previousLocation = getInventory()->get(kItemBeetle)->location;
+ ChapterIndex previousChapter = (ChapterIndex)getProgress().chapter;
+
+ // Setup scene & inventory
+ getProgress().chapter = kChapter2;
+ Scene *scene = getScenes()->get(kSceneBeetle);
+ getInventory()->get(kItemBeetle)->location = kObjectLocation3;
+
+ askForRedraw();
+ redrawScreen();
+
+ // Load the beetle game
+ Action *action = NULL;
+ Beetle *beetle = new Beetle(_engine);
+ if (!beetle->isLoaded())
+ beetle->load();
+
+ // Play the game
+ Common::Event ev;
+ bool playgame = true;
+ while (playgame) {
+ // Update beetle
+ beetle->update();
+
+ askForRedraw();
+ redrawScreen();
+
+ while (g_engine->getEventManager()->pollEvent(ev)) {
+
+ switch (ev.type) {
+ default:
+ break;
+
+ case Common::EVENT_KEYDOWN:
+ // Exit beetle game on escape
+ if (ev.kbd.keycode == Common::KEYCODE_ESCAPE)
+ playgame = false;
+
+ break;
+
+ case Common::EVENT_MOUSEMOVE: {
+ // Update cursor
+ CursorStyle style = kCursorNormal;
+ SceneHotspot *hotspot = NULL;
+ if (scene->checkHotSpot(ev.mouse, &hotspot)) {
+ if (!action)
+ action = new Action(_engine);
+
+ style = action->getCursor(*hotspot);
+ }
+
+ _engine->getCursor()->setStyle(style);
+ break;
+ }
+
+
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ // Update coordinates
+ getLogic()->getGameState()->setCoordinates(ev.mouse);
+
+ if (beetle->catchBeetle())
+ playgame = false;
+ break;
+ }
+
+ _engine->_system->delayMillis(10);
+ }
+ }
+
+ // Cleanup
+ beetle->unload();
+ delete beetle;
+ delete action;
+
+ // Pause for a second to be able to see the final scene
+ _engine->_system->delayMillis(1000);
+
+ // Restore state
+ getProgress().chapter = previousChapter;
+ getInventory()->get(kItemBeetle)->location = previousLocation;
+
+ // Restore loaded archive
+ restoreArchive();
+
+ // Stop audio and restore scene
+ getSound()->stopAllSound();
+
+ clearBg(GraphicsManager::kBackgroundAll);
+
+ Scene *oldScene = getScenes()->get(previousScene);
+ _engine->getGraphicsManager()->draw(oldScene, GraphicsManager::kBackgroundC);
+
+ askForRedraw();
+ redrawScreen();
+
+ resetCommand();
+ }
+ } else {
+ DebugPrintf("Syntax: beetle\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: adjusts the time delta
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdTimeDelta(int argc, const char **argv) {
+ if (argc == 2) {
+ int delta = getNumber(argv[1]);
+
+ if (delta <= 0 || delta > 500)
+ goto label_error;
+
+ getState()->timeDelta = (uint)delta;
+ } else {
+label_error:
+ DebugPrintf("Syntax: delta <time delta> (delta=1-500)\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: Convert between in-game time and human readable time
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdTime(int argc, const char **argv) {
+ if (argc == 2) {
+ int32 time = getNumber(argv[1]);
+
+ if (time < 0)
+ goto label_error;
+
+ // Convert to human-readable form
+ uint8 hours = 0;
+ uint8 minutes = 0;
+ State::getHourMinutes((uint32)time, &hours, &minutes);
+
+ DebugPrintf("%02d:%02d\n", hours, minutes);
+ } else {
+label_error:
+ DebugPrintf("Syntax: time <time to convert> (time=0-INT_MAX)\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: show game logic data
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdShow(int argc, const char **argv) {
+#define OUTPUT_DUMP(name, text) \
+ DebugPrintf(#name "\n"); \
+ DebugPrintf("--------------------------------------------------------------------\n\n"); \
+ DebugPrintf("%s", text); \
+ DebugPrintf("\n");
+
+ if (argc == 2) {
+
+ Common::String name(const_cast<char *>(argv[1]));
+
+ if (name == "state" || name == "st") {
+ OUTPUT_DUMP("Game state", getState()->toString().c_str());
+ } else if (name == "progress" || name == "pr") {
+ OUTPUT_DUMP("Progress", getProgress().toString().c_str());
+ } else if (name == "flags" || name == "fl") {
+ OUTPUT_DUMP("Flags", getFlags()->toString().c_str());
+ } else if (name == "inventory" || name == "inv") {
+ OUTPUT_DUMP("Inventory", getInventory()->toString().c_str());
+ } else if (name == "objects" || name == "obj") {
+ OUTPUT_DUMP("Objects", getObjects()->toString().c_str());
+ } else if (name == "savepoints" || name == "pt") {
+ OUTPUT_DUMP("SavePoints", getSavePoints()->toString().c_str());
+ } else if (name == "scene" || name == "sc") {
+ OUTPUT_DUMP("Current scene", getScenes()->get(getState()->scene)->toString().c_str());
+ } else {
+ goto label_error;
+ }
+
+ } else {
+label_error:
+ DebugPrintf("Syntax: state <option>\n");
+ DebugPrintf(" state / st\n");
+ DebugPrintf(" progress / pr\n");
+ DebugPrintf(" flags / fl\n");
+ DebugPrintf(" inventory / inv\n");
+ DebugPrintf(" objects / obj\n");
+ DebugPrintf(" savepoints / pt\n");
+ DebugPrintf(" scene / sc\n");
+ }
+
+ return true;
+
+#undef OUTPUT_DUMP
+}
+
+/**
+ * Command: shows entity data
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdEntity(int argc, const char **argv) {
+ if (argc == 2) {
+ EntityIndex index = (EntityIndex)getNumber(argv[1]);
+
+ if (index > 39)
+ goto label_error;
+
+ DebugPrintf("Entity %s\n", ENTITY_NAME(index));
+ DebugPrintf("--------------------------------------------------------------------\n\n");
+ DebugPrintf("%s", getEntities()->getData(index)->toString().c_str());
+
+ // The Player entity does not have any callback data
+ if (index != kEntityPlayer) {
+ EntityData *data = getEntities()->get(index)->getParamData();
+ for (uint callback = 0; callback < 9; callback++) {
+ DebugPrintf("Call parameters %d:\n", callback);
+ for (byte ix = 0; ix < 4; ix++)
+ DebugPrintf(" %s", data->getParameters(callback, ix)->toString().c_str());
+ }
+ }
+
+ DebugPrintf("\n");
+ } else {
+label_error:
+ DebugPrintf("Syntax: entity <index>\n");
+ for (int i = 0; i < 40; i += 4)
+ DebugPrintf(" %s - %d %s - %d %s - %d %s - %d\n", ENTITY_NAME(i), i, ENTITY_NAME(i+1), i+1, ENTITY_NAME(i+2), i+2, ENTITY_NAME(i+3), i+3);
+ }
+
+ return true;
+}
+
+/**
+ * Command: loads a game
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdLoadGame(int argc, const char **argv) {
+ if (argc == 2) {
+ int id = getNumber(argv[1]);
+
+ if (id == 0 || id > 6)
+ goto error;
+
+ getSaveLoad()->loadGame((GameId)(id - 1));
+ } else {
+error:
+ DebugPrintf("Syntax: loadgame <id> (id=1-6)\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: switch to a specific chapter
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdSwitchChapter(int argc, const char **argv) {
+ if (argc == 2) {
+ int id = getNumber(argv[1]);
+
+ if (id <= 1 || id > 6)
+ goto error;
+
+ // Store command
+ if (!hasCommand()) {
+ _command = WRAP_METHOD(Debugger, cmdSwitchChapter);
+ copyCommand(argc, argv);
+
+ return false;
+ } else {
+ // Sets the current chapter and then call Logic::switchChapter to proceed to the next chapter
+ getState()->progress.chapter = (ChapterIndex)(id - 1);
+
+ getLogic()->switchChapter();
+
+ resetCommand();
+ }
+ } else {
+error:
+ DebugPrintf("Syntax: chapter <id> (id=2-6)\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: clears the screen
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdClear(int argc, const char **) {
+ if (argc == 1) {
+ clearBg(GraphicsManager::kBackgroundAll);
+ askForRedraw();
+ redrawScreen();
+ } else {
+ DebugPrintf("Syntax: clear - clear the screen\n");
+ }
+
+ return true;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/debug.h b/engines/lastexpress/debug.h
new file mode 100644
index 0000000000..e935b35fc0
--- /dev/null
+++ b/engines/lastexpress/debug.h
@@ -0,0 +1,106 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_DEBUG_H
+#define LASTEXPRESS_DEBUG_H
+
+#include "gui/debugger.h"
+
+#include "lastexpress/data/snd.h"
+
+#include "lastexpress/shared.h"
+
+namespace LastExpress {
+
+enum {
+ kLastExpressDebugAll = 1 << 0,
+ kLastExpressDebugGraphics = 1 << 1,
+ kLastExpressDebugResource = 1 << 2,
+ kLastExpressDebugCursor = 1 << 3,
+ kLastExpressDebugSound = 1 << 4,
+ kLastExpressDebugSubtitle = 1 << 5,
+ kLastExpressDebugSavegame = 1 << 6,
+ kLastExpressDebugLogic = 1 << 7,
+ kLastExpressDebugScenes = 1 << 8,
+ kLastExpressDebugUnknown = 1 << 9
+ // the current limitation is 32 debug levels (1 << 31 is the last one)
+};
+
+class LastExpressEngine;
+
+class Debugger : public GUI::Debugger {
+public:
+ Debugger(LastExpressEngine *engine);
+ ~Debugger();
+
+ bool hasCommand() const;
+ void callCommand();
+
+private:
+ LastExpressEngine *_engine;
+
+ bool cmdHelp(int argc, const char **argv);
+
+ bool cmdListFiles(int argc, const char **argv);
+ bool cmdDumpFiles(int argc, const char **argv);
+
+ bool cmdShowFrame(int argc, const char **argv);
+ bool cmdShowBg(int argc, const char **argv);
+ bool cmdPlaySeq(int argc, const char **argv);
+ bool cmdPlaySnd(int argc, const char **argv);
+ bool cmdPlaySbe(int argc, const char **argv);
+ bool cmdPlayNis(int argc, const char **argv);
+
+ bool cmdLoadScene(int argc, const char **argv);
+ bool cmdFight(int argc, const char **argv);
+ bool cmdBeetle(int argc, const char **argv);
+
+ bool cmdTimeDelta(int argc, const char **argv);
+ bool cmdTime(int argc, const char **argv);
+ bool cmdShow(int argc, const char **argv);
+ bool cmdEntity(int argc, const char **argv);
+
+ bool cmdLoadGame(int argc, const char **argv);
+ bool cmdSwitchChapter(int argc, const char **argv);
+ bool cmdClear(int argc, const char **argv);
+
+ void resetCommand();
+ void copyCommand(int argc, const char **argv);
+ int getNumber(const char *arg) const;
+
+ void loadArchive(ArchiveIndex index) const;
+ void restoreArchive() const;
+
+ Debuglet *_command;
+ int _numParams;
+ char **_commandParams;
+
+ // Special sound stream for playing sounds
+ StreamedSound *_soundStream;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_DEBUG_H
diff --git a/engines/lastexpress/detection.cpp b/engines/lastexpress/detection.cpp
new file mode 100644
index 0000000000..d72a5eab86
--- /dev/null
+++ b/engines/lastexpress/detection.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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+static const PlainGameDescriptor lastExpressGames[] = {
+ // Games
+ {"lastexpress", "The Last Express"},
+ {0, 0}
+};
+
+static const ADGameDescription gameDescriptions[] = {
+
+ // The Last Express (English) - US Broderbund Release
+ // expressw.exe 1997-02-12 17:24:44
+ // express.exe 1997-02-12 17:29:08
+ {
+ "lastexpress",
+ "",
+ {
+ {"HD.HPF", 0, "2d331459e0e68cf277ef4e4043750413", 29865984}, // 1997-02-10 19:38:19
+ {"CD1.HPF", 0, "8c86db47304033fcff32c69fddd5a920", 525522944}, // 1997-02-10 17:04:40
+ {"CD2.HPF", 0, "58aa26e782d10ec5d2231e539d2fe6a2", 669581312}, // 1997-02-10 16:19:30
+ {"CD3.HPF", 0, "00554fbf78a2ad391d98578fbbbe1c48", 641128448}, // 1997-02-10 15:44:09
+ },
+ Common::EN_ANY,
+ Common::kPlatformUnknown,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+
+ // The Last Express (English) - UK Broderbund Release
+ // expressw.exe 1997-04-02 14:30:32
+ // express.exe 1997-04-02 15:00:50
+ {
+ "lastexpress",
+ "",
+ {
+ {"HD.HPF", 0, "2d331459e0e68cf277ef4e4043750413", 29865984}, // 1997-04-10 11:03:41
+ {"CD1.HPF", 0, "8c86db47304033fcff32c69fddd5a920", 525522944}, // 1997-04-10 11:03:36
+ {"CD2.HPF", 0, "2672348691e1ae22d37d9f46f3683a07", 669509632}, // 1997-04-11 09:48:33
+ {"CD3.HPF", 0, "33f5e35f51063cb90f6bed9974475aa6", 641056768}, // 1997-04-11 09:48:55
+ },
+ Common::EN_ANY,
+ Common::kPlatformUnknown,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+
+ // The Last Express (English) - Interplay Release
+ {
+ "lastexpress",
+ "",
+ {
+ {"HD.HPF", 0, "bcc32d977f92bb52c060a0b4e8589cac", 30715904},
+ {"CD1.HPF", 0, "8c86db47304033fcff32c69fddd5a920", 525522944},
+ {"CD2.HPF", 0, "58aa26e782d10ec5d2231e539d2fe6a2", 669581312},
+ {"CD3.HPF", 0, "00554fbf78a2ad391d98578fbbbe1c48", 641128448},
+ },
+ Common::EN_ANY,
+ Common::kPlatformUnknown,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+
+ // The Last Express (French) - Broderbund Release
+ // expressw.exe 1997-04-02 09:31:24
+ // express.exe 1997-04-02 10:01:12
+ {
+ "lastexpress",
+ "",
+ {
+ {"HD.HPF", 0, "c14c6d685d9bf8705d9f659062e6c5c2", 29505536}, // 1997-04-03 07:53:20
+ {"CD1.HPF", 0, "b4277b22bc5cd6ad3b00c2ec04d4645d", 522924032}, // 1997-04-03 07:53:14
+ {"CD2.HPF", 0, "8c9610aa4cb707ab51f61c30feb22c1a", 665710592}, // 1997-04-09 12:04:30
+ {"CD3.HPF", 0, "411c1bab57b3e8da4fb359c5b40ef5d7", 640884736}, // 1997-04-03 08:21:47
+ },
+ Common::FR_FRA,
+ Common::kPlatformUnknown,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+
+ // The Last Express (German)
+ {
+ "lastexpress",
+ "",
+ {
+ {"HD.HPF", 0, "7cdd70fc0b1555785f1e9e8d371ea85c", 31301632},
+ {"CD1.HPF", 0, "6d74cc861d172466bc745ff8bf0e59c5", 522971136},
+ {"CD2.HPF", 0, "b71ac9391de415807c74ff078f4fab22", 655702016},
+ {"CD3.HPF", 0, "ee55d4310546dd2a38560b096d1c2771", 641144832},
+ },
+ Common::DE_DEU,
+ Common::kPlatformUnknown,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+
+ // The Last Express (Spanish)
+ {
+ "lastexpress",
+ "",
+ {
+ {"HD.HPF", 0, "46bed8832f06cf7160883a2aae2d667f", 29657088},
+ {"CD1.HPF", 0, "367a3a8581f6f88ddc51af7cde105ba9", 519927808},
+ {"CD2.HPF", 0, "af5566df3000472852ec182c9ec57797", 662210560},
+ {"CD3.HPF", 0, "0d1901662f4d063a5c250c9fbf64b771", 639504384},
+ },
+ Common::ES_ESP,
+ Common::kPlatformUnknown,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+
+ // The Last Express (Demo) - Broderbund
+ // expressw.exe 1997-08-14 14:09:42
+ // express.exe 1997-08-14 14:19:34
+ {
+ "lastexpress",
+ "Demo",
+ {
+ {"Demo.HPF", 0, "baf3b1f64155d34872896e61c3d3cb78", 58191872}, // 1997-08-14 14:44:26
+ },
+ Common::EN_ANY,
+ Common::kPlatformUnknown,
+ ADGF_DEMO,
+ Common::GUIO_NONE
+ },
+ AD_TABLE_END_MARKER
+};
+
+static const ADParams detectionParams = {
+ // Pointer to ADGameDescription or its superset structure
+ (const byte *)gameDescriptions,
+ // Size of that superset structure
+ sizeof(ADGameDescription),
+ // Number of bytes to compute MD5 sum for
+ 5000,
+ // List of all engine targets
+ lastExpressGames,
+ // Structure for autoupgrading obsolete targets
+ 0,
+ // Name of single gameid (optional)
+ "lastexpress",
+ // List of files for file-based fallback detection (optional)
+ 0,
+ // Flags
+ 0,
+ // Additional GUI options (for every game}
+ Common::GUIO_NOSUBTITLES | Common::GUIO_NOSFX,
+ // Maximum directory depth
+ 1,
+ // List of directory globs
+ 0
+};
+
+
+class LastExpressMetaEngine : public AdvancedMetaEngine {
+public:
+ LastExpressMetaEngine() : AdvancedMetaEngine(detectionParams) {}
+
+ const char *getName() const {
+ return "LastExpress Engine";
+ }
+
+ const char *getOriginalCopyright() const {
+ return "LastExpress Engine (C) 1997 Smoking Car Productions";
+ }
+
+ bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
+};
+
+bool LastExpressMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const {
+ if (gd) {
+ *engine = new LastExpressEngine(syst, (const ADGameDescription *)gd);
+ }
+ return gd != 0;
+}
+
+} // End of namespace LastExpress
+
+#if PLUGIN_ENABLED_DYNAMIC(LASTEXPRESS)
+ REGISTER_PLUGIN_DYNAMIC(LASTEXPRESS, PLUGIN_TYPE_ENGINE, LastExpress::LastExpressMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(LASTEXPRESS, PLUGIN_TYPE_ENGINE, LastExpress::LastExpressMetaEngine);
+#endif
diff --git a/engines/lastexpress/drawable.h b/engines/lastexpress/drawable.h
new file mode 100644
index 0000000000..e273876362
--- /dev/null
+++ b/engines/lastexpress/drawable.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_DRAWABLE_H
+#define LASTEXPRESS_DRAWABLE_H
+
+#include "graphics/surface.h"
+
+namespace LastExpress {
+
+class Drawable {
+public:
+ virtual ~Drawable() {}
+
+ virtual Common::Rect draw(Graphics::Surface *surface) = 0;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_DRAWABLE_H
diff --git a/engines/lastexpress/entities/abbot.cpp b/engines/lastexpress/entities/abbot.cpp
new file mode 100644
index 0000000000..777767600f
--- /dev/null
+++ b/engines/lastexpress/entities/abbot.cpp
@@ -0,0 +1,1910 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/abbot.h"
+
+#include "lastexpress/entities/verges.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Abbot::Abbot(LastExpressEngine *engine) : Entity(engine, kEntityAbbot) {
+ ADD_CALLBACK_FUNCTION(Abbot, reset);
+ ADD_CALLBACK_FUNCTION(Abbot, draw);
+ ADD_CALLBACK_FUNCTION(Abbot, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Abbot, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Abbot, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Abbot, draw2);
+ ADD_CALLBACK_FUNCTION(Abbot, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Abbot, updateFromTicks);
+ ADD_CALLBACK_FUNCTION(Abbot, playSound);
+ ADD_CALLBACK_FUNCTION(Abbot, savegame);
+ ADD_CALLBACK_FUNCTION(Abbot, updateEntity);
+ ADD_CALLBACK_FUNCTION(Abbot, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Abbot, updatePosition);
+ ADD_CALLBACK_FUNCTION(Abbot, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Abbot, chapter1);
+ ADD_CALLBACK_FUNCTION(Abbot, chapter2);
+ ADD_CALLBACK_FUNCTION(Abbot, chapter3);
+ ADD_CALLBACK_FUNCTION(Abbot, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Abbot, function19);
+ ADD_CALLBACK_FUNCTION(Abbot, function20);
+ ADD_CALLBACK_FUNCTION(Abbot, function21);
+ ADD_CALLBACK_FUNCTION(Abbot, function22);
+ ADD_CALLBACK_FUNCTION(Abbot, function23);
+ ADD_CALLBACK_FUNCTION(Abbot, function24);
+ ADD_CALLBACK_FUNCTION(Abbot, function25);
+ ADD_CALLBACK_FUNCTION(Abbot, function26);
+ ADD_CALLBACK_FUNCTION(Abbot, function27);
+ ADD_CALLBACK_FUNCTION(Abbot, function28);
+ ADD_CALLBACK_FUNCTION(Abbot, function29);
+ ADD_CALLBACK_FUNCTION(Abbot, function30);
+ ADD_CALLBACK_FUNCTION(Abbot, function31);
+ ADD_CALLBACK_FUNCTION(Abbot, function32);
+ ADD_CALLBACK_FUNCTION(Abbot, function33);
+ ADD_CALLBACK_FUNCTION(Abbot, function34);
+ ADD_CALLBACK_FUNCTION(Abbot, function35);
+ ADD_CALLBACK_FUNCTION(Abbot, function36);
+ ADD_CALLBACK_FUNCTION(Abbot, function37);
+ ADD_CALLBACK_FUNCTION(Abbot, function38);
+ ADD_CALLBACK_FUNCTION(Abbot, chapter4);
+ ADD_CALLBACK_FUNCTION(Abbot, function40);
+ ADD_CALLBACK_FUNCTION(Abbot, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Abbot, function42);
+ ADD_CALLBACK_FUNCTION(Abbot, function43);
+ ADD_CALLBACK_FUNCTION(Abbot, function44);
+ ADD_CALLBACK_FUNCTION(Abbot, function45);
+ ADD_CALLBACK_FUNCTION(Abbot, function46);
+ ADD_CALLBACK_FUNCTION(Abbot, drinkAfterDefuse);
+ ADD_CALLBACK_FUNCTION(Abbot, function48);
+ ADD_CALLBACK_FUNCTION(Abbot, pickBomb);
+ ADD_CALLBACK_FUNCTION(Abbot, chapter5);
+ ADD_CALLBACK_FUNCTION(Abbot, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Abbot, function52);
+ ADD_CALLBACK_FUNCTION(Abbot, function53);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Abbot, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Abbot, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(3, Abbot, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(4, Abbot, enterExitCompartment2, ObjectIndex)
+ Entity::enterExitCompartment(savepoint, kPosition_6470, kPosition_6130, kCarRedSleeping, kObjectCompartmentC, true, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Abbot, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SSI(6, Abbot, draw2, EntityIndex)
+ Entity::draw2(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(7, Abbot, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(8, Abbot, updateFromTicks, uint32)
+ Entity::updateFromTicks(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(9, Abbot, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Abbot, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(11, Abbot, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 18) || getEntities()->isPlayerPosition(kCarRedSleeping, 18)) {
+ getSound()->excuseMe(kEntityAbbot);
+ } else {
+ if (getEvent(kEventAbbotIntroduction))
+ getSound()->playSound(kEntityPlayer, "CAT1013");
+ else
+ getSound()->excuseMeCath();
+ }
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIIS(12, Abbot, callSavepoint, EntityIndex, ActionIndex)
+ Entity::callSavepoint(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SII(13, Abbot, updatePosition, CarIndex, Position)
+ Entity::updatePosition(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Abbot, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Abbot, chapter1)
+ if (savepoint.action == kActionDefault)
+ getSavePoints()->addData(kEntityAbbot, kAction203073664, 0);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Abbot, chapter2)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityAbbot);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Abbot, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAbbot);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ getData()->clothes = kClothesDefault;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Abbot, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_draw("804DD");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityAbbot, kEntityCooks, kAction236976550);
+ getEntities()->drawSequenceRight(kEntityAbbot, "804DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAbbot);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 4:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(5);
+ setup_enterExitCompartment("617AC", kObjectCompartmentC);
+ break;
+
+ case 5:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function19();
+ break;
+ }
+ break;
+
+ case kAction192054567:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Abbot, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime1953000) {
+ if (!params->param1) {
+ params->param1 = 1;
+ setCallback(3);
+ setup_playSound("MrB3010");
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508A");
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122358304);
+
+ setCallback(1);
+ setup_playSound("Abb3010");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateFromTime(900);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508B");
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122288808);
+ setup_function20();
+ break;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Abbot, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime1966500 && getEntities()->isInRestaurant(kEntityBoutarel))
+ setup_function21();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "509A");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Abbot, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_draw("509B");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_enterExitCompartment("617Mc", kObjectCompartmentC);
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_draw("804US");
+ break;
+
+ case 5:
+ getEntities()->drawSequenceRight(kEntityAbbot, "029J");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAbbot);
+
+ setCallback(6);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 6:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "029H");
+ getSavePoints()->push(kEntityAbbot, kEntityPascale, kAction207769280);
+ break;
+
+ case 7:
+ setup_function22();
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ getSavePoints()->push(kEntityAbbot, kEntityTables4, kAction136455232);
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(7);
+ setup_draw("029B");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Abbot, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_SAVEPOINT(kTime1971000, params->param1, kEntityAbbot, kEntityServers0, kAction218586752);
+
+ if (getState()->time > kTime1989000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->inventoryItem = kItemNone;
+ setup_function23();
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAbbotIntroduction);
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "029E");
+ if (!getEvent(kEventAbbotIntroduction))
+ getData()->inventoryItem = (InventoryItem)kCursorProcess;
+ break;
+
+ case kActionCallback:
+ if (getCallback() != 1)
+ break;
+
+ getAction()->playAnimation(kEventAbbotIntroduction);
+ getSound()->playSound(kEntityPlayer, "LIB036");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "029E");
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Abbot, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->updatePositionEnter(kEntityAbbot, kCarRestaurant, 67);
+
+ setCallback(1);
+ setup_callSavepoint("029F", kEntityTables4, kActionDrawTablesWithChairs, "029G");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 67);
+ getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760);
+ getSavePoints()->push(kEntityAbbot, kEntityAnna, kAction238936000);
+ getEntities()->drawSequenceRight(kEntityAbbot, "804DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAbbot);
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment2("617Cc", kObjectCompartmentC);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function24();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Abbot, function24)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->time, 900);
+
+ setup_function25();
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject50, kEntityAbbot, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (savepoint.action == kActionKnock) {
+ setCallback(1);
+ setup_playSound("LIB012");
+ } else {
+ setCallback(2);
+ setup_playSound("LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAbbot);
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityAbbot, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound("Abb3001");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Abbot, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("617Dc", kObjectCompartmentC);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_updatePosition("115A", kCarRestaurant, 56);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+ getScenes()->loadSceneFromItemPosition(kItem3);
+
+ setup_function26();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Abbot, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param2, getState()->time, 4500);
+
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon())
+ setup_function27();
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAbbot, kEntityKronos, kAction157159392);
+ getEntities()->drawSequenceLeft(kEntityAbbot, "115B");
+ break;
+
+ case kAction101169422:
+ params->param1 = 1;
+ break;
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Abbot, function27)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updatePosition("115C", kCarRestaurant, 56);
+ break;
+
+ case 2:
+ getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
+
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(4);
+ setup_enterExitCompartment("617Ac", kObjectCompartmentC);
+ break;
+
+ case 4:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function28();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Abbot, function28)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTime2052000, params->param1, 1, setup_function29);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508A");
+
+ setCallback(1);
+ setup_playSound("abb3013");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508B");
+ break;
+
+ case kAction222609266:
+ setup_function30();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Abbot, function29)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122288808);
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(1);
+ setup_enterExitCompartment("617Bc", kObjectCompartmentC);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateFromTicks(450);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_updateFromTime(225);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 6:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(7);
+ setup_enterExitCompartment("617Ac", kObjectCompartmentC);
+ break;
+
+ case 7:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508B");
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Abbot, function30)
+switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_playSound("Abb3030");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122288808);
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(2);
+ setup_enterExitCompartment("617Bc", kObjectCompartmentC);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_updatePosition("115A", kCarRestaurant, 56);
+ break;
+
+ case 5:
+ getScenes()->loadSceneFromItemPosition(kItem3);
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function31();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Abbot, function31)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param4 != kTimeInvalid && params->param2 < getState()->time) {
+ if (getState()->time < getState()->time) {
+ params->param4 = kTimeInvalid;
+
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+ } else {
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param4)
+ params->param4 = (uint)getState()->time + 450;
+
+ if (params->param4 < getState()->time) {
+ params->param4 = kTimeInvalid;
+
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+ }
+ }
+ }
+
+ if (!params->param1)
+ break;
+
+ UPDATE_PARAM(params->param5, getState()->time, 450);
+
+ setCallback(6);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionDefault:
+ params->param2 = (uint)getState()->time + 4500;
+ params->param3 = (uint)getState()->time + 18000;
+
+ getEntities()->drawSequenceLeft(kEntityAbbot, "115B");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updatePosition("115E", kCarRestaurant, 56);
+ break;
+
+ case 2:
+ getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
+ getSavePoints()->push(kEntityAbbot, kEntityAlexei, kAction122358304);
+ getSound()->playSound(kEntityAbbot, "Abb3020");
+
+ setCallback(3);
+ setup_updatePosition("125A", kCarRestaurant, 52);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAbbot, "125B");
+
+ setCallback(4);
+ setup_playSound("Abb3021");
+ break;
+
+ case 4:
+ getSound()->playSound(kEntityAbbot, "Abb3023");
+ getEntities()->updatePositionEnter(kEntityAbbot, kCarRestaurant, 52);
+
+ setCallback(5);
+ setup_draw2("125C1", "125C2", kEntityAlexei);
+ break;
+
+ case 5:
+ getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 52);
+ getEntities()->drawSequenceLeft(kEntityAbbot, "125D");
+ getSavePoints()->push(kEntityAbbot, kEntityAlexei, kAction122288808);
+ params->param1 = 1;
+
+ UPDATE_PARAM(params->param5, getState()->time, 450);
+
+ setCallback(6);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 6:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(7);
+ setup_updatePosition("125E", kCarRestaurant, 52);
+ break;
+
+ case 7:
+ setup_function32();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Abbot, function32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(1);
+ setup_enterExitCompartment("617Ac", kObjectCompartmentC);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122358304);
+
+ setup_function33();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Abbot, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 != kTimeInvalid && getState()->time > kTime2115000) {
+ if (getState()->time <= kTime2124000) {
+ if (!getEntities()->isDistanceBetweenEntities(kEntityAbbot, kEntityPlayer, 2000) || !params->param1)
+ params->param1 = (uint)getState()->time;
+
+ if (params->param1 >= getState()->time)
+ break;
+ }
+
+ params->param1 = kTimeInvalid;
+
+ setCallback(1);
+ setup_playSound("Abb3014");
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508A");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508B");
+ break;
+
+ case kAction123712592:
+ setup_function34();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Abbot, function34)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_playSound("Abb3031");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122288808);
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(2);
+ setup_enterExitCompartment("617Bc", kObjectCompartmentC);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_updatePosition("115A", kCarRestaurant, 56);
+ break;
+
+ case 5:
+ getScenes()->loadSceneFromItemPosition(kItem3);
+
+ getData()->location = kLocationInsideCompartment;
+ setup_function35();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Abbot, function35)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2 == kTimeInvalid)
+ break;
+
+ if (params->param1 >= getState()->time) {
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param2)
+ params->param2 = (uint)getState()->time + 450;
+
+ if (params->param2 >= getState()->time)
+ break;
+ }
+
+ params->param2 = kTimeInvalid;
+
+ getSavePoints()->push(kEntityAbbot, kEntityAugust, kAction136196244);
+
+ setCallback(1);
+ setup_updateFromTime(0);
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "115B");
+ params->param1 = (uint)getState()->time + 9000;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+ getSound()->playSound(kEntityAbbot, "Abb3040", SoundManager::kFlagInvalid, 45);
+ getEntities()->updatePositionEnter(kEntityAbbot, kCarRestaurant, 57);
+
+ setCallback(3);
+ setup_callSavepoint("121A", kEntityAugust, kAction122358304, "BOGUS");
+ break;
+
+ case 3:
+ getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 57);
+ getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function36();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Abbot, function36)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ switch (params->param2) {
+ default:
+ break;
+
+ case 1:
+ if (params->param3 == kTimeInvalid)
+ break;
+
+ if (params->param1 >= getState()->time) {
+
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param3)
+ params->param3 = (uint)getState()->time + 675;
+
+ if (params->param3 >= getState()->time)
+ break;
+ }
+
+ params->param3 = kTimeInvalid;
+
+ getSound()->playSound(kEntityAbbot, "Abb3041");
+ break;
+
+ case 2:
+ UPDATE_PARAM(params->param4, getState()->time, 900);
+
+ getSound()->playSound(kEntityAbbot, "Abb3042");
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityAbbot, "Abb3043");
+ getEntities()->updatePositionEnter(kEntityAbbot, kCarRestaurant, 57);
+
+ setCallback(1);
+ setup_callSavepoint("121D", kEntityAugust, kAction122288808, "BOGUS");
+ break;
+ }
+ break;
+
+ case kActionEndSound:
+ ++params->param2;
+ break;
+
+ case kActionDefault:
+ params->param1 = (uint)getState()->time + 4500;
+ getEntities()->drawSequenceLeft(kEntityAbbot, "121B");
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 57))
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 50);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 57);
+ setup_function37();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Abbot, function37)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(2);
+ setup_enterExitCompartment("617Ac", kObjectCompartmentC);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122358304);
+
+ setup_function38();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Abbot, function38)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508A");
+
+ setCallback(1);
+ setup_playSound("Abb3014A");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ getEntities()->drawSequenceLeft(kEntityAbbot, "508B");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(39, Abbot, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAbbot);
+
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 1) = 0;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(40, Abbot, function40, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->updateEntity(kEntityAbbot, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ } else if (!getEvent(kEventAbbotInvitationDrink)
+ && getEntities()->isDistanceBetweenEntities(kEntityAbbot, kEntityPlayer, 1000)
+ && !getEntities()->isInsideCompartments(kEntityPlayer)
+ && !getEntities()->checkFields10(kEntityPlayer)) {
+
+ if (getData()->car == kCarGreenSleeping || getData()->car == kCarRedSleeping) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAbbotInvitationDrink);
+ }
+ }
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityAbbot, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventAbbotInvitationDrink);
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(41, Abbot, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_SAVEPOINT(kTime2358000, params->param1, kEntityAbbot, kEntityServers0, kAction218128129);
+
+ if (getState()->time > kTime2389500 && getEntities()->isSomebodyInsideRestaurantOrSalon())
+ setup_function42();
+
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAbbot, kEntityTables4, kAction136455232);
+ getEntities()->drawSequenceLeft(kEntityAbbot, "029E");
+ getData()->location = kLocationInsideCompartment;
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "029E");
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAbbot, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(42, Abbot, function42)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 67);
+
+ setCallback(1);
+ setup_callSavepoint("029F", kEntityTables4, kActionDrawTablesWithChairs, "029G");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 67);
+ getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760);
+ getEntities()->drawSequenceRight(kEntityAbbot, "804DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAbbot);
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment2("617Cc", kObjectCompartmentC);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityAbbot);
+
+ setup_function43();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(43, Abbot, function43)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 && params->param4 != kTimeInvalid && params->param2 < getState()->time) {
+ if (getState()->time < kTime2452500) {
+ params->param4 = kTimeInvalid;
+
+ setCallback(1);
+ setup_playSound("Abb4002");
+ break;
+ } else {
+ if (!getEntities()->isDistanceBetweenEntities(kEntityAbbot, kEntityPlayer, 1000) || getSound()->isBuffered(kEntityBoutarel) || !params->param4)
+ params->param4 = (uint)getState()->time + 450;
+
+ if (params->param4 < getState()->time) {
+ params->param4 = kTimeInvalid;
+
+ setCallback(1);
+ setup_playSound("Abb4002");
+ break;
+ }
+ }
+ }
+
+label_callback_1:
+ TIME_CHECK(kTime2466000, params->param5, setup_function44);
+
+ if (params->param3) {
+ UPDATE_PARAM(params->param6, getState()->timeTicks, 75);
+
+ params->param2 = 1;
+ params->param3 = 0;
+
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject50, kEntityAbbot, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param6 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject50, kEntityAbbot, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param3) {
+ setCallback(savepoint.param.intValue == 50 ? 5 : 6);
+ setup_playSound(savepoint.param.intValue == 50 ? getSound()->justAMinuteCath() : getSound()->wrongDoorCath());
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 2 : 3);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param2 || params->param3) {
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param2 = 0;
+ params->param3 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ case 3:
+ setCallback(4);
+ setup_playSound("Abb3001");
+ break;
+
+ case 4:
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject50, kEntityAbbot, kObjectLocation1, kCursorTalk, kCursorNormal);
+
+ params->param3 = 1;
+ break;
+
+ case 5:
+ case 6:
+ params->param2 = 1;
+ params->param3 = 0;
+ break;
+ }
+ break;
+
+ case kAction101687594:
+ params->param1 = 1;
+ break;
+
+ case kAction159003408:
+ params->param1 = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(44, Abbot, function44)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->clearSequences(kEntityAbbot);
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kAction104060776:
+ setup_function45();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(45, Abbot, function45)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6471;
+ getData()->car = kCarRedSleeping;
+ getData()->location = kLocationOutsideCompartment;
+
+ RESET_ENTITY_STATE(kEntityVerges, Verges, setup_function38);
+
+ getEntities()->drawSequenceLeft(kEntityAbbot, "617Ec");
+ getEntities()->enterCompartment(kEntityAbbot, kObjectCompartmentC, true);
+
+ setCallback(1);
+ setup_playSound("Abb4010");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("617Kc", kObjectCompartmentC);
+ break;
+
+ case 2:
+ getEntities()->exitCompartment(kEntityAbbot, kObjectCompartmentC, true);
+ getSavePoints()->push(kEntityAbbot, kEntityVerges, kAction125233040);
+
+ setup_function46();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(46, Abbot, function46)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6471;
+
+ setCallback(1);
+ setup_function40(kCarRestaurant, kPosition_850);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_drinkAfterDefuse();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(47, Abbot, drinkAfterDefuse)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kAction1:
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventAbbotDrinkGiveDetonator);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_draw("126A");
+ break;
+
+ case 2:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAbbot, "126B");
+ getData()->inventoryItem = kItemBomb;
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventAbbotDrinkGiveDetonator);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(48, Abbot, function48)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(0, 1))
+ getData()->inventoryItem = kItemInvalid;
+
+ UPDATE_PARAM_PROC(params->param1, getState()->time, 1800)
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(4);
+ setup_updatePosition("126C", kCarRedSleeping, 52);
+ UPDATE_PARAM_PROC_END
+
+ TIME_CHECK_CALLBACK_INVENTORY(kTime2533500, params->param2, 5, setup_callbackActionRestaurantOrSalon);
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(9);
+ setup_savegame(kSavegameTypeEvent, kEventAbbotDrinkDefuse);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_850;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->inventoryItem = kItemNone;
+
+ getSavePoints()->push(kEntityAbbot, kEntityVerges, kAction125233040);
+
+ setCallback(1);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updatePosition("126A", kCarRestaurant, 52);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAbbot, "126B");
+ break;
+
+ case 4:
+ if (!getEvent(kEventAbbotDrinkDefuse) && ENTITY_PARAM(0, 1))
+ getData()->inventoryItem = kItemInvalid;
+
+ getEntities()->drawSequenceLeft(kEntityAbbot, "126B");
+ params->param1 = 0;
+
+ TIME_CHECK_CALLBACK_INVENTORY(kTime2533500, params->param2, 5, setup_callbackActionRestaurantOrSalon);
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(6);
+ setup_updatePosition("126D", kCarRestaurant, 52);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_enterExitCompartment2("617Cc", kObjectCompartmentC);
+ break;
+
+ case 8:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityAbbot);
+
+ setup_function44();
+ break;
+
+ case 9:
+ getAction()->playAnimation(kEventAbbotDrinkDefuse);
+ getEntities()->drawSequenceLeft(kEntityAbbot, "126B");
+ getSavePoints()->push(kEntityAbbot, kEntityAnna, kAction100969180);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 58);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(49, Abbot, pickBomb)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->timeTicks, 150);
+
+ getSavePoints()->push(kEntityAbbot, kEntityAbbot, kAction157489665);
+ break;
+
+ case kActionKnock:
+ if (!getSound()->isBuffered("LIB012", true))
+ getSound()->playSound(kEntityPlayer, "LIB012");
+ break;
+
+ case kActionOpenDoor:
+ case kAction157489665:
+ getSavePoints()->push(kEntityAbbot, kEntityTatiana, kAction238790488);
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationInsideCompartment;
+
+ getSavePoints()->call(kEntityAbbot, kEntityTables4, kActionDrawTablesWithChairs, "029G");
+ getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760);
+ getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction125039808);
+ getObjects()->update(kObjectCompartment2, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(getObjects()->get(kObjectCompartment2).location2 < kObjectLocation2 ? kEventAbbotWrongCompartmentBed : kEventAbbotWrongCompartment);
+ getEntities()->updateEntity(kEntityAbbot, kCarRedSleeping, kPosition_6470);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadSceneFromObject(kObjectCompartment2, true);
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment2("617Cc", kObjectCompartmentC);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityAbbot);
+ getObjects()->update(kObjectCompartmentC, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setup_function43();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(50, Abbot, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAbbot);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ getData()->clothes = kClothesDefault;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(51, Abbot, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function52();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(52, Abbot, function52)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAbbot);
+
+ getData()->entityPosition = kPositionNone;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarNone;
+ break;
+
+ case kAction135600432:
+ setup_function53();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(53, Abbot, function53)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getInventory()->setLocationAndProcess(kItem25, kObjectLocation1);
+ getSavePoints()->push(kEntityAbbot, kEntityAnna, kAction158480160);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventLocomotiveAbbotGetSomeRest);
+ getScenes()->processScene();
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventLocomotiveAbbotShoveling);
+ getScenes()->processScene();
+ break;
+ }
+ break;
+
+ case kAction168646401:
+ if (!getEvent(kEventLocomotiveAbbotGetSomeRest)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventLocomotiveAbbotGetSomeRest);
+ break;
+ }
+
+ if (!getEvent(kEventLocomotiveAbbotShoveling)) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventLocomotiveAbbotShoveling);
+ break;
+ }
+
+ getAction()->playAnimation(kEventLocomotiveAbbotShoveling);
+ getScenes()->processScene();
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/abbot.h b/engines/lastexpress/entities/abbot.h
new file mode 100644
index 0000000000..7e7b78b3be
--- /dev/null
+++ b/engines/lastexpress/entities/abbot.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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ABBOT_H
+#define LASTEXPRESS_ABBOT_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Abbot : public Entity {
+public:
+ Abbot(LastExpressEngine *engine);
+ ~Abbot() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Draws the entity along with another one
+ *
+ * @param sequence1 The sequence to draw
+ * @param sequence2 The sequence to draw for the second entity
+ * @param entity The EntityIndex of the second entity
+ */
+ DECLARE_FUNCTION_3(draw2, const char *sequence1, const char *sequence2, EntityIndex entity)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param ticks The number of ticks to add
+ */
+ DECLARE_FUNCTION_1(updateFromTicks, uint32 ticks)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Call a savepoint (or draw sequence in default case)
+ *
+ * @param sequence1 The sequence to draw in the default case
+ * @param entity The entity
+ * @param action The action
+ * @param sequence2 The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_4(callSavepoint, const char *sequence1, EntityIndex entity, ActionIndex action, const char *sequence2)
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence1, CarIndex car, Position position)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+ DECLARE_FUNCTION(function19)
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(function28)
+ DECLARE_FUNCTION(function29)
+ DECLARE_FUNCTION(function30)
+ DECLARE_FUNCTION(function31)
+ DECLARE_FUNCTION(function32)
+ DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(function34)
+ DECLARE_FUNCTION(function35)
+ DECLARE_FUNCTION(function36)
+ DECLARE_FUNCTION(function37)
+ DECLARE_FUNCTION(function38)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * ???
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(function40, CarIndex car, EntityPosition position)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+ DECLARE_FUNCTION(function42)
+ DECLARE_FUNCTION(function43)
+ DECLARE_FUNCTION(function44)
+ DECLARE_FUNCTION(function45)
+ DECLARE_FUNCTION(function46)
+ DECLARE_FUNCTION(drinkAfterDefuse)
+ DECLARE_FUNCTION(function48)
+ DECLARE_FUNCTION(pickBomb)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+ DECLARE_FUNCTION(function52)
+ DECLARE_FUNCTION(function53)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ABBOT_H
diff --git a/engines/lastexpress/entities/alexei.cpp b/engines/lastexpress/entities/alexei.cpp
new file mode 100644
index 0000000000..59b99fe968
--- /dev/null
+++ b/engines/lastexpress/entities/alexei.cpp
@@ -0,0 +1,2002 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/alexei.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Alexei::Alexei(LastExpressEngine *engine) : Entity(engine, kEntityAlexei) {
+ ADD_CALLBACK_FUNCTION(Alexei, reset);
+ ADD_CALLBACK_FUNCTION(Alexei, playSound);
+ ADD_CALLBACK_FUNCTION(Alexei, updateFromTicks);
+ ADD_CALLBACK_FUNCTION(Alexei, draw);
+ ADD_CALLBACK_FUNCTION(Alexei, updatePosition);
+ ADD_CALLBACK_FUNCTION(Alexei, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Alexei, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Alexei, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Alexei, savegame);
+ ADD_CALLBACK_FUNCTION(Alexei, updateEntity);
+ ADD_CALLBACK_FUNCTION(Alexei, draw2);
+ ADD_CALLBACK_FUNCTION(Alexei, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Alexei, function13);
+ ADD_CALLBACK_FUNCTION(Alexei, function14);
+ ADD_CALLBACK_FUNCTION(Alexei, function15);
+ ADD_CALLBACK_FUNCTION(Alexei, function16);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter1);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Alexei, function19);
+ ADD_CALLBACK_FUNCTION(Alexei, function20);
+ ADD_CALLBACK_FUNCTION(Alexei, function21);
+ ADD_CALLBACK_FUNCTION(Alexei, function22);
+ ADD_CALLBACK_FUNCTION(Alexei, function23);
+ ADD_CALLBACK_FUNCTION(Alexei, function24);
+ ADD_CALLBACK_FUNCTION(Alexei, function25);
+ ADD_CALLBACK_FUNCTION(Alexei, function26);
+ ADD_CALLBACK_FUNCTION(Alexei, function27);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter2);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Alexei, function30);
+ ADD_CALLBACK_FUNCTION(Alexei, function31);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter3);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Alexei, function34);
+ ADD_CALLBACK_FUNCTION(Alexei, function35);
+ ADD_CALLBACK_FUNCTION(Alexei, function36);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter4);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Alexei, function39);
+ ADD_CALLBACK_FUNCTION(Alexei, function40);
+ ADD_CALLBACK_FUNCTION(Alexei, function41);
+ ADD_CALLBACK_FUNCTION(Alexei, function42);
+ ADD_CALLBACK_FUNCTION(Alexei, function43);
+ ADD_CALLBACK_FUNCTION(Alexei, function44);
+ ADD_CALLBACK_FUNCTION(Alexei, function45);
+ ADD_CALLBACK_FUNCTION(Alexei, function46);
+ ADD_CALLBACK_FUNCTION(Alexei, function47);
+ ADD_CALLBACK_FUNCTION(Alexei, chapter5);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Alexei, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Alexei, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(3, Alexei, updateFromTicks, uint32)
+ Entity::updateFromTicks(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(4, Alexei, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SII(5, Alexei, updatePosition, CarIndex, Position)
+ Entity::updatePosition(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(6, Alexei, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Alexei, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIIS(8, Alexei, callSavepoint, EntityIndex, ActionIndex)
+ Entity::callSavepoint(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(9, Alexei, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Alexei, updateEntity, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExcuseMeCath:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 18) || getEntities()->isPlayerPosition(kCarRedSleeping, 18)) {
+ getSound()->excuseMe(kEntityAlexei);
+ } else {
+ if (getEvent(kEventAlexeiSalonVassili) || (getEvent(kEventTatianaAskMatchSpeakRussian) && getInventory()->hasItem(kItemPassengerList))) {
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1012" : "CAT1012A");
+ } else {
+ getSound()->excuseMeCath();
+ }
+ }
+ // Stop execution here
+ return;
+
+ case kActionDefault:
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(11, Alexei, draw2)
+ Entity::draw2(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Alexei, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Alexei, function13)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_7500);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAlexei, kEntityMertens, kAction302614416);
+ getEntities()->drawSequenceLeft(kEntityAlexei, "602DB");
+ getEntities()->enterCompartment(kEntityAlexei, kObjectCompartment2, true);
+
+ getData()->location = kLocationInsideCompartment;
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_7500)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(kObjectCompartment2, true);
+ }
+ break;
+
+ case 2:
+ getEntities()->exitCompartment(kEntityAlexei, kObjectCompartment2, true);
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_7500;
+ getEntities()->clearSequences(kEntityAlexei);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction135664192:
+ setCallback(2);
+ setup_enterExitCompartment("602Eb", kObjectCompartment2);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Alexei, function14)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("602Fb", kObjectCompartment2);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityAlexei, kEntityMertens, kAction302614416);
+ getEntities()->drawSequenceLeft(kEntityAlexei, "602DB");
+ getEntities()->enterCompartment(kEntityAlexei, kObjectCompartment2, true);
+ }
+ break;
+
+ case kAction135664192:
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getEntities()->exitCompartment(kEntityAlexei, kObjectCompartment2, true);
+
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Alexei, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_CHECK(params->param2, getState()->time, params->param1)
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updatePosition("103D", kCarRestaurant, 52);
+ }
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 5 * (3 * rnd(60) + 90);
+
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updatePosition("103C", kCarRestaurant, 52);
+ break;
+
+ case 2:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAlexei, "103E");
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAlexei, "103B");
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IS(16, Alexei, function16, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param7 && params->param1 < getState()->time && !params->param8) {
+ params->param8 = 1;
+
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param5) {
+ UPDATE_PARAM(CURRENT_PARAM(1, 1), getState()->timeTicks, 75);
+
+ params->param5 = 0;
+ params->param6 = 1;
+
+ getObjects()->update(kObjectCompartment2, kEntityAlexei, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityAlexei, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ CURRENT_PARAM(1, 1) = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartment2, kEntityAlexei, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityAlexei, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param5) {
+ if (savepoint.param.intValue == 18) {
+ setCallback(4);
+ setup_playSound(getSound()->justAMinuteCath());
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(5);
+ setup_playSound(rnd(2) ? getSound()->wrongDoorCath() : "CAT1503");
+ } else {
+ setCallback(6);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAlexei, (char*)&params->seq);
+ getObjects()->update(kObjectCompartment2, kEntityAlexei, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityAlexei, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param6 || params->param5) {
+ getObjects()->update(kObjectCompartment2, kEntityAlexei, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityAlexei, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param5 = 0;
+ params->param6 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound("ALX1134A");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartment2, kEntityAlexei, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityAlexei, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param5 = 1;
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ params->param5 = 0;
+ params->param6 = 1;
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_updateFromTicks(300);
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_enterExitCompartment("602Gb", kObjectCompartment2);
+ break;
+
+ case 9:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityAlexei, kEntityMertens, kAction156567128);
+ getEntities()->drawSequenceLeft(kEntityAlexei, "602Hb");
+ getEntities()->enterCompartment(kEntityAlexei, kObjectCompartment2, true);
+ break;
+
+ case 10:
+ getEntities()->exitCompartment(kEntityAlexei, kObjectCompartment2, true);
+
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_7500;
+
+ getEntities()->drawSequenceLeft(kEntityAlexei, (char *)&params->seq);
+ getObjects()->update(kObjectCompartment2, kEntityAlexei, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityAlexei, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param7 = 0;
+ break;
+ }
+ break;
+
+ case kAction124697504:
+ setCallback(10);
+ setup_enterExitCompartment("602Ib", kObjectCompartment2);
+ break;
+
+ case kAction221617184:
+ params->param7 = 1;
+ getSavePoints()->push(kEntityAlexei, kEntityMertens, kAction100906246);
+
+ setCallback(7);
+ setup_playSound("CON1024");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Alexei, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler)
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject10, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Alexei, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime1089000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ params->param2 = kItemNone;
+
+ getData()->location = kLocationOutsideCompartment;
+ getData()->inventoryItem = kItemNone;
+
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarRestaurant, 63);
+ getInventory()->setLocationAndProcess(kItem17, kObjectLocation1);
+
+ setCallback(1);
+ setup_callSavepoint("005D", kEntityTables1, kActionDrawTablesWithChairs, "005E");
+ break;
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param3, getState()->timeTicks, 90);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
+ } else {
+ params->param3 = 0;
+ }
+ break;
+
+ case kAction1:
+ params->param2 = kItemNone;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventAlexeiDiner);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAlexei, kEntityTables1, kAction136455232);
+ getEntities()->drawSequenceLeft(kEntityAlexei, "005B");
+
+ params->param2 = kItemInvalid;
+ getData()->inventoryItem = kItemInvalid;
+ break;
+
+ case kActionDrawScene:
+ params->param1 = getEntities()->isPlayerPosition(kCarRestaurant, 63) ? 1 : 0;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 63);
+ setup_function19();
+ break;
+
+ case 2:
+ getAction()->playAnimation(getProgress().jacket == kJacketGreen ? kEventAlexeiDiner : kEventAlexeiDinerOriginalJacket);
+ getSavePoints()->push(kEntityAlexei, kEntityTables1, kActionDrawTablesWithChairs, "005E");
+
+ getData()->entityPosition = kPosition_3650;
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->clearSequences(kEntityAlexei);
+ getInventory()->get(kItem17)->location = kObjectLocation1;
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 63);
+
+ setup_function19();
+ break;
+ }
+ break;
+
+ case kAction168046720:
+ getData()->inventoryItem = kItemNone;
+ break;
+
+ case kAction168627977:
+ getData()->inventoryItem = (InventoryItem)LOW_BYTE(params->param2);
+ break;
+
+ case kAction225182640:
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Alexei, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_draw("811DS");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_9460);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_draw("811US");
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_draw("933");
+ break;
+
+ case 6:
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarRestaurant, 63);
+ getScenes()->loadSceneFromItemPosition(kItem17);
+ getSavePoints()->push(kEntityAlexei, kEntityTables1, kAction136455232);
+
+ setCallback(7);
+ setup_callSavepoint("005F", kEntityTables1, kActionDrawTablesWithChairs, "005G");
+ break;
+
+ case 7:
+ getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 63);
+ getSavePoints()->push(kEntityAlexei, kEntityServers1, kAction302996448);
+
+ setCallback(8);
+ setup_draw("934");
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_draw("811DS");
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_function13();
+ break;
+
+ case 10:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 61))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ setCallback(11);
+ setup_function16(kTime1098000, "411");
+ break;
+
+ case 11:
+ setup_function20();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Alexei, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function14();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_updatePosition("103A", kCarRestaurant, 52);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+ setup_function26();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Alexei, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_CHECK(params->param2, getState()->time, params->param1)
+ getData()->location = kLocationOutsideCompartment;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_updatePosition("103C", kCarRestaurant, 52);
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventAlexeiSalonPoem);
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAlexei, "103B");
+ params->param1 = 225 * (4 * rnd(3) + 4);
+
+ if (!getEvent(kEventAlexeiSalonPoem))
+ getData()->inventoryItem = kItemParchemin;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationInsideCompartment;
+ setup_function22();
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventAlexeiSalonPoem);
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->drawSequenceRight(kEntityAlexei, "103D");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarRestaurant, 52);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityAlexei, "103B");
+ getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 52);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Alexei, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_PROC(params->param2, getState()->time, params->param2)
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->location = kLocationOutsideCompartment;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_updatePosition("103D", kCarRestaurant, 52);
+ break;
+ }
+ UPDATE_PARAM_PROC_END
+
+ if (params->param3 == kTimeInvalid || getState()->time <= kTime1111500)
+ break;
+
+ if (getState()->time > kTime1138500) {
+ params->param3 = kTimeInvalid;
+ } else {
+ if (!getEntities()->isInSalon(kEntityPlayer) || getEntities()->isInSalon(kEntityPlayer) || !params->param3)
+ params->param3 = (uint)getState()->time;
+
+ if (params->param3 >= getState()->time)
+ break;
+
+ params->param3 = kTimeInvalid;
+ }
+
+ getData()->inventoryItem = kItemNone;
+
+ setup_function23();
+ break;
+
+ case kAction1:
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventAlexeiSalonPoem);
+ break;
+
+ case kActionDefault:
+ params->param1 = 255 * (4 * rnd(4) + 8);
+ getEntities()->drawSequenceLeft(kEntityAlexei, "103E");
+ if (!getEvent(kEventAlexeiSalonPoem))
+ getData()->inventoryItem = kItemParchemin;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationInsideCompartment;
+ setup_function21();
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventAlexeiSalonPoem);
+ getData()->inventoryItem = kItemNone;
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->drawSequenceRight(kEntityAlexei, "103D");
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarRestaurant, 52);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 52);
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function21();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Alexei, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ getData()->inventoryItem = (!getEntities()->isInRestaurant(kEntityAlexei) || getEvent(kEventAlexeiSalonPoem)) ? kItemNone : kItemParchemin;
+ break;
+
+ case kAction1:
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventAlexeiSalonPoem);
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationInsideCompartment;
+ getSavePoints()->push(kEntityAlexei, kEntityTatiana, kAction124973510);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventAlexeiSalonVassili);
+
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->drawSequenceLeft(kEntityAlexei, "103F");
+ getScenes()->processScene();
+
+ setup_function24();
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventAlexeiSalonPoem);
+
+ getData()->inventoryItem = kItemNone;
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+ break;
+ }
+ break;
+
+ case kAction157159392:
+ if (getEntities()->isInSalon(kEntityPlayer)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAlexeiSalonVassili);
+ } else {
+ setup_function24();
+ }
+ break;
+
+ case kAction188784532:
+ setup_function24();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Alexei, function24)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAlexeiSalonCath);
+ break;
+
+ case kActionDefault:
+ if (getEvent(kEventAlexeiSalonVassili))
+ getData()->inventoryItem = kItemInvalid;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventAlexeiSalonCath);
+ getData()->car = kCarRestaurant;
+ getData()->entityPosition = kPosition_9460;
+ getEntities()->clearSequences(kEntityAlexei);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+ setup_function25();
+ break;
+
+ case 2:
+ setup_function25();
+ break;
+ }
+ break;
+
+ case kAction135854208:
+ getData()->inventoryItem = kItemNone;
+ setCallback(2);
+ setup_draw("103G");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Alexei, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function13();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 61))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ setCallback(2);
+ setup_function16(kTime1179000, "411");
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function16(kTime1323000, "412");
+ break;
+
+ case 3:
+ setup_function26();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Alexei, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTime1512000, params->param1, setup_function27)
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_7500;
+ getData()->car = kCarGreenSleeping;
+ getData()->location = kLocationInsideCompartment;
+
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject10, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 61))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 66);
+
+ getEntities()->clearSequences(kEntityAlexei);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Alexei, function27)
+ if (savepoint.action == kActionDefault) {
+ getObjects()->update(kObject10, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 66))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ getEntities()->drawSequenceLeft(kEntityAlexei, "412");
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Alexei, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAlexei);
+
+ getObjects()->update(kObjectCompartment2, kEntityAlexei, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject10, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityAlexei, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Alexei, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16(kTime1791000, "411");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function14();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_draw("811US");
+ break;
+
+ case 5:
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarRestaurant, 63);
+
+ setCallback(6);
+ setup_callSavepoint("018B", kEntityTables1, kAction136455232, "BOGUS");
+ break;
+
+ case 6:
+ getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 63);
+ getSavePoints()->push(kEntityAlexei, kEntityTatiana, kAction290869168);
+ setup_function30();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Alexei, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getData()->car = kCarRestaurant;
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->drawSequenceLeft(kEntityAlexei, "018C");
+ getSavePoints()->push(kEntityAlexei, kEntityTables1, kAction136455232);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 63);
+ getSavePoints()->push(kEntityAlexei, kEntityTatiana, kAction156444784);
+ getEntities()->drawSequenceLeft(kEntityAlexei, "018E");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getProgress().field_68 = 1;
+
+ setCallback(2);
+ setup_playSound("TAT2116");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityAlexei, "TAt2116A");
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarRestaurant, 63);
+
+ setCallback(3);
+ setup_callSavepoint("018F", kEntityTatiana, kAction123857088, "BOGUS");
+ break;
+
+ case 3:
+ getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 63);
+ setup_function31();
+ break;
+ }
+ break;
+
+ case kAction236053296:
+ getEntities()->drawSequenceRight(kEntityAlexei, "018D1");
+ getEntities()->drawSequenceRight(kEntityTatiana, "018D2");
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarRestaurant, 63);
+
+ if (savepoint.param.intValue)
+ getScenes()->loadSceneFromPosition(kCarRestaurant, (Position)savepoint.param.intValue);
+
+ setCallback(1);
+ setup_callbackActionOnDirection();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Alexei, function31)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityAlexei, "811DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAlexei);
+
+ setCallback(1);
+ setup_callbackActionOnDirection();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function13();
+ break;
+
+ case 2:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 61))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ setCallback(3);
+ setup_function16(kTimeEnd, "411");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Alexei, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAlexei);
+
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject10, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Alexei, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function34();
+ break;
+
+ case kAction122288808:
+ getData()->entityPosition = kPosition_9270;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ setCallback(1);
+ setup_function13();
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAlexei, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Alexei, function34)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 61))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ setCallback(1);
+ setup_function16(kTime2083500, "411");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function14();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_updatePosition("103A", kCarRestaurant, 52);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function35();
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function13();
+ break;
+
+ case 7:
+ getObjects()->update(kObject10, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 61))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 66);
+
+ setCallback(8);
+ setup_function16(kTime2124000, "NONE");
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_function14();
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_function36();
+ break;
+
+ case 10:
+ getObjects()->update(kObject10, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 66))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ setCallback(11);
+ setup_function16(kTime16451100, "411");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Alexei, function35)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInSalon(kEntityPlayer)) {
+ UPDATE_PARAM_PROC(params->param2, getState()->time, 2700)
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+ UPDATE_PARAM_PROC_END
+ } else {
+ params->param2 = 0;
+ }
+
+ UPDATE_PARAM_PROC(params->param3, getState()->time, params->param1)
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ setCallback(3);
+ setup_function15();
+ break;
+ }
+ UPDATE_PARAM_PROC_END
+
+label_callback_3:
+ UPDATE_PARAM(params->param4, getState()->time, 9000);
+
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionDefault:
+ params->param1 = 15 * rnd(120);
+ getEntities()->drawSequenceLeft(kEntityAlexei, "103B");
+ getData()->location = kLocationInsideCompartment;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 4:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(getCallback() + 1);
+ setup_updatePosition("124C", kCarRestaurant, 52);
+ break;
+
+ case 2:
+ case 5:
+ CALLBACK_ACTION();
+ break;
+
+ case 3:
+ params->param1 = 15 * rnd(120);
+ params->param3 = 0;
+ goto label_callback_3;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Alexei, function36)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param3 || params->param2)
+ break;
+
+ UPDATE_PARAM(params->param4, getState()->timeTicks, params->param1);
+
+ getEntities()->drawSequenceRight(kEntityAlexei, "124B");
+
+ params->param2 = 1;
+ params->param4 = 0;
+ break;
+
+ case kActionExitCompartment:
+ if (params->param2) {
+ getEntities()->drawSequenceLeft(kEntityAlexei, "124A");
+ params->param1 = 5 * (3 * rnd(15) + 15);
+ params->param2 = 0;
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 5 * (3 * rnd(15) + 15);
+
+ setCallback(1);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityAlexei, kEntityAbbot, kAction222609266);
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updatePosition("103A", kCarRestaurant, 52);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAlexei, "124A");
+ break;
+
+ case 4:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ setCallback(4);
+ setup_function13();
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAlexei, "BLANK");
+ params->param3 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Alexei, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAlexei);
+
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject10, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Alexei, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16(kTime2354400, "411");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function39();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(39, Alexei, function39)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param2)
+ break;
+
+ if (!params->param4) {
+ params->param3 = (uint)getState()->time + 4500;
+ params->param4 = (uint)getState()->time + 9000;
+ }
+
+ if (params->param5 != kTimeInvalid && params->param3 < getState()->time) {
+
+ if (params->param4 >= getState()->time) {
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer) || !params->param5)
+ params->param5 = (uint)getState()->time;
+
+ if (params->param5 >= getState()->time)
+ break;
+ }
+
+ params->param4 = kTimeInvalid;
+
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarGreenSleeping, 70);
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarGreenSleeping, 71);
+
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityAlexei);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 72);
+ }
+
+ setup_function40();
+ }
+ break;
+
+ case kActionExitCompartment:
+ if (!params->param2 && !params->param2)
+ getEntities()->drawSequenceLeft(kEntityAlexei, "306F");
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("602FB", kObjectCompartment2);
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62)) {
+ if (params->param1) {
+ if (!params->param2)
+ break;
+ } else if (!params->param2) {
+ getEntities()->drawSequenceRight(kEntityAlexei, "306A");
+ break;
+ }
+
+ setup_function40();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityAlexei);
+
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityAlexei);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 72);
+ }
+
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarGreenSleeping, 70);
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarGreenSleeping, 71);
+ break;
+ }
+ break;
+
+ case kAction123536024:
+ params->param2 = 1;
+ break;
+
+ case kAction123712592:
+ getEntities()->clearSequences(kEntityAlexei);
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(40, Alexei, function40)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_7500);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceRight(kEntityAlexei, "602Eb");
+ getEntities()->enterCompartment(kEntityAlexei, kObjectCompartment2);
+
+ getData()->location = kLocationInsideCompartment;
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_7500)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(kObjectCompartment2);
+ }
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ getEntities()->exitCompartment(kEntityAlexei, kObjectCompartment2);
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityAlexei);
+
+ setup_function41();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(41, Alexei, function41)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 66))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ setCallback(1);
+ setup_function16(kTime2403000, "411");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function42();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(42, Alexei, function42)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function14();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAlexei, kEntityTatiana, kAction191198209);
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updatePosition("103A", kCarRestaurant, 52);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ setup_function43();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(43, Alexei, function43)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time < kTime1806300 && params->param2 < getState()->time) {
+ if (!params->param2)
+ params->param2 = (uint)getState()->time + params->param1;
+
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ setCallback(1);
+ setup_function15();
+ break;
+ }
+ }
+
+label_callback_1:
+ if (getState()->time > kTime2457000 && !params->param3) {
+ params->param3 = 1;
+
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 5 * (3 * rnd(120) + 180);
+ getEntities()->drawSequenceLeft(kEntityAlexei, "103B");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param1 = 5 * (3 * rnd(120) + 180);
+ params->param2 = 0;
+ goto label_callback_1;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updatePosition("124C", kCarRestaurant, 52);
+ break;
+
+ case 3:
+ setup_function44();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(44, Alexei, function44)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2457000 && !params->param1) {
+ params->param1 = 1;
+
+ getEntities()->updatePositionExit(kEntityAlexei, kCarGreenSleeping, 70);
+ getEntities()->updatePositionExit(kEntityAlexei, kCarGreenSleeping, 71);
+
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityAlexei);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 72);
+
+ setup_function45();
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->entityPosition = kPosition_9460;
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62)) {
+ setCallback(2);
+ setup_draw("306A");
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityAlexei);
+
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityAlexei);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 72);
+ }
+
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarGreenSleeping, 70);
+ getEntities()->updatePositionEnter(kEntityAlexei, kCarGreenSleeping, 71);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityAlexei, "306F");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(45, Alexei, function45)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function13();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 66))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ if (getInventory()->hasItem(kItemBomb)) {
+ setup_function46();
+ } else {
+ setCallback(2);
+ setup_function16(kTimeEnd, "412");
+ }
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(46, Alexei, function46)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 == kTimeInvalid)
+ break;
+
+ if (getState()->time <= kTime2493000) {
+
+ if (getEntities()->isInSalon(kEntityPlayer) || getEntities()->isInSalon(kEntityAugust) || !params->param1)
+ params->param1 = (uint)getState()->time;
+
+ if (params->param1 >= getState()->time)
+ break;
+ }
+
+ params->param1 = kTimeInvalid;
+
+ getScenes()->loadSceneFromItemPosition(kItem22);
+
+ if (getEntities()->isInSalon(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityAlexei);
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, getScenes()->get(getState()->scene)->position);
+ }
+
+ setCallback(4);
+ setup_function13();
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16(kTime2488500, "411");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function14();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 4:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 66))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ setCallback(5);
+ setup_function16(kTime2507400, "412");
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_enterExitCompartment("602Fb", kObjectCompartment2);
+ break;
+
+ case 6:
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(7);
+ setup_updateEntity(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case 7:
+ getEntities()->drawSequenceRight(kEntityAlexei, "602Eb");
+ getEntities()->enterCompartment(kEntityAlexei, kObjectCompartmentB);
+ getData()->location = kLocationInsideCompartment;
+
+ if (getEntities()->checkFields19(kEntityPlayer, kCarRedSleeping, kPosition_7850)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(kObjectCompartmentB);
+ }
+
+ setCallback(8);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 8:
+ getEntities()->exitCompartment(kEntityAlexei, kObjectCompartmentB);
+ getEntities()->clearSequences(kEntityAlexei);
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject48, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(9);
+ setup_playSound("TAT4167");
+ break;
+
+ case 9:
+ getSavePoints()->push(kEntityAlexei, kEntityChapters, kAction156435676);
+ setup_function47();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(47, Alexei, function47)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityAlexei);
+
+ getData()->entityPosition = kPositionNone;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarNone;
+
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(48, Alexei, chapter5)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityAlexei);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/alexei.h b/engines/lastexpress/entities/alexei.h
new file mode 100644
index 0000000000..420e6e87fc
--- /dev/null
+++ b/engines/lastexpress/entities/alexei.h
@@ -0,0 +1,213 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ALEXEI_H
+#define LASTEXPRESS_ALEXEI_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Alexei : public Entity {
+public:
+ Alexei(LastExpressEngine *engine);
+ ~Alexei() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param ticks The number of ticks to add
+ */
+ DECLARE_FUNCTION_1(updateFromTicks, uint32 ticks)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence1, CarIndex car, Position position)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Call a savepoint (or draw sequence in default case)
+ *
+ * @param sequence1 The sequence to draw in the default case
+ * @param entity The entity
+ * @param action The action
+ * @param sequence2 The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_4(callSavepoint, const char *sequence1, EntityIndex entity, ActionIndex action, const char *sequence2)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Draws the entity along with another one
+ *
+ * @param savepoint The savepoint
+ * - The sequence to draw
+ * - The sequence to draw for the second entity
+ * - The EntityIndex of the second entity
+ */
+ DECLARE_FUNCTION_NOSETUP(draw2)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ DECLARE_FUNCTION(function13)
+ DECLARE_FUNCTION(function14)
+ DECLARE_FUNCTION(function15)
+
+ /**
+ * ???
+ *
+ * @param timeValue The time value
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_2(function16, TimeValue timeValue, const char *sequence)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+ DECLARE_FUNCTION(function19)
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+ DECLARE_FUNCTION(function30)
+ DECLARE_FUNCTION(function31)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+ DECLARE_FUNCTION(function34)
+ DECLARE_FUNCTION(function35)
+ DECLARE_FUNCTION(function36)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+ DECLARE_FUNCTION(function39)
+ DECLARE_FUNCTION(function40)
+ DECLARE_FUNCTION(function41)
+ DECLARE_FUNCTION(function42)
+ DECLARE_FUNCTION(function43)
+ DECLARE_FUNCTION(function44)
+ DECLARE_FUNCTION(function45)
+ DECLARE_FUNCTION(function46)
+ DECLARE_FUNCTION(function47)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ALEXEI_H
diff --git a/engines/lastexpress/entities/alouan.cpp b/engines/lastexpress/entities/alouan.cpp
new file mode 100644
index 0000000000..2867fa726b
--- /dev/null
+++ b/engines/lastexpress/entities/alouan.cpp
@@ -0,0 +1,504 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/alouan.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Alouan::Alouan(LastExpressEngine *engine) : Entity(engine, kEntityAlouan) {
+ ADD_CALLBACK_FUNCTION(Alouan, reset);
+ ADD_CALLBACK_FUNCTION(Alouan, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Alouan, playSound);
+ ADD_CALLBACK_FUNCTION(Alouan, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Alouan, updateEntity);
+ ADD_CALLBACK_FUNCTION(Alouan, compartment6);
+ ADD_CALLBACK_FUNCTION(Alouan, compartment8);
+ ADD_CALLBACK_FUNCTION(Alouan, compartment6to8);
+ ADD_CALLBACK_FUNCTION(Alouan, compartment8to6);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter1);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Alouan, function12);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter2);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter3);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter4);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Alouan, function19);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter5);
+ ADD_CALLBACK_FUNCTION(Alouan, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Alouan, function22);
+ ADD_CALLBACK_FUNCTION(Alouan, function23);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Alouan, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(2, Alouan, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Alouan, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(4, Alouan, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(5, Alouan, updateEntity, CarIndex, EntityPosition)
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Alouan, compartment6)
+ COMPARTMENT_TO(Alouan, kObjectCompartment6, kPosition_4070, "621Cf", "621Df");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Alouan, compartment8)
+ COMPARTMENT_TO(Alouan, kObjectCompartment8, kPosition_2740, "621Ch", "621Dh");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Alouan, compartment6to8)
+ COMPARTMENT_FROM_TO(Alouan, kObjectCompartment6, kPosition_4070, "621Bf", kObjectCompartment8, kPosition_2740, "621Ah");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Alouan, compartment8to6)
+ COMPARTMENT_FROM_TO(Alouan, kObjectCompartment8, kPosition_2740, "621Bh", kObjectCompartment6, kPosition_4070, "621Af");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Alouan, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Alouan, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+
+ TIME_CHECK_CALLBACK(kTime1096200, params->param1, 1, setup_compartment8to6);
+
+label_callback1:
+ if (getState()->time > kTime1162800 && !params->param2) {
+ params->param2 = 1;
+ getSavePoints()->push(kEntityAlouan, kEntityTrain, kAction191070912, kPosition_4070);
+ getData()->entityPosition = kPosition_4070;
+ }
+
+ if (getState()->time > kTime1179000 && !params->param3) {
+ params->param3 = 1;
+ getSavePoints()->push(kEntityAlouan, kEntityTrain, kAction191070912, kPosition_4840);
+
+ setCallback(2);
+ setup_compartment6to8();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_4840;
+ goto label_callback1;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Alouan, function12)
+ if (savepoint.action == kActionDefault) {
+ getObjects()->update(kObjectCompartment7, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment5, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getEntities()->clearSequences(kEntityAlouan);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Alouan, chapter2)
+ if (savepoint.action != kActionDefault)
+ return;
+
+ getEntities()->clearSequences(kEntityAlouan);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ setup_chapter2Handler();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Alouan, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2 == kTimeInvalid)
+ break;
+
+ if (getState()->time <= kTime1777500) {
+ if (!getEntities()->isPlayerInCar(kCarGreenSleeping) || !params->param2)
+ params->param2 = (uint)getState()->time + 75;
+
+ if (params->param2 >= getState()->time)
+ break;
+ }
+
+ params->param2 = kTimeInvalid;
+
+ setCallback(params->param1 ? 1 : 2);
+ if (params->param1)
+ setup_compartment8();
+ else
+ setup_compartment6();
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAlouan, kEntityTrain, kAction191070912, kPosition_4840);
+ params->param1 = 1;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 3:
+ params->param1 = 0;
+ setCallback(4);
+ setup_playSound("Har2011");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_updateFromTime(900);
+ break;
+
+ case 5:
+ getSavePoints()->push(kEntityAlouan, kEntityFrancois, kAction190219584);
+ break;
+ }
+ break;
+
+ case kAction189489753:
+ setCallback(3);
+ setup_compartment8to6();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Alouan, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAlouan);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Alouan, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTimeCitySalzbourg, params->param1, 1, setup_compartment8to6);
+
+label_callback1:
+ if (params->param2 != kTimeInvalid && getState()->time > kTime1989000)
+ TIME_CHECK_CAR(kTime2119500, params->param5, 5, setup_compartment8);
+
+label_callback2:
+ TIME_CHECK_CALLBACK_1(kTime2052000, params->param3, 3, setup_playSound, "Har1005");
+
+label_callback3:
+ TIME_CHECK_CALLBACK(kTime2133000, params->param4, 4, setup_compartment6to8);
+
+label_callback4:
+ if (params->param5 != kTimeInvalid && getState()->time > kTime2151000)
+ TIME_CHECK_CAR(kTime2241000, params->param5, 5, setup_compartment8);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAlouan, kEntityTrain, kAction191070912, kPosition_4840);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_4840;
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 3:
+ goto label_callback3;
+
+ case 4:
+ goto label_callback4;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Alouan, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAlouan);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Alouan, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 != kTimeInvalid)
+ TIME_CHECK_CAR(kTime2443500, params->param1, 1, setup_compartment8);
+
+label_callback1:
+ TIME_CHECK_CALLBACK(kTime2455200, params->param2, 2, setup_compartment8to6);
+
+label_callback2:
+ if (getState()->time > kTime2475000 && !params->param3) {
+ params->param3 = 1;
+ getSavePoints()->push(kEntityAlouan, kEntityTrain, kAction191070912, kPosition_4840);
+
+ setCallback(3);
+ setup_compartment6to8();
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAlouan, kEntityTrain, kAction191070912, kPosition_4840);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback1;
+
+ case 2:
+ getSavePoints()->push(kEntityAlouan, kEntityTrain, kAction191070912, kPosition_4070);
+ goto label_callback2;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Alouan, function19)
+ if (savepoint.action == kActionDefault) {
+ getObjects()->update(kObjectCompartment7, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment5, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getEntities()->clearSequences(kEntityAlouan);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Alouan, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAlouan);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Alouan, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function22();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Alouan, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->time, 2700);
+ setup_function23();
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping))
+ setup_function23();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Alouan, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_4070);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("619AF", kObjectCompartment5);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityAlouan);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+
+ getObjects()->update(kObjectCompartment6, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(24, Alouan)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/alouan.h b/engines/lastexpress/entities/alouan.h
new file mode 100644
index 0000000000..33d5e2f23d
--- /dev/null
+++ b/engines/lastexpress/entities/alouan.h
@@ -0,0 +1,139 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ALOUAN_H
+#define LASTEXPRESS_ALOUAN_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Alouan : public Entity {
+public:
+ Alouan(LastExpressEngine *engine);
+ ~Alouan() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION(compartment6)
+ DECLARE_FUNCTION(compartment8)
+ DECLARE_FUNCTION(compartment6to8)
+ DECLARE_FUNCTION(compartment8to6)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+ DECLARE_FUNCTION(function12)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+ DECLARE_FUNCTION(function19)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ALOUAN_H
diff --git a/engines/lastexpress/entities/anna.cpp b/engines/lastexpress/entities/anna.cpp
new file mode 100644
index 0000000000..e6752dad48
--- /dev/null
+++ b/engines/lastexpress/entities/anna.cpp
@@ -0,0 +1,4032 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/anna.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/fight.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Anna::Anna(LastExpressEngine *engine) : Entity(engine, kEntityAnna) {
+ ADD_CALLBACK_FUNCTION(Anna, reset);
+ ADD_CALLBACK_FUNCTION(Anna, draw);
+ ADD_CALLBACK_FUNCTION(Anna, updatePosition);
+ ADD_CALLBACK_FUNCTION(Anna, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Anna, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Anna, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Anna, playSound);
+ ADD_CALLBACK_FUNCTION(Anna, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Anna, savegame);
+ ADD_CALLBACK_FUNCTION(Anna, updateEntity);
+ ADD_CALLBACK_FUNCTION(Anna, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Anna, function12);
+ ADD_CALLBACK_FUNCTION(Anna, draw2);
+ ADD_CALLBACK_FUNCTION(Anna, updateFromTicks);
+ ADD_CALLBACK_FUNCTION(Anna, function15);
+ ADD_CALLBACK_FUNCTION(Anna, chapter1);
+ ADD_CALLBACK_FUNCTION(Anna, function17);
+ ADD_CALLBACK_FUNCTION(Anna, function18);
+ ADD_CALLBACK_FUNCTION(Anna, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Anna, function20);
+ ADD_CALLBACK_FUNCTION(Anna, function21);
+ ADD_CALLBACK_FUNCTION(Anna, function22);
+ ADD_CALLBACK_FUNCTION(Anna, function23);
+ ADD_CALLBACK_FUNCTION(Anna, function24);
+ ADD_CALLBACK_FUNCTION(Anna, function25);
+ ADD_CALLBACK_FUNCTION(Anna, function26);
+ ADD_CALLBACK_FUNCTION(Anna, function27);
+ ADD_CALLBACK_FUNCTION(Anna, function28);
+ ADD_CALLBACK_FUNCTION(Anna, function29);
+ ADD_CALLBACK_FUNCTION(Anna, function30);
+ ADD_CALLBACK_FUNCTION(Anna, function31);
+ ADD_CALLBACK_FUNCTION(Anna, function32);
+ ADD_CALLBACK_FUNCTION(Anna, function33);
+ ADD_CALLBACK_FUNCTION(Anna, function34);
+ ADD_CALLBACK_FUNCTION(Anna, function35);
+ ADD_CALLBACK_FUNCTION(Anna, function36);
+ ADD_CALLBACK_FUNCTION(Anna, function37);
+ ADD_CALLBACK_FUNCTION(Anna, function38);
+ ADD_CALLBACK_FUNCTION(Anna, function39);
+ ADD_CALLBACK_FUNCTION(Anna, function40);
+ ADD_CALLBACK_FUNCTION(Anna, function41);
+ ADD_CALLBACK_FUNCTION(Anna, chapter2);
+ ADD_CALLBACK_FUNCTION(Anna, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Anna, chapter3);
+ ADD_CALLBACK_FUNCTION(Anna, function45);
+ ADD_CALLBACK_FUNCTION(Anna, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Anna, function47);
+ ADD_CALLBACK_FUNCTION(Anna, function48);
+ ADD_CALLBACK_FUNCTION(Anna, leaveTableWithAugust);
+ ADD_CALLBACK_FUNCTION(Anna, function50);
+ ADD_CALLBACK_FUNCTION(Anna, function51);
+ ADD_CALLBACK_FUNCTION(Anna, function52);
+ ADD_CALLBACK_FUNCTION(Anna, function53);
+ ADD_CALLBACK_FUNCTION(Anna, function54);
+ ADD_CALLBACK_FUNCTION(Anna, function55);
+ ADD_CALLBACK_FUNCTION(Anna, function56);
+ ADD_CALLBACK_FUNCTION(Anna, function57);
+ ADD_CALLBACK_FUNCTION(Anna, function58);
+ ADD_CALLBACK_FUNCTION(Anna, function59);
+ ADD_CALLBACK_FUNCTION(Anna, function60);
+ ADD_CALLBACK_FUNCTION(Anna, function61);
+ ADD_CALLBACK_FUNCTION(Anna, function62);
+ ADD_CALLBACK_FUNCTION(Anna, function63);
+ ADD_CALLBACK_FUNCTION(Anna, baggage);
+ ADD_CALLBACK_FUNCTION(Anna, function65);
+ ADD_CALLBACK_FUNCTION(Anna, chapter4);
+ ADD_CALLBACK_FUNCTION(Anna, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Anna, function68);
+ ADD_CALLBACK_FUNCTION(Anna, function69);
+ ADD_CALLBACK_FUNCTION(Anna, function70);
+ ADD_CALLBACK_FUNCTION(Anna, function71);
+ ADD_CALLBACK_FUNCTION(Anna, function72);
+ ADD_CALLBACK_FUNCTION(Anna, function73);
+ ADD_CALLBACK_FUNCTION(Anna, chapter5);
+ ADD_CALLBACK_FUNCTION(Anna, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Anna, function76);
+ ADD_CALLBACK_FUNCTION(Anna, function77);
+ ADD_CALLBACK_FUNCTION(Anna, function78);
+ ADD_CALLBACK_FUNCTION(Anna, function79);
+ ADD_CALLBACK_FUNCTION(Anna, function80);
+ ADD_CALLBACK_FUNCTION(Anna, finalSequence);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Anna, reset)
+ Entity::reset(savepoint, true, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Anna, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SII(3, Anna, updatePosition, CarIndex, Position)
+ Entity::updatePosition(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(4, Anna, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Anna, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIIS(6, Anna, callSavepoint, EntityIndex, ActionIndex)
+ Entity::callSavepoint(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(7, Anna, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Anna, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(9, Anna, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Anna, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ if (getEvent(kEventAugustPresentAnna) || getEvent(kEventAugustPresentAnnaFirstIntroduction) || getProgress().chapter >= kChapter2)
+ getSound()->playSound(kEntityPlayer, "CAT1001");
+ else
+ getSound()->excuseMeCath();
+
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(11, Anna, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Anna, function12)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param2 && ENTITY_PARAM(0, 1))
+ params->param2 = 1;
+
+ if (params->param6) {
+ UPDATE_PARAM_PROC(params->param7, getState()->timeTicks, 75)
+ getSavePoints()->push(kEntityAnna, kEntityAnna, kActionEndSound);
+
+ params->param6 = 0;
+ params->param7 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param4) {
+ UPDATE_PARAM(params->param8, getState()->timeTicks, 75);
+
+ params->param4 = 0;
+ params->param5 = 1;
+
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorHand);
+
+ --params->param1;
+
+ getSavePoints()->push(kEntityAnna, kEntityAnna, kActionEndSound);
+ }
+
+ params->param8 = 0;
+ break;
+
+ case kActionEndSound:
+ if (params->param2) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ ++params->param1;
+
+ switch (params->param1) {
+ default:
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityAnna, "ANN2135A");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityAnna, "ANN2135B");
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityAnna, "ANN2135C");
+ break;
+
+ case 4:
+ getSound()->playSound(kEntityAnna, "ANN2135C");
+ break;
+
+ case 5:
+ getSound()->playSound(kEntityAnna, "ANN2135L");
+ break;
+
+ case 6:
+ getSound()->playSound(kEntityAnna, "ANN2135K");
+ break;
+
+ case 7:
+ getSound()->playSound(kEntityAnna, "ANN2135H");
+ break;
+
+ case 8:
+ getSound()->playSound(kEntityAnna, "ANN2135K");
+ break;
+
+ case 9:
+ getSound()->playSound(kEntityAnna, "ANN2135I");
+ break;
+
+ case 10:
+ getSound()->playSound(kEntityAnna, "ANN2135J");
+ break;
+
+ case 11:
+ getSound()->playSound(kEntityAnna, "ANN2135M");
+ break;
+
+ case 12:
+ getSound()->playSound(kEntityAnna, "ANN2135L");
+ break;
+
+ case 13:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kActionKnock:
+ if (params->param4) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorHand);
+
+ if (savepoint.param.intValue == 53) {
+ getSound()->playSound(kEntityPlayer, getSound()->justAMinuteCath());
+ } else if (getInventory()->hasItem(kItemPassengerList)) {
+ if (rnd(2)) {
+ getSound()->playSound(kEntityPlayer, getSound()->wrongDoorCath());
+ } else {
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1506A" : "CAT1506");
+ }
+ } else {
+ getSound()->playSound(kEntityPlayer, getSound()->wrongDoorCath());
+ }
+
+ params->param4 = 0;
+ params->param5 = 0;
+ } else {
+ getSound()->removeFromQueue(kEntityAnna);
+
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_playSound("LIB012");
+ }
+ break;
+
+ case kActionOpenDoor:
+ getSound()->removeFromQueue(kEntityAnna);
+ setCallback(3);
+ setup_playSound("LIB013");
+ break;
+
+ case kActionDefault:
+ params->param1 = 1;
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 49))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+
+ getEntities()->drawSequenceLeft(kEntityAnna, "418C");
+
+ if (getSound()->isBuffered(kEntityAnna))
+ getSound()->processEntry(kEntityAnna);
+
+ getSound()->playSound(kEntityAnna, "ANN2135A");
+ break;
+
+ case kActionDrawScene:
+ if (params->param5 || params->param4) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ params->param4 = 0;
+ params->param5 = 0;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 60)) {
+ ++params->param3;
+ if (params->param3 == 2) {
+ setCallback(2);
+ setup_draw("418B");
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_playSound("Ann1016");
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorHand);
+ params->param4 = 1;
+ break;
+
+ case 3:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ setCallback(4);
+ setup_playSound("MAX1120");
+ break;
+ }
+ // Fallback to next case
+
+ case 4:
+ --params->param1;
+ params->param6 = 1;
+ break;
+
+ case 5:
+ getEntities()->drawSequenceLeft(kEntityAnna, "418A");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SSI(13, Anna, draw2, EntityIndex)
+ Entity::draw2(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(14, Anna, updateFromTicks, uint32)
+ Entity::updateFromTicks(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IS(15, Anna, function15, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 < getState()->time && !params->param7) {
+ params->param7 = 1;
+
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param5) {
+ UPDATE_PARAM(params->param8, getState()->timeTicks, 75);
+
+ params->param5 = 0;
+ params->param6 = 1;
+
+ CursorStyle cursor = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal;
+
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, cursor);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, cursor);
+ }
+
+ params->param8 = 0;
+ break;
+
+ case kActionOpenDoor:
+ if (getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070)) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_playSound("LIB013");
+ break;
+ }
+ // Fallback to next action
+
+ case kActionKnock:
+ if (params->param5) {
+ CursorStyle cursor = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal;
+
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, cursor);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, cursor);
+
+ if (savepoint.param.intValue == kObject53) {
+ setCallback(6);
+ setup_playSound(getSound()->justAMinuteCath());
+ } else {
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(7);
+ setup_playSound(rnd(2) ? getSound()->wrongDoorCath() : (rnd(2) ? "CAT1506" : "CAT1506A"));
+ } else {
+ setCallback(8);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ }
+ } else {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 3 : 4);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getEntities()->drawSequenceLeft(kEntityAnna, (char *)&params->seq);
+ break;
+
+ case kActionDrawScene:
+ if (params->param6 || params->param5) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param5 = 0;
+ params->param6 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ setCallback(2);
+ setup_playSound("MAX1120");
+ break;
+ }
+ // Fallback to next case
+
+ case 2:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 3:
+ case 4:
+ setCallback(5);
+ setup_playSound("ANN1016");
+ break;
+
+ case 5:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param5 = 1;
+ break;
+
+ case 6:
+ case 7:
+ case 8:
+ params->param5 = 0;
+ params->param6 = 1;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Anna, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityAnna, kAction291662081, 0);
+ getSavePoints()->addData(kEntityAnna, kAction238936000, 1);
+
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(17, Anna, function17, uint32, uint32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ getData()->inventoryItem = (params->param3 && getEntities()->isDistanceBetweenEntities(kEntityAnna, kEntityPlayer, 2000)) ? (InventoryItem)LOW_BYTE(params->param3) : kItemNone;
+
+ if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ getData()->inventoryItem = kItemNone;
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kAction1:
+ if (savepoint.param.intValue == 8) {
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem & kItemToggleLow);
+ params->param3 &= 0xFFFFFFF7;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaGiveScarf);
+ } else {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventGotALight);
+ }
+ break;
+
+ case kActionExcuseMeCath:
+ if (getEvent(kEventAugustPresentAnna) || getEvent(kEventAugustPresentAnnaFirstIntroduction) || getProgress().chapter >= kChapter2)
+ getSound()->playSound(kEntityPlayer, "CAT1001");
+ else
+ getSound()->excuseMeCath();
+ break;
+
+ case kActionExcuseMe:
+ getSound()->excuseMe(kEntityAnna);
+ break;
+
+ case kActionDefault:
+ if (getProgress().jacket == kJacketGreen) {
+ if (!getEvent(kEventGotALight) && !getEvent(kEventGotALightD) && !getEvent(kEventAugustPresentAnna) && !getEvent(kEventAugustPresentAnnaFirstIntroduction))
+ params->param3 = kItemInvalid;
+
+ if (!params->param3 && !getEvent(kEventAnnaGiveScarfAsk) && !getEvent(kEventAnnaGiveScarfDinerAsk) && !getEvent(kEventAnnaGiveScarfSalonAsk))
+ params->param3 |= 8;
+ }
+
+ if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEvent(kEventAnnaGiveScarf)
+ || getEvent(kEventAnnaGiveScarfDiner)
+ || getEvent(kEventAnnaGiveScarfSalon)
+ || getEvent(kEventAnnaGiveScarfMonogram)
+ || getEvent(kEventAnnaGiveScarfDinerMonogram)
+ || getEvent(kEventAnnaGiveScarfSalonMonogram))
+ getAction()->playAnimation(kEventAnnaGiveScarfAsk);
+ else if (getEvent(kEventAugustPresentAnna)
+ || getEvent(kEventAugustPresentAnnaFirstIntroduction))
+ getAction()->playAnimation(kEventAnnaGiveScarfMonogram);
+ else
+ getAction()->playAnimation(kEventAnnaGiveScarf);
+
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ break;
+
+ case 2:
+ getAction()->playAnimation(getData()->direction == kDirectionUp ? kEventGotALightD : kEventGotALight);
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem & kItemToggleHigh);
+ params->param3 &= 0xFFFFFF7F;
+
+ if (getProgress().jacket == kJacketGreen && !getEvent(kEventAnnaGiveScarfAsk) && !getEvent(kEventAnnaGiveScarfDinerAsk) && !getEvent(kEventAnnaGiveScarfSalonAsk))
+ params->param3 |= 8;
+
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(18, Anna, function18, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 && params->param1 < getState()->time && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->inventoryItem = kItemNone;
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param5 && !params->param4) {
+ UPDATE_PARAM_PROC(params->param6, getState()->time, 900)
+ params->param2 |= kItemScarf;
+ params->param5 = 0;
+ params->param6 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param3) {
+ UPDATE_PARAM(params->param7, getState()->timeTicks, 90);
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
+ } else {
+ params->param7 = 0;
+ }
+ break;
+
+ case kAction1:
+ setCallback(savepoint.param.intValue == 8 ? 1 : 2);
+ setup_savegame(kSavegameTypeEvent, savepoint.param.intValue == 8 ? kEventAnnaGiveScarf : kEventDinerMindJoin);
+ break;
+
+ case kActionDefault:
+ if (getProgress().jacket == kJacketGreen) {
+ if (!getEvent(kEventDinerMindJoin) && !getEvent(kEventAugustPresentAnna) && !getEvent(kEventAugustPresentAnnaFirstIntroduction))
+ params->param2 |= kItemInvalid;
+
+ if (!params->param2 && !getEvent(kEventAnnaGiveScarfAsk) && !getEvent(kEventAnnaGiveScarfDinerAsk) && !getEvent(kEventAnnaGiveScarfSalonAsk))
+ params->param2 |= 8;
+ }
+
+ getData()->inventoryItem = (InventoryItem)LOW_BYTE(params->param2);
+ break;
+
+ case kActionDrawScene:
+ params->param3 = getEntities()->isPlayerPosition(kCarRestaurant, 62);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEvent(kEventAnnaGiveScarf) || getEvent(kEventAnnaGiveScarfDiner) || getEvent(kEventAnnaGiveScarfSalon)
+ || getEvent(kEventAnnaGiveScarfMonogram) || getEvent(kEventAnnaGiveScarfDinerMonogram) || getEvent(kEventAnnaGiveScarfSalonMonogram)) {
+ getAction()->playAnimation(kEventAnnaGiveScarfDinerAsk);
+ } else {
+ getAction()->playAnimation((getEvent(kEventAugustPresentAnna) || getEvent(kEventAugustPresentAnnaFirstIntroduction)) ? kEventAnnaGiveScarfDinerMonogram : kEventAnnaGiveScarfDiner);
+ params->param5 = 1;
+ }
+
+ params->param2 &= 0xFFFFFFF7;
+ getData()->inventoryItem = (InventoryItem)params->param2;
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventDinerMindJoin);
+
+ params->param2 &= 0xFFFFFFF7;
+
+ if (getProgress().jacket == kJacketGreen
+ && !getEvent(kEventAnnaGiveScarfAsk)
+ && !getEvent(kEventAnnaGiveScarfDinerAsk)
+ && !getEvent(kEventAnnaGiveScarfSalonAsk)) {
+ params->param2 |= 8;
+ }
+
+ getData()->inventoryItem = (InventoryItem)LOW_BYTE(params->param2);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
+ break;
+ }
+ break;
+
+ case kAction168046720:
+ getData()->inventoryItem = kItemNone;
+ params->param4 = 1;
+ break;
+
+ case kAction168627977:
+ getData()->inventoryItem = (InventoryItem)LOW_BYTE(params->param2);
+ params->param4 = 0;
+ break;
+
+ case kAction170016384:
+ case kAction259136835:
+ case kAction268773672:
+ getData()->inventoryItem = kItemNone;
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Anna, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("618Ca", kObjectCompartment1);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_8514;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment("618Af", kObjectCompartmentF);
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityAnna);
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function20();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Anna, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function15(kTime1093500, "NONE");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("618Bf", kObjectCompartmentF);
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction71277948);
+ setup_function21();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Anna, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function17(kCarRestaurant, kPosition_850);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_draw("801US");
+ break;
+
+ case 3:
+ getEntities()->drawSequenceRight(kEntityAnna, "001B");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAnna);
+
+ setCallback(4);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 4:
+ setup_function22();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Anna, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAnna, "001A");
+ getSavePoints()->push(kEntityAnna, kEntityPascale, kAction223262556);
+ break;
+
+ case kAction157370960:
+ getData()->location = kLocationInsideCompartment;
+ setup_function23();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Anna, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAnna, "001D");
+ getSavePoints()->push(kEntityAnna, kEntityServers0, kAction270410280);
+ getSavePoints()->push(kEntityAnna, kEntityTables0, kAction136455232);
+
+ setCallback(1);
+ setup_function18(kTimeNone);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityAnna, "001E");
+ setCallback(2);
+ setup_playSound("ANN1048");
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_draw("001F");
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityAnna, kEntityServers0, kAction203859488);
+ setup_function24();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Anna, function24)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAnna, "001G");
+
+ setCallback(1);
+ setup_function18(kTimeNone);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityAnna, "001H");
+ setCallback(2);
+ setup_playSound("ANN1049");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityAnna, kEntityServers0, kAction136702400);
+ setup_function25();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Anna, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAnna, "001J");
+ getProgress().field_28 = 1;
+
+ setCallback(1);
+ setup_function18(kTimeNone);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 2:
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ setup_function26();
+ break;
+ }
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAnna, "BLANK");
+ break;
+
+ case kAction201437056:
+ getEntities()->drawSequenceLeft(kEntityAnna, "001J");
+ setCallback(2);
+ setup_function18(kTime1138500);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Anna, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->updatePositionExit(kEntityAnna, kCarRestaurant, 62);
+
+ setCallback(1);
+ setup_callSavepoint("001L", kEntityTables0, kActionDrawTablesWithChairs, "001H");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->updatePositionExit(kEntityAnna, kCarRestaurant, 62);
+ getSavePoints()->push(kEntityAnna, kEntityServers0, kAction237485916);
+ getEntities()->drawSequenceRight(kEntityAnna, "801DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAnna);
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function17(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment("618Af", kObjectCompartmentF);
+ break;
+
+ case 4:
+ getEntities()->clearSequences(kEntityAnna);
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function27();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Anna, function27)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction101687594);
+ setCallback(1);
+ setup_function15(kTime1156500, "NONE");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ if (getProgress().field_14 == 29) {
+ params->param1 = (uint)(getState()->time + 900);
+ setCallback(2);
+ setup_function15((TimeValue)params->param1, "NONE");
+ } else {
+ setCallback(3);
+ setup_enterExitCompartment("618Bf", kObjectCompartmentF);
+ }
+ break;
+
+ case 3:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction71277948);
+ setup_function28();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Anna, function28)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function17(kCarRestaurant, kPosition_850);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+ getData()->entityPosition = kPosition_1540;
+ getScenes()->loadSceneFromItemPosition(kItem3);
+
+ setCallback(3);
+ setup_updatePosition("104A", kCarRestaurant, 56);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ setup_function29();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Anna, function29)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2) {
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 900)
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem | kItemScarf);
+ params->param2 = 0;
+ params->param3 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param4, getState()->timeTicks, 90);
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+ } else {
+ params->param4 = 0;
+ }
+ break;
+
+ case kAction1:
+ setCallback(savepoint.param.intValue == 8 ? 1 : 2);
+ setup_savegame(kSavegameTypeEvent, savepoint.param.intValue == 8 ? kEventAnnaGiveScarf : kEventAnnaIntroductionRejected);
+ break;
+
+ case kActionDefault:
+ getData()->inventoryItem = kItemNone;
+
+ if (getProgress().jacket == kJacketGreen
+ && !getEvent(kEventAnnaConversationGoodNight)
+ && !getEvent(kEventAnnaIntroductionRejected))
+ getData()->inventoryItem = kItemInvalid;
+
+ if (getProgress().jacket == kJacketGreen
+ && getData()->inventoryItem == kItemNone
+ && !getEvent(kEventAnnaGiveScarfAsk)
+ && !getEvent(kEventAnnaGiveScarfDinerAsk)
+ && !getEvent(kEventAnnaGiveScarfSalonAsk))
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem | kItemScarf);
+
+ getEntities()->drawSequenceLeft(kEntityAnna, "104B");
+ break;
+
+ case kActionDrawScene:
+ params->param1 = getEntities()->isPlayerPosition(kCarRestaurant, 56);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEvent(kEventAnnaGiveScarf)
+ || getEvent(kEventAnnaGiveScarfDiner)
+ || getEvent(kEventAnnaGiveScarfSalon)
+ || getEvent(kEventAnnaGiveScarfMonogram)
+ || getEvent(kEventAnnaGiveScarfDinerMonogram)
+ || getEvent(kEventAnnaGiveScarfSalonMonogram)) {
+ getAction()->playAnimation(kEventAnnaGiveScarfSalonAsk);
+ } else {
+ getAction()->playAnimation((getEvent(kEventAugustPresentAnna) || getEvent(kEventAugustPresentAnnaFirstIntroduction)) ? kEventAnnaGiveScarfSalonMonogram : kEventAnnaGiveScarfSalon);
+ params->param2 = 1;
+ }
+
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem & kItemToggleLow);
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 51);
+ break;
+
+ case 2:
+ getAction()->playAnimation((getEvent(kEventAugustPresentAnna) || getEvent(kEventAugustPresentAnnaFirstIntroduction)) ? kEventAnnaConversationGoodNight : kEventAnnaIntroductionRejected);
+
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem & kItemToggleLow);
+
+ if (getProgress().jacket == kJacketGreen
+ && !getEvent(kEventAnnaGiveScarfAsk)
+ && !getEvent(kEventAnnaGiveScarfDinerAsk)
+ && !getEvent(kEventAnnaGiveScarfSalonAsk))
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem | kItemScarf);
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 51);
+ break;
+ }
+ break;
+
+ case kAction123712592:
+ getData()->inventoryItem = kItemNone;
+ setup_function30();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Anna, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param3 != kTimeInvalid && getState()->time) {
+ if (getState()->time > kTime1188000) {
+ params->param3 = kTimeInvalid;
+ getSound()->playSound(kEntityAnna, "AUG1004");
+ } else {
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param3)
+ params->param3 = (uint)(getState()->time + 450);
+
+ if (params->param3 < getState()->time) {
+ params->param3 = kTimeInvalid;
+ getSound()->playSound(kEntityAnna, "AUG1004");
+ }
+ }
+ }
+
+ if (params->param2 && params->param4 != kTimeInvalid && getState()->time > kTime1179000) {
+
+ if (getState()->time > kTime1192500) {
+ params->param4 = kTimeInvalid;
+ setup_function30();
+ break;
+ }
+
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param4)
+ params->param4 = (uint)(getState()->time + 150);
+
+ if (params->param4 < getState()->time) {
+ params->param4 = kTimeInvalid;
+ setup_function30();
+ break;
+ }
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 90);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+ } else {
+ params->param5 = 0;
+ }
+ break;
+
+ case kActionEndSound:
+ params->param2 = 1;
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAnna, kEntityAugust, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityAnna, "106B");
+ break;
+
+ case kActionDrawScene:
+ params->param1 = getEntities()->isPlayerPosition(kCarRestaurant, 56);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Anna, function31)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getSound()->playSound(kEntityAnna, "AUG1005");
+
+ setCallback(2);
+ setup_updateFromTicks(150);
+ break;
+
+ case 2:
+ getEntities()->updatePositionEnter(kEntityAnna, kCarRestaurant, 56);
+
+ setCallback(3);
+ setup_draw2("106C1", "106C2", kEntityAugust);
+ break;
+
+ case 3:
+ getEntities()->updatePositionExit(kEntityAnna, kCarRestaurant, 56);
+ getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
+ getSavePoints()->push(kEntityAnna, kEntityAugust, kAction159332865);
+
+ setup_function32();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Anna, function32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function17(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("618Af", kObjectCompartmentF);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityAnna);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function33();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Anna, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction101687594);
+
+ params->param1 = (uint)(getState()->time + 4500);
+ setCallback(1);
+ setup_function15((TimeValue)params->param1, "NONE");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getObjects()->updateLocation2(kObjectCompartmentF, kObjectLocation1);
+ setup_function34();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Anna, function34)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1 && getEntities()->isPlayerPosition(kCarRedSleeping, 60)) {
+ UPDATE_PARAM_PROC(params->param2, getState()->time, 150)
+ setCallback(1);
+ setup_draw("419B");
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+label_callback_1:
+ TIME_CHECK(kTime1489500, params->param3, setup_function35);
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 2 : 3);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 78))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->drawSequenceLeft(kEntityAnna, "419A");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityAnna, "419C");
+ params->param1 = 1;
+ goto label_callback_1;
+
+ case 2:
+ case 3:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ setCallback(4);
+ setup_playSound("MAX1120");
+ break;
+ }
+ // Fallback to next case
+
+ case 4:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Anna, function35)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1)
+ break;
+
+ UPDATE_PARAM(params->param3, getState()->timeTicks, 75);
+
+ switch (params->param2) {
+ default:
+ break;
+
+ case 0:
+ getSound()->playSound(kEntityAnna, "ANN2135E");
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityAnna, "ANN2135F");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityAnna, "ANN2135G");
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityAnna, "ANN2135D");
+ break;
+ }
+
+ params->param1 = 0;
+ params->param3 = 0;
+ break;
+
+ case kActionEndSound:
+ ++params->param2;
+
+ if (params->param2 > 3)
+ params->param2 = 0;
+
+ params->param1 = 1;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (getSound()->isBuffered(kEntityAnna))
+ getSound()->processEntry(kEntityAnna);
+
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaVisitToCompartmentGun);
+ break;
+
+ case kActionDefault:
+ getData()->clothes = kClothes1;
+ params->param1 = 1;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventAnnaVisitToCompartmentGun);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getData()->location = kLocationOutsideCompartment;
+ getData()->entityPosition = kPosition_4840;
+
+ getEntities()->updateEntity(kEntityAnna, kCarRedSleeping, kPosition_8200);
+ getScenes()->loadSceneFromObject(kObjectCompartmentF, true);
+ getSavePoints()->push(kEntityAnna, kEntityVassili, kAction339669520);
+ getSavePoints()->push(kEntityAnna, kEntityVerges, kAction339669520);
+ getSavePoints()->push(kEntityAnna, kEntityCoudert, kAction339669520);
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction71277948);
+
+ setup_function36();
+ break;
+
+ case 2:
+ setup_function36();
+ break;
+ }
+ break;
+
+ case kAction226031488:
+ if (getSound()->isBuffered(kEntityAnna))
+ getSound()->processEntry(kEntityAnna);
+
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction71277948);
+ break;
+
+ case kAction238358920:
+ setCallback(2);
+ setup_enterExitCompartment("608Cf", kObjectCompartmentF);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Anna, function36)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_8200);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(2);
+ setup_enterExitCompartment("608Aa", kObjectCompartmentA);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityAnna);
+
+ setup_function37();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Anna, function37)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+ break;
+
+ case kAction191477936:
+ setup_function38();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Anna, function38)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_7500;
+
+ setCallback(1);
+ setup_playSound("ANN1010");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getSound()->playSound(kEntityPlayer, "MUS043");
+ setup_function40();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(39, Anna, function39, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ getData()->inventoryItem = kItemNone;
+
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kAction1:
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaGoodNight);
+ break;
+
+ case kActionExcuseMe:
+ getSound()->playSound(kEntityAnna, "ANN1107A");
+ break;
+
+ case kActionDefault:
+ getData()->inventoryItem = kItemNone;
+ if (!getEvent(kEventAnnaGoodNight) && !getEvent(kEventAnnaGoodNightInverse))
+ getData()->inventoryItem = kItemInvalid;
+
+ if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ getData()->inventoryItem = kItemNone;
+
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(getData()->direction == kDirectionNone ? kEventAnnaGoodNight : kEventAnnaGoodNightInverse);
+ getData()->inventoryItem = kItemNone;
+
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(40, Anna, function40)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("608Cb", kObjectCompartmentB);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_function39(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment("608Bf", kObjectCompartmentF);
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityAnna);
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(4);
+ setup_updateFromTime(150);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("608Cf", kObjectCompartmentF);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(6);
+ setup_function39(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_enterExitCompartment("608Bb", kObjectCompartmentB);
+ break;
+
+ case 7:
+ getEntities()->clearSequences(kEntityAnna);
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(8);
+ setup_updateFromTime(150);
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_enterExitCompartment("608Cb", kObjectCompartmentB);
+ break;
+
+ case 9:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(10);
+ setup_function39(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_enterExitCompartment("608Bf", kObjectCompartmentF);
+ break;
+
+ case 11:
+ getEntities()->clearSequences(kEntityAnna);
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_4070;
+
+ setup_function41();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(41, Anna, function41)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param2, getState()->time, 2700);
+
+ params->param5++;
+ switch (params->param5) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityAnna, "419A");
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityAnna, "419B");
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityAnna, "419C");
+ params->param1 = 0;
+ break;
+ }
+
+ params->param2 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction101687594);
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getEntities()->drawSequenceLeft(kEntityAnna, "419C");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ setCallback(3);
+ setup_playSound("MAX1120");
+ break;
+ }
+ // Fallback to next case
+
+ case 3:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(42, Anna, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAnna);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothes1;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(43, Anna, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(1);
+ setup_function12();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function15(kTime1786500, "418C");
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function12();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function15(kTime1818000, "418C");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function12();
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function15(kTimeEnd, "418C");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(44, Anna, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAnna);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothes3;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(45, Anna, function45, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_enterExitCompartment("625Bf", kObjectCompartmentF);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAnna, kEntityCoudert, params->param1 ? kAction185737168 : kAction185671840);
+ getSound()->playSound(kEntityAnna, "Ann3147");
+ getEntities()->drawSequenceLeft(kEntityAnna, "625EF");
+ getEntities()->enterCompartment(kEntityAnna, kObjectCompartmentF, true);
+ break;
+
+ case 2:
+ getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF, true);
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction157894320:
+ setCallback(2);
+ setup_updateFromTime(75);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(46, Anna, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 60))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+
+ setCallback(1);
+ setup_function12();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1 || getCallback() == 2) {
+ if (ENTITY_PARAM(0, 1)) {
+ setup_function47();
+ } else {
+ setCallback(2);
+ setup_function15((TimeValue)(getState()->time + 4500), "418C");
+ }
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(47, Anna, function47)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(1);
+ setup_enterExitCompartment("688Bf", kObjectCompartmentF);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction71277948);
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("801VS");
+ break;
+
+ case 4:
+ getSound()->playSound(kEntityAnna, getEvent(kEventAugustLunch) ? "Ann3136" : "Ann3136A", SoundManager::kFlagInvalid, 30);
+ getSavePoints()->push(kEntityAnna, kEntityAugust, kAction122358304);
+
+ setCallback(5);
+ setup_draw2("026B1", "026B2", kEntityAugust);
+ break;
+
+ case 5:
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+ setup_function48();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(48, Anna, function48)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1)
+ break;
+
+ if (params->param3 != kTimeInvalid && getState()->time > kTime1969200) {
+ UPDATE_PARAM_PROC_TIME(kTime1983600, (!getEntities()->isInRestaurant(kEntityPlayer) || getSound()->isBuffered(kEntityBoutarel)), params->param3, 150)
+ setCallback(3);
+ setup_playSound("Aug3007A");
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+label_callback_4:
+ if (ENTITY_PARAM(0, 2)) {
+ if (!params->param2)
+ params->param2 = (uint)(getState()->time + 4500);
+
+ if (params->param4 != kTimeInvalid) {
+ if (params->param2 >= getState()->time) {
+ if (!getEntities()->isInRestaurant(kEntityPlayer) || !params->param4)
+ params->param4 = (uint)(getState()->time + 450);
+
+ if (params->param4 >= getState()->time)
+ break;
+ }
+
+ params->param4 = kTimeInvalid;
+
+ setup_function50();
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAnna, "026C");
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(1);
+ setup_updateFromTime(450);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_playSound("Ann3137B");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityAnna, kEntityServers0, kAction218983616);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_playSound("Aug3006A");
+ break;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ setCallback(6);
+ setup_updateFromTime(900);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_playSound("Aug3006");
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_updateFromTime(2700);
+ break;
+
+ case 8:
+ getEntities()->drawSequenceLeft(kEntityAnna, "026H");
+ params->param1 = 1;
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityAnna, "026C");
+
+ setCallback(5);
+ setup_playSound("Ann3138A");
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAnna, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(49, Anna, leaveTableWithAugust)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getSavePoints()->push(kEntityAnna, kEntityTables3, kActionDrawTablesWithChairs, "010M");
+ getEntities()->clearSequences(kEntityAugust);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityTables3, "026J3");
+ getEntities()->drawSequenceRight(kEntityAugust, "026J2");
+ getEntities()->drawSequenceRight(kEntityAnna, "026J1");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(50, Anna, function50)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_playSound("ann3141");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+ setCallback(3);
+ setup_leaveTableWithAugust();
+ break;
+
+ case 3:
+ setup_function51();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(51, Anna, function51)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getSound()->playSound(kEntityAnna, "Aug3008");
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_draw2("112E1", "112E2", kEntityAugust);
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityAnna, "Aug3142", SoundManager::kFlagInvalid, 30);
+ getEntities()->updatePositionEnter(kEntityAnna, kCarRestaurant, 57);
+ getEntities()->drawSequenceRight(kEntityAnna, "112A");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAnna);
+
+ setCallback(1);
+ setup_callbackActionOnDirection();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAnna, "112B");
+ getEntities()->updatePositionExit(kEntityAnna, kCarRestaurant, 57);
+ getSavePoints()->push(kEntityAnna, kEntityServers1, kAction219377792);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityAnna, kEntityAugust, kAction122288808);
+
+ setup_function52();
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityAnna, "112D");
+
+ if (getState()->time >= kTimeEnterAttnangPuchheim) {
+ params->param1 = 1;
+ } else {
+ setCallback(4);
+ setup_playSound("Ann3142A");
+ }
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_updateFromTime(1800);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_playSound("Aug3007");
+ break;
+
+ case 6:
+ params->param1 = 1;
+ break;
+ }
+ break;
+
+ case kAction101169422:
+ if (getEvent(kEventKronosVisit)) {
+ setCallback(3);
+ setup_updatePosition("112J", kCarRestaurant, 57);
+ break;
+ }
+
+ if (getState()->time >= kTimeEnterAttnangPuchheim) {
+ params->param1 = 1;
+ } else {
+ setCallback(4);
+ setup_playSound("Ann3142A");
+ }
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityAnna, "112D");
+ getSavePoints()->push(kEntityAnna, kEntityKronos, kAction157159392);
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAnna, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(52, Anna, function52)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF);
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->clearSequences(kEntityAnna);
+
+ setup_function53();
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->drawSequenceRight(kEntityAnna, "688Af");
+ getEntities()->enterCompartment(kEntityAnna, kObjectCompartmentF);
+ getData()->location = kLocationInsideCompartment;
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_4070) || getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_4455)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(kObjectCompartmentF);
+ }
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(53, Anna, function53)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().field_48 && params->param5 != kTimeInvalid) {
+ UPDATE_PARAM_PROC_TIME(kTime2065500, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param5, 150)
+ setup_function54();
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param3) {
+ UPDATE_PARAM_PROC(params->param6, getState()->time, 9000)
+ params->param4 = !params->param4;
+ getEntities()->drawSequenceLeft(kEntityAnna, params->param4 ? "417B" : "417A");
+ params->param6 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param7, getState()->timeTicks, 75);
+
+ CursorStyle cursor = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal;
+
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, cursor);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, cursor);
+
+ params->param1 = 0;
+ params->param2 = 1;
+ }
+
+ params->param7 = 0;
+ break;
+
+ case kActionOpenDoor:
+ if (getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070)) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_playSound("LIB013");
+ break;
+ }
+ // Fallback to next case
+
+ case kActionKnock:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param1) {
+ if (savepoint.param.intValue == 53) {
+ setCallback(6);
+ setup_playSound(getSound()->justAMinuteCath());
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(7);
+ setup_playSound(rnd(2) ? getSound()->wrongDoorCath() : (rnd(2) ? "CAT1506" : "CAT1506A"));
+ break;
+ }
+
+ setCallback(8);
+ setup_playSound(getSound()->wrongDoorCath());
+ break;
+ }
+
+ setCallback(savepoint.action == kActionKnock ? 3 : 4);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction101687594);
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->clothes = kClothes2;
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param1 = 0;
+ params->param2 = 0;
+ }
+
+ if (!params->param3 && (getEntities()->isPlayerPosition(kCarRedSleeping, 60) || getState()->time > kTime2034000)) {
+ params->param3 = 1;
+
+ setCallback(9);
+ setup_draw("416");
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ setCallback(2);
+ setup_playSound("MAX1120");
+ break;
+ }
+ // Fallback to next case
+
+ case 2:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 3:
+ case 4:
+ setCallback(5);
+ setup_playSound("ANN1016");
+ break;
+
+ case 5:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param1 = 1;
+ break;
+
+ case 6:
+ case 7:
+ case 8:
+ if (getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070)) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorHand);
+ }
+
+ params->param1 = 0;
+ params->param2 = 1;
+ break;
+
+ case 9:
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 60))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 78);
+ getEntities()->drawSequenceLeft(kEntityAnna, "417B");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(54, Anna, function54)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param3) {
+ TIME_CHECK(kTime2079000, params->param5, setup_function55);
+
+ UPDATE_PARAM_PROC(params->param6, getState()->time, 9000)
+ params->param4 = !params->param4;
+ getEntities()->drawSequenceLeft(kEntityAnna, params->param4 ? "417B" : "417A");
+ params->param6 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param7, getState()->timeTicks, 75);
+
+ CursorStyle cursor = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal;
+
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, cursor);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, cursor);
+
+ params->param1 = 0;
+ params->param2 = 1;
+ }
+
+ params->param7 = 0;
+ break;
+
+ case kActionOpenDoor:
+ if (getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070)) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_playSound("LIB013");
+ break;
+ }
+ // Fallback to next case
+
+ case kActionKnock:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param1) {
+ if (savepoint.param.intValue == 53) {
+ setCallback(6);
+ setup_playSound(getSound()->justAMinuteCath());
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(7);
+ setup_playSound(rnd(2) ? getSound()->wrongDoorCath() : (rnd(2) ? "CAT1506" : "CAT1506A"));
+ break;
+ }
+
+ setCallback(8);
+ setup_playSound(getSound()->wrongDoorCath());
+ break;
+ }
+
+ setCallback(savepoint.action == kActionKnock ? 3 : 4);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 60))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 78);
+
+ getSavePoints()->push(kEntityAnna, kEntityCoudert, kAction189750912);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param1 = 0;
+ params->param2 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ setCallback(2);
+ setup_playSound("MAX1120");
+ break;
+ }
+ // Fallback to next case
+
+ case 2:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 3:
+ case 4:
+ setCallback(5);
+ setup_playSound("ANN1016");
+ break;
+
+ case 5:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param1 = 1;
+ break;
+
+ case 6:
+ case 7:
+ case 8:
+ if (getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070)) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorHand);
+ }
+
+ params->param1 = 0;
+ params->param2 = 1;
+ break;
+
+ case 9:
+ getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF, true);
+ getEntities()->clearSequences(kEntityAnna);
+
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_4070;
+ params->param3 = 1;
+
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 78))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+ getEntities()->drawSequenceLeft(kEntityAnna, "417B");
+ break;
+ }
+ break;
+
+ case kAction123733488:
+ setCallback(9);
+ setup_enterExitCompartment("629Ef", kObjectCompartmentF);
+ break;
+
+ case kAction156049968:
+ getEntities()->drawSequenceLeft(kEntityAnna, "629DF");
+ getEntities()->enterCompartment(kEntityAnna, kObjectCompartmentF, true);
+ break;
+
+ case kAction253868128:
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(55, Anna, function55)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 78))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getInventory()->setLocationAndProcess(kItemKey, kObjectLocation1);
+
+ setCallback(1);
+ setup_function45(true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_9270);
+ break;
+
+ case 2:
+ setup_function56();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(56, Anna, function56)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAnna);
+ getData()->entityPosition = kPosition_6000;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarKronos;
+ break;
+
+ case kAction191668032:
+ setup_function57();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(57, Anna, function57)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_850;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_5790);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAnna, kEntityAugust, kAction191668032);
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getSavePoints()->push(kEntityAnna, kEntityCoudert, kAction205033696);
+ getEntities()->drawSequenceLeft(kEntityAnna, "625Ef");
+ getEntities()->enterCompartment(kEntityAnna, kObjectCompartmentF, true);
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityAnna, "625Gf");
+ getEntities()->enterCompartment(kEntityAnna, kObjectCompartmentF, true);
+ getSavePoints()->push(kEntityAnna, kEntityAugust, kAction169032608);
+ break;
+
+ case 4:
+ if (getSound()->isBuffered(kEntityAugust)) {
+ setCallback(4);
+ setup_updateFromTime(75);
+ } else {
+ setCallback(5);
+ setup_playSound("Aug3009");
+ }
+ break;
+
+ case 5:
+ getSound()->playSound(kEntityAnna, "Aug3009A");
+
+ setCallback(6);
+ setup_enterExitCompartment("628Bf", kObjectCompartmentF);
+ break;
+
+ case 6:
+ getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF, true);
+ getSavePoints()->push(kEntityAnna, kEntityAugust, kAction122288808);
+
+ setup_function59();
+ break;
+ }
+ break;
+
+ case kAction123712592:
+ getEntities()->drawSequenceLeft(kEntityAnna, "628Af");
+
+ if (getSound()->isBuffered(kEntityAugust)) {
+ setCallback(4);
+ setup_updateFromTime(75);
+ } else {
+ setCallback(5);
+ setup_playSound("Aug3009");
+ }
+ break;
+
+ case kAction192063264:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_4070)
+ || getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_4455)) {
+ getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF, true);
+ setup_function58();
+ } else {
+ setCallback(3);
+ setup_enterExitCompartment("625Ff", kObjectCompartmentF);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(58, Anna, function58)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaSearchingCompartment);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventAnnaSearchingCompartment);
+ getEntities()->clearSequences(kEntityAnna);
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 8);
+ getSound()->playSound(kEntityAnna, "lib015");
+ getSavePoints()->push(kEntityAnna, kEntityAugust, kAction122288808);
+ setup_function59();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(59, Anna, function59)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getInventory()->hasItem(kItemKey) && params->param4 != kTimeInvalid && getState()->time > kTime2218500) {
+ if (getState()->time > kTime2248200) {
+ params->param4 = kTimeInvalid;
+ setup_function61();
+ break;
+ }
+
+ if (!params->param3
+ || (!getEntities()->isPlayerInCar(kCarRedSleeping)
+ && !getEntities()->isInSalon(kEntityPlayer)
+ && !getEntities()->isInRestaurant(kEntityPlayer))
+ || !params->param4)
+ params->param4 = (uint)getState()->time;
+
+ if (params->param4 < getState()->time) {
+ params->param4 = kTimeInvalid;
+ setup_function61();
+ break;
+ }
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+
+ CursorStyle style = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal;
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, style);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, style);
+
+ params->param1= 0;
+ params->param2 = 1;
+ }
+
+ params->param5 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param1) {
+ if (savepoint.param.intValue == 53) {
+ setCallback(4);
+ setup_playSound(getSound()->justAMinuteCath());
+ } else if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(5);
+ setup_playSound(rnd(2) ? getSound()->wrongDoorCath() : (rnd(2) ? "CAT1506" : "CAT1506A"));
+ } else {
+ setCallback(6);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityAnna);
+
+ getObjects()->update(kObject107, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 60))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 78);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ params->param1 = 0;
+ params->param2 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound("ANN1016");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param1 = 1;
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ params->param1 = 0;
+ params->param2 = 1;
+ break;
+
+ case 7:
+ getSavePoints()->push(kEntityAnna, kEntityTatiana, kAction100906246);
+ break;
+ }
+ break;
+
+ case kAction156622016:
+ if (params->param3) {
+ setCallback(8);
+ setup_function60();
+ }
+ break;
+
+ case kAction236241630:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(7);
+ setup_playSound("Ann1016A");
+ break;
+
+ case kAction236517970:
+ params->param3 = 1;
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(60, Anna, function60)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAnna, kEntityMax, kAction122358304);
+ getSound()->playSound(kEntityAnna, rnd(2) ? "Ann3126" : "Ann3127");
+
+ setCallback(1);
+ setup_enterExitCompartment("630Cf", kObjectCompartmentF);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("630Df", kObjectCompartmentF);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityAnna);
+ getSavePoints()->push(kEntityAnna, kEntityCoudert, kAction189026624);
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityAnna);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction156049968:
+ setCallback(3);
+ setup_enterExitCompartment("629EF", kObjectCompartmentF);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(61, Anna, function61)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getState()->timeDelta = 3;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeIndex, 0);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_function45(false);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_draw("802US");
+ break;
+
+ case 5:
+ getEntities()->drawSequenceRight(kEntityAnna, "802UD");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAnna);
+
+ setCallback(6);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 6:
+ getEntities()->clearSequences(kEntityAnna);
+ setup_function62();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(62, Anna, function62)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2259000 && !params->param2) {
+ params->param2 = 1;
+ getSavePoints()->push(kEntityAnna, kEntityVesna, kAction189299008);
+ setup_function63();
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarBaggage;
+ getProgress().field_54 = 1;
+ break;
+
+ case kAction235856512:
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(63, Anna, function63)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAnna, kEntityChapters, kAction171843264);
+ break;
+
+ // Game over with Anna killed!
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventAnnaKilled);
+ getLogic()->gameOver(kSavegameTypeTime, kTime2250000, kSceneGameOverAnnaDied, true);
+ }
+ break;
+
+ // Anna will get killed...
+ case kAction272177921:
+ if (getSound()->isBuffered("MUS012"))
+ getSound()->processEntry("MUS012");
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaKilled);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(64, Anna, baggage)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAnna);
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaBaggageArgument);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventAnnaBaggageArgument);
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeTime, (EventIndex)kTimeNone);
+ break;
+
+ case 2:
+ params->param1 = getFight()->setup(kFightAnna);
+
+ if (params->param1)
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, params->param1 == Fight::kFightEndLost);
+ else {
+ getState()->time = (TimeValue)(getState()->time + 1800);
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaBagagePart2);
+ }
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventAnnaBagagePart2);
+ getScenes()->loadSceneFromPosition(kCarBaggage, 96);
+
+ getProgress().field_54 = 0;
+ getState()->time = kTime2266200;
+
+ setup_function65();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(65, Anna, function65)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothes3;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(1);
+ setup_function15(kTimeEnd, "NONE");
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(66, Anna, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAnna);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothes2;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(67, Anna, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 46)) {
+ UPDATE_PARAM_GOTO(params->param4, getState()->timeTicks, 30, label_next);
+
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 8);
+ }
+
+ params->param4 = 0;
+
+label_next:
+ if (params->param1) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 1;
+
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal);
+ }
+
+ params->param5 = 0;
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaConversation_34);
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param1) {
+ setCallback(5);
+ setup_playSound(getSound()->justAMinuteCath());
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 2 : 3);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getEntities()->drawSequenceLeft(kEntityAnna, "511B");
+ break;
+
+ case kActionDrawScene:
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ params->param1 = 0;
+ params->param2 = 0;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventAnnaConversation_34);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 8);
+
+ setup_function68();
+ break;
+
+ case 2:
+ case 3:
+ setCallback(4);
+ setup_playSound("ANN1016");
+ break;
+
+ case 4:
+ getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param1 = 1;
+ break;
+
+ case 5:
+ params->param1 = 0;
+ params->param2 = 1;
+ break;
+ }
+ break;
+
+ case kAction191001984:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getData()->inventoryItem = kItemNone;
+
+ setup_function69();
+ break;
+
+ case kAction219971920:
+ params->param3 = 1;
+ getData()->inventoryItem = kItemInvalid;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(68, Anna, function68)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ setCallback(1);
+ setup_function15(kTime2511900, "NONE");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ break;
+
+ case kAction191001984:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ setup_function69();
+ break;
+
+ case kAction201431954:
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(69, Anna, function69)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM(params->param2, getState()->time, 4500);
+
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_9270;
+ getData()->location = kLocationOutsideCompartment;
+
+ setup_function70();
+ break;
+ }
+
+ TIME_CHECK_CALLBACK(kTime2535300, params->param3, 4, setup_callbackActionRestaurantOrSalon);
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 && getEntities()->isInsideTrainCar(kEntityPlayer, kCarRedSleeping)) {
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationOutsideCompartment;
+
+ setup_function70();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updatePosition("127A", kCarRestaurant, 56);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAnna, "127B");
+ getSavePoints()->push(kEntityAnna, kEntityServers1, kAction258136010);
+ break;
+
+ case 4:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_updatePosition("127G", kCarRestaurant, 56);
+ break;
+
+ case 5:
+ setup_function70();
+ break;
+ }
+ break;
+
+ case kAction100969180:
+ getEntities()->clearSequences(kEntityAnna);
+ params->param1 = 1;
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityAnna, "127E");
+ getSavePoints()->push(kEntityAnna, kEntityAbbot, kAction203073664);
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAnna, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(70, Anna, function70)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function72(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function71();
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->clearSequences(kEntityAnna);
+ setup_function73();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(71, Anna, function71)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF);
+ getData()->entityPosition = kPosition_4070;
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityAnna, "625Af");
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 7)
+ || getEntities()->isPlayerPosition(kCarRedSleeping, 28)
+ || getEntities()->isPlayerPosition(kCarRedSleeping, 56))
+ getScenes()->loadScene(getScenes()->processIndex(getState()->scene));
+
+ getEntities()->enterCompartment(kEntityAnna, kObjectCompartmentF);
+
+ getData()->location = kLocationInsideCompartment;
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_4070)
+ || getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_4455)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(kObjectCompartmentF, true);
+ }
+ break;
+
+ case kActionDrawScene:
+ if (!getEvent(kEventAnnaTiredKiss)
+ && getEntities()->isDistanceBetweenEntities(kEntityPlayer, kEntityAnna, 2000)
+ && getEntities()->hasValidFrame(kEntityAnna)
+ && getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaTiredKiss);
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventAnnaTiredKiss);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 29);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(72, Anna, function72, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEvent(kEventAnnaTired) || getEntities()->isWalkingOppositeToPlayer(kEntityAnna))
+ getData()->inventoryItem = kItemNone;
+ else
+ getData()->inventoryItem = kItemInvalid;
+
+ if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ getData()->inventoryItem = kItemNone;
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaTired);
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ } else if (!getEvent(kEventAnnaTired))
+ getData()->inventoryItem = kItemInvalid;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventAnnaTired);
+
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(73, Anna, function73)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param3 == kTimeInvalid || params->param1 >= getState()->time)
+ break;
+
+ if (params->param2 >= getState()->time) {
+ if (!((getEntities()->isPlayerInCar(kCarGreenSleeping) || getEntities()->isPlayerInCar(kCarRedSleeping)) && params->param3))
+ params->param3 = (uint)getState()->time;
+
+ if (params->param3 >= getState()->time)
+ break;
+ }
+
+ params->param3 = kTimeInvalid;
+
+ if (!getEntities()->isPlayerInCar(kCarGreenSleeping) && !getEntities()->isPlayerInCar(kCarRedSleeping))
+ getSound()->playSound(kEntityPlayer, "BUMP");
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventTrainHijacked);
+ break;
+
+ case kActionKnock:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(2);
+ setup_playSound("LIB012");
+ break;
+
+ case kActionOpenDoor:
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaKissTrainHijacked);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getState()->timeDelta = 1;
+
+ params->param1 = (uint)(getState()->time + 4500);
+ params->param2 = (uint)(getState()->time + 9000);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventTrainHijacked);
+ getSavePoints()->push(kEntityAnna, kEntityChapters, kAction139254416);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_playSound("Ann4200");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventAnnaKissTrainHijacked);
+ getSavePoints()->push(kEntityAnna, kEntityChapters, kAction139254416);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(74, Anna, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAnna);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarBaggageRear;
+ getData()->clothes = kClothes3;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectOutsideAnnaCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(75, Anna, chapter5Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (getProgress().field_C)
+ getAction()->playAnimation(getEvent(kEventAnnaKissTrainHijacked) ? kEventAnnaBaggageTies2 : kEventAnnaBaggageTies);
+ else
+ getAction()->playAnimation(getEvent(kEventAnnaKissTrainHijacked) ? kEventAnnaBaggageTies3 : kEventAnnaBaggageTies4);
+
+ getScenes()->loadSceneFromPosition(kCarBaggage, 8);
+ setup_function76();
+ }
+ break;
+
+ case kAction272177921:
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaBaggageTies);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(76, Anna, function76)
+ if (savepoint.action == kAction158480160)
+ setup_function77();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(77, Anna, function77)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime3645000 && !params->param2) {
+ params->param2 = 1;
+ getState()->timeDelta = 0;
+ }
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getSound()->playSound(kEntityPlayer, savepoint.action == kActionKnock ? "LIB012" : "LIB014");
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventAnnaDialogGoToJerusalem);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObject106, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (!params->param1 && getEntities()->isInsideTrainCar(kEntityPlayer, kCarBaggage)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param1 = 1;
+ break;
+
+ case 2:
+ getObjects()->update(kObject106, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getAction()->playAnimation(kEventAnnaDialogGoToJerusalem);
+
+ getState()->time = kTimeCityConstantinople;
+ getState()->timeDelta = 0;
+
+ getSavePoints()->push(kEntityAnna, kEntityTatiana, kAction236060709);
+
+ getScenes()->loadSceneFromPosition(kCarBaggage, 97, 1);
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case 3:
+ setup_function78();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(78, Anna, function78)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDrawScene:
+ if ((getEntities()->isInRestaurant(kEntityPlayer) || getEntities()->isInSalon(kEntityPlayer)) && getInventory()->hasItem(kItemFirebird)) {
+ setup_function80();
+ break;
+ }
+
+ getState()->time = kTimeInvalid2;
+
+ setCallback(getInventory()->get(kItemFirebird)->location == kObjectLocation4 ? 2 : 1);
+ setup_savegame(kSavegameTypeEvent, getInventory()->get(kItemFirebird)->location == kObjectLocation4 ? kEventKronosHostageAnna : kEventKronosHostageAnnaNoFirebird);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventKronosHostageAnnaNoFirebird);
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventAugustUnhookCarsBetrayal, kSceneNone, true);
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventKronosHostageAnna);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
+ getSound()->playSound(kEntityAnna, "Mus024", SoundManager::kFlagDefault);
+ setup_function79();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(79, Anna, function79)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ getState()->time = kTime5933;
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaPunch);
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isInRestaurant(kEntityPlayer) && getInventory()->hasItem(kItemFirebird)) {
+ setup_function80();
+ break;
+ }
+
+ if (getEntities()->isInSalon(kEntityPlayer) && !getEvent(kEventKahinaPunch)) {
+ getState()->time = kTime5933;
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaPunch);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getAction()->playAnimation(kEventKahinaPunchSalon);
+ else if (getEntities()->isInRestaurant(kEntityPlayer))
+ getAction()->playAnimation(kEventKahinaPunchRestaurant);
+ else if (getEntities()->isInKitchen(kEntityPlayer))
+ getAction()->playAnimation(kEventKahinaPunchKitchen);
+ else if (getEntities()->isInBaggageCarEntrance(kEntityPlayer))
+ getAction()->playAnimation(kEventKahinaPunchBaggageCarEntrance);
+ else if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarBaggage))
+ getAction()->playAnimation(kEventKahinaPunchBaggageCar);
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventKahinaPunchSalon);
+ break;
+ }
+
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(80, Anna, function80)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->timeTicks, 450);
+
+ getSound()->playSound(kEntityPlayer, "Kro5001", SoundManager::kFlagDefault);
+ break;
+
+ case kActionEndSound:
+ getSound()->playSound(kEntityPlayer, "Kro5002", SoundManager::kFlagDefault);
+ getState()->time = kTime4923000;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKronosBringFirebird);
+ break;
+
+ case kActionDefault:
+ getState()->time = kTime4929300;
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaPunch);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getSound()->isBuffered(kEntityAnna))
+ getSound()->processEntry(kEntityAnna);
+
+ getAction()->playAnimation(kEventKronosBringFirebird);
+ getScenes()->loadSceneFromItem(kItemFirebird);
+ getSound()->playSound(kEntityAnna, "Mus025", SoundManager::kFlagDefault);
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventKahinaPunch);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ break;
+
+ case 3:
+ getProgress().isEggOpen = true;
+
+ if (getSound()->isBuffered(kEntityAnna))
+ getSound()->processEntry(kEntityAnna);
+
+ getAction()->playAnimation(kEventKronosOpenFirebird);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 3);
+
+ setup_finalSequence();
+ break;
+ }
+ break;
+
+ case kAction205294778:
+ getState()->time = kTime4929300;
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventKronosOpenFirebird);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(81, Anna, finalSequence)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->timeTicks, 180);
+
+ getSound()->playSound(kEntityTrain, "LIB069");
+ getLogic()->gameOver(kSavegameTypeIndex, 2, kSceneNone, true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventCathCloseEggNoBackground);
+ getAction()->playAnimation(kEventKronosGiveFirebird);
+
+ if (getInventory()->hasItem(kItemWhistle))
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverTrainExplosion, true);
+ else if (getInventory()->get(kItemWhistle)->location == kObjectLocation1)
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventAnnaDialogGoToJerusalem, kSceneNone, true);
+ else
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventAugustUnhookCarsBetrayal, kSceneGameOverTrainExplosion2, true);
+ break;
+
+ case 2:
+ getInventory()->removeItem(kItemWhistle);
+ getLogic()->playFinalSequence();
+ break;
+ }
+ break;
+
+ case kAction224309120:
+ getProgress().isEggOpen = false;
+ getState()->time = kTimeCityConstantinople;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKronosGiveFirebird);
+ break;
+
+ case kActionUseWhistle:
+ getProgress().isEggOpen = false;
+ setGlobalTimer(0);
+ getState()->time = kTimeCityConstantinople;
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventFinalSequence);
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/anna.h b/engines/lastexpress/entities/anna.h
new file mode 100644
index 0000000000..5297d6f745
--- /dev/null
+++ b/engines/lastexpress/entities/anna.h
@@ -0,0 +1,252 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ANNA_H
+#define LASTEXPRESS_ANNA_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Anna : public Entity {
+public:
+ Anna(LastExpressEngine *engine);
+ ~Anna() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence1, CarIndex car, Position position)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Call a savepoint (or draw sequence in default case)
+ *
+ * @param sequence1 The sequence to draw in the default case
+ * @param entity The entity
+ * @param action The action
+ * @param sequence2 The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_4(callSavepoint, const char *sequence1, EntityIndex entity, ActionIndex action, const char *sequence2)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ DECLARE_FUNCTION(function12)
+
+ /**
+ * Draws the entity along with another one
+ *
+ * @param sequence1 The sequence to draw
+ * @param sequence2 The sequence to draw for the second entity
+ * @param entity The EntityIndex of the second entity
+ */
+ DECLARE_FUNCTION_3(draw2, const char *sequence1, const char *sequence2, EntityIndex entity)
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param ticks The number of ticks to add
+ */
+ DECLARE_FUNCTION_1(updateFromTicks, uint32 ticks)
+
+ DECLARE_FUNCTION_2(function15, TimeValue timeValue, const char *sequence)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION_2(function17, uint32, uint32)
+
+ DECLARE_FUNCTION_1(function18, TimeValue timeValue)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(function28)
+ DECLARE_FUNCTION(function29)
+ DECLARE_FUNCTION(function30)
+ DECLARE_FUNCTION(function31)
+ DECLARE_FUNCTION(function32)
+ DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(function34)
+ DECLARE_FUNCTION(function35)
+ DECLARE_FUNCTION(function36)
+ DECLARE_FUNCTION(function37)
+ DECLARE_FUNCTION(function38)
+ DECLARE_FUNCTION_2(function39, CarIndex car, EntityPosition entityPosition)
+ DECLARE_FUNCTION(function40)
+ DECLARE_FUNCTION(function41)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+ DECLARE_FUNCTION_1(function45, bool useAction1)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+ DECLARE_FUNCTION(function47)
+ DECLARE_FUNCTION(function48)
+ DECLARE_FUNCTION(leaveTableWithAugust)
+ DECLARE_FUNCTION(function50)
+ DECLARE_FUNCTION(function51)
+ DECLARE_FUNCTION(function52)
+ DECLARE_FUNCTION(function53)
+ DECLARE_FUNCTION(function54)
+ DECLARE_FUNCTION(function55)
+ DECLARE_FUNCTION(function56)
+ DECLARE_FUNCTION(function57)
+ DECLARE_FUNCTION(function58)
+ DECLARE_FUNCTION(function59)
+ DECLARE_FUNCTION(function60)
+ DECLARE_FUNCTION(function61)
+ DECLARE_FUNCTION(function62)
+ DECLARE_FUNCTION(function63)
+ DECLARE_FUNCTION(baggage)
+ DECLARE_FUNCTION(function65)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function68)
+ DECLARE_FUNCTION(function69)
+ DECLARE_FUNCTION(function70)
+ DECLARE_FUNCTION(function71)
+ DECLARE_FUNCTION_2(function72, CarIndex car, EntityPosition entityPosition)
+ DECLARE_FUNCTION(function73)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+ DECLARE_FUNCTION(function76)
+ DECLARE_FUNCTION(function77)
+ DECLARE_FUNCTION(function78)
+ DECLARE_FUNCTION(function79)
+ DECLARE_FUNCTION(function80)
+ DECLARE_FUNCTION(finalSequence)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ANNA_H
diff --git a/engines/lastexpress/entities/august.cpp b/engines/lastexpress/entities/august.cpp
new file mode 100644
index 0000000000..e9aff248e4
--- /dev/null
+++ b/engines/lastexpress/entities/august.cpp
@@ -0,0 +1,3536 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/august.h"
+
+#include "lastexpress/entities/alexei.h"
+#include "lastexpress/entities/salko.h"
+#include "lastexpress/entities/verges.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+August::August(LastExpressEngine *engine) : Entity(engine, kEntityAugust) {
+ ADD_CALLBACK_FUNCTION(August, reset);
+ ADD_CALLBACK_FUNCTION(August, updateFromTime);
+ ADD_CALLBACK_FUNCTION(August, draw);
+ ADD_CALLBACK_FUNCTION(August, updatePosition);
+ ADD_CALLBACK_FUNCTION(August, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(August, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(August, enterExitCompartment3);
+ ADD_CALLBACK_FUNCTION(August, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(August, callSavepoint);
+ ADD_CALLBACK_FUNCTION(August, callSavepointNoDrawing);
+ ADD_CALLBACK_FUNCTION(August, draw2);
+ ADD_CALLBACK_FUNCTION(August, playSound);
+ ADD_CALLBACK_FUNCTION(August, playSound16);
+ ADD_CALLBACK_FUNCTION(August, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(August, savegame);
+ ADD_CALLBACK_FUNCTION(August, updateEntity);
+ ADD_CALLBACK_FUNCTION(August, function17);
+ ADD_CALLBACK_FUNCTION(August, updateEntity2);
+ ADD_CALLBACK_FUNCTION(August, function19);
+ ADD_CALLBACK_FUNCTION(August, function20);
+ ADD_CALLBACK_FUNCTION(August, function21);
+ ADD_CALLBACK_FUNCTION(August, chapter1);
+ ADD_CALLBACK_FUNCTION(August, function23);
+ ADD_CALLBACK_FUNCTION(August, dinner);
+ ADD_CALLBACK_FUNCTION(August, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(August, function26);
+ ADD_CALLBACK_FUNCTION(August, function27);
+ ADD_CALLBACK_FUNCTION(August, function28);
+ ADD_CALLBACK_FUNCTION(August, function29);
+ ADD_CALLBACK_FUNCTION(August, restaurant);
+ ADD_CALLBACK_FUNCTION(August, function31);
+ ADD_CALLBACK_FUNCTION(August, function32);
+ ADD_CALLBACK_FUNCTION(August, function33);
+ ADD_CALLBACK_FUNCTION(August, function34);
+ ADD_CALLBACK_FUNCTION(August, chapter2);
+ ADD_CALLBACK_FUNCTION(August, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(August, function37);
+ ADD_CALLBACK_FUNCTION(August, function38);
+ ADD_CALLBACK_FUNCTION(August, function39);
+ ADD_CALLBACK_FUNCTION(August, chapter3);
+ ADD_CALLBACK_FUNCTION(August, function41);
+ ADD_CALLBACK_FUNCTION(August, function42);
+ ADD_CALLBACK_FUNCTION(August, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(August, function44);
+ ADD_CALLBACK_FUNCTION(August, function45);
+ ADD_CALLBACK_FUNCTION(August, function46);
+ ADD_CALLBACK_FUNCTION(August, function47);
+ ADD_CALLBACK_FUNCTION(August, function48);
+ ADD_CALLBACK_FUNCTION(August, function49);
+ ADD_CALLBACK_FUNCTION(August, function50);
+ ADD_CALLBACK_FUNCTION(August, function51);
+ ADD_CALLBACK_FUNCTION(August, function52);
+ ADD_CALLBACK_FUNCTION(August, function53);
+ ADD_CALLBACK_FUNCTION(August, function54);
+ ADD_CALLBACK_FUNCTION(August, function55);
+ ADD_CALLBACK_FUNCTION(August, function56);
+ ADD_CALLBACK_FUNCTION(August, chapter4);
+ ADD_CALLBACK_FUNCTION(August, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(August, function59);
+ ADD_CALLBACK_FUNCTION(August, function60);
+ ADD_CALLBACK_FUNCTION(August, function61);
+ ADD_CALLBACK_FUNCTION(August, function62);
+ ADD_CALLBACK_FUNCTION(August, function63);
+ ADD_CALLBACK_FUNCTION(August, function64);
+ ADD_CALLBACK_FUNCTION(August, function65);
+ ADD_CALLBACK_FUNCTION(August, chapter5);
+ ADD_CALLBACK_FUNCTION(August, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(August, function68);
+ ADD_CALLBACK_FUNCTION(August, unhookCars);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, August, reset)
+ Entity::reset(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(2, August, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, August, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SII(4, August, updatePosition, CarIndex, Position)
+ Entity::updatePosition(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(5, August, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(6, August, enterExitCompartment2, ObjectIndex)
+ Entity::enterExitCompartment(savepoint, kPosition_6470, kPosition_6130, kCarGreenSleeping, kObjectCompartment3, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(7, August, enterExitCompartment3, ObjectIndex)
+ if (savepoint.action == kAction4) {
+ getEntities()->exitCompartment(kEntityAugust, (ObjectIndex)params->param4);
+ CALLBACK_ACTION();
+ return;
+ }
+
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, August, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIIS(9, August, callSavepoint, EntityIndex, ActionIndex)
+ Entity::callSavepoint(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IIS(10, August, callSavepointNoDrawing, EntityIndex, ActionIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ if (!params->param6)
+ getSavePoints()->call(kEntityAugust, (EntityIndex)params->param1, (ActionIndex)params->param2, (char *)&params->seq);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kAction10:
+ if (!params->param6) {
+ getSavePoints()->call(kEntityAugust, (EntityIndex)params->param1, (ActionIndex)params->param2, (char *)&params->seq);
+ params->param6 = 1;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SSI(11, August, draw2, EntityIndex)
+ Entity::draw2(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(12, August, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(13, August, playSound16)
+ Entity::playSound(savepoint, false, SoundManager::kFlagDefault);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, August, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(15, August, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(16, August, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ getProgress().eventMetAugust ? getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1002A" : "CAT1002") : getSound()->excuseMeCath();
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 < getState()->time && !params->param2) {
+ params->param2 = 1;
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (getEntities()->isPlayerInCar(kCarGreenSleeping) || getEntities()->isPlayerInCar(kCarRedSleeping)) {
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
+ setCallback(2);
+ setup_updateEntity2(kCarGreenSleeping, kPosition_540);
+ } else {
+ setCallback(3);
+ setup_updateEntity2(kCarRedSleeping, kPosition_9460);
+ }
+ }
+ break;
+
+ case kActionDefault:
+ ENTITY_PARAM(0, 1) = 0;
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_540);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (ENTITY_PARAM(0, 1)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityAugust);
+ break;
+
+ case 2:
+ case 3:
+ if (ENTITY_PARAM(0, 1)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityAugust);
+
+ setCallback(4);
+ setup_updateFromTime(450);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_updateEntity2(kCarRedSleeping, kPosition_540);
+ break;
+
+ case 5:
+ if (ENTITY_PARAM(0, 1)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityAugust);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(18, August, updateEntity2, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ } else if (getEntities()->isDistanceBetweenEntities(kEntityAugust, kEntityPlayer, 1000)
+ && !getEntities()->isInGreenCarEntrance(kEntityPlayer)
+ && !getEntities()->isInsideCompartments(kEntityPlayer)
+ && !getEntities()->checkFields10(kEntityPlayer)) {
+
+ if (getData()->car == kCarGreenSleeping || getData()->car == kCarRedSleeping) {
+ ENTITY_PARAM(0, 1) = 1;
+ CALLBACK_ACTION();
+ }
+ }
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(19, August, function19, bool, bool)
+ // Expose parameters as IISS and ignore the default exposed parameters
+ EntityData::EntityParametersIISS *parameters = (EntityData::EntityParametersIISS*)_data->getCurrentParameters();
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ getSound()->playSound(kEntityPlayer, "CAT1002");
+ getSound()->playSound(kEntityAugust, "AUG3101", SoundManager::kFlagInvalid, 15);
+ break;
+
+ case kActionDefault:
+ getData()->inventoryItem = kItemNone;
+
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ strcpy((char *)&parameters->seq1, "626");
+ break;
+
+ case kChapter2:
+ case kChapter3:
+ if (getData()->clothes != kClothes2) {
+ strcpy((char *)&parameters->seq1, "666");
+ break;
+ }
+ // Fallback to next action
+
+ case kChapter4:
+ case kChapter5:
+ strcpy((char *)&parameters->seq1, "696");
+ break;
+ }
+
+ getSavePoints()->push(kEntityAugust, kEntityMertens, kAction303343617);
+
+ strcpy((char *)&parameters->seq2, (char *)&parameters->seq1);
+ strcat((char *)&parameters->seq2, "Pc");
+
+ getEntities()->drawSequenceLeft(kEntityAugust, (char *)&parameters->seq2);
+ getEntities()->enterCompartment(kEntityAugust, kObjectCompartment3, true);
+
+ setCallback(1);
+ setup_playSound("AUG2096");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ strcpy((char *)&parameters->seq2, (char *)&parameters->seq1);
+ strcat((char *)&parameters->seq2, "Qc");
+
+ getEntities()->drawSequenceLeft(kEntityAugust, (char *)&parameters->seq2);
+ if (parameters->param2)
+ getData()->inventoryItem = kItem147;
+ break;
+
+ case 2:
+ strcpy((char *)&parameters->seq2, (char *)&parameters->seq1);
+ strcat((char *)&parameters->seq2, parameters->param1 ? "Fc" : "Dc");
+
+ setCallback(3);
+ setup_enterExitCompartment((char *)&parameters->seq2, kObjectCompartment3);
+ break;
+
+ case 3:
+ getEntities()->exitCompartment(kEntityAugust, kObjectCompartment3, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityAugust);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction69239528:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(2);
+ setup_updateFromTime(75);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(20, August, function20, bool)
+ // Expose parameters as ISSI and ignore the default exposed parameters
+ EntityData::EntityParametersISSI *parameters = (EntityData::EntityParametersISSI*)_data->getCurrentParameters();
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ strcpy((char *)&parameters->seq1, "626");
+ break;
+
+ case kChapter2:
+ case kChapter3:
+ if (getData()->clothes != kClothes2) {
+ strcpy((char *)&parameters->seq1, "666");
+ break;
+ }
+ // Fallback to next case
+
+ case kChapter4:
+ case kChapter5:
+ strcpy((char *)&parameters->seq1, "696");
+ break;
+ }
+
+ if (params->param1) {
+ strcpy((char *)&parameters->seq2, Common::String::format("%s%s", (char *)&parameters->seq1, "Gc").c_str());
+
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+ } else {
+ strcpy((char *)&parameters->seq2, Common::String::format("%s%s", (char *)&parameters->seq1, "Ec").c_str());
+ }
+
+ setCallback(1);
+ setup_enterExitCompartment((char *)&parameters->seq2, kObjectCompartment3);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1: {
+ getData()->location = kLocationOutsideCompartment;
+
+ Common::String sequence2 = Common::String::format("%s%s", (char *)&parameters->seq2, "Pc");
+ strcpy((char *)&parameters->seq2, (char *)&parameters->seq1);
+
+ getEntities()->drawSequenceLeft(kEntityAugust, sequence2.c_str());
+ getEntities()->enterCompartment(kEntityAugust, kObjectCompartment3, true);
+
+ if (getProgress().chapter != kChapter3 || getState()->time >= kTime1998000) {
+ setCallback(3);
+ setup_playSound("AUG2095");
+ } else {
+ setCallback(2);
+ setup_playSound("AUG2094");
+ }
+ }
+ break;
+
+ case 2:
+ case 3:
+ getSavePoints()->push(kEntityAugust, kEntityMertens, kAction269436673);
+ strcpy((char *)&parameters->seq2, Common::String::format("%s%s", (char *)&parameters->seq1, "Qc").c_str());
+
+ getEntities()->drawSequenceLeft(kEntityAugust, (char *)&parameters->seq2);
+ break;
+ }
+ break;
+
+ case kAction69239528:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getEntities()->exitCompartment(kEntityAugust, kObjectCompartment3, true);
+
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(21, August, function21, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param4 && params->param1 < getState()->time && !params->param7) {
+ params->param7 = 1;
+
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param2) {
+ UPDATE_PARAM_GOTO(params->param8, getState()->timeTicks, 75, label_continue);
+
+ params->param2 = 0;
+ params->param3 = 1;
+
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, (getProgress().eventMetAugust || getProgress().jacket != kJacketGreen) ? kCursorNormal : kCursorHand);
+ }
+
+ params->param8 = 0;
+
+label_continue:
+ if (getProgress().chapter != kChapter1)
+ break;
+
+ if (params->param6) {
+ UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->time, 6300)
+ params->param6 = 0;
+ CURRENT_PARAM(1, 1) = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (!params->param4
+ && !getProgress().eventMetAugust
+ && !params->param6
+ && (params->param1 - 4500) > getState()->time
+ && !getProgress().field_14) {
+ getProgress().field_14 = 2;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->entityPosition = kPosition_8200;
+
+ setCallback(1);
+ setup_function20(false);
+ }
+ break;
+
+ case kActionOpenDoor:
+ if (getProgress().chapter == kChapter1 && !getProgress().eventMetAugust && getProgress().jacket == kJacketGreen) {
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventMeetAugustHisCompartment);
+ break;
+ }
+ // Fallback to next case
+
+ case kActionKnock:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param2) {
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(12);
+ setup_playSound(rnd(2) ? getSound()->wrongDoorCath() : (rnd(2) ? "CAT1502" : "CAT1502A"));
+ } else {
+ setCallback(13);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 7 : 8);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param2 || params->param3) {
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param2 = 0;
+ params->param3 = 0;
+ params->param5 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function23((TimeValue)(params->param1 - 2700));
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function19(false, false);
+ break;
+
+ case 5:
+ if (getProgress().field_14 == 2)
+ getProgress().field_14 = 0;
+
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param2 = 0;
+ params->param3 = 0;
+ params->param5 = 0;
+ params->param6 = 0;
+ CURRENT_PARAM(1, 1) = 0;
+ break;
+
+ case 6:
+ getAction()->playAnimation(getObjects()->get(kObjectCompartment3).location2 == kObjectLocation1 ? kEventMeetAugustHisCompartmentBed : kEventMeetAugustHisCompartment);
+ getProgress().eventMetAugust = true;
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ params->param2 = 0;
+ params->param3 = 1;
+
+ getScenes()->loadSceneFromObject(kObjectCompartment3, true);
+ break;
+
+ case 7:
+ case 8:
+ ++params->param5;
+
+ switch(params->param5) {
+ default:
+ // Fall to next case
+ break;
+
+ case 1:
+ setCallback(9);
+ setup_playSound(rnd(2) ? "AUG1128A" : "AUG1128B");
+ return;
+
+ case 2:
+ setCallback(10);
+ setup_playSound(getProgress().eventMetAugust ? "AUG1128E" : "AUG1128G");
+ return;
+
+ case 3:
+ setCallback(11);
+ setup_playSound(getProgress().eventMetAugust ? "AUG1128F" : "AUG1128H");
+ return;
+ }
+ // Fallback to next case
+
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorTalk, (getProgress().eventMetAugust || getProgress().jacket != kJacketGreen) ? kCursorNormal : kCursorHand);
+
+ if (getCallback() == 12 || getCallback() == 13) {
+ params->param2 = 0;
+ params->param3 = 1;
+ } else {
+ params->param2= 1;
+ }
+ break;
+
+ case 14:
+ setCallback(15);
+ setup_updateFromTime(75);
+ break;
+
+ case 15:
+ setCallback(16);
+ setup_playSound("AUG1128I");
+ break;
+
+ case 16:
+ getSavePoints()->push(kEntityAugust, kEntityMertens, kAction100906246);
+ break;
+
+ case 17:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityAugust, kEntityMertens, kAction156567128);
+ getEntities()->drawSequenceLeft(kEntityAugust, "626Lc");
+ getEntities()->enterCompartment(kEntityAugust, kObjectCompartment3, true);
+ break;
+
+ case 18:
+ getEntities()->exitCompartment(kEntityAugust, kObjectCompartment3, true);
+ getData()->location = kLocationInsideCompartment; // BUG: in the original, this is set to 6470
+ getEntities()->clearSequences(kEntityAugust);
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param4 = 0;
+ break;
+ }
+ break;
+
+ case kAction124697504:
+ getSound()->playSound(kEntityAugust, "CON1023A");
+
+ setCallback(18);
+ setup_enterExitCompartment("626Mc", kObjectCompartment3);
+ break;
+
+ case kAction192849856:
+ setCallback(17);
+ setup_enterExitCompartment("626Kc", kObjectCompartment3);
+ break;
+
+ case kAction221617184:
+ params->param4 = 1;
+ getSavePoints()->push(kEntityAugust, kEntityMertens, kAction102675536);
+
+ setCallback(14);
+ setup_playSound("CON1023");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, August, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject11, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getData()->entityPosition = kPosition_4691;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+
+ getProgress().eventMetAugust = false;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(23, August, function23, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().field_14 == 29 || getProgress().field_14 == 3) {
+ if (params->param3) {
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_enterExitCompartment("626Ea", kObjectCompartment1);
+ } else {
+ getEntities()->exitCompartment(kEntityAugust, kObjectCompartment1, true);
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+
+ if (!params->param2) {
+
+ if (!CURRENT_PARAM(1, 3))
+ CURRENT_PARAM(1, 3) = getState()->timeTicks + 45;
+
+ if (CURRENT_PARAM(1, 3) >= getState()->timeTicks)
+ break;
+
+ if (!params->param5) {
+ setCallback(8);
+ setup_playSound("AUG1002B");
+ break;
+ }
+
+label_callback_8:
+ UPDATE_PARAM_PROC(CURRENT_PARAM(1, 4), getState()->timeTicks, 75)
+ getEntities()->exitCompartment(kEntityAugust, kObjectCompartment1, true);
+
+ if (getProgress().eventCorpseMovedFromFloor) {
+ setCallback(9);
+ setup_enterExitCompartment("626Da", kObjectCompartment1);
+ } else if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
+ setCallback(10);
+ setup_enterExitCompartment3("626Da", kObjectCompartment1);
+ } else {
+ getScenes()->loadSceneFromPosition(kCarNone, 1);
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ setCallback(11);
+ setup_savegame(kSavegameTypeEvent, kEventAugustFindCorpse);
+ }
+ break;
+ UPDATE_PARAM_PROC_END
+
+label_callback_9:
+ if (params->param3 && params->param1 < getState()->time && !CURRENT_PARAM(1, 5)) {
+ CURRENT_PARAM(1, 5) = 1;
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(12);
+ setup_enterExitCompartment("626Ea", kObjectCompartment1);
+ }
+ break;
+ }
+
+ if (!CURRENT_PARAM(1, 1))
+ CURRENT_PARAM(1, 1) = getState()->timeTicks + 45;
+
+ if (CURRENT_PARAM(1, 1) >= getState()->timeTicks)
+ break;
+
+ if (getObjects()->get(kObjectCompartment1).location == kObjectLocation1) {
+ UPDATE_PARAM(CURRENT_PARAM(1, 2), getState()->timeTicks, 75);
+
+ getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ params->param6++;
+
+ switch (params->param6) {
+ default:
+ break;
+
+ case 1:
+ setCallback(5);
+ setup_playSound("LIB013");
+ return;
+
+ case 2:
+ setCallback(7);
+ setup_playSound("LIB012");
+ return;
+
+ case 3:
+ params->param8++;
+
+ if (params->param8 >= 3) {
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+ CALLBACK_ACTION();
+ break;
+ }
+
+ params->param6 = 0;
+ }
+
+ getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, params->param4 ? kCursorNormal : kCursorTalk, kCursorHand);
+ CURRENT_PARAM(1, 2) = 0;
+ } else {
+
+ if (getProgress().eventCorpseMovedFromFloor && getProgress().jacket != kJacketBlood) {
+ params->param7 = (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) ? 8 : 7;
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventMeetAugustTylerCompartment);
+ } else {
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventAugustFindCorpse);
+ }
+ }
+ break;
+
+ case kActionKnock:
+ if (params->param3) {
+ getObjects()->update(kObjectCompartment1, kEntityAugust, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(15);
+ setup_playSound("LIB012");
+ } else if (!params->param4) {
+ getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ setCallback(17);
+ setup_playSound("AUG1002A");
+ }
+ break;
+
+ case kActionOpenDoor:
+ if (getProgress().eventCorpseMovedFromFloor && getProgress().jacket != kJacketBlood) {
+ if (params->param3) {
+ getData()->location = kLocationInsideCompartment;
+
+ params->param7 = (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) ? kEventMeetAugustHisCompartmentBed : kEventMeetAugustHisCompartment;
+ } else {
+ params->param7 = (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) ? kEventMeetAugustTylerCompartmentBed : kEventMeetAugustTylerCompartment;
+ }
+
+ setCallback(14);
+ setup_savegame(kSavegameTypeEvent, kEventMeetAugustTylerCompartment);
+ } else {
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(13);
+ setup_savegame(kSavegameTypeEvent, kEventAugustFindCorpse);
+ }
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_8200)
+ || getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_7850)
+ || getEntities()->isOutsideAlexeiWindow()) {
+ getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ if (getEntities()->isOutsideAlexeiWindow())
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, kCursorTalk, kCursorHand);
+
+ params->param2 = 1;
+ } else {
+ setCallback(1);
+ setup_enterExitCompartment("626Aa", kObjectCompartment1);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityAugust, "626Ba");
+ getEntities()->enterCompartment(kEntityAugust, kObjectCompartment1, true);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ CALLBACK_ACTION();
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityPlayer, "LIB014");
+ getAction()->playAnimation(kEventAugustFindCorpse);
+ if (getEvent(kEventDinerAugustOriginalJacket))
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventDinerAugustOriginalJacket, getProgress().eventCorpseFound ? kSceneGameOverStopPolice : kSceneGameOverPolice, true);
+ else if (getProgress().eventCorpseMovedFromFloor)
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ else
+ getLogic()->gameOver(kSavegameTypeIndex, 1, getProgress().eventCorpseFound ? kSceneGameOverStopPolice : kSceneGameOverPolice, true);
+ break;
+
+ case 4:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getSound()->playSound(kEntityPlayer, "LIB014");
+ getEntities()->clearSequences(kEntityAugust);
+ getData()->location = kLocationInsideCompartment;
+
+ getAction()->playAnimation((EventIndex)params->param7);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getProgress().eventMetAugust = true;
+ getData()->location = kLocationOutsideCompartment;
+
+ getScenes()->loadScene(kScene41);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_playSound16("AUG1002B");
+ break;
+
+ case 6:
+ case 7:
+ getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, params->param4 ? kCursorNormal : kCursorTalk, kCursorHand);
+ ENTITY_PARAM(1, 2) = 0;
+ break;
+
+ case 8:
+ params->param5 = 1;
+ goto label_callback_8;
+
+ case 9:
+ params->param3 = 1;
+ getEntities()->clearSequences(kEntityAugust);
+ getData()->location = kLocationInsideCompartment;
+ getObjects()->update(kObjectCompartment1, kEntityAugust, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ goto label_callback_9;
+
+ case 10:
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ setCallback(11);
+ setup_savegame(kSavegameTypeEvent, kEventAugustFindCorpse);
+ break;
+
+ case 11:
+ getAction()->playAnimation(kEventAugustFindCorpse);
+
+ getLogic()->gameOver(getEvent(kEventDinerAugustOriginalJacket) ? kSavegameTypeEvent2 : kSavegameTypeIndex,
+ getEvent(kEventDinerAugustOriginalJacket) ? kEventDinerAugustOriginalJacket : 1,
+ getProgress().eventCorpseFound ? kSceneGameOverStopPolice : kSceneGameOverPolice,
+ true);
+ break;
+
+ case 12:
+ getData()->location = kLocationOutsideCompartment;
+ CALLBACK_ACTION();
+ break;
+
+ case 13:
+ getSound()->playSound(kEntityPlayer, getObjects()->get(kObjectCompartment1).location == kObjectLocation1 ? "LIB032" : "LIB014");
+ getAction()->playAnimation(kEventAugustFindCorpse);
+
+ if (getEvent(kEventDinerAugustOriginalJacket))
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventDinerAugustOriginalJacket, getProgress().eventCorpseFound ? kSceneGameOverStopPolice : kSceneGameOverPolice, true);
+ else if (getProgress().eventCorpseMovedFromFloor)
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ else
+ getLogic()->gameOver(kSavegameTypeIndex, 1, getProgress().eventCorpseFound ? kSceneGameOverStopPolice : kSceneGameOverPolice, true);
+ break;
+
+ case 14:
+ if (!params->param2)
+ getSound()->playSound(kEntityPlayer, getObjects()->get(kObjectCompartment1).location == kObjectLocation1 ? "LIB032" : "LIB014");
+
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getAction()->playAnimation((EventIndex)params->param7);
+ getProgress().eventMetAugust = true;
+ getData()->location = kLocationOutsideCompartment;
+
+ getScenes()->loadScene(kScene41);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 15:
+ setCallback(16);
+ setup_playSound("AUG1128A");
+ break;
+
+ case 16:
+ getObjects()->update(kObjectCompartment1, kEntityAugust, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 17:
+ params->param4 = 1;
+ getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorHand);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, August, dinner)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventDinerAugust);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+
+ getAction()->playAnimation(getEntities()->isInRestaurant(kEntityAlexei) ? kEventDinerAugustAlexeiBackground : kEventDinerAugust);
+ getProgress().eventMetAugust = true;
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, August, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1 && getProgress().eventCorpseFound) {
+ getSavePoints()->push(kEntityAugust, kEntityPascale, kAction239072064);
+ params->param1 = 1;
+ }
+
+ if (getState()->time > kTime1080000 && !params->param3) {
+ params->param3 = 1;
+
+ if (!params->param1) {
+ getSavePoints()->push(kEntityAugust, kEntityPascale, kAction239072064);
+ params->param1 = 1;
+ }
+ }
+
+ if (getState()->time > kTime1093500 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->location = kLocationOutsideCompartment;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_callSavepoint("010J", kEntityTables3, kActionDrawTablesWithChairs, "010K");
+ }
+ break;
+
+ case kAction1:
+ params->param2 = 0;
+ getData()->inventoryItem = kItemNone;
+ getSavePoints()->push(kEntityAugust, kEntityPascale, kAction191604416);
+
+ if (getProgress().jacket == kJacketGreen) {
+ setCallback(3);
+ setup_dinner();
+ } else {
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventDinerAugustOriginalJacket);
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAugust, kEntityTables3, kAction136455232);
+ getEntities()->drawSequenceLeft(kEntityAugust, "010B");
+
+ if (!getProgress().eventMetAugust)
+ params->param2 = kItemInvalid;
+
+ getData()->inventoryItem = (InventoryItem)params->param2;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction204704037);
+ getEntities()->drawSequenceRight(kEntityAugust, "803DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAugust);
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ setup_function26();
+ break;
+
+ case 3:
+ setup_function28();
+ break;
+
+ case 4:
+ getSavePoints()->push(kEntityAugust, kEntityAlexei, kAction225182640);
+ getAction()->playAnimation(kEventDinerAugustOriginalJacket);
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ getData()->location = kLocationOutsideCompartment;
+
+ getSavePoints()->push(kEntityAugust, kEntityTables3, kActionDrawTablesWithChairs, "010K");
+ getEntities()->drawSequenceRight(kEntityAugust, "010P");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
+
+ setCallback(5);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 5:
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction204704037);
+ getEntities()->drawSequenceRight(kEntityAugust, "803DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAugust);
+
+ setCallback(6);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 6:
+ getProgress().field_14 = 2;
+
+ setCallback(7);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_function23(kTimeNone);
+ break;
+
+ case 8:
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, true);
+ break;
+ }
+ break;
+
+ case kAction168046720:
+ getData()->inventoryItem = kItemNone;
+ break;
+
+ case kAction168627977:
+ getData()->inventoryItem = (InventoryItem)params->param2;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, August, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getProgress().eventMetAugust || getProgress().field_14) {
+ setCallback(5);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ } else {
+ getProgress().field_14 = 2;
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function23((TimeValue)(getState()->time + 13500));
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function19(false, false);
+ break;
+
+ case 4:
+ if (getProgress().field_14 == 2)
+ getProgress().field_14 = 0;
+
+ setCallback(7);
+ setup_function21((TimeValue)(getState()->time + 900));
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function19(false, false);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function21((TimeValue)(getState()->time + 900));
+ break;
+
+ case 7:
+ setup_function27();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, August, function27)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(false);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("803US");
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityAugust, "010A");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAugust);
+
+ setCallback(5);
+ setup_callSavepointNoDrawing(kEntityTables3, kAction136455232, "BOGUS");
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ setup_function28();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, August, function28)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ params->param1 = 0;
+
+ setCallback(3);
+ setup_dinner();
+ break;
+
+ case kActionDefault:
+ if (!getProgress().eventMetAugust && getProgress().jacket == kJacketGreen)
+ params->param1 = kItemInvalid;
+
+ getEntities()->drawSequenceLeft(kEntityAugust, "010B");
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction304061224);
+ getData()->inventoryItem = (InventoryItem)params->param1;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction203859488);
+ getData()->inventoryItem = (InventoryItem)params->param1;
+ getEntities()->drawSequenceLeft(kEntityAugust, "010B");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction136702400);
+ getEntities()->drawSequenceLeft(kEntityAugust, "010B");
+ setup_function29();
+ break;
+ }
+ break;
+
+ case kAction168046720:
+ getData()->inventoryItem = kItemNone;
+ break;
+
+ case kAction168627977:
+ getData()->inventoryItem = (InventoryItem)params->param1;
+ break;
+
+ case kAction170016384:
+ getData()->inventoryItem = kItemNone;
+ getEntities()->drawSequenceLeft(kEntityServers0, "BLANK");
+ getEntities()->drawSequenceLeft(kEntityAugust, "010G");
+
+ setCallback(2);
+ setup_playSound("AUG1053");
+ break;
+
+ case kAction268773672:
+ getData()->inventoryItem = kItemNone;
+ getEntities()->drawSequenceLeft(kEntityAugust, "010D");
+
+ setCallback(1);
+ setup_playSound("AUG1052");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, August, function29)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getProgress().field_28 || (params->param2 && params->param3 == kTimeInvalid))
+ break;
+
+ if (getState()->time < kTime1134000) {
+
+ if (!getEntities()->isInRestaurant(kEntityPlayer)
+ || getSound()->isBuffered("MRB1076") || getSound()->isBuffered("MRB1078") || getSound()->isBuffered("MRB1078A"))
+ params->param3 = (uint)getState()->time + 225;
+
+ if (params->param3 > getState()->time)
+ break;
+ }
+
+ params->param3 = kTimeInvalid;
+ getData()->inventoryItem = kItemNone;
+ getProgress().field_28 = 0;
+
+ setup_restaurant();
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ params->param1 = kItemNone;
+
+ setCallback(1);
+ setup_dinner();
+ break;
+
+ case kActionDefault:
+ if (!getProgress().eventMetAugust && getProgress().jacket == kJacketGreen)
+ params->param1 = kItemInvalid;
+
+ getData()->inventoryItem = (InventoryItem)LOW_BYTE(params->param1);
+
+ getEntities()->drawSequenceLeft(kEntityAugust, "010H");
+ break;
+
+ case kAction168046720:
+ getData()->inventoryItem = kItemNone;
+ break;
+
+ case kAction168627977:
+ getData()->inventoryItem = (InventoryItem)LOW_BYTE(params->param1);
+ break;
+
+ case kAction189426612:
+ params->param2 = 1;
+ break;
+
+ case kAction235257824:
+ params->param2 = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, August, restaurant)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param3, getState()->timeTicks, 75);
+
+ getData()->inventoryItem = kItemInvalid;
+ break;
+
+ case kAction1:
+ params->param1 = 1;
+ getData()->inventoryItem = kItemNone;
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 62);
+ getEntities()->updatePositionEnter(kEntityAugust, kCarRestaurant, 61);
+ getEntities()->updatePositionEnter(kEntityAugust, kCarRestaurant, 64);
+ break;
+
+ case kActionEndSound:
+ if (params->param1) {
+ getData()->inventoryItem = kItemNone;
+ getEntities()->updatePositionExit(kEntityAugust, kCarRestaurant, 61);
+ getEntities()->updatePositionExit(kEntityAugust, kCarRestaurant, 64);
+
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventAugustPresentAnna);
+ break;
+ }
+
+ if (params->param2) {
+ params->param2 = 0;
+ if (getProgress().eventMetAugust)
+ getData()->inventoryItem = kItemNone;
+
+ getSound()->playSound(kEntityAugust, "Aug1003A");
+ } else {
+ getData()->inventoryItem = kItemNone;
+ getSavePoints()->push(kEntityAugust, kEntityAnna, kAction201437056);
+
+ setCallback(8);
+ setup_draw("010P");
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAugust, kEntityBoutarel, kAction135854206);
+
+ setCallback(1);
+ setup_updateFromTime(450);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityAugust, kEntityAnna, kAction259136835);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_callSavepoint("010N", kEntityTables3, kActionDrawTablesWithChairs, "010K");
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction292758554);
+ getSavePoints()->push(kEntityAugust, kEntityAnna, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityAugust, "001K");
+ getSound()->playSound(kEntityAugust, "AUG1003");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getProgress().field_60 = 1;
+
+ params->param2 = 1;
+ break;
+
+ case 4:
+
+ break;
+
+ case 5:
+ case 7:
+ case 9:
+ getSavePoints()->push(kEntityAugust, kEntityBoutarel, kAction134466544);
+
+ setup_function31();
+ break;
+
+ case 6:
+ case 8:
+ getEntities()->drawSequenceRight(kEntityAugust, "803DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAugust);
+
+ setCallback(getCallback() + 1);
+ setup_callbackActionOnDirection();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, August, function31)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function19(false, false);
+ break;
+
+ case 2:
+ setCallback(2);
+ setup_function21(kTime1161000);
+ break;
+
+ case 3:
+ case 4:
+ if (getProgress().field_14 == 29) {
+ setCallback(4);
+ setup_function21((TimeValue)(getState()->time + 900));
+ } else {
+ setup_function32();
+ }
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, August, function32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_PROC_TIME(kTime1179000, (!getEntities()->isInSalon(kEntityAnna) || getEntities()->isInSalon(kEntityPlayer)), params->param6, 0);
+ getSavePoints()->push(kEntityAugust, kEntityAnna, kAction123712592);
+ UPDATE_PARAM_PROC_END
+
+ if (params->param1 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ if (!params->param4) {
+ params->param4 = (uint)getState()->time + 1800;
+ params->param5 = (uint)getState()->time + 9000;
+ }
+
+ if (params->param7 != kTimeInvalid && params->param4 < getState()->time) {
+ UPDATE_PARAM_PROC_TIME(params->param5, getEntities()->isInSalon(kEntityPlayer), params->param7, 0);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_updatePosition("109D", kCarRestaurant, 56);
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+ }
+
+ if (params->param3) {
+ UPDATE_PARAM(params->param8, getState()->timeTicks, 90);
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+ } else {
+ params->param8 = 0;
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(false);
+ break;
+
+ case kActionDrawScene:
+ if (params->param2) {
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 57)) {
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 50);
+ params->param3 = true;
+ } else if (!getEntities()->isPlayerPosition(kCarRestaurant, 50)) {
+ params->param3 = false;
+ }
+ } else {
+ params->param3 = getEntities()->isPlayerPosition(kCarRestaurant, 56) && params->param1;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_updatePosition("105A", kCarRestaurant, 57);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAugust, "105B");
+ params->param2 = 1;
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function19(false, false);
+ break;
+
+ case 7:
+ setup_function33();
+ break;
+ }
+ break;
+
+ case kAction122358304:
+ params->param2 = 0;
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+ break;
+
+ case kAction159332865:
+ getEntities()->drawSequenceLeft(kEntityAugust, "106E");
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, August, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(getProgress().eventMetAugust ? 1 : 2);
+ setup_function21(getProgress().eventMetAugust ? (TimeValue)(getState()->time + 9000) : kTimeBedTime);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1 || getCallback() == 2)
+ setup_function34();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, August, function34)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getSound()->isBuffered(kEntityAugust) && getProgress().field_18 != 4)
+ getSound()->playSound(kEntityAugust, "AUG1057"); // August snoring
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getEntities()->clearSequences(kEntityAugust);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, August, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAugust);
+
+ getData()->entityPosition = kPosition_3970;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes1;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject11, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, August, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_SAVEPOINT(kTime1755000, params->param2, kEntityAugust, kEntityServers0, kAction252568704);
+
+ if (getState()->time > kTime1773000 && params->param1 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->inventoryItem = kItemNone;
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->updatePositionEnter(kEntityAugust, kCarRestaurant, 62);
+
+ setCallback(2);
+ setup_callSavepoint("016C", kEntityTables0, kActionDrawTablesWithChairs, "016D");
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAugustGoodMorning);
+ break;
+
+ case kActionDefault:
+ if (!getEvent(kEventAugustGoodMorning))
+ getData()->inventoryItem = kItemInvalid;
+
+ getSavePoints()->push(kEntityAugust, kEntityTables0, kAction136455232);
+ getEntities()->drawSequenceLeft(kEntityAugust, "016B");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventAugustGoodMorning);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
+ break;
+
+ case 2:
+ getEntities()->updatePositionExit(kEntityAugust, kCarRestaurant, 62);
+ getEntities()->drawSequenceRight(kEntityAugust, "803ES");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAugust);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction286534136);
+
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function19(true, false);
+ break;
+
+ case 5:
+ setup_function37();
+ break;
+
+ case 6:
+ if (!getEvent(kEventAugustGoodMorning))
+ getData()->inventoryItem = kItemInvalid;
+
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction219522616);
+ getEntities()->drawSequenceLeft(kEntityAugust, "016B");
+ params->param1 = 1;
+ break;
+ }
+ break;
+
+ case kAction123712592:
+ getEntities()->drawSequenceLeft(kEntityAugust, "016A");
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(6);
+ setup_playSound("AUG2113");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, August, function37)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK_1(kTime1791000, params->param2, 5, setup_function20, true);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getEntities()->drawSequenceLeft(kEntityAugust, "506A2");
+ break;
+
+ case kActionDrawScene:
+ if (getState()->time > kTime1786500 && getEntities()->isPlayerPosition(kCarGreenSleeping, 43)) {
+ if (params->param1) {
+ setCallback(2);
+ setup_draw("506C2");
+ } else {
+ params->param1 = 1;
+
+ setCallback(1);
+ setup_draw("506B2");
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 16);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function20(true);
+ break;
+
+ case 3:
+ case 5:
+ setCallback(getCallback() + 1);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 4:
+ case 6:
+ setup_function38();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, August, function38)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_SAVEPOINT(kTime1801800, params->param1, kEntityAugust, kEntityRebecca, kAction155980128);
+
+ TIME_CHECK_CALLBACK(kTime1820700, params->param2, 3, setup_callbackActionRestaurantOrSalon);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updatePosition("109A", kCarRestaurant, 56);
+ break;
+
+ case 2:
+ getScenes()->loadSceneFromItemPosition(kItem3);
+ getData()->location = kLocationInsideCompartment;
+ break;
+
+ case 3:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_updatePosition("109D2", kCarRestaurant, 56);
+ break;
+
+ case 4:
+ getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
+
+ setCallback(5);
+ setup_function17(kTime1849500);
+ break;
+
+ case 5:
+ setup_function39();
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_playSound("AUG2114");
+ break;
+
+ case 7:
+ getEntities()->drawSequenceLeft(kEntityAugust, "108C");
+ getEntities()->updatePositionEnter(kEntityAugust, kCarRestaurant, 56);
+ getEntities()->updatePositionEnter(kEntityAugust, kCarRestaurant, 57);
+
+ setCallback(8);
+ setup_playSound("AUG2114A");
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_playSound("AUG2115");
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_draw2("108D1", "108D2", kEntityRebecca);
+ break;
+
+ case 10:
+ getEntities()->drawSequenceLeft(kEntityAugust, "109B");
+ getEntities()->updatePositionExit(kEntityAugust, kCarRestaurant, 56);
+ getEntities()->updatePositionExit(kEntityAugust, kCarRestaurant, 57);
+ getSavePoints()->push(kEntityAugust, kEntityRebecca, kAction125496184);
+ break;
+ }
+ break;
+
+ case kAction169358379:
+ getSavePoints()->push(kEntityAugust, kEntityRebecca, kAction155465152);
+ getEntities()->drawSequenceLeft(kEntityAugust, "108A");
+
+ setCallback(6);
+ setup_updateFromTime(900);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(39, August, function39)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (!ENTITY_PARAM(0, 1))
+ getSound()->playSound(kEntityPlayer, "BUMP");
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAugustArrivalInMunich);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventAugustArrivalInMunich);
+ getSavePoints()->push(kEntityAugust, kEntityChapters, kActionChapter3);
+ getEntities()->clearSequences(kEntityAugust);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(40, August, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAugust);
+
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothes1;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(41, August, function41, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param3 && getEntities()->isDistanceBetweenEntities(kEntityAugust, kEntityPlayer, 2000))
+ getData()->inventoryItem = kItemInvalid;
+ else
+ getData()->inventoryItem = kItemNone;
+
+ if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (!getEvent(kEventAugustMerchandise)
+ && getEntities()->isDistanceBetweenEntities(kEntityAugust, kEntityPlayer, 1000)
+ && !getEntities()->isInsideCompartments(kEntityPlayer)
+ && !getEntities()->checkFields10(kEntityPlayer)) {
+ if (getData()->car == kCarGreenSleeping || getData()->car == kCarGreenSleeping) {
+ getAction()->playAnimation(kEventAugustMerchandise);
+
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ }
+ }
+ break;
+
+ case kAction1:
+ params->param3 = kItemNone;
+ getData()->inventoryItem = kItemNone;
+
+ getAction()->playAnimation((getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition) ? kEventAugustTalkGoldDay : kEventAugustTalkGold);
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ break;
+
+ case kActionExcuseMeCath:
+ if (getProgress().eventMetAugust)
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1002" : "CAT1002A");
+ else
+ getSound()->excuseMeCath();
+ break;
+
+ case kActionExcuseMe:
+ getSound()->excuseMe(kEntityAugust);
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (getEvent(kEventAugustMerchandise) && !getEvent(kEventAugustTalkGold) && !getEvent(kEventAugustTalkGoldDay))
+ params->param3 = kItemInvalid;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_III(42, August, function42, CarIndex, EntityPosition, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param4 && getEntities()->isDistanceBetweenEntities(kEntityAugust, kEntityPlayer, 2000))
+ getData()->inventoryItem = kItemInvalid;
+ else
+ getData()->inventoryItem = kItemNone;
+
+ if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ getData()->inventoryItem = kItemNone;
+
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kAction1:
+ params->param4 = 0;
+ getData()->inventoryItem = kItemNone;
+
+ getSound()->playSound(kEntityPlayer, "CAT1002");
+ getSound()->playSound(kEntityAugust, getEvent(kEventAugustBringBriefcase) ? "AUG3103" : "AUG3100", SoundManager::kFlagInvalid, 15);
+ break;
+
+ case kActionExcuseMe:
+ if (!getSound()->isBuffered(kEntityAugust))
+ getSound()->excuseMe(kEntityAugust);
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param3) {
+ params->param4 = 128;
+
+ if (!getEvent(kEventAugustBringBriefcase))
+ params->param4 = 147;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(43, August, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_SAVEPOINT(kTime1953000, params->param2, kEntityAugust, kEntityAnna, kAction291662081);
+
+ // Set as same position as Anna
+ if (params->param1) {
+ getData()->entityPosition = getEntityData(kEntityAnna)->entityPosition;
+ getData()->car = getEntityData(kEntityAnna)->car;
+ }
+
+ if (getState()->time > kTime2016000 && !params->param1) {
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->inventoryItem = kItemNone;
+ setup_function44();
+ }
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventAugustLunch);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function41(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("803VS");
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityAugust, "010A2");
+
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAugust);
+
+ setCallback(5);
+ setup_callSavepointNoDrawing(kEntityTables3, kAction136455232, "BOGUS");
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAugust, "010B2");
+
+ if (!getEvent(kEventAugustLunch))
+ getData()->inventoryItem = kItemInvalid;
+ break;
+
+ case 6:
+ getAction()->playAnimation(kEventAugustLunch);
+ getScenes()->processScene();
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ params->param1 = 0;
+ getData()->inventoryItem = kItemNone;
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->drawSequenceLeft(kEntityAugust, "112G");
+ break;
+
+ case kAction122358304:
+ params->param1 = 1;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(44, August, function44)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_updatePosition("122H", kCarRestaurant, 57);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEvent(kEventAugustMerchandise)) {
+ setCallback(4);
+ setup_function41(kCarGreenSleeping, kPosition_6470);
+ } else {
+ setCallback(2);
+ setup_function17(kTime2043000);
+ }
+ break;
+
+ case 2:
+ if (!ENTITY_PARAM(0, 1)) {
+ setCallback(4);
+ setup_function41(kCarGreenSleeping, kPosition_6470);
+ } else {
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventAugustMerchandise);
+ }
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventAugustMerchandise);
+ if (getData()->car == kCarGreenSleeping && getEntities()->checkDistanceFromPosition(kEntityAugust, kPosition_6470, 500))
+ getData()->entityPosition = kPosition_5970;
+
+ getEntities()->updateEntity(kEntityAugust, kCarGreenSleeping, kPosition_6470);
+
+ getEntities()->loadSceneFromEntityPosition(getData()->car,
+ (EntityPosition)(getData()->entityPosition + 750 * (getData()->direction == kDirectionUp ? -1 : 1)),
+ getData()->direction == kDirectionUp);
+
+ setCallback(4);
+ setup_function41(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function19(true, false);
+ break;
+
+ case 5:
+ setup_function45();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(45, August, function45)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2061000 && !params->param1) {
+ params->param1 = 1;
+ getData()->inventoryItem = kItemNone;
+
+ setup_function46();
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ getSound()->playSound(kEntityPlayer, "CAT1002");
+ getSound()->playSound(kEntityAugust, "AUG3102", SoundManager::kFlagInvalid, 15);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getEntities()->drawSequenceLeft(kEntityAugust, "506A2");
+ getData()->inventoryItem = kItem146; // TODO which item is that?
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(46, August, function46)
+ switch (savepoint.action) {
+ default:
+ TIME_CHECK_CALLBACK(kTime2088000, params->param1, 1, setup_function47);
+ break;
+
+ case kActionNone:
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 43)) {
+ setCallback(2);
+ setup_draw("507B2");
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setup_function48();
+ break;
+
+ case 2:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 43))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 34);
+
+ getEntities()->clearSequences(kEntityAugust);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(47, August, function47)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function41(kCarGreenSleeping, kPosition_9460);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityAugust);
+ setCallback(3);
+ setup_updateFromTime(2700);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function41(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function19(false, false);
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(48, August, function48)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeCityLinz, params->param1, setup_function49);
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (!getEvent(kEventAugustTalkCompartmentDoor) && !getEvent(kEventAugustTalkCompartmentDoorBlueRedingote)
+ && !getEvent(kEventAugustBringEgg) && !getEvent(kEventAugustBringBriefcase)) {
+
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAugustTalkCompartmentDoor);
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getData()->clothes = kClothes2;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventAugustTalkCompartmentDoor);
+ getScenes()->processScene();
+
+ setCallback(2);
+ setup_function21(kTimeCityLinz);
+ break;
+
+ case 2:
+ setup_function49();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(49, August, function49)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(false);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarKronos, kPosition_9270);
+ break;
+
+ case 2:
+ setup_function50();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(50, August, function50)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getEntities()->clearSequences(kEntityAugust);
+
+ getData()->entityPosition = kPosition_6000;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarKronos;
+ break;
+
+ case kAction191668032:
+ setup_function51();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(51, August, function51)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_850;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_function42(kCarGreenSleeping, kPosition_5790, false);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityAugust, kEntityTatiana, kAction191668032);
+
+ setCallback(2);
+ setup_function42(kCarRedSleeping, kPosition_540, true);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityAugust);
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+ getSavePoints()->push(kEntityAugust, kEntityAnna, kAction123712592);
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ setup_function52();
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+ break;
+
+ case kAction169032608:
+ setCallback(3);
+ setup_function42(kCarRedSleeping, kPosition_3820, true);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(52, August, function52)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (getInventory()->hasItem(kItemBriefcase)) {
+ getData()->location = kLocationInsideCompartment;
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventAugustBringBriefcase);
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemFirebird) && !getEvent(kEventAugustBringEgg)) {
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventAugustBringEgg);
+ break;
+ }
+
+ if (!getEvent(kEventAugustTalkCompartmentDoorBlueRedingote) && !getEvent(kEventAugustBringEgg) && !getEvent(kEventAugustBringBriefcase)) {
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventAugustBringEgg);
+ break;
+ }
+
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 6 : 7);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function42(kCarGreenSleeping, kPosition_6470, true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function19(false, true);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getSavePoints()->push(kEntityAugust, kEntityKahina, kAction134611040);
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventAugustBringBriefcase);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ RESET_ENTITY_STATE(kEntitySalko, Salko, setup_function17);
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 13);
+
+ setup_function53();
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventAugustBringEgg);
+ getScenes()->processScene();
+ break;
+
+ case 5:
+ getAction()->playAnimation(kEventAugustTalkCompartmentDoorBlueRedingote);
+ getScenes()->processScene();
+ break;
+
+ case 6:
+ case 7:
+ setCallback(8);
+ setup_playSound("AUG1128F");
+ break;
+
+ case 8:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(53, August, function53)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateFromTime(2700);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function20(false);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setup_function54();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(54, August, function54)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param4 || params->param2 || getProgress().field_44)
+ getData()->inventoryItem = kItemNone;
+ else
+ getData()->inventoryItem = kItemInvalid;
+
+ if (!params->param2 && params->param1) {
+ UPDATE_PARAM(params->param5, getState()->time, params->param1);
+
+ getData()->inventoryItem = kItemNone;
+ setup_function55();
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventAugustTalkCigar);
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->updatePositionExit(kEntityAugust, kCarRestaurant, 57);
+ getEntities()->drawSequenceLeft(kEntityAugust, "105B3");
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionDrawScene:
+ if (!getEntities()->isPlayerPosition(kCarRestaurant, 60) || params->param3) {
+ if (!params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 57))
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 50);
+ } else if (!params->param2) {
+ getEntities()->updatePositionEnter(kEntityAugust, kCarRestaurant, 57);
+ getEntities()->drawSequenceRight(kEntityAugust, "105C3");
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updatePosition("105A3", kCarRestaurant, 57);
+ break;
+
+ case 2:
+ getData()->location = kLocationInsideCompartment;
+ getSavePoints()->push(kEntityAugust, kEntityAbbot, kAction123712592);
+ getEntities()->drawSequenceLeft(kEntityAugust, "105B3");
+ params->param4 = 1;
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventAugustTalkCigar);
+ getEntities()->drawSequenceLeft(kEntityAugust, params->param3 ? "122B" : "105B3");
+ getScenes()->processScene();
+
+ params->param1 = 9000;
+ params->param4 = 0;
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityAugust, "122B");
+ params->param2 = 0;
+
+ if (getEvent(kEventAugustTalkCigar))
+ params->param1 = 9000;
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+ params->param2 = 1;
+ params->param3 = 1;
+ break;
+
+ case kAction136196244:
+ params->param2 = 1;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(55, August, function55)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updatePosition("105D3", kCarRestaurant, 57);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function19(true, false);
+ break;
+
+ case 4:
+ setup_function56();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(56, August, function56)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getEntities()->drawSequenceLeft(kEntityAugust, "507A3");
+ break;
+
+ case kActionDrawScene:
+ if (!params->param1 && getEntities()->isPlayerPosition(kCarGreenSleeping, 43)) {
+ setCallback(1);
+ setup_draw("507B3");
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ params->param1 = 1;
+ getEntities()->drawSequenceLeft(kEntityAugust, "507A3");
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(57, August, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAugust);
+
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothes2;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(58, August, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(false);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("803WS");
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityAugust, "010A3");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAugust);
+
+ setCallback(5);
+ setup_callSavepointNoDrawing(kEntityTables3, kAction136455232, "BOGUS");
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ setup_function59();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(59, August, function59)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAugust, "010B3");
+ getSavePoints()->push(kEntityAugust, kEntityPascale, kAction190605184);
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+ break;
+
+ case kAction123793792:
+ setup_function60();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(60, August, function60)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone: {
+ bool pushSavepoint = false;
+ if (!params->param2) {
+ pushSavepoint = true;
+ params->param2 = (uint)getState()->time + 450;
+ }
+
+ if (params->param2 < getState()->time) {
+ pushSavepoint = true;
+ params->param2 = kTimeInvalid;
+ }
+
+ if (pushSavepoint)
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction207330561);
+
+ if (!params->param1)
+ break;
+
+ UPDATE_PARAM(params->param3, getState()->time, 9000);
+
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAugust, "010B3");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_callSavepoint("010J3", kEntityTables3, kActionDrawTablesWithChairs, "010M");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityAugust, kEntityServers0, kAction286403504);
+ setup_function61();
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityAugust, "010B3");
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+ break;
+
+ case kAction201964801:
+ getEntities()->drawSequenceLeft(kEntityAugust, "010H3");
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(61, August, function61)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->drawSequenceRight(kEntityAugust, "803FS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityAugust);
+
+ setCallback(1);
+ setup_callbackActionOnDirection();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function19(false, false);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function21((TimeValue)(getState()->time + 4500));
+ break;
+
+ case 4:
+ setup_function62();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(62, August, function62)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->time, 900);
+
+ getSound()->playSound(kEntityAugust, "Aug4003A");
+
+ setCallback(5);
+ setup_updatePosition("122C", kCarRestaurant, 57);
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_enterExitCompartment("696Ec", kObjectCompartment3);
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 57))
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 50);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_updatePosition("122A", kCarRestaurant, 57);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityAugust, "122B");
+ break;
+
+ case 5:
+ getEntities()->drawSequenceLeft(kEntityAugust, "122B");
+ getSavePoints()->push(kEntityAugust, kEntityServers1, kAction291721418);
+ break;
+ }
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+ break;
+
+ case kAction125826561:
+ setup_function63();
+ break;
+
+ case kAction134486752:
+ getEntities()->drawSequenceLeft(kEntityAugust, "122B");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(63, August, function63)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 1800)
+ getData()->inventoryItem = kItemInvalid;
+ UPDATE_PARAM_PROC_END
+
+ if (getState()->time > kTime2488500 && !params->param4) {
+ params->param4 = 1;
+ getData()->inventoryItem = kItemNone;
+ setup_function64();
+ break;
+ }
+
+ UPDATE_PARAM(params->param5, getState()->timeTicks, params->param1);
+
+ params->param2 = (params->param6 < 1 ? 1 : 0);
+
+ getEntities()->drawSequenceLeft(kEntityAugust, params->param2 ? "122H" : "122F");
+
+ params->param1 = 5 * (3 * rnd(20) + 15);
+ params->param5 = 0;
+ break;
+
+ case kAction1:
+ if (getEntities()->isInSalon(kEntityAlexei))
+ RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_function44);
+
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAugustDrink);
+ break;
+
+ case kActionDefault:
+ params->param1 = 5 * (3 * rnd(20) + 15);
+ getEntities()->drawSequenceLeft(kEntityAugust, "122F");
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 57))
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 50);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventAugustDrink);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+
+ setup_function64();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(64, August, function64)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1)
+ params->param1 = (uint)getState()->time + 1800;
+
+ if (params->param1 >= getState()->time)
+ break;
+
+ if (getState()->time > kTime2430000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_updatePosition("122J", kCarRestaurant, 57);
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityAugust, "122H");
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 57))
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 50);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment2("696Dc", kObjectCompartment3);
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityAugust);
+ setup_function65();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(65, August, function65)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ getSound()->playSound(kEntityAugust, "AUG1057"); // August snoring
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getEntities()->clearSequences(kEntityAugust);
+
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ if (!getSound()->isBuffered(kEntityAugust))
+ getSound()->playSound(kEntityAugust, "AUG1057"); // August snoring
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(66, August, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityAugust);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes2;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(67, August, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function68();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(68, August, function68)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM(params->param4, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 1;
+
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param4 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (params->param1) {
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_playSound(getSound()->justCheckingCath());
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 2 : 3);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ params->param1 = 0;
+ params->param2 = 0;
+ params->param3 = 0;
+
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param1 = 0;
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 2:
+ case 3:
+ ++params->param3;
+
+ switch (params->param3) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(4);
+ setup_playSound("Aug5002");
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(5);
+ setup_playSound("Aug5002A");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(6);
+ setup_playSound("Aug5002B");
+ break;
+ }
+ break;
+
+ case 4:
+ params->param1 = 1;
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorTalk, kCursorNormal);
+ break;
+
+ case 5:
+ getObjects()->update(kObjectCompartment3, kEntityAugust, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 6:
+ params->param2 = 1;
+ break;
+ }
+ break;
+
+ case kAction203078272:
+ getSavePoints()->push(kEntityAugust, kEntityTatiana, kAction203078272);
+
+ setup_unhookCars();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(69, August, unhookCars)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ getSavePoints()->pushAll(kEntityAugust, kAction135800432);
+ setup_nullfunction();
+ break;
+
+ case kActionDefault:
+ getSound()->processEntries();
+ if (getSound()->isBuffered("ARRIVE"))
+ getSound()->removeFromQueue("ARRIVE");
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventAugustUnhookCarsBetrayal);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(getProgress().field_C ? kEventAugustUnhookCarsBetrayal : kEventAugustUnhookCars);
+ getEntities()->clearSequences(kEntityAugust);
+ getSound()->resetState();
+ getSound()->playSound(kEntityPlayer, "MUS050");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 85, 1);
+ getSavePoints()->pushAll(kEntityAugust, kActionProceedChapter5);
+
+ RESET_ENTITY_STATE(kEntityVerges, Verges, setup_function42)
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(70, August)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/august.h b/engines/lastexpress/entities/august.h
new file mode 100644
index 0000000000..1a883a0ed5
--- /dev/null
+++ b/engines/lastexpress/entities/august.h
@@ -0,0 +1,275 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_AUGUST_H
+#define LASTEXPRESS_AUGUST_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class August : public Entity {
+public:
+ August(LastExpressEngine *engine);
+ ~August() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence1, CarIndex car, Position position)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment3, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Call a savepoint (or draw sequence in default case)
+ *
+ * @param sequence1 The sequence to draw in the default case
+ * @param entity The entity
+ * @param action The action
+ * @param sequence2 The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_4(callSavepoint, const char *sequence1, EntityIndex entity, ActionIndex action, const char *sequence2)
+
+ /**
+ * Call a savepoint
+ *
+ * @param param1 The entity
+ * @param param2 The action
+ * @param seq The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_3(callSavepointNoDrawing, EntityIndex entity, ActionIndex action, const char *sequence)
+
+ /**
+ * Draws the entity along with another one
+ *
+ * @param sequence1 The sequence to draw
+ * @param sequence2 The sequence to draw for the second entity
+ * @param entity The EntityIndex of the second entity
+ */
+ DECLARE_FUNCTION_3(draw2, const char *sequence1, const char *sequence2, EntityIndex entity)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound16, const char *filename)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION_1(function17, TimeValue timeValue)
+
+ /**
+ * Updates the entity
+ *
+ * @param param1 The car
+ * @param param2 The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity2, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION_2(function19, bool, bool)
+
+ DECLARE_FUNCTION_1(function20, bool)
+ DECLARE_FUNCTION_1(function21, TimeValue timeValue)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION_1(function23, TimeValue timeValue)
+ DECLARE_FUNCTION(dinner)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(function28)
+ DECLARE_FUNCTION(function29)
+ DECLARE_FUNCTION(restaurant)
+ DECLARE_FUNCTION(function31)
+ DECLARE_FUNCTION(function32)
+ DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(function34)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function37)
+ DECLARE_FUNCTION(function38)
+ DECLARE_FUNCTION(function39)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ DECLARE_FUNCTION_2(function41, CarIndex car, EntityPosition entityPosition)
+ DECLARE_FUNCTION_3(function42, CarIndex car, EntityPosition entityPosition, bool)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function44)
+ DECLARE_FUNCTION(function45)
+ DECLARE_FUNCTION(function46)
+ DECLARE_FUNCTION(function47)
+ DECLARE_FUNCTION(function48)
+ DECLARE_FUNCTION(function49)
+ DECLARE_FUNCTION(function50)
+ DECLARE_FUNCTION(function51)
+ DECLARE_FUNCTION(function52)
+ DECLARE_FUNCTION(function53)
+ DECLARE_FUNCTION(function54)
+ DECLARE_FUNCTION(function55)
+ DECLARE_FUNCTION(function56)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function59)
+ DECLARE_FUNCTION(function60)
+ DECLARE_FUNCTION(function61)
+ DECLARE_FUNCTION(function62)
+ DECLARE_FUNCTION(function63)
+ DECLARE_FUNCTION(function64)
+ DECLARE_FUNCTION(function65)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function68)
+ DECLARE_FUNCTION(unhookCars)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_AUGUST_H
diff --git a/engines/lastexpress/entities/boutarel.cpp b/engines/lastexpress/entities/boutarel.cpp
new file mode 100644
index 0000000000..b4378c95c4
--- /dev/null
+++ b/engines/lastexpress/entities/boutarel.cpp
@@ -0,0 +1,1260 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/boutarel.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Boutarel::Boutarel(LastExpressEngine *engine) : Entity(engine, kEntityBoutarel) {
+ ADD_CALLBACK_FUNCTION(Boutarel, reset);
+ ADD_CALLBACK_FUNCTION(Boutarel, playSound);
+ ADD_CALLBACK_FUNCTION(Boutarel, draw);
+ ADD_CALLBACK_FUNCTION(Boutarel, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Boutarel, updatePosition);
+ ADD_CALLBACK_FUNCTION(Boutarel, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Boutarel, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Boutarel, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Boutarel, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Boutarel, updateEntity);
+ ADD_CALLBACK_FUNCTION(Boutarel, function11);
+ ADD_CALLBACK_FUNCTION(Boutarel, enterTableWithMmeBoutarel);
+ ADD_CALLBACK_FUNCTION(Boutarel, leaveTableWithMmeBoutarel);
+ ADD_CALLBACK_FUNCTION(Boutarel, function14);
+ ADD_CALLBACK_FUNCTION(Boutarel, function15);
+ ADD_CALLBACK_FUNCTION(Boutarel, function16);
+ ADD_CALLBACK_FUNCTION(Boutarel, function17);
+ ADD_CALLBACK_FUNCTION(Boutarel, function18);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter1);
+ ADD_CALLBACK_FUNCTION(Boutarel, function20);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Boutarel, function22);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter2);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Boutarel, function25);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter3);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Boutarel, function28);
+ ADD_CALLBACK_FUNCTION(Boutarel, function29);
+ ADD_CALLBACK_FUNCTION(Boutarel, function30);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter4);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Boutarel, function33);
+ ADD_CALLBACK_FUNCTION(Boutarel, function34);
+ ADD_CALLBACK_FUNCTION(Boutarel, function35);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter5);
+ ADD_CALLBACK_FUNCTION(Boutarel, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Boutarel, function38);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Boutarel, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Boutarel, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Boutarel, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(4, Boutarel, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SII(5, Boutarel, updatePosition, CarIndex, Position)
+ Entity::updatePosition(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(6, Boutarel, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(7, Boutarel, enterExitCompartment2, ObjectIndex)
+ Entity::enterExitCompartment(savepoint, kPosition_6470, kPosition_6130, kCarRedSleeping, kObjectCompartmentC, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Boutarel, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Boutarel, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Boutarel, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+
+ if (getInventory()->hasItem(kItemPassengerList) && getState()->time > kTime1089000)
+ getSound()->playSound(kEntityPlayer, "CAT1022");
+ else
+ getSound()->excuseMeCath();
+
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(11, Boutarel, function11, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(0, 1) && ENTITY_PARAM(0, 2)) {
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 1) = 0;
+
+ setCallback(5);
+ setup_callbackActionRestaurantOrSalon();
+ }
+ break;
+
+ case kActionDefault:
+ if (params->param1) {
+ if (getProgress().chapter == kChapter4) {
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(1);
+ setup_enterExitCompartment("607Hc", kObjectCompartmentC);
+ } else {
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(2);
+ setup_enterExitCompartment("607Dc", kObjectCompartmentC);
+ }
+ } else {
+ setCallback(3);
+ setup_enterExitCompartment("607Bc", kObjectCompartmentC);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 2:
+ case 3:
+ if (getCallback() == 2)
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ else
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ // Fallback to next case
+
+ case 1:
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityBoutarel, kEntityFrancois, kAction101107728);
+
+ setCallback(4);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 4:
+ getEntities()->clearSequences(kEntityBoutarel);
+ break;
+
+ case 5:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(6);
+ setup_draw("812US");
+ break;
+
+ case 6:
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ getSound()->playSound(kEntityBoutarel, "MRB1075", SoundManager::kFlagInvalid, 60);
+ break;
+
+ case kChapter3:
+ getSound()->playSound(kEntityBoutarel, "MRB3101");
+ break;
+ }
+
+ setCallback(7);
+ setup_enterTableWithMmeBoutarel();
+ break;
+
+ case 7:
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Boutarel, enterTableWithMmeBoutarel)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+ getSavePoints()->push(kEntityBoutarel, kEntityTables2, kAction136455232);
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityTables2, "008A3");
+ getEntities()->drawSequenceRight(kEntityMmeBoutarel, "008A2");
+ getEntities()->drawSequenceRight(kEntityBoutarel, "008A1");
+
+ if (getEntities()->isInSalon(kEntityPlayer)) {
+ getEntities()->updateFrame(kEntityBoutarel);
+ getEntityData(kEntityMmeBoutarel)->location = getData()->location;
+ getEntityData(kEntityTables2)->location = getData()->location;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Boutarel, leaveTableWithMmeBoutarel)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getSavePoints()->push(kEntityBoutarel, kEntityTables2, kActionDrawTablesWithChairs, "008F");
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityTables2, "008E3");
+ getEntities()->drawSequenceRight(kEntityMmeBoutarel, "008E2");
+ getEntities()->drawSequenceRight(kEntityBoutarel, "008E1");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(14, Boutarel, function14, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getSound()->playSound(kEntityBoutarel, "MRB1079");
+
+ setCallback(2);
+ setup_leaveTableWithMmeBoutarel();
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction326144276);
+ getEntities()->drawSequenceRight(kEntityBoutarel, "812DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityBoutarel);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ getEntityData(kEntityFrancois)->entityPosition = kPosition_540;
+ getEntityData(kEntityMmeBoutarel)->entityPosition = kPosition_540;
+ getData()->entityPosition = kPosition_540;
+
+ getEntityData(kEntityFrancois)->location = kLocationOutsideCompartment;
+ getEntityData(kEntityMmeBoutarel)->location = kLocationOutsideCompartment;
+
+ getEntities()->clearSequences(kEntityBoutarel);
+ getSavePoints()->push(kEntityBoutarel, kEntityMmeBoutarel, kAction100901266);
+
+ setCallback(4);
+ setup_updateFromTime(450);
+ break;
+
+ case 4:
+ getSavePoints()->push(kEntityBoutarel, kEntityFrancois, kAction100901266);
+
+ setCallback(5);
+ setup_updateFromTime(450);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 6:
+ setCallback(params->param1 ? 7: 8);
+ setup_enterExitCompartment2(params->param1 ? "607Gc" : "607Ac", kObjectCompartmentC);
+ break;
+
+ case 7:
+ case 8:
+ getEntities()->clearSequences(kEntityBoutarel);
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IS(15, Boutarel, function15, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (params->param1)
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(params->param1 ? 1 : 2);
+ setup_enterExitCompartment(params->param1 ? "607Dc" : "607Bc", kObjectCompartmentC);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(3);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_updatePosition(params->seq, kCarRestaurant, 52);
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Parameters:
+// bool
+// const char *
+IMPLEMENT_FUNCTION_IS(16, Boutarel, function16, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updatePosition((const char *)&params->seq, kCarRestaurant, 52);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 3:
+ setCallback(params->param1 ? 4 : 5);
+ setup_enterExitCompartment2(params->param1 ? "607Gc" : "607Ac", kObjectCompartmentC);
+ break;
+
+ case 4:
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityBoutarel);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IS(17, Boutarel, function17, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK_ACTION(params->param1, params->param6);
+
+ if (params->param5) {
+ UPDATE_PARAM(params->param7, getState()->timeTicks, 90)
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 51);
+ } else {
+ params->param7 = 0;
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, (char *)&params->seq);
+ break;
+
+ case kActionDrawScene:
+ params->param5 = (getEntities()->isPlayerPosition(kCarRestaurant, 52) ? 1 : 0);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(18, Boutarel, function18, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 < getState()->time && !params->param4) {
+ params->param4 = 1;
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param2) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+
+ params->param2 = 0;
+ params->param3 = 1;
+
+ getObjects()->update(kObjectCompartmentC, kEntityBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject50, kEntityBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param5 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentC, kEntityBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject50, kEntityBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param2) {
+ if (savepoint.param.intValue == 50) {
+ setCallback(4);
+ setup_playSound(getSound()->justAMinuteCath());
+ } else if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(5);
+ setup_playSound(rnd(2) ? "CAT1511" : getSound()->wrongDoorCath());
+ } else {
+ setCallback(6);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentC, kEntityBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param3 || params->param2) {
+ getObjects()->update(kObjectCompartmentC, kEntityBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param2 = 0;
+ params->param3 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound(rnd(2) ? "MRB1001" : "MRB1001A");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentC, kEntityBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject50, kEntityBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+
+ params->param2 = 1;
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ params->param2 = 0;
+ params->param3 = 1;
+ break;
+
+ case 7:
+ getSavePoints()->push(kEntityBoutarel, kEntityCoudert, kAction123199584);
+ break;
+
+ }
+ break;
+
+ case kAction122865568:
+ getSavePoints()->push(kEntityBoutarel, kEntityCoudert, kAction88652208);
+ break;
+
+ case kAction221683008:
+ setCallback(7);
+ setup_playSound("MRB1001");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Boutarel, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityBoutarel, kAction203520448, 0);
+ getSavePoints()->addData(kEntityBoutarel, kAction237889408, 1);
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject42, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getData()->entityPosition = kPosition_1750;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Boutarel, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1)
+ break;
+
+ if (!params->param2) {
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 4500)
+ setCallback(3);
+ setup_playSound("MRB1078A");
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+ TIME_CHECK_CALLBACK_1(kTime1138500, params->param4, 4, setup_function14, false);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function11(false);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "008B");
+
+ setCallback(2);
+ setup_playSound("MRB1076");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848);
+ break;
+
+ case 3:
+ TIME_CHECK_CALLBACK_1(kTime1138500, params->param4, 4, setup_function14, false);
+ break;
+
+ case 4:
+ getSavePoints()->push(kEntityBoutarel, kEntityCooks, kAction224849280);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction134466544:
+ params->param2 = 0;
+ break;
+
+ case kAction135854206:
+ params->param2 = 1;
+ break;
+
+ case kAction168717392:
+ params->param1 = 1;
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "008D");
+
+ if (!params->param2) {
+ setCallback(5);
+ setup_playSound("MRB1078");
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Boutarel, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function17(kTime1071000, "101A");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function16(false, "101B");
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function18(kTime1102500);
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 54) || getEntities()->isPlayerPosition(kCarRedSleeping, 44))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 10);
+
+ getEntities()->updatePositionExit(kEntityBoutarel, kCarRedSleeping, 54);
+ getEntities()->updatePositionExit(kEntityBoutarel, kCarRedSleeping, 44);
+
+ setCallback(4);
+ setup_playSound("MRB1074");
+ break;
+
+ case 4:
+ getEntities()->updatePositionExit(kEntityBoutarel, kCarRedSleeping, 54);
+ getEntities()->updatePositionExit(kEntityBoutarel, kCarRedSleeping, 44);
+
+ setCallback(5);
+ setup_function20();
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function18(kTimeEnterChalons);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function15(false, "102A");
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_function17(kTime1183500, "102B");
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_function16(false, "102C");
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_function18(kTime1215000);
+ break;
+
+ case 10:
+ setup_function22();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Boutarel, function22)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getEntities()->clearSequences(kEntityBoutarel);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Boutarel, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityBoutarel);
+
+ getData()->entityPosition = kPosition_4689;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Boutarel, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK_1(kTime1759500, params->param2, 1, setup_function14, false);
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "008D");
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isInRestaurant(kEntityPlayer) && !params->param1) {
+ getSound()->playSound(kEntityBoutarel, "MRB2001");
+ params->param1 = 1;
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function25();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Boutarel, function25)
+ if (savepoint.action == kActionDefault) {
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "510");
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Boutarel, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityBoutarel);
+
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Boutarel, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "510");
+ break;
+
+ case kAction122288808:
+ setup_function28();
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Boutarel, function28)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function11(true);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function29();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Boutarel, function29)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_PROC(params->param2, getState()->time, 450)
+ getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848);
+ UPDATE_PARAM_PROC_END
+
+ if (!params->param1)
+ break;
+
+ if (getEntities()->isInRestaurant(kEntityAnna)
+ && getEntities()->isInRestaurant(kEntityAugust)
+ && !getSound()->isBuffered(kEntityBoutarel)
+ && params->param3 != kTimeInvalid) {
+
+ if (getState()->time <= kTime1998000)
+ if (!getEntities()->isInRestaurant(kEntityPlayer) || !params->param3)
+ params->param3 = (uint)(getState()->time + 450);
+
+ if (params->param3 < getState()->time || getState()->time > kTime1998000) {
+ params->param3 = kTimeInvalid;
+
+ setCallback(1);
+ setup_playSound("MRB3102");
+ break;
+ }
+ }
+
+ TIME_CHECK_CALLBACK_1(kTime2002500, params->param4, 1, setup_function14, true);
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "008B");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ TIME_CHECK_CALLBACK_1(kTime2002500, params->param4, 1, setup_function14, true);
+ break;
+
+ case 2:
+ setup_function30();
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "008D");
+ params->param1 = 1;
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Boutarel, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "510");
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "510");
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Boutarel, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityBoutarel);
+
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Boutarel, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTime2367000, params->param1, setup_function33);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "510");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Boutarel, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1)
+ TIME_CHECK_CALLBACK_1(kTime2389500, params->param2, 3, setup_function14, false);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function11(true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "008B");
+
+ setCallback(2);
+ setup_updateFromTime(450);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848);
+ break;
+
+ case 3:
+ setup_function34();
+ break;
+ }
+ break;
+
+ case kAction122288808:
+ params->param1 = 1;
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "008D");
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Boutarel, function34)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTime2470500, params->param1, setup_function35);
+
+ if (getState()->time > kTime2457000 && getEvent(kEventAugustDrink)) {
+ getSavePoints()->push(kEntityBoutarel, kEntityAbbot, kAction159003408);
+
+ setCallback(1);
+ setup_function15(false, "102A");
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityBoutarel, kEntityAbbot, kAction101687594);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function17(kTime2479500, "102B");
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function16(false, "102C");
+ break;
+
+ case 3:
+ case 7:
+ setup_function35();
+ break;
+
+ case 4:
+ case 8:
+ if (getState()->time >= kTime2470500) {
+ setup_function35();
+ break;
+ }
+
+ if (getEvent(kEventAugustDrink)) {
+ setCallback(5);
+ setup_function15(false, "102A");
+ } else {
+ setCallback(8);
+ setup_function18((TimeValue)(getState()->time + 900));
+ }
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function17(kTime2479500, "102B");
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function16(false, "102C");
+ break;
+
+ case 9:
+ getSavePoints()->push(kEntityBoutarel, kEntityCoudert, kAction123199584);
+ break;
+ }
+ break;
+
+ case kAction122865568:
+ getSavePoints()->push(kEntityBoutarel, kEntityCoudert, kAction88652208);
+ break;
+
+ case kAction125039808:
+ setCallback(4);
+ setup_function18(kTime2457000);
+ break;
+
+ case kAction221683008:
+ setCallback(9);
+ setup_playSound("Mrb1001");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Boutarel, function35)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->clearSequences(kEntityBoutarel);
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Boutarel, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityBoutarel);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Boutarel, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function38();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Boutarel, function38)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(39, Boutarel)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/boutarel.h b/engines/lastexpress/entities/boutarel.h
new file mode 100644
index 0000000000..0ac051df77
--- /dev/null
+++ b/engines/lastexpress/entities/boutarel.h
@@ -0,0 +1,188 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_BOUTAREL_H
+#define LASTEXPRESS_BOUTAREL_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Boutarel : public Entity {
+public:
+ Boutarel(LastExpressEngine *engine);
+ ~Boutarel() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence1, CarIndex car, Position position)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION_1(function11, bool)
+ DECLARE_FUNCTION(enterTableWithMmeBoutarel)
+ DECLARE_FUNCTION(leaveTableWithMmeBoutarel)
+ DECLARE_FUNCTION_1(function14, bool)
+ DECLARE_FUNCTION_2(function15, bool, const char *sequence)
+ DECLARE_FUNCTION_2(function16, bool, const char *sequence)
+ DECLARE_FUNCTION_2(function17, TimeValue timeValue, const char *sequence)
+ DECLARE_FUNCTION_1(function18, TimeValue timeValue)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+ DECLARE_FUNCTION(function20)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function22)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function25)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function28)
+ DECLARE_FUNCTION(function29)
+ DECLARE_FUNCTION(function30)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(function34)
+ DECLARE_FUNCTION(function35)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function38)
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_BOUTAREL_H
diff --git a/engines/lastexpress/entities/chapters.cpp b/engines/lastexpress/entities/chapters.cpp
new file mode 100644
index 0000000000..a057da23d3
--- /dev/null
+++ b/engines/lastexpress/entities/chapters.cpp
@@ -0,0 +1,1820 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/chapters.h"
+
+#include "lastexpress/entities/abbot.h"
+#include "lastexpress/entities/alexei.h"
+#include "lastexpress/entities/alouan.h"
+#include "lastexpress/entities/anna.h"
+#include "lastexpress/entities/august.h"
+#include "lastexpress/entities/boutarel.h"
+#include "lastexpress/entities/coudert.h"
+#include "lastexpress/entities/cooks.h"
+#include "lastexpress/entities/francois.h"
+#include "lastexpress/entities/gendarmes.h"
+#include "lastexpress/entities/hadija.h"
+#include "lastexpress/entities/ivo.h"
+#include "lastexpress/entities/kahina.h"
+#include "lastexpress/entities/kronos.h"
+#include "lastexpress/entities/mahmud.h"
+#include "lastexpress/entities/max.h"
+#include "lastexpress/entities/mertens.h"
+#include "lastexpress/entities/milos.h"
+#include "lastexpress/entities/mmeboutarel.h"
+#include "lastexpress/entities/pascale.h"
+#include "lastexpress/entities/rebecca.h"
+#include "lastexpress/entities/salko.h"
+#include "lastexpress/entities/servers0.h"
+#include "lastexpress/entities/servers1.h"
+#include "lastexpress/entities/sophie.h"
+#include "lastexpress/entities/tatiana.h"
+#include "lastexpress/entities/vassili.h"
+#include "lastexpress/entities/verges.h"
+#include "lastexpress/entities/vesna.h"
+#include "lastexpress/entities/yasmin.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/menu.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+Chapters::Chapters(LastExpressEngine *engine) : Entity(engine, kEntityChapters) {
+ ADD_CALLBACK_FUNCTION(Chapters, savegame);
+ ADD_CALLBACK_FUNCTION(Chapters, enterStation);
+ ADD_CALLBACK_FUNCTION(Chapters, exitStation);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter1);
+ ADD_CALLBACK_FUNCTION(Chapters, resetMainEntities);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter1End);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter1Init);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter1Next);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter2);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter2Init);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter3);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter3Init);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Chapters, viennaEvents);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter4);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter4Init);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter5);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter4Init);
+ ADD_CALLBACK_FUNCTION(Chapters, chapter4Handler);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(1, Chapters, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(2, Chapters, enterStation, CityIndex)
+ enterExitStation(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Chapters, exitStation)
+ enterExitStation(savepoint, false);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Chapters, chapter1)
+ if (savepoint.action == kActionDefault) {
+ getSavePoints()->addData(kEntityChapters, kAction171843264, 0);
+ setup_chapter1Init();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Chapters, resetMainEntities)
+ if (savepoint.action != kActionDefault)
+ return;
+
+ RESET_ENTITY_STATE(kEntityAbbot, Abbot, setup_reset);
+ RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_reset);
+ RESET_ENTITY_STATE(kEntityAlouan, Alouan, setup_reset);
+ RESET_ENTITY_STATE(kEntityAnna, Anna, setup_reset);
+ RESET_ENTITY_STATE(kEntityAugust, August, setup_reset);
+ RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_reset);
+ RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_reset);
+ RESET_ENTITY_STATE(kEntityFrancois, Francois, setup_reset);
+ RESET_ENTITY_STATE(kEntityHadija, Hadija, setup_reset);
+ RESET_ENTITY_STATE(kEntityIvo, Ivo, setup_reset);
+ RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_reset);
+ RESET_ENTITY_STATE(kEntityMmeBoutarel, MmeBoutarel, setup_reset);
+ RESET_ENTITY_STATE(kEntityMahmud, Mahmud, setup_reset);
+ RESET_ENTITY_STATE(kEntityMax, Max, setup_reset);
+ RESET_ENTITY_STATE(kEntityMilos, Milos, setup_reset);
+ RESET_ENTITY_STATE(kEntityBoutarel, Boutarel, setup_reset);
+ RESET_ENTITY_STATE(kEntityGendarmes, Gendarmes, setup_reset);
+ RESET_ENTITY_STATE(kEntityRebecca, Rebecca, setup_reset);
+ RESET_ENTITY_STATE(kEntitySalko, Salko, setup_reset);
+ RESET_ENTITY_STATE(kEntitySophie, Sophie, setup_reset);
+ RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_reset);
+ RESET_ENTITY_STATE(kEntityVerges, Verges, setup_reset);
+ RESET_ENTITY_STATE(kEntityVassili, Vassili, setup_reset);
+ RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_reset);
+ RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_reset);
+
+ CALLBACK_ACTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Chapters, chapter1End)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ getSound()->playSound(kEntityChapters, "MUS0009", SoundManager::kFlagDefault);
+ break;
+
+ case kActionKnock:
+ if (!getSound()->isBuffered("LIB012", true))
+ getSound()->playSound(kEntityPlayer, "LIB012");
+ break;
+
+ case kActionOpenDoor:
+ if (params->param1) {
+ getEntities()->clearSequences(kEntityChapters);
+ getSound()->processEntry(kEntityChapters);
+ getSound()->playSound(kEntityPlayer, "LIB014");
+ getSound()->resetState();
+
+ ENTITY_PARAM(0, 4) = 7;
+
+ getSound()->playSteam(kCityPolice);
+
+ getAction()->playAnimation(kEventCathDream);
+
+ getState()->timeDelta = 3;
+ getProgress().field_18 = 1;
+ getProgress().field_84 = 0;
+
+ getObjects()->update(kObject63, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getScenes()->loadScene(kScene41);
+
+ CALLBACK_ACTION();
+ } else {
+ getSound()->playSound(kEntityPlayer, "LIB014");
+ getSound()->playSound(kEntityPlayer, "LIB015", SoundManager::kFlagDefault, 15);
+
+ if (!getSound()->isBuffered(kEntityChapters))
+ getSound()->playSound(kEntityChapters, "MUS009", SoundManager::kFlagDefault);
+
+ getScenes()->loadSceneFromPosition(kCarLocomotive, 38);
+
+ getObjects()->update(kObject63, kEntityChapters, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ params->param1 = 1;
+ }
+ break;
+
+ case kActionDefault:
+ RESET_ENTITY_STATE(kEntityPascale, Pascale, setup_function19);
+ RESET_ENTITY_STATE(kEntityServers0, Servers0, setup_function22);
+ RESET_ENTITY_STATE(kEntityServers1, Servers1, setup_function16);
+ RESET_ENTITY_STATE(kEntityCooks, Cooks, setup_function7);
+
+ RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_function42);
+ RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_chapter1Handler);
+ RESET_ENTITY_STATE(kEntityVerges, Verges, setup_chapter1Handler);
+
+ getSavePoints()->push(kEntityChapters, kEntityMertens, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954);
+
+ RESET_ENTITY_STATE(kEntityKronos, Kronos, setup_function10);
+ RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function13);
+ RESET_ENTITY_STATE(kEntityAnna, Anna, setup_function34);
+ RESET_ENTITY_STATE(kEntityAugust, August, setup_function34);
+ RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function24);
+ RESET_ENTITY_STATE(kEntityVassili, Vassili, setup_function7);
+ RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_function26);
+ RESET_ENTITY_STATE(kEntityMilos, Milos, setup_function18);
+ RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_function15);
+ RESET_ENTITY_STATE(kEntityIvo, Ivo, setup_function17);
+ RESET_ENTITY_STATE(kEntitySalko, Salko, setup_function11);
+ RESET_ENTITY_STATE(kEntityFrancois, Francois, setup_function20);
+ RESET_ENTITY_STATE(kEntityMmeBoutarel, MmeBoutarel, setup_function16);
+ RESET_ENTITY_STATE(kEntityBoutarel, Boutarel, setup_function22);
+ RESET_ENTITY_STATE(kEntityRebecca, Rebecca, setup_function27);
+ RESET_ENTITY_STATE(kEntitySophie, Sophie, setup_function5);
+ RESET_ENTITY_STATE(kEntityMahmud, Mahmud, setup_resetChapter);
+ RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_function10);
+ RESET_ENTITY_STATE(kEntityHadija, Hadija, setup_function12);
+ RESET_ENTITY_STATE(kEntityHadija, Alouan, setup_function12);
+
+ if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
+ getSound()->removeFromQueue(kEntityChapters);
+
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ }
+
+ getSound()->processEntries();
+
+ if (getSound()->isBuffered("CON1505"))
+ getSound()->processEntry("CON1505");
+
+ if (getSound()->isBuffered("AUG1057"))
+ getSound()->processEntry("AUG1057");
+
+ if (getSound()->isBuffered("ZFX1005"))
+ getSound()->processEntry("ZFX1005");
+
+ if (getSound()->isBuffered("ZFX1006"))
+ getSound()->processEntry("ZFX1006");
+
+ if (getSound()->isBuffered("ZFX1007"))
+ getSound()->processEntry("ZFX1007");
+
+ if (getSound()->isBuffered("ZFX1007A"))
+ getSound()->processEntry("ZFX1007A");
+
+ if (getSound()->isBuffered("ZFX1007B"))
+ getSound()->processEntry("ZFX1007B");
+
+
+ getSound()->playSound(kEntityPlayer, "MUS008", SoundManager::kFlagDefault);
+ getInventory()->unselectItem();
+
+ // FIXME add event pump ?
+ while (getSound()->isBuffered("MUS008"))
+ getSound()->updateQueue();
+
+ getProgress().field_84 = true;
+
+ getScenes()->loadSceneFromPosition(kCarLocomotive, 75);
+ getInventory()->show();
+
+ getState()->time = kTime1492200;
+ getProgress().field_18 = 4;
+ getState()->timeDelta = 0;
+
+ getObjects()->update(kObject63, kEntityChapters, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
+
+ getProgress().isTrainRunning = false;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kAction225358684:
+ params->param2++;
+
+ if (params->param2 >= 3) {
+
+ if (!getSound()->isBuffered("LIB031", true))
+ getSound()->playSound(kEntityPlayer, "LIB031");
+
+ if (params->param2 == 3) {
+ getData()->car = kCarGreenSleeping;
+ getEntities()->drawSequenceLeft(kEntityChapters, "JUGL");
+ }
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Chapters, chapter1Init)
+ if (savepoint.action != kActionDefault)
+ return;
+
+ getProgress().chapter = kChapter1;
+ getSound()->resetState();
+
+ getState()->time = kTimeChapter1;
+ getState()->timeDelta = 0;
+ getProgress().isTrainRunning = true;
+ getProgress().portrait = kPortraitOriginal;
+ getProgress().field_18 = 1;
+
+ // Setup inventory & items location
+ getInventory()->addItem(kItemTelegram);
+ getInventory()->addItem(kItemArticle);
+
+ getInventory()->setLocationAndProcess(kItemScarf, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItemParchemin, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItemGreenJacket, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItemCorpse, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItemPassengerList, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItem5, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItem7, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItemMatch, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItem22, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItemPaper, kObjectLocation1);
+
+ getProgress().field_7C = 1;
+
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ for (uint i = kObjectCompartment1; i <= kObjectCompartment8; i++) {
+ getObjects()->updateLocation2((ObjectIndex)i, kObjectLocation2);
+ }
+
+ for (uint i = kObjectCompartmentA; i <= kObjectCompartmentH; i++) {
+ getObjects()->updateLocation2((ObjectIndex)i, kObjectLocation2);
+ }
+
+ params->param1 = 40;
+
+ getObjects()->updateLocation2(kObject25, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectTrainTimeTable, kObjectLocation1);
+ getObjects()->updateLocation2(kObject98, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectRestaurantCar, kObjectLocation1);
+
+ getObjects()->update(kObject25, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObjectTrainTimeTable, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObjectRedSleepingCar, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject28, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject56, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject54, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObjectRestaurantCar, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject59, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject66, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject64, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject65, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject69, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObject98, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHandKnock);
+ getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHandKnock);
+ getObjects()->update(kObject101, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setup_chapter1Handler();
+}
+
+//////////////////////////////////////////////////////////////////////////
+#define PLAY_STEAM() { \
+ getSound()->resetState(); \
+ getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4)); \
+ ENTITY_PARAM(0, 2) = 0; \
+ }
+
+IMPLEMENT_FUNCTION(8, Chapters, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getProgress().isTrainRunning || getState()->time >= kTime1458000)
+ goto label_processStations;
+
+ UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, params->param2)
+ // Play sound FX
+ getSound()->playLocomotiveSound();
+
+ params->param2 = 225 * (4 * rnd(5) + 20);
+ params->param6 = 0;
+ UPDATE_PARAM_PROC_END
+
+label_processStations:
+ // Process stations
+ TIME_CHECK_CALLBACK_2(kTime1039500, params->param7, 1, setup_savegame, kSavegameTypeTime, kTimeNone);
+
+label_enter_epernay:
+ // Entering Epernay station
+ TIME_CHECK_CALLBACK_2(kTimeEnterEpernay, params->param8, 1, setup_enterStation, "Epernay", kCityEpernay);
+
+label_exit_epernay:
+ // Exiting Epernay station
+ if (getState()->time > kTimeExitEpernay && !CURRENT_PARAM(1, 1)) {
+ CURRENT_PARAM(1, 1) = 1;
+ params->param4 = 1;
+ setCallback(3);
+ setup_exitStation("Epernay");
+ break;
+ }
+
+label_epernay_police:
+ if (params->param5 && !ENTITY_PARAM(0, 2)) {
+ setCallback(4);
+ setup_exitStation("Unschedu");
+ break;
+ }
+
+label_enter_chalons:
+ if (getState()->time > kTimeEnterChalons && !CURRENT_PARAM(1, 2)) {
+ CURRENT_PARAM(1, 2) = 1;
+ getProgress().field_18 = 2;
+ }
+
+ // Skip to callback 18 checks
+ if (params->param1)
+ goto label_exit_strasbourg;
+
+ // Entering Chalons station
+ TIME_CHECK_CALLBACK_2(kTimeEnterChalons, CURRENT_PARAM(1, 3), 5, setup_enterStation, "Chalons", kCityChalons);
+
+label_exit_chalons:
+ // Exiting Chalons station
+ TIME_CHECK_CALLBACK_1(kTimeExitChalons, CURRENT_PARAM(1, 4), 6, setup_exitStation, "Chalons");
+
+label_enter_barleduc:
+ // Entering Bar-Le-Duc station
+ TIME_CHECK_CALLBACK_2(kTimeCityBarLeDuc, CURRENT_PARAM(1, 5), 7, setup_enterStation, "BarLeDuc", kCityBarleduc);
+
+label_exit_barleduc:
+ // Exiting Bar-Le-Duc station
+ TIME_CHECK_CALLBACK_1(kTimeExitBarLeDuc, CURRENT_PARAM(1, 6), 8, setup_exitStation, "BarLeDuc");
+
+label_enter_nancy:
+ if (getState()->time > kTime1260000 && !CURRENT_PARAM(1, 7)) {
+ CURRENT_PARAM(1, 7) = 1;
+ getState()->timeDelta = 1;
+ }
+
+ // Entering Nancy station
+ TIME_CHECK_CALLBACK_2(kTimeCityNancy, CURRENT_PARAM(1, 8), 9, setup_enterStation, "Nancy", kCityNancy);
+
+label_exit_nancy:
+ // Exiting Nancy station
+ TIME_CHECK_CALLBACK_1(kTimeExitNancy, CURRENT_PARAM(2, 1), 10, setup_exitStation, "Nancy");
+
+label_enter_luneville:
+ // Entering Luneville station
+ TIME_CHECK_CALLBACK_2(kTimeCityLuneville, CURRENT_PARAM(2, 2), 11, setup_enterStation, "Luneville", kCityLuneville);
+
+label_exit_luneville:
+ // Exiting Luneville station
+ TIME_CHECK_CALLBACK_1(kTimeExitLuneville, CURRENT_PARAM(2, 3), 12, setup_exitStation, "Luneville");
+
+label_enter_avricourt:
+ // Entering Avricourt station
+ TIME_CHECK_CALLBACK_2(kTimeCityAvricourt, CURRENT_PARAM(2, 4), 13, setup_enterStation, "Avricourt", kCityAvricourt);
+
+label_exit_avricourt:
+ // Exiting Avricourt station
+ TIME_CHECK_CALLBACK_1(kTimeExitAvricourt, CURRENT_PARAM(2, 5), 14, setup_exitStation, "Avricourt");
+
+label_enter_deutschavricourt:
+ // Entering Deutsch-Avricourt station
+ TIME_CHECK_CALLBACK_2(kTimeCityDeutschAvricourt, CURRENT_PARAM(2, 6), 15, setup_enterStation, "DeutschA", kCityDeutschAvricourt);
+
+label_exit_deutschavricourt:
+ // Exiting Avricourt station
+ TIME_CHECK_CALLBACK_1(kTimeExitDeutschAvricourt, CURRENT_PARAM(2, 7), 16, setup_exitStation, "DeutschA");
+
+label_enter_strasbourg:
+ TIME_CHECK_CALLBACK_2(kTimeCityStrasbourg, CURRENT_PARAM(2, 8), 17, setup_savegame, kSavegameTypeTime, kTimeNone);
+
+label_exit_strasbourg:
+ // Exiting Strasbourg station
+ TIME_CHECK_CALLBACK_1(kTimeExitStrasbourg, CURRENT_PARAM(3, 1), 19, setup_exitStation, "Strasbou");
+
+label_enter_badenoos:
+ // Entering Baden Oos station
+ TIME_CHECK_CALLBACK_2(kTimeCityBadenOos, CURRENT_PARAM(3, 2), 20, setup_enterStation, "BadenOos", kCityBadenOos);
+
+label_exit_badenoos:
+ // Exiting Baden Oos station
+ TIME_CHECK_CALLBACK_1(kTimeExitBadenOos, CURRENT_PARAM(3, 3), 21, setup_exitStation, "BadenOos");
+
+label_chapter1_next:
+ if (getState()->time > kTimeChapter1End3 && ! CURRENT_PARAM(3, 4)) {
+ CURRENT_PARAM(3, 4) = 1;
+ setup_chapter1Next();
+ }
+ break;
+
+ case kActionEndSound:
+ if (ENTITY_PARAM(0, 2)) {
+
+ getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
+
+ if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) {
+ PLAY_STEAM();
+ break;
+ }
+
+ if (getEntities()->isOutsideAlexeiWindow()) {
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+ PLAY_STEAM();
+ break;
+ }
+
+ if (getEntities()->isOutsideAnnaWindow()) {
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+ PLAY_STEAM();
+ break;
+ }
+
+ CarIndex car = getEntityData(kEntityPlayer)->car;
+ if (car < kCarRedSleeping || car > kCarCoalTender) {
+ if (car < kCarBaggageRear || car > kCarGreenSleeping) {
+ PLAY_STEAM();
+ break;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
+ PLAY_STEAM();
+ break;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
+ PLAY_STEAM();
+ break;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
+ PLAY_STEAM();
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 3)) {
+ getSound()->resetState();
+ ENTITY_PARAM(0, 3) = 0;
+
+ if (params->param4) {
+ getSavePoints()->push(kEntityChapters, getProgress().field_24 ? kEntityVerges : kEntityMertens, getProgress().field_24 ? kAction168187490 : kAction224122407);
+ params->param4 = 0;
+ }
+ }
+ break;
+
+ case kActionDefault:
+ params->param2 = 225 * (4 * rnd(5) + 20);
+ break;
+
+ case kActionDrawScene:
+ if (!params->param3) {
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 1)) {
+ getState()->time = kTimeChapter1;
+ getState()->timeDelta = 3;
+ params->param3 = 1;
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_enter_epernay;
+
+ case 2:
+ goto label_exit_epernay;
+
+ case 3:
+ goto label_epernay_police;
+
+ case 4:
+ params->param5 = 0;
+ goto label_enter_chalons;
+
+ case 5:
+ goto label_exit_chalons;
+
+ case 6:
+ goto label_enter_barleduc;
+
+ case 7:
+ goto label_exit_barleduc;
+
+ case 8:
+ goto label_enter_nancy;
+
+ case 9:
+ goto label_exit_nancy;
+
+ case 10:
+ goto label_enter_luneville;
+
+ case 11:
+ goto label_exit_luneville;
+
+ case 12:
+ goto label_enter_avricourt;
+
+ case 13:
+ goto label_exit_avricourt;
+
+ case 14:
+ goto label_enter_deutschavricourt;
+
+ case 15:
+ goto label_exit_deutschavricourt;
+
+ case 16:
+ getState()->time = kTimeEnterStrasbourg;
+ goto label_enter_strasbourg;
+
+ case 17:
+ getProgress().field_18 = 1;
+ setCallback(18);
+ setup_enterStation("Strasbou", kCityStrasbourg);
+ break;
+
+ case 18:
+ goto label_exit_strasbourg;
+
+ case 19:
+ getState()->timeDelta = 1;
+ goto label_enter_badenoos;
+
+ case 20:
+ goto label_exit_badenoos;
+
+ case 21:
+ goto label_chapter1_next;
+
+ case 22:
+ params->param5 = 1;
+ break;
+
+ case 23:
+ params->param1 = 1;
+ break;
+ }
+ break;
+
+ case kAction169629818:
+ setCallback(22);
+ setup_enterStation("Unschedu", kCityPolice);
+ break;
+
+ case kActionEndChapter:
+ getProgress().field_18 = 3;
+
+ if (getState()->time >= kTimeChapter1End) {
+ setup_chapter1Next();
+ } else {
+ setCallback(23);
+ setup_chapter1End();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Chapters, chapter1Next)
+ if (savepoint.action == kActionDefault) {
+ // Reset sound cache
+ if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
+ getSound()->removeFromQueue(kEntityChapters);
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ }
+
+ getSound()->playSound(kEntityPlayer, "MUS008", SoundManager::kFlagDefault);
+ getInventory()->unselectItem();
+
+ while (getSound()->isBuffered("MUS008"))
+ getSound()->updateQueue();
+
+ setup_chapter2();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Chapters, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ // Setup for chapter 2 in case it hasn't been done before
+ if (getProgress().chapter != kChapter2) {
+ getProgress().chapter = kChapter2;
+ getEntities()->setupChapter(kChapter2);
+ }
+
+ // Set game time & delta
+ getState()->time = kTimeChapter2;
+ getState()->timeDelta = 5;
+
+ // Save game
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (!_engine->getResourceManager()->loadArchive(kArchiveCd2)) {
+ getMenu()->show(false, kSavegameTypeIndex, 0);
+ return;
+ }
+
+ // Load scene data
+ getScenes()->loadSceneDataFile(kArchiveCd2);
+ setup_chapter2Init();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Chapters, chapter2Init)
+ if (savepoint.action != kActionDefault)
+ return;
+
+ getProgress().eventCorpseMovedFromFloor = true;
+ getProgress().field_18 = 1;
+ getProgress().isTrainRunning = true;
+ getProgress().eventCorpseFound = true;
+
+ // Switch to green jacket/portrait
+ getProgress().jacket = kJacketGreen;
+ getProgress().portrait = kPortraitGreen;
+
+ // Setup inventory & items location
+ getInventory()->addItem(kItemGreenJacket);
+
+ getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
+
+ getInventory()->setLocationAndProcess(kItemBeetle, kObjectLocation3);
+ getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
+
+ for (uint i = 1; i < 9; i++) {
+ getObjects()->updateLocation2((ObjectIndex)i, kObjectLocation2);
+ }
+
+ for (uint i = 33; i < 40; i++) {
+ getObjects()->updateLocation2((ObjectIndex)i, kObjectLocation2);
+ }
+
+ params->param1 = 40;
+
+ getSavePoints()->push(kEntityChapters, kEntityTables0, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables1, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables2, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables3, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables4, kActionDrawTablesWithChairs);
+
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ // Reset sound cache
+ if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
+ getSound()->removeFromQueue(kEntityChapters);
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ }
+
+ getAction()->playAnimation(kEventTrainPassing);
+
+ if (getInventory()->hasItem(kItemScarf))
+ getScenes()->loadScene(kScene41);
+ else
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 79);
+
+ setup_chapter2Handler();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Chapters, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getProgress().isTrainRunning)
+ break;
+
+ UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1);
+
+ getSound()->playLocomotiveSound();
+
+ params->param1 = 225 * (4 * rnd(5) + 20);
+ params->param2 = 0;
+ break;
+
+ case kActionDefault:
+ params->param1 = 225 * (4 * rnd(5) + 20);
+ break;
+
+ case kActionChapter3:
+ setup_chapter3();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Chapters, chapter3)
+ if (savepoint.action == kActionDefault) {
+ // Setup for chapter 3 in case it hasn't been done before
+ if (getProgress().chapter != kChapter3) {
+ getProgress().chapter = kChapter3;
+ getEntities()->setupChapter(kChapter3);
+ }
+
+ // Set game time & delta
+ getState()->time = kTimeChapter3;
+ getState()->timeDelta = 5;
+
+ setup_chapter3Init();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Chapters, chapter3Init)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityChapters, kEntityTables0, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables1, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables2, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables3, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables4, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables5, kActionDrawTablesWithChairs);
+
+ getProgress().isTrainRunning = true;
+
+ getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
+ getInventory()->setLocationAndProcess(kItemBriefcase, kObjectLocation1);
+ getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartment1, kObjectLocation2);
+ getObjects()->update(kObject107, kEntityPlayer, kObjectLocation3, kCursorKeepValue, kCursorKeepValue);
+
+ if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
+ getSound()->removeFromQueue(kEntityChapters);
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 60);
+ getInventory()->show();
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_chapter3Handler();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Chapters, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().isTrainRunning) {
+ UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, params->param1)
+ getSound()->playLocomotiveSound();
+
+ params->param1 = 225 * (4 * rnd(5) + 20);
+ params->param4 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ UPDATE_PARAM_PROC(params->param5, getState()->timeTicks, params->param2)
+ switch (rnd(2)) {
+ default:
+ break;
+
+ case 0:
+ getSound()->playSound(kEntityPlayer, "ZFX1008", (SoundManager::FlagType)(rnd(15) + 2));
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityPlayer, "ZFX1009", (SoundManager::FlagType)(rnd(15) + 2));
+ break;
+ }
+
+ params->param2 = 225 * (4 * rnd(6) + 8);
+ params->param5 = 0;
+ UPDATE_PARAM_PROC_END
+
+ TIME_CHECK_CALLBACK_2(kTimeEnterSalzbourg, params->param6, 1, setup_enterStation, "Salzburg", kCitySalzbourg);
+
+label_callback_1:
+ TIME_CHECK_CALLBACK_1(kTimeExitSalzbourg, params->param7, 2, setup_exitStation, "Salzburg");
+
+label_callback_2:
+ TIME_CHECK_CALLBACK_2(kTimeEnterAttnangPuchheim, params->param8, 3, setup_enterStation, "Attnang", kCityAttnangPuchheim);
+
+label_callback_3:
+ TIME_CHECK_CALLBACK_1(kTimeExitAttnangPuchheim, CURRENT_PARAM(1, 1), 4, setup_exitStation, "Attnang");
+
+label_callback_4:
+ TIME_CHECK_CALLBACK_2(kTimeEnterWels, CURRENT_PARAM(1, 2), 5, setup_enterStation, "Wels", kCityWels);
+
+label_callback_5:
+ TIME_CHECK_CALLBACK_1(kTimeEnterWels, CURRENT_PARAM(1, 3), 6, setup_exitStation, "Wels");
+
+label_callback_6:
+ TIME_CHECK_CALLBACK_2(kTimeEnterLinz, CURRENT_PARAM(1, 4), 7, setup_enterStation, "Linz", kCityLinz);
+
+label_callback_7:
+ TIME_CHECK_CALLBACK_1(kTimeCityLinz, CURRENT_PARAM(1, 5), 8, setup_exitStation, "Linz");
+
+label_callback_8:
+ if (getState()->time > kTime2187000 && !CURRENT_PARAM(1, 6)) {
+ CURRENT_PARAM(1, 6) = 1;
+ getState()->timeDelta = 5;
+ }
+
+ TIME_CHECK_CALLBACK_2(kTimeCityVienna, CURRENT_PARAM(1, 7), 9, setup_enterStation, "Vienna", kCityVienna);
+ break;
+
+ case kActionEndSound:
+ if (ENTITY_PARAM(0, 2)) {
+ getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
+
+ if (getEntityData(kEntityPlayer)->location == kLocationOutsideTrain) {
+
+ if (getEntities()->isOutsideAlexeiWindow()) {
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+ } else if (getEntities()->isOutsideAnnaWindow()) {
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+ } else {
+ CarIndex car = getEntityData(kEntityPlayer)->car;
+
+ if (car < kCarRedSleeping || car > kCarCoalTender) {
+ if (car >= kCarBaggageRear && car <= kCarGreenSleeping) {
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
+ } else {
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
+ }
+ }
+ } else {
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
+ }
+ }
+ }
+
+ getSound()->resetState();
+ getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4));
+
+ ENTITY_PARAM(0, 2) = 0;
+ if (params->param1)
+ setup_viennaEvents();
+
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 3)) {
+ getSound()->resetState();
+ ENTITY_PARAM(0, 3) = 0;
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 225 * (4 * rnd(5) + 20);
+ params->param2 = 225 * (4 * rnd(6) + 8);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+
+ case 8:
+ goto label_callback_8;
+
+ case 9:
+ params->param3 = 1;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Chapters, viennaEvents)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventViennaAugustUnloadGuns);
+ if (getEvent(kEventConcertLeaveWithBriefcase))
+ getLogic()->gameOver(kSavegameTypeTime, kTime2187000, kSceneNone, true);
+ else if (getEvent(kEventCathJumpDownCeiling))
+ getLogic()->gameOver(kSavegameTypeEvent, kEventCathJumpDownCeiling, kSceneNone, true);
+ else
+ getLogic()->gameOver(kSavegameTypeTime, kTime2155500, kSceneNone, true);
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventViennaKronosFirebird);
+ if (getEvent(kEventKronosBringEggCeiling))
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventKronosBringEggCeiling, kSceneGameOverVienna1, true);
+ else if (getEvent(kEventKronosBringEgg)) {
+ if (getEvent(kEventKronosBringEggCeiling))
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventKronosBringEggCeiling, kSceneGameOverVienna1, true);
+ else
+ getLogic()->gameOver(kSavegameTypeTime, kTime2155500, kSceneGameOverVienna1, true);
+ } else {
+ if (getProgress().field_C0) {
+ if (getEvent(kEventKronosReturnBriefcase))
+ getLogic()->gameOver(kSavegameTypeTime, getProgress().field_C0, kSceneGameOverVienna2, true);
+ else
+ getLogic()->gameOver(kSavegameTypeTime, kTime2155500, kSceneGameOverVienna2, true);
+ } else {
+ if (getEvent(kEventKronosReturnBriefcase))
+ getLogic()->gameOver(kSavegameTypeEvent, kEventKronosReturnBriefcase, kSceneGameOverVienna, true);
+ else
+ getLogic()->gameOver(kSavegameTypeTime, kTime2155500, kSceneGameOverVienna, true);
+ }
+ }
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventVergesAnnaDead);
+ getLogic()->gameOver(kSavegameTypeTime, kTime2250000, kSceneGameOverAnnaDied, true);
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventViennaContinueGame);
+ setup_chapter4();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Chapters, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ // Setup for chapter 4 in case it hasn't been done before
+ if (getProgress().chapter != kChapter4) {
+ getProgress().chapter = kChapter4;
+ getEntities()->setupChapter(kChapter4);
+ }
+
+ // Set game time & delta
+ getState()->time = kTimeChapter4;
+ getState()->timeDelta = 5;
+
+ // Save game
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (!_engine->getResourceManager()->loadArchive(kArchiveCd3)) {
+ getMenu()->show(false, kSavegameTypeIndex, 0);
+ return;
+ }
+
+ // Load scene data
+ getScenes()->loadSceneDataFile(kArchiveCd3);
+ setup_chapter4Init();
+ }
+ break;
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Chapters, chapter4Init)
+ if (savepoint.action != kActionDefault)
+ return;
+
+ getSound()->processEntries();
+ getSound()->resetState();
+
+ getProgress().isTrainRunning = true;
+
+ getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
+
+ getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStartRunning);
+ getSavePoints()->push(kEntityChapters, kEntityTables0, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables1, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables2, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables3, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables4, kActionDrawTablesWithChairs);
+ getSavePoints()->push(kEntityChapters, kEntityTables5, kActionDrawTablesWithChairs);
+
+ getScenes()->loadSceneFromItemPosition(kItem3);
+
+ getInventory()->setLocationAndProcess(kItemBomb, kObjectLocation1);
+
+ if (getInventory()->get(kItemBeetle)->location == kObjectLocation3)
+ getScenes()->loadSceneFromItemPosition(kItemBeetle);
+
+ getObjects()->updateLocation2(kObject25, kObjectLocation2);
+ getObjects()->update(kObject107, kEntityPlayer, kObjectLocation3, kCursorKeepValue, kCursorKeepValue);
+
+ if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
+ getSound()->removeFromQueue(kEntityChapters);
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ }
+
+ if (getInventory()->hasItem(kItemFirebird))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 76);
+ else
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 69);
+
+ getInventory()->show();
+ setup_chapter4Handler();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Chapters, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().isTrainRunning) {
+ UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, params->param4);
+ getSound()->playLocomotiveSound();
+
+ params->param4 = 225 * (4 * rnd(5) + 20);
+ params->param6 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ UPDATE_PARAM_PROC(params->param7, getState()->timeTicks, params->param5)
+ switch (rnd(2)) {
+ default:
+ break;
+
+ case 0:
+ getSound()->playSound(kEntityPlayer, "ZFX1008", (SoundManager::FlagType)(rnd(15) + 2));
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityPlayer, "ZFX1009", (SoundManager::FlagType)(rnd(15) + 2));
+ break;
+ }
+
+ params->param5 = 225 * (4 * rnd(6) + 8);
+ params->param7 = 0;
+ UPDATE_PARAM_PROC_END
+
+ TIME_CHECK_CALLBACK_2(kTimeEnterPoszony, params->param8, 1, setup_enterStation, "Pozsony", kCityPoszony);
+
+label_exitPozsony:
+ TIME_CHECK_CALLBACK_1(kTimeExitPoszony, CURRENT_PARAM(1, 1), 2, setup_exitStation, "Pozsony");
+
+label_enterGalanta:
+ if (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) {
+ if (getState()->time > kTime2403000 && !CURRENT_PARAM(1, 2)) {
+ CURRENT_PARAM(1, 2) = 1;
+ getProgress().field_18 = 2;
+ }
+ }
+
+ if (params->param1)
+ goto label_callback_4;
+
+ TIME_CHECK_CALLBACK_2(kTimeEnterGalanta, CURRENT_PARAM(1, 3), 3, setup_enterStation, "Galanta", kCityGalanta);
+
+label_exitGalanta:
+ TIME_CHECK_CALLBACK_1(kTimeExitGalanta, CURRENT_PARAM(1, 4), 4, setup_exitStation, "Galanta");
+
+label_callback_4:
+ if (getState()->time > kTime2470500 && !CURRENT_PARAM(1, 5)) {
+ CURRENT_PARAM(1, 5) = 1;
+
+ if (getProgress().field_18 == 2)
+ getState()->timeDelta = 1;
+ }
+
+ if (getState()->time > kTime2506500 && !CURRENT_PARAM(1, 6)) {
+ CURRENT_PARAM(1, 6) = 1;
+
+ if (getProgress().field_18 == 2)
+ getProgress().field_18 = 1;
+ }
+
+ if (getState()->time > kTime2520000 && !CURRENT_PARAM(1, 7)) {
+ CURRENT_PARAM(1, 7) = 1;
+
+ if (!params->param2 && !params->param3) {
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventTrainExplosionBridge);
+ }
+ }
+ break;
+
+ case kActionEndSound:
+ if (ENTITY_PARAM(0, 2)) {
+
+ getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
+
+ if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) {
+ PLAY_STEAM();
+ break;
+ }
+
+ if (getEntities()->isOutsideAlexeiWindow()) {
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+ PLAY_STEAM();
+ break;
+ }
+
+ if (getEntities()->isOutsideAnnaWindow()) {
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+ PLAY_STEAM();
+ break;
+ }
+
+ CarIndex car = getEntityData(kEntityPlayer)->car;
+ if (car < kCarRedSleeping || car > kCarCoalTender) {
+ if (car < kCarBaggageRear || car > kCarGreenSleeping) {
+ PLAY_STEAM();
+ break;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
+ PLAY_STEAM();
+ break;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
+ PLAY_STEAM();
+ break;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
+ PLAY_STEAM();
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 3)) {
+ getSound()->resetState();
+ ENTITY_PARAM(0, 3) = 0;
+ } else if (!params->param2 && !params->param3) {
+ getSound()->playSound(kEntityChapters, "ZFX1001");
+ }
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->clearSequences(kEntityChapters);
+
+ setCallback(11);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kActionDefault:
+ params->param4 = 225 * (4 * rnd(5) + 20);
+ params->param5 = 225 * (4 * rnd(6) + 8);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_exitPozsony;
+
+ case 2:
+ goto label_enterGalanta;
+
+ case 3:
+ goto label_exitGalanta;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ if (getSound()->isBuffered(kEntityChapters))
+ getSound()->removeFromQueue(kEntityChapters);
+
+ getAction()->playAnimation(kEventTrainExplosionBridge);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ break;
+
+ case 6:
+ getSound()->processEntries();
+ getAction()->playAnimation(kEventTylerCastleDream);
+ getSound()->resetState();
+
+ getProgress().field_18 = 1;
+
+ getScenes()->loadScene(kScene41);
+ getSavePoints()->push(kEntityChapters, kEntityTatiana, kAction169360385);
+
+ getState()->timeDelta = 1;
+ getState()->time = kTime2511900;
+
+ getInventory()->setLocationAndProcess(kItem2, kObjectLocation1);
+ getScenes()->loadSceneFromItemPosition(kItem22);
+
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationInsideCompartment;
+
+ getSound()->playSound(kEntityChapters, "ZFX1001");
+ break;
+
+ case 7:
+ getAction()->playAnimation(kEventTrainExplosionBridge);
+ getLogic()->gameOver(kSavegameTypeTime, kTime2430000, kSceneNone, true);
+ break;
+
+ case 8:
+ getSound()->playSound(kEntityPlayer, "MUS022");
+
+ if (getState()->time < kTime2517300)
+ getState()->time = kTime2517300;
+ break;
+
+ case 9:
+ getAction()->playAnimation(kEventCathDefusingBomb);
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 73);
+ break;
+
+ case 10:
+ getAction()->playAnimation(kEventDefuseBomb);
+ RESET_ENTITY_STATE(kEntityAbbot, Abbot, setup_function48);
+ getSavePoints()->push(kEntityChapters, kEntityAnna, kAction191001984);
+ getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction191001984);
+ getScenes()->loadSceneFromItemPosition(kItem2);
+
+ getInventory()->get(kItem2)->location = kObjectLocationNone;
+ params->param2 = 1;
+
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 2);
+ break;
+
+ case 11:
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 74);
+ getSound()->playSound(kEntityTrain, "ZFX4001", SoundManager::kFlagDefault);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ break;
+ }
+ break;
+
+ case kActionChapter5:
+ setup_chapter5();
+ break;
+
+ case kAction156435676:
+ getSavePoints()->push(kEntityChapters, kEntityTatiana, kAction169360385);
+ getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954);
+
+ getState()->timeDelta = 1;
+ getState()->time = kTime2511900;
+
+ getInventory()->setLocationAndProcess(kItem2, kObjectLocation1);
+
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationInsideCompartment;
+
+ getSound()->playSound(kEntityChapters, "ZFX1001");
+ break;
+
+ case kAction158610240:
+ setCallback(8);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kAction169300225:
+ if (getState()->time < kTime2519100)
+ getState()->time = kTime2519100;
+
+ params->param3 = 1;
+
+ getEntities()->drawSequenceRight(kEntityChapters, "BOMB");
+ break;
+
+ case kAction190346110:
+ getProgress().field_18 = 3;
+
+ params->param1 = 1;
+
+ if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
+ getSound()->removeFromQueue(kEntityChapters);
+
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ }
+
+ getSound()->playSound(kEntityPlayer, "MUS008", SoundManager::kFlagDefault);
+ getInventory()->unselectItem();
+
+ while (getSound()->isBuffered("MUS008"))
+ getSound()->updateQueue();
+
+ if (getInventory()->hasItem(kItemBomb)) {
+ RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_function47);
+ RESET_ENTITY_STATE(kEntityAnna, Anna, setup_function68);
+ RESET_ENTITY_STATE(kEntityAugust, August, setup_function65);
+ RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_function48);
+ RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_function53);
+ RESET_ENTITY_STATE(kEntityServers0, Servers0, setup_chapter4Handler);
+ RESET_ENTITY_STATE(kEntityServers1, Servers1, setup_chapter4Handler);
+ RESET_ENTITY_STATE(kEntityPascale, Pascale, setup_chapter4Handler);
+ RESET_ENTITY_STATE(kEntityVerges, Verges, setup_chapter4Handler);
+ RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function49);
+ RESET_ENTITY_STATE(kEntityAbbot, Abbot, setup_function44);
+ RESET_ENTITY_STATE(kEntityMilos, Milos, setup_function32);
+ RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_function27);
+ RESET_ENTITY_STATE(kEntityIvo, Ivo, setup_function29);
+ RESET_ENTITY_STATE(kEntitySalko, Salko, setup_function22);
+ RESET_ENTITY_STATE(kEntityMmeBoutarel, MmeBoutarel, setup_function25);
+ RESET_ENTITY_STATE(kEntityBoutarel, Boutarel, setup_function35);
+ RESET_ENTITY_STATE(kEntityRebecca, Rebecca, setup_function45);
+ RESET_ENTITY_STATE(kEntitySophie, Sophie, setup_function9);
+ RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_function17);
+ RESET_ENTITY_STATE(kEntityHadija, Hadija, setup_function19);
+ RESET_ENTITY_STATE(kEntityAlouan, Alouan, setup_function19);
+ RESET_ENTITY_STATE(kEntityMax, Max, setup_chapter4Handler);
+ getSavePoints()->push(kEntityChapters, kEntityAnna, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityMertens, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityServers0, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityServers1, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityPascale, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954);
+
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventTylerCastleDream);
+ } else {
+ getState()->time = kTime2520000;
+
+ setCallback(7);
+ setup_savegame(kSavegameTypeEvent, kEventTrainExplosionBridge);
+ }
+ break;
+
+ case kAction191001984:
+ getState()->time = kTime2520000;
+
+ if (getSound()->isBuffered(kEntityChapters))
+ getSound()->removeFromQueue(kEntityChapters);
+
+ getEntities()->clearSequences(kEntityChapters);
+ getInventory()->removeItem(kItemTelegram);
+
+ getState()->timeDelta = 5;
+
+ setCallback(10);
+ setup_savegame(kSavegameTypeEvent, kEventDefuseBomb);
+ break;
+
+ case kAction201959744:
+ if (getSound()->isBuffered(kEntityChapters))
+ getSound()->removeFromQueue(kEntityChapters);
+
+ getSound()->playSound(kEntityTrain, "ZFX4001", SoundManager::kFlagDefault);
+
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, true);
+ break;
+
+ case kAction225367984:
+ setCallback(9);
+ setup_savegame(kSavegameTypeEvent, kEventCathDefusingBomb);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Chapters, chapter5)
+ if (savepoint.action == kActionDefault) {
+ // Setup for chapter 5 in case it hasn't been done before
+ if (getProgress().chapter != kChapter5) {
+ getProgress().chapter = kChapter5;
+ getEntities()->setupChapter(kChapter5);
+ }
+
+ // Set game time & delta
+ getState()->time = kTimeChapter5;
+ getState()->timeDelta = 2;
+
+ setup_chapter5Init();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Chapters, chapter5Init)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityTables0);
+ getEntities()->clearSequences(kEntityTables1);
+ getEntities()->clearSequences(kEntityTables2);
+ getEntities()->clearSequences(kEntityTables3);
+ getEntities()->clearSequences(kEntityTables4);
+ getEntities()->clearSequences(kEntityTables5);
+
+ getProgress().isTrainRunning = true;
+
+ getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment4, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment5, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment6, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment7, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment8, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleBathroom, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectKitchen, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject20, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject21, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject22, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject48, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getProgress().field_18 = 1;
+ getProgress().field_84 = 1;
+ getProgress().portrait = kCursorPortraitYellow;
+
+ getInventory()->unselectItem();
+
+ getInventory()->removeItem(kItemKey);
+ getInventory()->removeItem(kItemBomb);
+ getInventory()->removeItem(kItemMatch);
+
+ if (getInventory()->hasItem(kItemFirebird)) {
+ getInventory()->removeItem(kItemFirebird);
+ getInventory()->setLocationAndProcess(kItemFirebird, kObjectLocation3);
+
+ if (getInventory()->hasItem(kItemWhistle)) {
+ getInventory()->removeItem(kItemWhistle);
+ getInventory()->setLocationAndProcess(kItemWhistle, kObjectLocation3);
+ }
+ }
+
+ getObjects()->update(kObject93, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObject94, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObject101, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getObjects()->updateLocation2(kObject98, kObjectLocation2);
+ getObjects()->updateLocation2(kObjectRestaurantCar, kObjectLocation2);
+
+ if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
+ getSound()->removeFromQueue(kEntityChapters);
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarBaggageRear, 95);
+ getInventory()->show();
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_chapter5Handler();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Chapters, chapter5Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2907000 && !params->param2) {
+ params->param2 = 1;
+
+ if (!getProgress().isNightTime) {
+ getSound()->playSound(kEntityChapters, "ARRIVE", SoundManager::kFlag8);
+ getSound()->processEntries();
+ }
+ }
+
+ if (getState()->time > kTimeTrainStopped2 && !params->param3) {
+ params->param3 = 1;
+
+ if (!getEvent(kEventLocomotiveMilosDay) && !getEvent(kEventLocomotiveMilosNight)) {
+ getSound()->playSound(kEntityChapters, "ARRIVE", SoundManager::kFlag8);
+ getSound()->processEntries();
+ }
+ }
+ break;
+
+ case kActionEndSound:
+ if (getState()->time <= kTimeTrainStopped2) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventTrainStopped);
+ } else {
+ getLogic()->gameOver(kSavegameTypeTime, kTimeTrainStopped2, kSceneGameOverTrainStopped, true);
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 225 * (4 * rnd(10) + 20);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventTrainStopped);
+ getLogic()->gameOver(kSavegameTypeTime, kTimeTrainStopped, kSceneGameOverTrainStopped, true);
+ }
+ break;
+
+ case kAction135800432:
+ getProgress().isNightTime = true;
+ getState()->time = kTime2916000;
+
+ if (getSound()->isBuffered(kEntityChapters))
+ getSound()->removeFromQueue(kEntityChapters);
+ break;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions
+//////////////////////////////////////////////////////////////////////////
+void Chapters::enterExitStation(const SavePoint &savepoint, bool isEnteringStation) {
+ if (savepoint.action == kActionDefault) {
+ if (!ENTITY_PARAM(0, 2) && !ENTITY_PARAM(0, 3)) {
+ enterExitHelper(isEnteringStation);
+ return;
+ }
+
+ getSound()->removeFromQueue(kEntityChapters);
+
+ if (!ENTITY_PARAM(0, 2)) {
+ if (ENTITY_PARAM(0, 3))
+ ENTITY_PARAM(0, 3) = 0;
+
+ enterExitHelper(isEnteringStation);
+ return;
+ }
+
+ getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
+
+ if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) {
+ ENTITY_PARAM(0, 2) = 0;
+ enterExitHelper(isEnteringStation);
+ return;
+ }
+
+ // Green sleeping car
+ if (getEntities()->isOutsideAlexeiWindow()) {
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+ ENTITY_PARAM(0, 2) = 0;
+ enterExitHelper(isEnteringStation);
+ return;
+ }
+
+ // Red sleeping car
+ if (getEntities()->isOutsideAnnaWindow()) {
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+ ENTITY_PARAM(0, 2) = 0;
+ enterExitHelper(isEnteringStation);
+ return;
+ }
+
+ // Other cars
+ if (getEntityData(kEntityPlayer)->car < kCarRedSleeping || getEntityData(kEntityPlayer)->car > kCarCoalTender) {
+
+ if (getEntityData(kEntityPlayer)->car < kCarBaggageRear || getEntityData(kEntityPlayer)->car > kCarGreenSleeping) {
+ ENTITY_PARAM(0, 2) = 0;
+ enterExitHelper(isEnteringStation);
+ return;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
+ ENTITY_PARAM(0, 2) = 0;
+ enterExitHelper(isEnteringStation);
+ return;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
+ ENTITY_PARAM(0, 2) = 0;
+ enterExitHelper(isEnteringStation);
+ return;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
+ ENTITY_PARAM(0, 2) = 0;
+ enterExitHelper(isEnteringStation);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+void Chapters::enterExitHelper(bool isEnteringStation) {
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS);
+
+ getSound()->playSound(kEntityChapters, isEnteringStation ? "ARRIVE" : "DEPART", SoundManager::kFlag8);
+ getSound()->processEntries();
+
+ getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, isEnteringStation ? kCursorNormal : kCursorHand);
+ getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, isEnteringStation ? kCursorNormal : kCursorHand);
+
+ getProgress().isTrainRunning = isEnteringStation ? false : true;
+
+ if (isEnteringStation) {
+ ENTITY_PARAM(0, 2) = 1;
+ ENTITY_PARAM(0, 4) = params->param4;
+ } else {
+ getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStartRunning);
+ ENTITY_PARAM(0, 3) = 1;
+ }
+
+ CALLBACK_ACTION();
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/chapters.h b/engines/lastexpress/entities/chapters.h
new file mode 100644
index 0000000000..6a31727c23
--- /dev/null
+++ b/engines/lastexpress/entities/chapters.h
@@ -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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_CHAPTERS_H
+#define LASTEXPRESS_CHAPTERS_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Chapters : public Entity {
+public:
+ Chapters(LastExpressEngine *engine);
+ ~Chapters() {}
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Exit a train station
+ *
+ * @param stationName The name of the train station
+ * @param index The index of the train station
+ */
+ DECLARE_FUNCTION_2(enterStation, const char *stationName, CityIndex index)
+
+ /**
+ * Exit a train station
+ *
+ * @param stationName The name of the train station
+ */
+ DECLARE_FUNCTION_1(exitStation, const char *stationName)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Reset main entities
+ */
+ DECLARE_FUNCTION(resetMainEntities)
+
+ /**
+ * Handle end of Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1End)
+
+ /**
+ * Init Chapter 1 data
+ */
+ DECLARE_FUNCTION(chapter1Init)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ /**
+ * Handle switching to Chapter 2 after the end of Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1Next)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Init Chapter 2 data
+ */
+ DECLARE_FUNCTION(chapter2Init)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Init Chapter 3 data
+ */
+ DECLARE_FUNCTION(chapter3Init)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ /**
+ * Handle Vienna events
+ */
+ DECLARE_FUNCTION(viennaEvents)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Init Chapter 4 data
+ */
+ DECLARE_FUNCTION(chapter4Init)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Init Chapter 5 data
+ */
+ DECLARE_FUNCTION(chapter5Init)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+private:
+ void enterExitStation(const SavePoint &savepoint, bool isEnteringStation);
+ void enterExitHelper(bool isEnteringStation);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_CHAPTERS_H
diff --git a/engines/lastexpress/entities/cooks.cpp b/engines/lastexpress/entities/cooks.cpp
new file mode 100644
index 0000000000..51e723887b
--- /dev/null
+++ b/engines/lastexpress/entities/cooks.cpp
@@ -0,0 +1,571 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/cooks.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Cooks::Cooks(LastExpressEngine *engine) : Entity(engine, kEntityCooks) {
+ ADD_CALLBACK_FUNCTION(Cooks, draw);
+ ADD_CALLBACK_FUNCTION(Cooks, playSound);
+ ADD_CALLBACK_FUNCTION(Cooks, function3);
+ ADD_CALLBACK_FUNCTION(Cooks, function4);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter1);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Cooks, function7);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter2);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter3);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter4);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Cooks, chapter5);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(1, Cooks, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Cooks, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(3, Cooks, function3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityCooks, "308A");
+ getEntities()->updatePositionEnter(kEntityCooks, kCarRestaurant, 75);
+ getEntities()->updatePositionEnter(kEntityCooks, kCarRestaurant, 78);
+
+ switch (getProgress().chapter) {
+ default:
+ getSound()->playSound(kEntityCooks, "KIT1011");
+ setCallback(3);
+ setup_draw("308B");
+ break;
+
+ case kChapter1:
+ setCallback(1);
+ setup_playSound("KIT1010");
+ break;
+
+ case kChapter3:
+ setCallback(2);
+ setup_playSound("KIT1012");
+ break;
+ }
+ break;
+
+ case kActionDrawScene:
+ if (!getEntities()->isInKitchen(kEntityPlayer)) {
+ getEntities()->clearSequences(kEntityCooks);
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 46)) {
+ getEntities()->drawSequenceLeft(kEntityCooks, "308D");
+
+ if (!getSound()->isBuffered(kEntityCooks)) {
+ if (params->param1) {
+ if (!getEntities()->hasValidFrame(kEntityCooks)) {
+ getSound()->playSound(kEntityCooks, "LIB015");
+ getEntities()->clearSequences(kEntityCooks);
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+
+ // Kitchen apprentice getting a lesson :D
+ getSound()->playSound(kEntityCooks, "KIT1011A");
+ params->param1 = 1;
+ }
+ }
+
+ if (params->param1 && !getEntities()->hasValidFrame(kEntityCooks)) {
+ getSound()->playSound(kEntityCooks, "LIB015");
+ getEntities()->clearSequences(kEntityCooks);
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ getSound()->playSound(kEntityCooks, "KIT1011");
+ setCallback(3);
+ setup_draw("308B");
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityCooks, "308C");
+ getEntities()->updatePositionExit(kEntityCooks, kCarRestaurant, 75);
+ getEntities()->updatePositionExit(kEntityCooks, kCarRestaurant, 78);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Cooks, function4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityCooks, "308A");
+ getEntities()->updatePositionEnter(kEntityCooks, kCarRestaurant, 75);
+ getEntities()->updatePositionEnter(kEntityCooks, kCarRestaurant, 78);
+
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ setCallback(2);
+ setup_playSound("ZFX1011");
+ break;
+
+ case kChapter3:
+ setCallback(2);
+ setup_playSound("ZFX1011");
+ break;
+ }
+
+ getSound()->playSound(kEntityCooks, "KIT1011");
+ setCallback(3);
+ setup_draw("308B");
+ break;
+
+ case kActionDrawScene:
+ if (!getEntities()->isInKitchen(kEntityPlayer)) {
+ getEntities()->clearSequences(kEntityCooks);
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 80)) {
+ getEntities()->drawSequenceLeft(kEntityCooks, "308D");
+
+ if (!getSound()->isBuffered(kEntityCooks)) {
+ if (params->param1) {
+ if (!getEntities()->hasValidFrame(kEntityCooks)) {
+ getSound()->playSound(kEntityCooks, "LIB015");
+ getEntities()->clearSequences(kEntityCooks);
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+
+ // Kitchen apprentice getting a lesson :D
+ getSound()->playSound(kEntityCooks, "KIT1011A");
+ params->param1 = 1;
+ }
+ }
+
+ if (params->param1 && !getEntities()->hasValidFrame(kEntityCooks)) {
+ getSound()->playSound(kEntityCooks, "LIB015");
+ getEntities()->clearSequences(kEntityCooks);
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ getSound()->playSound(kEntityCooks, "KIT1011");
+ setCallback(3);
+ setup_draw("308B");
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityCooks, "308C");
+ getEntities()->updatePositionExit(kEntityCooks, kCarRestaurant, 75);
+ getEntities()->updatePositionEnter(kEntityCooks, kCarRestaurant, 78);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Cooks, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+
+ getProgress().field_4C = 0;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param4, getState()->time, params->param2);
+
+ // Broken plate sound
+ getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks));
+ params->param2 = 225 * (4 * rnd(30) + 120);
+ params->param4 = 0;
+ break;
+
+ case kActionDefault:
+ params->param1 = 1;
+ params->param2 = 225 * (4 * rnd(30) + 120);
+ break;
+
+ case kActionDrawScene:
+ if (!getEntities()->isInKitchen(kEntityPlayer))
+ break;
+
+ if (params->param1) {
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 73)) {
+ setCallback(1);
+ setup_function3();
+ }
+ } else {
+ if (params->param3) {
+ setCallback(2);
+ setup_playSound("ZFX1011");
+ } else {
+ setCallback(3);
+ setup_playSound("ZFX1012");
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param1 = 0;
+ break;
+
+ case 2:
+ case 3:
+ params->param3 = !params->param3;
+ break;
+ }
+ break;
+
+ case kAction101632192:
+ setup_function7();
+ break;
+
+ case kAction224849280:
+ getProgress().field_4C = 1;
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Cooks, function7)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ // Snoring...
+ setCallback(1);
+ setup_playSound("WAT1200");
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_3650;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+
+ getEntities()->clearSequences(kEntityCooks);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Cooks, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityCooks);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ getProgress().field_4C = 1;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Cooks, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param3, getState()->time, params->param1);
+
+ // Broken plate sound
+ getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks));
+ params->param1 = 225 * (4 * rnd(30) + 120);
+ params->param3 = 0;
+ break;
+
+ case kActionDefault:
+ params->param1 = 225 * (4 * rnd(30) + 120);
+ break;
+
+ case kActionDrawScene:
+ if (params->param2) {
+ setCallback(1);
+ setup_playSound("ZFX1011");
+ } else {
+ setCallback(2);
+ setup_playSound("ZFX1012");
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1 || getCallback() == 2)
+ params->param2 = !params->param2;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Cooks, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityCooks);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ getProgress().field_4C = 0;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Cooks, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_PROC(params->param4, getState()->time, params->param2)
+ // Broken plate sound
+ getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks));
+ params->param2 = 225 * (4 * rnd(30) + 120);
+ params->param4 = 0;
+ UPDATE_PARAM_PROC_END
+
+ if (getState()->time > kTime2079000 && !params->param5) {
+ params->param1 = 0;
+ params->param5 = 1;
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 1;
+ params->param2 = 225 * (4 * rnd(30) + 120);
+ break;
+
+ case kActionDrawScene:
+ if (!getEntities()->isInKitchen(kEntityPlayer))
+ break;
+
+ if (params->param1) {
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 80)) {
+ setCallback(1);
+ setup_function4();
+ }
+ } else {
+ if (params->param3) {
+ setCallback(2);
+ setup_playSound("ZFX1011");
+ } else {
+ setCallback(3);
+ setup_playSound("ZFX1012");
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param1 = 0;
+ break;
+
+ case 2:
+ case 3:
+ params->param3 = !params->param3;
+ break;
+ }
+ break;
+
+ case kAction236976550:
+ getProgress().field_4C = 1;
+ break;
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Cooks, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityCooks);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ getProgress().field_4C = 1;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Cooks, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param3, getState()->time, params->param1)
+
+ // Broken plate sound
+ getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks));
+ params->param1 = 225 * (4 * rnd(30) + 120);
+ params->param3 = 0;
+ break;
+
+ case kActionDefault:
+ params->param1 = 225 * (4 * rnd(30) + 120);
+ break;
+
+ case kActionDrawScene:
+ if (!getEntities()->isInKitchen(kEntityPlayer))
+ break;
+
+ // Kitchen background sound
+ if (params->param2) {
+ setCallback(1);
+ setup_playSound("ZFX1011");
+ } else {
+ setCallback(2);
+ setup_playSound("ZFX1012");
+ }
+ break;
+
+
+ case kActionCallback:
+ // Play the next part of background sound
+ if (getCallback() == 1 || getCallback() == 2) {
+ params->param2 = !params->param2;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Cooks, chapter5)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityCooks);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/cooks.h b/engines/lastexpress/entities/cooks.h
new file mode 100644
index 0000000000..fc3a0cb78c
--- /dev/null
+++ b/engines/lastexpress/entities/cooks.h
@@ -0,0 +1,109 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_COOKS_H
+#define LASTEXPRESS_COOKS_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Cooks : public Entity {
+public:
+ Cooks(LastExpressEngine *engine);
+ ~Cooks() {}
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ DECLARE_FUNCTION(function3)
+
+ DECLARE_FUNCTION(function4)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function7)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_COOKS_H
diff --git a/engines/lastexpress/entities/coudert.cpp b/engines/lastexpress/entities/coudert.cpp
new file mode 100644
index 0000000000..6dece39161
--- /dev/null
+++ b/engines/lastexpress/entities/coudert.cpp
@@ -0,0 +1,4179 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/coudert.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+#define SAVEGAME_BLOOD_JACKET() \
+ if (getProgress().jacket == kJacketBlood \
+ && getEntities()->isDistanceBetweenEntities(kEntityCoudert, kEntityPlayer, 1000) \
+ && !getEntities()->isInsideCompartments(kEntityPlayer) \
+ && !getEntities()->checkFields10(kEntityPlayer)) { \
+ setCallback(1); \
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket); \
+ }
+
+Coudert::Coudert(LastExpressEngine *engine) : Entity(engine, kEntityCoudert) {
+ ADD_CALLBACK_FUNCTION(Coudert, reset);
+ ADD_CALLBACK_FUNCTION(Coudert, bloodJacket);
+ ADD_CALLBACK_FUNCTION(Coudert, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Coudert, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Coudert, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Coudert, playSound);
+ ADD_CALLBACK_FUNCTION(Coudert, playSound16);
+ ADD_CALLBACK_FUNCTION(Coudert, savegame);
+ ADD_CALLBACK_FUNCTION(Coudert, updateEntity);
+ ADD_CALLBACK_FUNCTION(Coudert, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Coudert, updateFromTicks);
+ ADD_CALLBACK_FUNCTION(Coudert, excuseMe);
+ ADD_CALLBACK_FUNCTION(Coudert, function13);
+ ADD_CALLBACK_FUNCTION(Coudert, function14);
+ ADD_CALLBACK_FUNCTION(Coudert, function15);
+ ADD_CALLBACK_FUNCTION(Coudert, function16);
+ ADD_CALLBACK_FUNCTION(Coudert, function17);
+ ADD_CALLBACK_FUNCTION(Coudert, function18);
+ ADD_CALLBACK_FUNCTION(Coudert, function19);
+ ADD_CALLBACK_FUNCTION(Coudert, function20);
+ ADD_CALLBACK_FUNCTION(Coudert, function21);
+ ADD_CALLBACK_FUNCTION(Coudert, function22);
+ ADD_CALLBACK_FUNCTION(Coudert, function23);
+ ADD_CALLBACK_FUNCTION(Coudert, visitCompartmentF);
+ ADD_CALLBACK_FUNCTION(Coudert, function25);
+ ADD_CALLBACK_FUNCTION(Coudert, function26);
+ ADD_CALLBACK_FUNCTION(Coudert, function27);
+ ADD_CALLBACK_FUNCTION(Coudert, visitCompartmentB);
+ ADD_CALLBACK_FUNCTION(Coudert, visitCompartmentA);
+ ADD_CALLBACK_FUNCTION(Coudert, function30);
+ ADD_CALLBACK_FUNCTION(Coudert, function31);
+ ADD_CALLBACK_FUNCTION(Coudert, function32);
+ ADD_CALLBACK_FUNCTION(Coudert, function33);
+ ADD_CALLBACK_FUNCTION(Coudert, function34);
+ ADD_CALLBACK_FUNCTION(Coudert, function35);
+ ADD_CALLBACK_FUNCTION(Coudert, chapter1);
+ ADD_CALLBACK_FUNCTION(Coudert, function37);
+ ADD_CALLBACK_FUNCTION(Coudert, function38);
+ ADD_CALLBACK_FUNCTION(Coudert, function39);
+ ADD_CALLBACK_FUNCTION(Coudert, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Coudert, function41);
+ ADD_CALLBACK_FUNCTION(Coudert, chapter2);
+ ADD_CALLBACK_FUNCTION(Coudert, function43);
+ ADD_CALLBACK_FUNCTION(Coudert, chapter3);
+ ADD_CALLBACK_FUNCTION(Coudert, function45);
+ ADD_CALLBACK_FUNCTION(Coudert, function46);
+ ADD_CALLBACK_FUNCTION(Coudert, function47);
+ ADD_CALLBACK_FUNCTION(Coudert, function48);
+ ADD_CALLBACK_FUNCTION(Coudert, function49);
+ ADD_CALLBACK_FUNCTION(Coudert, function50);
+ ADD_CALLBACK_FUNCTION(Coudert, function51);
+ ADD_CALLBACK_FUNCTION(Coudert, chapter4);
+ ADD_CALLBACK_FUNCTION(Coudert, function53);
+ ADD_CALLBACK_FUNCTION(Coudert, function54);
+ ADD_CALLBACK_FUNCTION(Coudert, function55);
+ ADD_CALLBACK_FUNCTION(Coudert, function56);
+ ADD_CALLBACK_FUNCTION(Coudert, chapter5);
+ ADD_CALLBACK_FUNCTION(Coudert, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Coudert, function59);
+ ADD_CALLBACK_FUNCTION(Coudert, function60);
+ ADD_CALLBACK_FUNCTION(Coudert, function61);
+ ADD_CALLBACK_FUNCTION(Coudert, function62);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Coudert, reset)
+ Entity::reset(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Coudert, bloodJacket)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityCoudert, (char *)&params->seq1);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(3, Coudert, enterExitCompartment, ObjectIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ return;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ return;
+ }
+
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Coudert, callbackActionOnDirection)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getData()->direction != kDirectionRight) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIII(5, Coudert, enterExitCompartment2, ObjectIndex, EntityPosition, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ return;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ return;
+ }
+
+ Entity::enterExitCompartment(savepoint, (EntityPosition)params->param5, (EntityPosition)params->param6, kCarRedSleeping, (ObjectIndex)params->param4, false);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(6, Coudert, playSound)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionEndSound:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityCoudert, (char *)&params->seq1);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(7, Coudert, playSound16)
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS);
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionEndSound:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityCoudert, (char *)&params->seq1, SoundManager::kFlagDefault);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(8, Coudert, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(9, Coudert, updateEntity, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param3 && getEntities()->isDistanceBetweenEntities(kEntityCoudert, kEntityPlayer, 2000))
+ getData()->inventoryItem = kItemInvalid;
+ else
+ getData()->inventoryItem = kItemNone;
+
+ if (getProgress().jacket != kJacketBlood
+ || !getEntities()->isDistanceBetweenEntities(kEntityCoudert, kEntityPlayer, 1000)
+ || getEntities()->isInsideCompartments(kEntityPlayer)
+ || getEntities()->checkFields10(kEntityPlayer)) {
+ if (getEntities()->updateEntity(kEntityCoudert, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ getData()->inventoryItem = kItemNone;
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
+ break;
+
+ case kAction1:
+ params->param3 = 0;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventCoudertAskTylerCompartment);
+ break;
+
+ case kActionExcuseMeCath:
+ if (getData()->clothes == kClothes1)
+ getSound()->playSound(kEntityPlayer, "ZFX1003", getSound()->getSoundFlag(kEntityCoudert));
+ else if (!getSound()->isBuffered(kEntityCoudert))
+ getSound()->playSound(kEntityPlayer, "JAC1112", getSound()->getSoundFlag(kEntityCoudert));
+ break;
+
+ case kActionExcuseMe:
+ if (getData()->clothes == kClothes1)
+ getSound()->playSound(kEntityPlayer, "ZFX1003", getSound()->getSoundFlag(kEntityCoudert));
+ else
+ getSound()->excuseMe(kEntityCoudert);
+ break;
+
+ case kActionDefault:
+ if (!getProgress().eventCorpseFound && !getEvent(kEventCoudertAskTylerCompartment))
+ params->param3 = kItemInvalid;
+
+ if (getEntities()->updateEntity(kEntityCoudert, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventCoudertAskTylerCompartment);
+
+ if (getData()->direction != kDirectionUp)
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750));
+ else
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition - 750), true);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(10, Coudert, updateFromTime, uint32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+
+ UPDATE_PARAM(params->param2, getState()->time, params->param1);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(11, Coudert, updateFromTicks, uint32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+
+ UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Parameters
+// - EntityIndex
+IMPLEMENT_FUNCTION_I(12, Coudert, excuseMe, EntityIndex)
+ if (savepoint.action != kActionDefault)
+ return;
+
+ if (getSound()->isBuffered(kEntityCoudert)) {
+ CALLBACK_ACTION();
+ return;
+ }
+
+ if (isNight()) {
+ if (Entities::isFemale((EntityIndex)params->param1)) {
+ getSound()->playSound(kEntityCoudert, Entities::isMarried((EntityIndex)params->param1) ? "JAC1112C" : "JAC1112F");
+ } else {
+ if (!params->param1 && getProgress().field_18 == 2) {
+ switch (rnd(4)) {
+ default:
+ break;
+
+ case 0:
+ getSound()->playSound(kEntityCoudert, "JAC1013");
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityCoudert, "JAC1013A");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityCoudert, "JAC1113");
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityCoudert, "JAC1113A");
+ break;
+ }
+ } else {
+ getSound()->playSound(kEntityCoudert, "JAC1112D");
+ }
+ }
+ } else {
+ if (Entities::isFemale((EntityIndex)params->param1))
+ getSound()->playSound(kEntityCoudert, Entities::isMarried((EntityIndex)params->param1) ? "JAC1112B" : "JAC1112G");
+ else
+ getSound()->playSound(kEntityCoudert, "JAC1112E");
+ }
+
+ CALLBACK_ACTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(13, Coudert, function13, bool, EntityIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+
+ if (!params->param2 && !params->param3) {
+
+ if (!params->param4) {
+ params->param4 = getState()->timeTicks + 75;
+
+ if (!params->param4) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(4);
+ setup_function19(true);
+ break;
+ }
+ }
+
+ if (params->param4 < getState()->timeTicks) {
+ params->param4 = kTimeInvalid;
+
+ getData()->inventoryItem = kItemNone;
+ setCallback(4);
+ setup_function19(true);
+ break;
+ }
+ }
+
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 225);
+
+ getData()->inventoryItem = kItemNone;
+ setCallback(5);
+ setup_function19(true);
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(9);
+ setup_savegame(kSavegameTypeEvent, kEventCoudertAskTylerCompartment);
+ break;
+
+ case kAction11:
+ ++params->param3;
+
+ setCallback(8);
+ setup_excuseMe(savepoint.entity2);
+ break;
+
+ case kActionDefault:
+ if (params->param2)
+ params->param3 = 1;
+
+ setCallback(1);
+ setup_excuseMe((EntityIndex)params->param2);
+ break;
+
+ case kAction16:
+ --params->param3;
+
+ if (params->param2 && !params->param3) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(7);
+ setup_function19(true);
+ }
+ break;
+
+ case kActionDrawScene:
+ if (!params->param3) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(6);
+ setup_function19(true);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function17(true);
+ break;
+
+ case 2:
+ if (getProgress().chapter == kChapter1 && !getProgress().eventCorpseFound && !getEvent(kEventCoudertAskTylerCompartment))
+ getData()->inventoryItem = kItemInvalid;
+
+ getEntities()->drawSequenceLeft(kEntityCoudert, params->param1 ? "667I" : "667H");
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ // BUG: the original game continues executing code here
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ CALLBACK_ACTION();
+ break;
+
+ case 9:
+ getAction()->playAnimation(kEventCoudertAskTylerCompartment);
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 25);
+ break;
+ }
+ break;
+
+ case kAction201439712:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627K");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(14, Coudert, function14, EntityIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionDefault:
+ if (ENTITY_PARAM(2, 1)) {
+ ENTITY_PARAM(2, 1) = 0;
+
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_1500);
+ } else {
+ setCallback(1);
+ setup_updateFromTime(15);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityCoudert, (EntityIndex)params->param1, kAction202558662);
+
+ setCallback(2);
+ setup_function17(false);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityCoudert, (EntityIndex)params->param1, kAction155853632);
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627K");
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityCoudert, (EntityIndex)params->param1, kAction202558662);
+ getSavePoints()->push(kEntityCoudert, (EntityIndex)params->param1, kAction155853632);
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627K");
+ getScenes()->loadSceneFromItemPosition(kItem5);
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction125499160:
+ switch (params->param1) {
+ default:
+ break;
+
+ case kEntityVerges:
+ ENTITY_PARAM(0, 3) = 0;
+ break;
+
+ case kEntityMmeBoutarel:
+ ENTITY_PARAM(0, 4) = 0;
+ break;
+
+ case kEntityMertens:
+ ENTITY_PARAM(0, 5) = 0;
+ break;
+ }
+
+ setCallback(5);
+ setup_function19(false);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(15, Coudert, function15, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ ENTITY_PARAM(0, 8) = 0;
+ ENTITY_PARAM(1, 1) = 0;
+
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case 2:
+ if (params->param1)
+ getSound()->playSound(kEntityCoudert, "Tat3163");
+ else
+ getSound()->playSound(kEntityCoudert, (getProgress().chapter != kChapter3 || getState()->time > kTime1449000) ? "Tat3162A" : "Tat3161A");
+
+ setCallback(3);
+ setup_enterExitCompartment("627Xb", kObjectCompartmentB);
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityCoudert, kEntityTatiana, kAction69239528);
+ getData()->entityPosition = kPosition_7250;
+
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function18();
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Coudert, function16)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (ENTITY_PARAM(2, 1)) {
+ ENTITY_PARAM(2, 1) = 0;
+ getInventory()->setLocationAndProcess(kItem5, kObjectLocation1);
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ setCallback(ENTITY_PARAM(0, 2) ? 1 : 2);
+ setup_bloodJacket(ENTITY_PARAM(0, 2) ? "627C" : "627F");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ getInventory()->setLocationAndProcess(kItem5, kObjectLocation1);
+ if (!getEntities()->isPlayerPosition(kCarRedSleeping, 2))
+ getData()->entityPosition = kPosition_2088;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(17, Coudert, function17, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getScenes()->loadSceneFromItemPosition(kItem5);
+
+ if (ENTITY_PARAM(2, 1)) {
+ ENTITY_PARAM(2, 1) = 0;
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param1) {
+ setCallback(1);
+ setup_bloodJacket("627H");
+ break;
+ }
+
+ if (params->param2) {
+ setCallback(2);
+ setup_bloodJacket("627C");
+ break;
+ }
+
+ setCallback(3);
+ setup_bloodJacket("627F");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Coudert, function18)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (ENTITY_PARAM(0, 6) || ENTITY_PARAM(0, 8)
+ || ENTITY_PARAM(1, 1) || ENTITY_PARAM(1, 2) || ENTITY_PARAM(1, 3) || ENTITY_PARAM(1, 5) || ENTITY_PARAM(1, 6) || ENTITY_PARAM(1, 7) || ENTITY_PARAM(1, 8)
+ || ENTITY_PARAM(2, 4) || ENTITY_PARAM(2, 6)) {
+ getInventory()->setLocationAndProcess(kItem5, kObjectLocation1);
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_540);
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 3) || ENTITY_PARAM(0, 5) || ENTITY_PARAM(0, 4)) {
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627K");
+ getScenes()->loadSceneFromItemPosition(kItem5);
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->drawSequenceRight(kEntityCoudert, ENTITY_PARAM(0, 2) ? "627A" : "627D");
+ getScenes()->loadSceneFromItemPosition(kItem5);
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 68)) {
+ if (!getSound()->isBuffered(kEntityCoudert))
+ getSound()->playSound(kEntityCoudert, "JAC1111");
+
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 25);
+ }
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityCoudert);
+ ENTITY_PARAM(2, 1) = 1;
+
+ setCallback(2);
+ setup_updateFromTime(75);
+ break;
+
+ case 2:
+ CALLBACK_ACTION();
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityCoudert, ENTITY_PARAM(0, 2) ? "627B" : "627E");
+ ENTITY_PARAM(0, 1) = 0;
+ getSavePoints()->push(kEntityCoudert, kEntityCoudert, kActionDrawScene);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(19, Coudert, function19, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (ENTITY_PARAM(0, 6) || ENTITY_PARAM(0, 8)
+ || ENTITY_PARAM(1, 1) || ENTITY_PARAM(1, 2) || ENTITY_PARAM(1, 3) || ENTITY_PARAM(1, 5) || ENTITY_PARAM(1, 6) || ENTITY_PARAM(1, 7) || ENTITY_PARAM(1, 8)
+ || ENTITY_PARAM(2, 4) || ENTITY_PARAM(2, 6)) {
+ getInventory()->setLocationAndProcess(kItem5, kObjectLocation1);
+ ENTITY_PARAM(2, 1) = 1;
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 3) || ENTITY_PARAM(0, 5) || ENTITY_PARAM(0, 4)) {
+ getScenes()->loadSceneFromItemPosition(kItem5);
+ ENTITY_PARAM(2, 1) = 1;
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param1)
+ getEntities()->drawSequenceRight(kEntityCoudert, "697H");
+ else
+ getEntities()->drawSequenceRight(kEntityCoudert, ENTITY_PARAM(0, 2) ? "627A" : "627D");
+
+ getScenes()->loadSceneFromItemPosition(kItem5);
+
+ setCallback(1);
+ setup_callbackActionOnDirection();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->drawSequenceLeft(kEntityCoudert, ENTITY_PARAM(0, 2) ? "627B" : "627E");
+ ENTITY_PARAM(0, 1) = 0;
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(20, Coudert, function20, ObjectIndex, ObjectIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_PROC(CURRENT_PARAM(1, 3), getState()->time, 300)
+ getSound()->playSound(kEntityPlayer, "ZFX1004", getSound()->getSoundFlag(kEntityCoudert));
+ UPDATE_PARAM_PROC_END
+
+ UPDATE_PARAM(CURRENT_PARAM(1, 4), getState()->time, 900);
+
+ getObjects()->updateLocation2((ObjectIndex)params->param1, kObjectLocation1);
+
+ if (params->param4 != kObjectLocation2)
+ getObjects()->update((ObjectIndex)params->param1, (EntityIndex)params->param3, (ObjectLocation)params->param4, (CursorStyle)params->param5, (CursorStyle)params->param6);
+
+ if (params->param2)
+ getObjects()->update((ObjectIndex)params->param2, (EntityIndex)params->param7, (ObjectLocation)params->param8, (CursorStyle)CURRENT_PARAM(1, 1), (CursorStyle)CURRENT_PARAM(1, 2));
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update((ObjectIndex)params->param1, kEntityCoudert, kObjectLocation1, kCursorNormal, kCursorNormal);
+ if (params->param2)
+ getObjects()->update((ObjectIndex)params->param2, kEntityCoudert, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ params->param3 = getObjects()->get((ObjectIndex)params->param1).entity;
+ params->param4 = getObjects()->get((ObjectIndex)params->param1).location;
+ params->param5 = getObjects()->get((ObjectIndex)params->param1).cursor;
+ params->param6 = getObjects()->get((ObjectIndex)params->param1).cursor2;
+
+ if (params->param2) {
+ params->param7 = getObjects()->get((ObjectIndex)params->param2).entity;
+ params->param8 = getObjects()->get((ObjectIndex)params->param2).location;
+ CURRENT_PARAM(1, 1) = getObjects()->get((ObjectIndex)params->param2).cursor;
+ CURRENT_PARAM(1, 2) = getObjects()->get((ObjectIndex)params->param2).cursor2;
+
+ getObjects()->update((ObjectIndex)params->param2, kEntityCoudert, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+
+ if (params->param4 != kObjectLocation2)
+ getObjects()->update((ObjectIndex)params->param1, kEntityCoudert, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ if (params->param1 == kObjectCompartmentA || params->param1 == kObjectCompartmentC
+ || params->param1 == kObjectCompartmentG || params->param1 == kObjectCompartmentH) {
+ setCallback(3);
+ setup_playSound("Jac1001B");
+ } else {
+ setCallback(4);
+ setup_playSound("Jac1001A");
+ }
+ break;
+
+ case 3:
+ case 4:
+ getObjects()->update((ObjectIndex)params->param1, kEntityCoudert, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ if (params->param2)
+ getObjects()->update((ObjectIndex)params->param2, kEntityCoudert, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Coudert, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+
+ setCallback(3);
+ setup_enterExitCompartment("627Zh", kObjectCompartmentH);
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_2740);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("627Vh", kObjectCompartmentH);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityCoudert, kEntityIvo, kAction221683008);
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wh");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentH, true);
+ break;
+
+ case 3:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentH, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(4);
+ setup_function20(kObjectCompartmentH, kObjectNone);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("697Ah", kObjectCompartmentH);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ getSavePoints()->push(kEntityCoudert, kEntityIvo, kAction122865568);
+ break;
+
+ case 7:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentH, true);
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(8);
+ setup_function20(kObjectCompartmentH, kObjectNone);
+ break;
+
+ case 8:
+ getSound()->playSound(kEntityCoudert, "JAC1013A");
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(9);
+ setup_enterExitCompartment("667Uh", kObjectCompartmentH);
+ break;
+
+ case 9:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityCoudert, kEntityIvo, kAction123852928);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction88652208:
+ setCallback(7);
+ setup_enterExitCompartment("667Th", kObjectCompartmentH);
+ break;
+
+ case kAction123199584:
+ params->param1 = 1;
+
+ setCallback(6);
+ setup_playSound("JAC1012");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Coudert, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+
+ setCallback(3);
+ setup_enterExitCompartment("627Rg", kObjectCompartmentG);
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_3050);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("627Mg", kObjectCompartmentG);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityCoudert, kEntityMilos, kAction221683008);
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Ng");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentG, true);
+ break;
+
+ case 3:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentG, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(4);
+ setup_function20(kObjectCompartmentG, kObjectNone);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("627Sg", kObjectCompartmentG);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ getSavePoints()->push(kEntityCoudert, kEntityMilos, kAction122865568);
+ break;
+
+ case 7:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentG, true);
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(8);
+ setup_function20(kObjectCompartmentG, kObjectNone);
+ break;
+
+ case 8:
+ getSound()->playSound(kEntityCoudert, "JAC1013A");
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(9);
+ setup_enterExitCompartment("627Ug", kObjectCompartmentG);
+ break;
+
+ case 9:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityCoudert, kEntityMilos, kAction123852928);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction88652208:
+ setCallback(7);
+ setup_enterExitCompartment("627Tg", kObjectCompartmentG);
+ break;
+
+ case kAction123199584:
+ params->param1 = 1;
+
+ setCallback(6);
+ setup_playSound("JAC1030");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Coudert, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("627Vf", kObjectCompartmentF);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wf");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentF, true);
+ getSavePoints()->push(kEntityCoudert, kEntityMax, kAction158007856);
+
+ setCallback(3);
+ setup_updateFromTime(150);
+ break;
+
+ case 3:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentF, true);
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Coudert, visitCompartmentF)
+ visitCompartment(savepoint, kPosition_4070, "627Vf", kObjectCompartmentF, "627Wf", "627Zf", kPosition_4455, kObject53, "697Af");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Coudert, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_4840);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("627Me", kObjectCompartmentE);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Ne");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentE, true);
+
+ setCallback(3);
+ setup_updateFromTime(45);
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityCoudert, kEntityRebecca, kAction254915200);
+
+ setCallback(4);
+ setup_updateFromTime(450);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment2("627Re", kObjectCompartmentE, kPosition_4840, kPosition_4455);
+ break;
+
+ case 5:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentE, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(6);
+ setup_function20(kObjectCompartmentE, kObject52);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_enterExitCompartment("627Se", kObjectCompartmentE);
+ break;
+
+ case 7:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityCoudert, kEntityRebecca, kAction123852928);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Coudert, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+
+ setCallback(3);
+ setup_enterExitCompartment2("627Zd", kObjectCompartmentD, kPosition_5790, kPosition_6130);
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("627Vd", kObjectCompartmentD);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityCoudert, kEntityMmeBoutarel, kAction221683008);
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wd");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentD, true);
+ break;
+
+ case 3:
+ case 7:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentD, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(getCallback() + 1);
+ setup_function20(kObjectCompartmentD, kObject51);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("697Ad", kObjectCompartmentD);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ getSavePoints()->push(kEntityCoudert, kEntityMmeBoutarel, kAction122865568);
+ break;
+
+ case 8:
+ getSound()->playSound(kEntityCoudert, "JAC1013");
+
+ setCallback(9);
+ setup_enterExitCompartment("697Ad", kObjectCompartmentD);
+ break;
+
+ case 9:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityCoudert, kEntityMmeBoutarel, kAction123852928);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction88652208:
+ setCallback(7);
+ setup_enterExitCompartment2("627Zd", kObjectCompartmentD, kPosition_5790, kPosition_6130);
+ break;
+
+ case kAction123199584:
+ params->param1 = 1;
+
+ setCallback(6);
+ setup_playSound("JAC1012");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Coudert, function27)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+
+ setCallback(3);
+ setup_enterExitCompartment2("627Rc", kObjectCompartmentC, kPosition_6470, kPosition_6130);
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("627Mc", kObjectCompartmentC);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityCoudert, kEntityBoutarel, kAction221683008);
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Nc");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentC, true);
+ break;
+
+ case 3:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentC, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(4);
+ setup_function20(kObjectCompartmentC, kObject50);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("627Sc", kObjectCompartmentC);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ getSavePoints()->push(kEntityCoudert, kEntityBoutarel, kAction122865568);
+ break;
+
+ case 7:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentC, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(8);
+ setup_function20(kObjectCompartmentC, kObject50);
+ break;
+
+ case 8:
+ getSound()->playSound(kEntityCoudert, "JAC1013");
+
+ setCallback(9);
+ setup_enterExitCompartment("627Uc", kObjectCompartmentC);
+ break;
+
+ case 9:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityCoudert, kEntityBoutarel, kAction123852928);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction88652208:
+ setCallback(7);
+ setup_enterExitCompartment2("627Rc", kObjectCompartmentC, kPosition_6470, kPosition_6130);
+ break;
+
+ case kAction123199584:
+ params->param1 = 1;
+
+ setCallback(6);
+ setup_playSound("JAC1012");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Coudert, visitCompartmentB)
+ visitCompartment(savepoint, kPosition_7500, "627Vb", kObjectCompartmentB, "627Wb", "627Zb", kPosition_7850, kObject49, "697Ab");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Coudert, visitCompartmentA)
+ visitCompartment(savepoint, kPosition_8200, "627Ma", kObjectCompartmentA, "627Na", "627Ra", kPosition_7850, kObject48, "627Sa");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(30, Coudert, function30, ObjectIndex)
+ // Expose parameters as IIIIIS and ignore the default exposed parameters
+ EntityData::EntityParametersI5S *parameters = (EntityData::EntityParametersI5S*)_data->getCurrentParameters();
+ EntityData::EntityParametersSIIS *parameters1 = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(1);
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ switch (parameters->param1) {
+ default:
+ CALLBACK_ACTION();
+ // Stop processing here
+ return;
+
+ case kObjectCompartmentA:
+ parameters->param2 = kPosition_8200;
+ parameters->param3 = kPosition_7850;
+ strcpy((char *)&parameters->seq, "627Ma");
+ strcpy((char *)&parameters1->seq1, "627Na");
+ break;
+
+ case kObjectCompartmentB:
+ parameters->param2 = kPosition_7500;
+ parameters->param3 = kPosition_7850;
+ parameters->param4 = true;
+ strcpy((char *)&parameters->seq, "627Vb");
+ strcpy((char *)&parameters1->seq1, "627Wb");
+ break;
+
+ case kObjectCompartmentC:
+ parameters->param2 = kPosition_6470;
+ parameters->param3 = kPosition_6130;
+ strcpy((char *)&parameters->seq, "627Mc");
+ strcpy((char *)&parameters1->seq1, "627Nc");
+ break;
+
+ case kObjectCompartmentD:
+ parameters->param2 = kPosition_5790;
+ parameters->param3 = kPosition_6130;
+ parameters->param4 = true;
+ strcpy((char *)&parameters->seq, "627Vd");
+ strcpy((char *)&parameters1->seq1, "627Wd");
+ break;
+
+ case kObjectCompartmentE:
+ parameters->param2 = kPosition_4840;
+ parameters->param3 = kPosition_4455;
+ parameters->param4 = true;
+ strcpy((char *)&parameters->seq, "627Me");
+ strcpy((char *)&parameters1->seq1, "627Ne");
+ break;
+
+ case kObjectCompartmentF:
+ parameters->param2 = kPosition_4070;
+ parameters->param3 = kPosition_4455;
+ parameters->param4 = true;
+ strcpy((char *)&parameters->seq, "627Vf");
+ strcpy((char *)&parameters1->seq1, "627Wf");
+ break;
+ }
+
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, (EntityPosition)parameters->param2);
+ break;
+
+ case 2:
+ if (getEntities()->checkFields19(kEntityPlayer, kCarRedSleeping, (EntityPosition)parameters->param3)
+ || ((parameters->param1 == kObjectCompartmentE || parameters->param1 == kObjectCompartmentF) && getEntities()->isOutsideAnnaWindow())) {
+ getObjects()->update((ObjectIndex)parameters->param1, kEntityPlayer, getObjects()->get((ObjectIndex)parameters->param1).location, kCursorNormal, kCursorNormal);
+ parameters->param5 = true;
+ }
+
+ setCallback(3);
+ setup_enterExitCompartment((char *)&parameters->seq, (ObjectIndex)parameters->param1);
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityCoudert, (char *)&parameters1->seq1);
+ getEntities()->enterCompartment(kEntityCoudert, (ObjectIndex)parameters->param1, true);
+
+ setCallback(4);
+ setup_playSound(parameters->param4 ? "JAC3020" : "JAC3021");
+ break;
+
+ case 4:
+ if (parameters->param5)
+ getObjects()->update((ObjectIndex)parameters->param1, kEntityPlayer, getObjects()->get((ObjectIndex)parameters->param1).location, kCursorHandKnock, kCursorHand);
+
+ getEntities()->exitCompartment(kEntityCoudert, (ObjectIndex)parameters->param1, true);
+
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function18();
+ break;
+
+ case 6:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(31, Coudert, function31, uint32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ setCallback(3);
+ setup_function19(true);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_bloodJacket("627G");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getSound()->isBuffered(kEntityCoudert)) {
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627K");
+ } else {
+ setCallback(2);
+ setup_function19(true);
+ }
+ break;
+
+ case 2:
+ case 3:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Coudert, function32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityCoudert);
+ setCallback(3);
+ setup_updateFromTime(900);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function18();
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Coudert, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (ENTITY_PARAM(0, 3) || ENTITY_PARAM(0, 4) || ENTITY_PARAM(0, 5) || ENTITY_PARAM(0, 6) || ENTITY_PARAM(0, 7)
+ || ENTITY_PARAM(1, 2) || ENTITY_PARAM(1, 7)
+ || ENTITY_PARAM(2, 2)) {
+ ENTITY_PARAM(2, 6) = 1;
+
+ if (ENTITY_PARAM(0, 3) || ENTITY_PARAM(0, 4) || ENTITY_PARAM(0, 5)) {
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_1500);
+ } else {
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_540);
+ }
+ } else {
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ ENTITY_PARAM(2, 1) = 1;
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(2);
+ setup_function14(kEntityVerges);
+ break;
+ }
+ // Fallback to next case
+
+ case 2:
+ if (ENTITY_PARAM(0, 5)) {
+ setCallback(3);
+ setup_function14(kEntityMertens);
+ break;
+ }
+ // Fallback to next case
+
+ case 3:
+ if (ENTITY_PARAM(0, 4)) {
+ setCallback(4);
+ setup_function14(kEntityMmeBoutarel);
+ break;
+ }
+ // Fallback to next case
+
+ case 4:
+ ENTITY_PARAM(2, 6) = 0;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 5:
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(6);
+ setup_updateFromTime(75);
+ break;
+
+ case 6:
+ if (ENTITY_PARAM(0, 6) || ENTITY_PARAM(0, 7)) {
+ setCallback(7);
+ setup_function37();
+ break;
+ }
+ // Fallback to next case
+
+ case 7:
+ if (ENTITY_PARAM(2, 2)) {
+ setCallback(8);
+ setup_function39();
+ break;
+ }
+ // Fallback to next case
+
+ case 8:
+ if (ENTITY_PARAM(1, 2)) {
+ setCallback(9);
+ setup_function55();
+ break;
+ }
+ // Fallback to next case
+
+ case 9:
+ if (ENTITY_PARAM(1, 7)) {
+ setCallback(10);
+ setup_function34(false);
+ break;
+ }
+ // Fallback to next case
+
+ case 10:
+ ENTITY_PARAM(2, 6) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(34, Coudert, function34, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ if (!params->param1) {
+ getSound()->playSound(kEntityCoudert, "Ann3124");
+
+ ENTITY_PARAM(1, 7) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+
+ setCallback(7);
+ setup_function35((bool)params->param1);
+ } else {
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Vf");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentF, true);
+
+ setCallback(3);
+ setup_playSound("LIB012");
+ }
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_playSound("Jac1001");
+ break;
+
+ case 4:
+ getSound()->playSound(kEntityCoudert, "Ann3125");
+
+ setCallback(5);
+ setup_enterExitCompartment("629Bf", kObjectCompartmentF);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_enterExitCompartment("629Ff", kObjectCompartmentF);
+ break;
+
+ case 6:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentF, true);
+
+ ENTITY_PARAM(1, 7) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+
+ setCallback(7);
+ setup_function35((bool)params->param1);
+ break;
+
+ case 7:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(35, Coudert, function35, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarBaggage)) {
+ getAction()->playAnimation(kEventCoudertBaggageCar);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
+ }
+
+ UPDATE_PARAM(params->param2, getState()->time, 2700);
+
+ getSavePoints()->push(kEntityCoudert, kEntityMax, kActionMaxFreeFromCage);
+
+ getData()->clothes = kClothesDefault;
+
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case kActionDefault:
+ if (params->param1)
+ getSavePoints()->push(kEntityCoudert, kEntityAnna, kAction156049968);
+
+ getSavePoints()->push(kEntityCoudert, kEntityMax, kAction122358304);
+
+ getData()->clothes = kClothes1;
+ getData()->entityPosition = kPosition_4370;
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_8200);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (!getSound()->isBuffered(kEntityCoudert))
+ getSound()->playSound(kEntityCoudert, "Ann3124");
+
+ if (params->param1)
+ getSavePoints()->push(kEntityCoudert, kEntityAnna, kAction123733488);
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityCoudert);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function18();
+ break;
+
+ case 4:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Coudert, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTimeChapter1, params->param1, 1, setup_chapter1Handler)
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityCoudert, kAction292048641, 7);
+ getSavePoints()->addData(kEntityCoudert, kAction326348944, 8);
+ getSavePoints()->addData(kEntityCoudert, kAction171394341, 2);
+ getSavePoints()->addData(kEntityCoudert, kAction154005632, 4);
+ getSavePoints()->addData(kEntityCoudert, kAction169557824, 3);
+ getSavePoints()->addData(kEntityCoudert, kAction226031488, 5);
+ getSavePoints()->addData(kEntityCoudert, kAction339669520, 6);
+ getSavePoints()->addData(kEntityCoudert, kAction189750912, 10);
+ getSavePoints()->addData(kEntityCoudert, kAction185737168, 12);
+ getSavePoints()->addData(kEntityCoudert, kAction185671840, 13);
+ getSavePoints()->addData(kEntityCoudert, kAction205033696, 15);
+ getSavePoints()->addData(kEntityCoudert, kAction157026693, 14);
+ getSavePoints()->addData(kEntityCoudert, kAction189026624, 11);
+ getSavePoints()->addData(kEntityCoudert, kAction168254872, 17);
+ getSavePoints()->addData(kEntityCoudert, kAction201431954, 18);
+ getSavePoints()->addData(kEntityCoudert, kAction188570113, 19);
+
+ ENTITY_PARAM(0, 1) = 0;
+ ENTITY_PARAM(0, 2) = 1;
+
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->updateLocation2(kObject111, kObjectLocation1);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_chapter1Handler();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Coudert, function37)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getSound()->isBuffered(kEntityCoudert))
+ getSound()->processEntry(kEntityCoudert);
+
+ if (ENTITY_PARAM(0, 7)) {
+ getData()->entityPosition = kPosition_8200;
+
+ setCallback(4);
+ setup_enterExitCompartment2("698Ha", kObjectCompartmentA, kPosition_8200, kPosition_7850);
+ } else {
+ setCallback(1);
+ setup_function16();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityCoudert, kEntityAnna, kAction238358920);
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_8200);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment2("698Ha", kObjectCompartmentA, kPosition_8200, kPosition_7850);
+ break;
+
+ case 4:
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+ setup_function38();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Coudert, function38)
+switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+
+ setCallback(2);
+ setup_function18();
+ break;
+
+ case 2:
+ setup_chapter1Handler();
+ break;
+ }
+ break;
+
+ case kAction191477936:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartment4, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(39, Coudert, function39)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_playSound("LIB070");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function16();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment("627Vd", kObjectCompartmentD);
+ break;
+
+ case 4:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wd");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentD, true);
+
+ setCallback(5);
+ setup_playSound("MME1151A");
+ break;
+
+ case 5:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentD, true);
+
+ setCallback(6);
+ setup_enterExitCompartment("627Zd", kObjectCompartmentD);
+ break;
+
+ case 6:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(7);
+ setup_playSound("MME1151");
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_enterExitCompartment("MME1151", kObjectCompartmentD);
+ break;
+
+ case 8:
+ getSavePoints()->push(kEntityCoudert, kEntityMmeBoutarel, kAction223068211);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(9);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_function18();
+ break;
+
+ case 10:
+ getSavePoints()->push(kEntityCoudert, kEntityVerges, kAction167854368);
+ ENTITY_PARAM(2, 2) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(40, Coudert, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(2, 3)) {
+ ENTITY_PARAM(0, 1) = 1;
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(0, 4) = 0;
+ ENTITY_PARAM(0, 5) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(1, 1) = 0;
+
+ ENTITY_PARAM(2, 1) = 0;
+ ENTITY_PARAM(2, 2) = 0;
+
+ getEntities()->drawSequenceLeft(kEntityCoudert, "697F");
+
+ params->param1 = 1;
+ params->param2 = 1;
+
+ ENTITY_PARAM(2, 3) = 0;
+ }
+
+ getData()->inventoryItem = (getProgress().eventCorpseFound || getEvent(kEventCoudertAskTylerCompartment)) ? kItemNone : kItemInvalid;
+
+ if (ENTITY_PARAM(0, 8)) {
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(4);
+ setup_function15(true);
+ break;
+ }
+
+label_callback_4:
+ if (ENTITY_PARAM(1, 1)) {
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(5);
+ setup_function15(false);
+ break;
+ }
+
+label_callback_5:
+ if (ENTITY_PARAM(0, 6) || ENTITY_PARAM(0, 7)) {
+ getData()->inventoryItem = kItemNone;
+ setup_function37();
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 3)) {
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(6);
+ setup_function14(kEntityVerges);
+ break;
+ }
+
+label_callback_6:
+ if (ENTITY_PARAM(0, 5)) {
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(7);
+ setup_function14(kEntityMertens);
+ break;
+ }
+
+label_callback_7:
+ if (ENTITY_PARAM(0, 4)) {
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(8);
+ setup_function14(kEntityMmeBoutarel);
+ break;
+ }
+
+label_callback_8:
+ if (ENTITY_PARAM(2, 2)) {
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(9);
+ setup_function39();
+ break;
+ }
+
+label_callback_9:
+ if (ENTITY_PARAM(0, 1) && !getSound()->isBuffered(kEntityCoudert))
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "JAC1065" : "JAC1065A");
+
+ if (getState()->time > kTime1107000 && !ENTITY_PARAM(0, 1) && !getEvent(kEventVassiliSeizure)) {
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(10);
+ setup_function41();
+ break;
+ }
+
+label_callback_10:
+ if (getState()->time > kTime1189800 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 2700);
+ ENTITY_PARAM(0, 2) = 1;
+ ENTITY_PARAM(0, 1) = 1;
+
+ getEntities()->drawSequenceLeft(kEntityCoudert, "697F");
+
+ params->param3 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (!ENTITY_PARAM(0, 2))
+ break;
+
+ TIME_CHECK_OBJECT(kTime1107000, params->param4, kObject111, kObjectLocation2);
+ TIME_CHECK_OBJECT(kTime1161000, params->param5, kObject111, kObjectLocation3);
+ TIME_CHECK_OBJECT(kTime1206000, params->param6, kObject111, kObjectLocation4);
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(11);
+ setup_savegame(kSavegameTypeEvent, kEventCoudertAskTylerCompartment);
+ break;
+
+ case kAction11:
+ if (!ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(13);
+ setup_function13((bool)savepoint.param.intValue, savepoint.entity2);
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+
+ getScenes()->loadSceneFromItemPosition(kItem5);
+ break;
+
+ case kActionDrawScene:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+
+ if (!getEntities()->isPlayerPosition(kCarRedSleeping, 1) && !getEntities()->isPlayerPosition(kCarRedSleeping, 23))
+ break;
+
+ if (getProgress().jacket == kJacketBlood) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventCoudertBloodJacket);
+ } else {
+ setCallback(getEntities()->isPlayerPosition(kCarRedSleeping, 1) ? 2 : 3);
+ setup_function13(true, kEntityPlayer);
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ break;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+
+ case 8:
+ goto label_callback_8;
+
+ case 9:
+ goto label_callback_9;
+
+ case 10:
+ params->param1 = 1;
+ goto label_callback_10;
+
+ case 11:
+ getAction()->playAnimation(kEventCoudertAskTylerCompartment);
+ getEntities()->drawSequenceRight(kEntityCoudert, ENTITY_PARAM(0, 2) ? "627A" : "627D");
+ getScenes()->loadSceneFromItemPosition(kItem5);
+
+ ENTITY_PARAM(0, 1) = 0;
+
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 25);
+
+ setCallback(12);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 12:
+ getEntities()->drawSequenceLeft(kEntityCoudert, ENTITY_PARAM(0, 2) ? "627B" : "627E");
+ break;
+
+ case 14:
+ setCallback(15);
+ setup_function18();
+ break;
+ }
+ break;
+
+ case kAction168253822:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ getData()->inventoryItem = kItemNone;
+ getSound()->playSound(kEntityCoudert, "JAC1120");
+
+ setCallback(14);
+ setup_bloodJacket("697D");
+ }
+ break;
+
+ case kAction225358684:
+ if (!ENTITY_PARAM(0, 1)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(16);
+ setup_function30((ObjectIndex)savepoint.param.intValue);
+ }
+ break;
+
+ case kAction225932896:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1))
+ getSavePoints()->push(kEntityCoudert, kEntityFrancois, kAction205346192);
+ break;
+
+ case kAction305159806:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(17);
+ setup_function31(savepoint.param.intValue);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(41, Coudert, function41)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_visitCompartmentA();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function33();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_visitCompartmentB();
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function33();
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function27();
+ break;
+
+ case 6:
+ getSavePoints()->push(kEntityCoudert, kEntityRebecca, kAction285528346);
+
+ setCallback(7);
+ setup_function33();
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_function26();
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_function33();
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_function25();
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_function33();
+ break;
+
+ case 11:
+ setCallback(12);
+ setup_function23();
+ break;
+
+ case 12:
+ setCallback(13);
+ setup_function33();
+ break;
+
+ case 13:
+ setCallback(14);
+ setup_function22();
+ break;
+
+ case 14:
+ setCallback(15);
+ setup_function33();
+ break;
+
+ case 15:
+ setCallback(16);
+ setup_function21();
+ break;
+
+ case 16:
+ setCallback(17);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 17:
+ setCallback(18);
+ setup_function18();
+ break;
+
+ case 18:
+ getSavePoints()->push(kEntityCoudert, kEntityMilos, kAction208228224);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(42, Coudert, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_function18();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityCoudert);
+
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(0, 4) = 0;
+ ENTITY_PARAM(0, 5) = 0;
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+ ENTITY_PARAM(1, 8) = 0;
+
+ ENTITY_PARAM(2, 4) = 0;
+
+ getObjects()->updateLocation2(kObject111, kObjectLocation5);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function43();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(43, Coudert, function43)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(0, 8)) {
+ setCallback(1);
+ setup_function15(true);
+ break;
+ }
+
+label_callback1:
+ if (!ENTITY_PARAM(1, 1)) {
+ setCallback(2);
+ setup_function15(false);
+ break;
+ }
+
+label_callback2:
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(3);
+ setup_function14(kEntityVerges);
+ }
+ break;
+
+ case kAction11:
+ if (!ENTITY_PARAM(2, 1)) {
+ setCallback(4);
+ setup_function13((bool)savepoint.param.intValue, savepoint.entity2);
+ }
+ break;
+
+ case kActionDrawScene:
+ if (ENTITY_PARAM(2, 1))
+ break;
+
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 1)) {
+ setCallback(5);
+ setup_function13(true, kEntityPlayer);
+
+ } else if (getEntities()->isPlayerPosition(kCarRedSleeping, 23)) {
+ setCallback(6);
+ setup_function13(false, kEntityPlayer);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 7:
+ setCallback(8);
+ setup_function18();
+ break;
+ }
+ break;
+
+ case kAction225358684:
+ if (!ENTITY_PARAM(0, 1)) {
+ setCallback(9);
+ setup_function30((ObjectIndex)savepoint.param.intValue);
+ }
+ break;
+
+ case kAction226078300:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ getSound()->playSound(kEntityCoudert, "JAC2020");
+
+ setCallback(7);
+ setup_bloodJacket("697D");
+ }
+ break;
+
+ case kAction305159806:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(10);
+ setup_function31(savepoint.param.intValue);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(44, Coudert, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_function18();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityCoudert);
+
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(0, 4) = 0;
+ ENTITY_PARAM(0, 5) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+ ENTITY_PARAM(1, 8) = 0;
+
+ ENTITY_PARAM(2, 4) = 0;
+ ENTITY_PARAM(2, 5) = 0;
+
+ getObjects()->updateLocation2(kObject111, kObjectLocation6);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function45();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(45, Coudert, function45)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(0, 8)) {
+ setCallback(1);
+ setup_function15(true);
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(1, 1)) {
+ setCallback(2);
+ setup_function15(false);
+ break;
+ }
+
+label_callback_2:
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(3);
+ setup_function14(kEntityVerges);
+ break;
+ }
+
+label_callback_3:
+ if (ENTITY_PARAM(0, 5)) {
+ setCallback(4);
+ setup_function14(kEntityMertens);
+ break;
+ }
+
+label_callback_4:
+ if (ENTITY_PARAM(1, 3)) {
+ setCallback(5);
+ setup_function46();
+ break;
+ }
+
+label_callback_5:
+ if (ENTITY_PARAM(1, 5)) {
+ setCallback(6);
+ setup_function47(true);
+ break;
+ }
+
+label_callback_6:
+ if (ENTITY_PARAM(1, 6)) {
+ setCallback(7);
+ setup_function47(false);
+ break;
+ }
+
+label_callback_7:
+ if (ENTITY_PARAM(1, 8)) {
+ setCallback(8);
+ setup_function48();
+ break;
+ }
+
+label_callback_8:
+ if (ENTITY_PARAM(2, 4)) {
+ setCallback(9);
+ setup_function49();
+ break;
+ }
+
+label_callback_9:
+ if (ENTITY_PARAM(1, 4)) {
+ setCallback(10);
+ setup_function34(true);
+ break;
+ }
+
+label_callback_10:
+ if (ENTITY_PARAM(1, 7)) {
+ setCallback(11);
+ setup_function34(false);
+ break;
+ }
+
+label_callback_11:
+ if (ENTITY_PARAM(0, 4)) {
+ setCallback(12);
+ setup_function14(kEntityMmeBoutarel);
+ break;
+ }
+
+label_callback_12:
+ // BUG: Can never be called... FAIL!
+ if (ENTITY_PARAM(2, 5) && getState()->time > kTime2056500 && getState()->time < kTime1417500) {
+ setCallback(13);
+ setup_function50();
+ break;
+ }
+
+label_callback_13:
+ TIME_CHECK_CALLBACK(kTime2088900, params->param1, 14, setup_function32);
+
+label_callback_14:
+ TIME_CHECK_CALLBACK(kTime2119500, params->param2, 15, setup_function32);
+
+label_callback_15:
+ TIME_CHECK_CALLBACK(kTime2138400, params->param3, 16, setup_function32);
+
+label_callback_16:
+ TIME_CHECK_CALLBACK(kTime2147400, params->param4, 17, setup_function32);
+
+label_callback_17:
+ TIME_CHECK_CALLBACK(kTime2160000, params->param5, 18, setup_function32);
+
+label_callback_18:
+ TIME_CHECK_CALLBACK(kTime2205000, params->param6, 19, setup_function32);
+
+label_callback_19:
+ if (ENTITY_PARAM(0, 2)) {
+ TIME_CHECK_OBJECT(kTime2025000, params->param7, kObject111, kObjectLocation7);
+ TIME_CHECK_OBJECT(kTime2133000, params->param8, kObject111, kObjectLocation8);
+ TIME_CHECK_OBJECT(kTime2173500, CURRENT_PARAM(1, 1), kObject111, kObjectLocation9);
+ }
+ break;
+
+ case kAction11:
+ if (!ENTITY_PARAM(2, 1)) {
+ setCallback(20);
+ setup_function13((bool)savepoint.param.intValue, savepoint.entity2);
+ }
+ break;
+
+ case kActionDrawScene:
+ if (!ENTITY_PARAM(2, 1)) {
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 1)) {
+ setCallback(21);
+ setup_function13(true, kEntityPlayer);
+ } else if (getEntities()->isPlayerPosition(kCarRedSleeping, 23)) {
+ setCallback(22);
+ setup_function13(false, kEntityPlayer);
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+
+ case 8:
+ goto label_callback_8;
+
+ case 9:
+ goto label_callback_9;
+
+ case 10:
+ goto label_callback_10;
+
+ case 11:
+ goto label_callback_11;
+
+ case 12:
+ getSavePoints()->push(kEntityCoudert, kEntityVerges, kAction168255788);
+ goto label_callback_12;
+
+ case 13:
+ goto label_callback_13;
+
+ case 14:
+ goto label_callback_14;
+
+ case 15:
+ goto label_callback_15;
+
+ case 16:
+ goto label_callback_16;
+
+ case 17:
+ goto label_callback_17;
+
+ case 18:
+ goto label_callback_18;
+
+ case 19:
+ goto label_callback_19;
+
+ case 23:
+ setCallback(24);
+ setup_function18();
+ break;
+ }
+ break;
+
+ case kAction225358684:
+ if (!ENTITY_PARAM(0, 1)) {
+ setCallback(25);
+ setup_function30((ObjectIndex)savepoint.param.intValue);
+ }
+ break;
+
+ case kAction226078300:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ getSound()->playSound(kEntityCoudert, "JAC2020");
+
+ setCallback(23);
+ setup_bloodJacket("697D");
+ }
+ break;
+
+ case kAction305159806:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(26);
+ setup_function31(savepoint.param.intValue);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(46, Coudert, function46)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Vf");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentF, true);
+ getSavePoints()->push(kEntityCoudert, kEntityAnna, kAction253868128);
+
+ setCallback(3);
+ setup_playSound("LIB012");
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wf");
+
+ setCallback(4);
+ setup_playSound("Ann1016A");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_playSound("Ann4150");
+ break;
+
+ case 5:
+ getSound()->playSound(kEntityCoudert, "Ann3121");
+
+ setCallback(6);
+ setup_enterExitCompartment("629Bf", kObjectCompartmentF);
+ break;
+
+ case 6:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "629Cf");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentF, true);
+ // Fallback to next case
+
+ case 7:
+ if (getSound()->isBuffered(kEntityCoudert)) {
+ setCallback(7);
+ setup_updateFromTime(75);
+ } else {
+ setCallback(8);
+ setup_playSound("Ann3122");
+ }
+ break;
+
+ case 8:
+ getSound()->playSound(kEntityCoudert, "Ann3123");
+
+ setCallback(9);
+ setup_updateFromTicks(75);
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_enterExitCompartment("629Ff", kObjectCompartmentF);
+ break;
+
+ case 10:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentF, true);
+ ENTITY_PARAM(1, 3) = 0;
+
+ setCallback(11);
+ setup_function35(true);
+ break;
+
+ case 11:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(47, Coudert, function47, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment("627Xf", kObjectCompartmentF);
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wf");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentF);
+ // Fallback to next case
+
+ case 4:
+ if (getSound()->isBuffered(kEntityCoudert)) {
+ setCallback(4);
+ setup_updateFromTime(225);
+ } else {
+ setCallback(5);
+ setup_playSound(params->param1 ? "Ann3149" : "Ann3147a");
+ }
+ break;
+
+ case 5:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentF, true);
+ getSavePoints()->push(kEntityCoudert, kEntityAnna, kAction157894320);
+
+ setCallback(6);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 6:
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+
+ setCallback(7);
+ setup_function18();
+ break;
+
+ case 7:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(48, Coudert, function48)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityCoudert, "Ann3148A");
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Ann3148B" : "Ann3148");
+ setCallback(3);
+ setup_enterExitCompartment("627Xf", kObjectCompartmentF);
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityCoudert, kEntityAnna, kAction192063264);
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 4:
+ ENTITY_PARAM(1, 8) = 0;
+ setCallback(5);
+ setup_function18();
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(49, Coudert, function49)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment("627Vb", kObjectCompartmentB);
+ break;
+
+ case 3:
+ if (getEntities()->isInsideCompartment(kEntityTatiana, kCarRedSleeping, kPosition_7500)) {
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wb");
+
+ setCallback(4);
+ setup_playSound("Jac3006");
+ } else {
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wb");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentB, true);
+
+ setCallback(8);
+ setup_playSound("LIB012");
+ }
+ break;
+
+ case 4:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentB, true);
+
+ setCallback(5);
+ setup_enterExitCompartment("627Zb", kObjectCompartmentB);
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(6);
+ setup_playSound("Jac3006A");
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_enterExitCompartment("697Ab", kObjectCompartmentB);
+ break;
+
+ case 7:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(10);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_updateFromTime(150);
+ break;
+
+ case 9:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentB, true);
+
+ setCallback(10);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 10:
+ getSavePoints()->push(kEntityCoudert, kEntityMmeBoutarel, kAction242526416);
+ ENTITY_PARAM(2, 4) = 0;
+ ENTITY_PARAM(2, 5) = 1;
+
+ setCallback(11);
+ setup_function18();
+ break;
+
+ case 11:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(50, Coudert, function50)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4840);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Me");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentE, true);
+
+ setCallback(3);
+ setup_playSound("LIB012");
+ break;
+
+ case 3:
+ if (!getEntities()->isInsideCompartment(kEntityRebecca, kCarRedSleeping, kPosition_4840)) {
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentE, true);
+
+ setCallback(8);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ } else {
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Ne");
+
+ setCallback(4);
+ setup_playSound("Jac3005");
+ }
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("627Re", kObjectCompartmentE);
+ break;
+
+ case 5:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentE, true);
+
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(6);
+ setup_playSound("Jac3005A");
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_enterExitCompartment("627Se", kObjectCompartmentE);
+ break;
+
+ case 7:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(8);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 8:
+ ENTITY_PARAM(2, 5) = 0;
+
+ setCallback(9);
+ setup_function18();
+ break;
+
+ case 9:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(51, Coudert, function51)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2133000 && !getProgress().field_40) {
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentB);
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ }
+ break;
+
+ case kActionOpenDoor:
+ if (savepoint.param.intValue == kObjectCompartmentB)
+ getData()->entityPosition = kPosition_7500;
+
+ getSound()->playSound(kEntityPlayer, "LIB014");
+ getAction()->playAnimation(kEventCoudertGoingOutOfVassiliCompartment);
+ getEntities()->updateEntity(kEntityCoudert, kCarRedSleeping, kPosition_2000);
+ getScenes()->loadSceneFromObject(savepoint.param.intValue == kObjectCompartmentB ? kObjectCompartmentB : kObjectCompartmentA);
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentB, true);
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationOutsideCompartment;
+
+ getSavePoints()->push(kEntityCoudert, kEntityMax, kActionMaxFreeFromCage);
+
+ if (ENTITY_PARAM(0, 5)) {
+ ENTITY_PARAM(0, 5) = 0;
+
+ getSavePoints()->push(kEntityCoudert, kEntityMertens, kAction155853632);
+ getSavePoints()->push(kEntityCoudert, kEntityMertens, kActionEndSound);
+ }
+
+ if (ENTITY_PARAM(0, 3)) {
+ ENTITY_PARAM(0, 3) = 0;
+
+ getSavePoints()->push(kEntityCoudert, kEntityVerges, kAction155853632);
+ getSavePoints()->push(kEntityCoudert, kEntityVerges, kActionEndSound);
+ }
+
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wb");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentB, true);
+ getSavePoints()->push(kEntityCoudert, kEntityTatiana, kAction154071333);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function18();
+ break;
+
+ case 2:
+ case 4:
+ case 6:
+ setup_function45();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function18();
+ break;
+
+ case 5:
+ setCallback(5);
+ setup_function18();
+ break;
+ }
+ break;
+
+ case kAction168316032:
+ getObjects()->update(kObjectCompartmentA, kEntityCoudert, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObjectCompartmentB, kEntityCoudert, kObjectLocation1, kCursorNormal, kCursorHand);
+ break;
+
+ case kAction235061888:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentB, true);
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(52, Coudert, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_function18();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityCoudert);
+
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(0, 4) = 0;
+ ENTITY_PARAM(0, 5) = 0;
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+ ENTITY_PARAM(1, 8) = 0;
+
+ ENTITY_PARAM(2, 3) = 0;
+ ENTITY_PARAM(2, 4) = 0;
+
+ getObjects()->updateLocation2(kObject111, kObjectLocation10);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ ENTITY_PARAM(1, 2) = 1;
+ setup_function53();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(53, Coudert, function53)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(2, 3)) {
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+
+ params->param1 = 1;
+
+ getObjects()->updateLocation2(kObjectCompartmentA, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartmentB, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartmentC, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartmentD, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartmentE, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartmentF, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartmentG, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartmentH, kObjectLocation1);
+
+ ENTITY_PARAM(2, 3) = 0;
+
+ setCallback(1);
+ setup_function54();
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(1, 2)) {
+ if (!params->param2)
+ params->param2 = (uint)(getState()->time + 4500);
+
+ if (params->param3 != kTimeInvalid) {
+ UPDATE_PARAM_PROC_TIME(params->param2, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param3, 0)
+ setCallback(2);
+ setup_function55();
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+ }
+
+label_callback_2:
+ if (ENTITY_PARAM(1, 7)) {
+ setCallback(3);
+ setup_function34(false);
+ break;
+ }
+
+label_callback_3:
+ if (!params->param1) {
+ TIME_CHECK_CALLBACK(kTime2394000, params->param4, 4, setup_function56);
+
+label_callback_4:
+ TIME_CHECK_CALLBACK(kTime2434500, params->param5, 5, setup_function32);
+
+label_callback_5:
+ TIME_CHECK_CALLBACK(kTime2448000, params->param6, 6, setup_function32);
+ }
+
+label_callback_6:
+ if (getState()->time > kTime2538000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
+ UPDATE_PARAM(params->param7, getState()->time, 2700);
+
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 1) = 1;
+
+ getEntities()->drawSequenceLeft(kEntityCoudert, "697F");
+
+ params->param7 = 0;
+ }
+ break;
+
+ case kAction11:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(7);
+ setup_function13((bool)savepoint.param.intValue, savepoint.entity2);
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+
+ getScenes()->loadSceneFromItemPosition(kItem5);
+ break;
+
+ case kActionDrawScene:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 1)) {
+ setCallback(8);
+ setup_function13(true, kEntityPlayer);
+ } else if (getEntities()->isPlayerPosition(kCarRedSleeping, 23)) {
+ setCallback(9);
+ setup_function13(false, kEntityPlayer);
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 10:
+ setCallback(11);
+ setup_function18();
+ break;
+ }
+ break;
+
+ case kAction225358684:
+ if (!ENTITY_PARAM(0, 1)) {
+ setCallback(12);
+ setup_function30((ObjectIndex)savepoint.param.intValue);
+ }
+ break;
+
+ case kAction226078300:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ getSound()->playSound(kEntityCoudert, "JAC2020");
+
+ setCallback(10);
+ setup_bloodJacket("697D");
+ }
+ break;
+
+ case kAction305159806:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(13);
+ setup_function31(savepoint.param.intValue);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(54, Coudert, function54)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getEntities()->hasValidFrame(kEntityCoudert)) {
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_540);
+ } else {
+ getData()->car = kCarLocomotive;
+ getData()->entityPosition = kPosition_540;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityCoudert);
+ getData()->car = kCarLocomotive;
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function18();
+ break;
+
+ case 3:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction191001984:
+ getData()->car = kCarRedSleeping;
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_1500);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(55, Coudert, function55)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_playSound("LIB070");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function16();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Wf");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentF, true);
+
+ setCallback(4);
+ setup_playSound("Ann4150A");
+ break;
+
+ case 4:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentF, true);
+ getSavePoints()->push(kEntityCoudert, kEntityAnna, kAction219971920);
+ getSavePoints()->push(kEntityCoudert, kEntityPascale, kAction101824388);
+
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 5:
+ getEntities()->clearSequences(kEntityCoudert);
+ getSavePoints()->push(kEntityCoudert, kEntityPascale, kAction136059947);
+ break;
+
+ case 6:
+ ENTITY_PARAM(1, 2) = 0;
+
+ setCallback(7);
+ setup_function18();
+ break;
+
+ case 7:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction123712592:
+ setCallback(6);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(56, Coudert, function56)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function21();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function33();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function22();
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function33();
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_visitCompartmentF();
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function33();
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_function25();
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_function33();
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_function26();
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_function33();
+ break;
+
+ case 11:
+ setCallback(12);
+ setup_function27();
+ break;
+
+ case 12:
+ setCallback(13);
+ setup_function33();
+ break;
+
+ case 13:
+ setCallback(14);
+ setup_visitCompartmentB();
+ break;
+
+ case 14:
+ setCallback(15);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 15:
+ setCallback(16);
+ setup_function18();
+ break;
+
+ case 16:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(57, Coudert, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityCoudert);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(58, Coudert, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function59();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(59, Coudert, function59)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getSound()->playSound(kEntityCoudert, "Jac5010"); // Situation is under control, please remain in your compartment
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627K");
+ setup_function60();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(60, Coudert, function60)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function61();
+ break;
+
+ case kAction155991520:
+ setCallback(1);
+ setup_updateFromTime(225);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(61, Coudert, function61)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_4840);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("627Me", kObjectCompartmentE);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityCoudert, "627Ne");
+ getEntities()->enterCompartment(kEntityCoudert, kObjectCompartmentE, true);
+
+ setCallback(3);
+ setup_updateFromTime(75);
+ break;
+
+ case 3:
+ getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentE, true);
+
+ setCallback(4);
+ setup_enterExitCompartment("627Re", kObjectCompartmentE);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->clearSequences(kEntityCoudert);
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ setCallback(5);
+ setup_playSound("Reb5010");
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_enterExitCompartment("627Se", kObjectCompartmentE);
+ break;
+
+ case 6:
+ getSavePoints()->push(kEntityCoudert, kEntityRebecca, kAction155604840);
+
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(7);
+ setup_updateEntity(kCarRedSleeping, kPosition_2740);
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_enterExitCompartment("627Zh", kObjectCompartmentH);
+ break;
+
+ case 8:
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->clearSequences(kEntityCoudert);
+ getSavePoints()->push(kEntityCoudert, kEntityPascale, kAction169750080);
+
+ setup_function62();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(62, Coudert, function62)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM(params->param4, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 1;
+
+ getObjects()->update(kObjectCompartmentH, kEntityCoudert, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param4 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (params->param1) {
+ getObjects()->update(kObjectCompartmentH, kEntityCoudert, kObjectLocation1, kCursorNormal, kCursorNormal);
+ params->param1 = 0;
+
+ setCallback(1);
+ setup_playSound(getSound()->justCheckingCath());
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 2 : 3);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentH, kEntityCoudert, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ params->param1 = 0;
+ params->param2 = 0;
+ params->param3 = 0;
+
+ getObjects()->update(kObjectCompartmentH, kEntityCoudert, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentH, kEntityCoudert, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 2:
+ case 3:
+ ++params->param3;
+
+ if (params->param3 == 1 || params->param2) {
+ getObjects()->update(kObjectCompartmentH, kEntityCoudert, kObjectLocation1, kCursorNormal, kCursorNormal);
+ setCallback(params->param3 == 1 ? 4 : 5);
+ setup_playSound(params->param3 == 1 ? "Jac5002" : "Jac5002A");
+ }
+ break;
+
+ case 4:
+ params->param1 = 1;
+ getObjects()->update(kObjectCompartmentH, kEntityCoudert, kObjectLocation1, kCursorTalk, kCursorNormal);
+ break;
+
+ case 5:
+ params->param2 = 1;
+ break;
+ }
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(63, Coudert)
+
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions
+//////////////////////////////////////////////////////////////////////////
+void Coudert::visitCompartment(const SavePoint &savepoint, EntityPosition position, const char *seq1, ObjectIndex compartment, const char *seq2, const char *seq3, EntityPosition sittingPosition, ObjectIndex object, const char *seq4) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, position);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment(seq1, compartment);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityCoudert, seq2);
+ getEntities()->enterCompartment(kEntityCoudert, compartment, true);
+
+ setCallback(3);
+ setup_updateFromTime(150);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment2(seq3, compartment, position, sittingPosition);
+ break;
+
+ case 4:
+ getEntities()->exitCompartment(kEntityCoudert, compartment, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityCoudert);
+
+ setCallback(5);
+ setup_function20(compartment, object);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_enterExitCompartment(seq4, compartment);
+ break;
+
+ case 6:
+ getData()->location = kLocationOutsideCompartment;
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/coudert.h b/engines/lastexpress/entities/coudert.h
new file mode 100644
index 0000000000..13dad6f122
--- /dev/null
+++ b/engines/lastexpress/entities/coudert.h
@@ -0,0 +1,229 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_COUDERT_H
+#define LASTEXPRESS_COUDERT_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Coudert : public Entity {
+public:
+ Coudert(LastExpressEngine *engine);
+ ~Coudert() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Handle meeting Coudert with the blooded jacket
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(bloodJacket, const char *sequence)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ * @param entityPosition1 The entity position 1
+ * @param entityPosition2 The entity position 2
+ */
+ DECLARE_FUNCTION_4(enterExitCompartment2, const char *sequence, ObjectIndex compartment, EntityPosition entityPosition1, EntityPosition entityPosition2)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Plays sound
+ *
+ * @param savepoint The savepoint
+ * - the sound filename
+ */
+ DECLARE_FUNCTION_NOSETUP(playSound16)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param ticks The number of ticks to add
+ */
+ DECLARE_FUNCTION_1(updateFromTicks, uint32 ticks)
+
+ DECLARE_FUNCTION_1(excuseMe, EntityIndex entity)
+ DECLARE_FUNCTION_2(function13, bool, EntityIndex entity)
+ DECLARE_FUNCTION_1(function14, EntityIndex entity)
+ DECLARE_FUNCTION_1(function15, bool)
+ DECLARE_FUNCTION(function16)
+ DECLARE_FUNCTION_1(function17, bool)
+ DECLARE_FUNCTION(function18)
+ DECLARE_FUNCTION_1(function19, bool)
+
+ /**
+ * ???
+ *
+ * @param object1 The first object index
+ * @param object2 The second object index
+ */
+ DECLARE_FUNCTION_2(function20, ObjectIndex object1, ObjectIndex object2)
+
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(visitCompartmentF)
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(visitCompartmentB)
+ DECLARE_FUNCTION(visitCompartmentA)
+
+ /**
+ * ???
+ *
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_1(function30, ObjectIndex compartment)
+
+ DECLARE_FUNCTION_1(function31, uint32)
+ DECLARE_FUNCTION(function32)
+ DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION_1(function34, bool)
+ DECLARE_FUNCTION_1(function35, bool)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+ DECLARE_FUNCTION(function37)
+ DECLARE_FUNCTION(function38)
+ DECLARE_FUNCTION(function39)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function41)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ DECLARE_FUNCTION(function43)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ DECLARE_FUNCTION(function45)
+ DECLARE_FUNCTION(function46)
+ DECLARE_FUNCTION_1(function47, bool)
+ DECLARE_FUNCTION(function48)
+ DECLARE_FUNCTION(function49)
+ DECLARE_FUNCTION(function50)
+ DECLARE_FUNCTION(function51)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ DECLARE_FUNCTION(function53)
+ DECLARE_FUNCTION(function54)
+ DECLARE_FUNCTION(function55)
+ DECLARE_FUNCTION(function56)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function59)
+ DECLARE_FUNCTION(function60)
+ DECLARE_FUNCTION(function61)
+ DECLARE_FUNCTION(function62)
+
+ DECLARE_NULL_FUNCTION()
+
+private:
+ void visitCompartment(const SavePoint &savepoint, EntityPosition position, const char *seq1, ObjectIndex compartment, const char *seq2, const char *seq3, EntityPosition sittingPosition, ObjectIndex object, const char *seq4);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_COUDERT_H
diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp
new file mode 100644
index 0000000000..3291b49e9b
--- /dev/null
+++ b/engines/lastexpress/entities/entity.cpp
@@ -0,0 +1,486 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/entity.h"
+
+#include "lastexpress/entities/entity_intern.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/state.h"
+#include "lastexpress/game/savegame.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// EntityData
+//////////////////////////////////////////////////////////////////////////
+
+void EntityData::EntityCallData::saveLoadWithSerializer(Common::Serializer &s) {
+ for (uint i = 0; i < ARRAYSIZE(callbacks); i++)
+ s.syncAsByte(callbacks[i]);
+
+ s.syncAsByte(currentCall);
+ s.syncAsUint16LE(entityPosition);
+ s.syncAsUint16LE(location);
+ s.syncAsUint16LE(car);
+ s.syncAsByte(field_497);
+ s.syncAsByte(entity);
+ s.syncAsByte(inventoryItem);
+ s.syncAsByte(direction);
+ s.syncAsUint16LE(field_49B);
+ s.syncAsUint16LE(currentFrame);
+ s.syncAsUint16LE(currentFrame2);
+ s.syncAsUint16LE(field_4A1);
+ s.syncAsUint16LE(field_4A3);
+ s.syncAsByte(clothes);
+ s.syncAsByte(position);
+ s.syncAsByte(car2);
+ s.syncAsByte(doProcessEntity);
+ s.syncAsByte(field_4A9);
+ s.syncAsByte(field_4AA);
+ s.syncAsByte(directionSwitch);
+
+ // Sync strings
+#define SYNC_STRING(varName, count) { \
+ char seqName[13]; \
+ memset(&seqName, 0, count); \
+ if (s.isSaving()) strcpy((char *)&seqName, varName.c_str()); \
+ s.syncBytes((byte *)&seqName, count); \
+ if (s.isLoading()) varName = seqName; \
+}
+
+ SYNC_STRING(sequenceName, 13);
+ SYNC_STRING(sequenceName2, 13);
+ SYNC_STRING(sequenceNamePrefix, 7);
+ SYNC_STRING(sequenceNameCopy, 13);
+
+#undef SYNC_STRING
+
+ // Skip pointers to frame & sequences
+ s.skip(5 * 4);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// EntityData
+//////////////////////////////////////////////////////////////////////////
+EntityData::EntityParameters *EntityData::getParameters(uint callback, byte index) const {
+ if (callback >= 9)
+ error("EntityData::getParameters: invalid callback value (was: %d, max: 9)", callback);
+
+ if (index >= 4)
+ error("EntityData::getParameters: invalid index value (was: %d, max: 4)", index);
+
+ return _parameters[callback].parameters[index];
+}
+
+int EntityData::getCallback(uint callback) const {
+ if (callback >= 16)
+ error("EntityData::getParameters: invalid callback value (was: %d, max: 16)", callback);
+
+ return _data.callbacks[callback];
+}
+
+void EntityData::setCallback(uint callback, byte index) {
+ if (callback >= 16)
+ error("EntityData::getParameters: invalid callback value (was: %d, max: 16)", callback);
+
+ _data.callbacks[callback] = index;
+}
+
+void EntityData::updateParameters(uint32 index) const {
+ if (index < 8)
+ getParameters(8, 0)->update(index);
+ else if (index < 16)
+ getParameters(8, 1)->update(index - 8);
+ else if (index < 24)
+ getParameters(8, 2)->update(index - 16);
+ else if (index < 32)
+ getParameters(8, 3)->update(index - 24);
+ else
+ error("EntityData::updateParameters: invalid param index to update (was:%d, max:32)!", index);
+}
+
+void EntityData::saveLoadWithSerializer(Common::Serializer &s) {
+ for (uint i = 0; i < ARRAYSIZE(_parameters); i++)
+ _parameters[i].saveLoadWithSerializer(s);
+
+ _data.saveLoadWithSerializer(s);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Entity
+//////////////////////////////////////////////////////////////////////////
+Entity::Entity(LastExpressEngine *engine, EntityIndex index) : _engine(engine), _entityIndex(index) {
+ _data = new EntityData();
+
+ // Add first empty entry to callbacks array
+ _callbacks.push_back(NULL);
+}
+
+Entity::~Entity() {
+ for (uint i = 0; i < _callbacks.size(); i++)
+ delete _callbacks[i];
+
+ delete _data;
+
+ // Zero-out passed pointers
+ _engine = NULL;
+}
+
+void Entity::setup(ChapterIndex index) {
+ switch(index) {
+ case kChapterAll:
+ getSavePoints()->setCallback(_entityIndex, _callbacks[_data->getCurrentCallback()]);
+ break;
+
+ case kChapter1:
+ setup_chapter1();
+ break;
+
+ case kChapter2:
+ setup_chapter2();
+ break;
+
+ case kChapter3:
+ setup_chapter3();
+ break;
+
+ case kChapter4:
+ setup_chapter4();
+ break;
+
+ case kChapter5:
+ setup_chapter5();
+ break;
+
+ default:
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Shared functions
+//////////////////////////////////////////////////////////////////////////
+
+void Entity::reset(const SavePoint &savepoint, bool resetClothes, bool resetItem) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kAction1:
+ if (resetClothes) {
+ // Select next available clothes
+ getData()->clothes = (ClothesIndex)(getData()->clothes + 1);
+ if (getData()->clothes > kClothes3)
+ getData()->clothes = kClothesDefault;
+ }
+ break;
+
+ case kActionNone:
+ if (getEntities()->updateEntity(_entityIndex, kCarGreenSleeping, (EntityPosition)params->param1))
+ params->param1 = (params->param1 == 10000) ? 0 : 10000;
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPositionNone;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ if (resetItem)
+ getData()->inventoryItem = kItemInvalid;
+
+ params->param1 = 10000;
+ break;
+ }
+}
+
+void Entity::savegame(const SavePoint &savepoint) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getSaveLoad()->saveGame((SavegameType)params->param1, _entityIndex, (EventIndex)params->param2);
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+void Entity::playSound(const SavePoint &savepoint, bool resetItem, SoundManager::FlagType flag) {
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ if (resetItem)
+ getData()->inventoryItem = kItemNone;
+
+ getSound()->playSound(_entityIndex, (char *)&params->seq1, flag);
+ break;
+ }
+}
+
+void Entity::draw(const SavePoint &savepoint, bool handleExcuseMe) {
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMeCath:
+ if (handleExcuseMe && !params->param4) {
+ getSound()->excuseMe(_entityIndex);
+ params->param4 = 1;
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq1);
+ break;
+ }
+}
+
+void Entity::draw2(const SavePoint &savepoint) {
+ EXPOSE_PARAMS(EntityData::EntityParametersSSII)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq1);
+ getEntities()->drawSequenceRight((EntityIndex)params->param7, (char *)&params->seq2);
+ break;
+ }
+}
+
+void Entity::updateFromTicks(const SavePoint &savepoint) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1)
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+void Entity::updateFromTime(const SavePoint &savepoint) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param2, getState()->time, params->param1)
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+void Entity::callbackActionOnDirection(const SavePoint &savepoint) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ if (getData()->direction != kDirectionRight)
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+void Entity::callbackActionRestaurantOrSalon(const SavePoint &savepoint) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ case kActionDefault:
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon())
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+void Entity::updateEntity(const SavePoint &savepoint, bool handleExcuseMe) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExcuseMeCath:
+ if (handleExcuseMe)
+ getSound()->excuseMeCath();
+ break;
+
+ case kActionExcuseMe:
+ if (handleExcuseMe)
+ getSound()->excuseMe(_entityIndex);
+ break;
+
+ case kActionNone:
+ case kActionDefault:
+ if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+void Entity::callSavepoint(const SavePoint &savepoint, bool handleExcuseMe) {
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ if (!CURRENT_PARAM(1, 1))
+ getSavePoints()->call(_entityIndex, (EntityIndex)params->param4, (ActionIndex)params->param5, (char *)&params->seq2);
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMeCath:
+ if (handleExcuseMe && !CURRENT_PARAM(1, 2)) {
+ getSound()->excuseMe(_entityIndex);
+ CURRENT_PARAM(1, 2) = 1;
+ }
+ break;
+
+ case kAction10:
+ if (!CURRENT_PARAM(1, 1)) {
+ getSavePoints()->call(_entityIndex, (EntityIndex)params->param4, (ActionIndex)params->param5, (char *)&params->seq2);
+ CURRENT_PARAM(1, 1) = 1;
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq1);
+ break;
+ }
+}
+
+void Entity::enterExitCompartment(const SavePoint &savepoint, EntityPosition position1, EntityPosition position2, CarIndex car, ObjectIndex compartment, bool alternate, bool updateLocation) {
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->exitCompartment(_entityIndex, (ObjectIndex)params->param4);
+ if (position1)
+ getData()->entityPosition = position1;
+
+ if (updateLocation)
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq1);
+ getEntities()->enterCompartment(_entityIndex, (ObjectIndex)params->param4);
+
+ if (position1) {
+ getData()->location = kLocationInsideCompartment;
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, car, position1) || getEntities()->isInsideCompartment(kEntityPlayer, car, position2)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(compartment, alternate);
+ }
+ }
+ break;
+ }
+}
+
+void Entity::updatePosition(const SavePoint &savepoint, bool handleExcuseMe) {
+ EXPOSE_PARAMS(EntityData::EntityParametersSIII)
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->updatePositionExit(_entityIndex, (CarIndex)params->param4, (Position)params->param5);
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMeCath:
+ if (handleExcuseMe && !params->param6) {
+ getSound()->excuseMe(_entityIndex);
+ params->param6 = 1;
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq);
+ getEntities()->updatePositionEnter(_entityIndex, (CarIndex)params->param4, (Position)params->param5);
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h
new file mode 100644
index 0000000000..33ca244c5e
--- /dev/null
+++ b/engines/lastexpress/entities/entity.h
@@ -0,0 +1,800 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ENTITY_H
+#define LASTEXPRESS_ENTITY_H
+
+#include "lastexpress/shared.h"
+
+#include "lastexpress/game/sound.h"
+
+#include "common/array.h"
+#include "common/func.h"
+#include "common/serializer.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+class Sequence;
+class SequenceFrame;
+struct SavePoint;
+
+class EntityData : Common::Serializable {
+public:
+
+ struct EntityParameters : Common::Serializable{
+ virtual ~EntityParameters() {}
+ virtual Common::String toString() = 0;
+
+ virtual void update(uint32 index) = 0;
+
+ virtual void saveLoadWithSerializer(Common::Serializer &s) = 0;
+ };
+
+ struct EntityParametersIIII : EntityParameters {
+ uint param1;
+ uint param2;
+ uint param3;
+ uint param4;
+ uint param5;
+ uint param6;
+ uint param7;
+ uint param8;
+
+ EntityParametersIIII() {
+ param1 = 0;
+ param2 = 0;
+ param3 = 0;
+ param4 = 0;
+ param5 = 0;
+ param6 = 0;
+ param7 = 0;
+ param8 = 0;
+ }
+
+ bool hasNonNullParameter() {
+ return param1 || param2 || param3 || param4 || param5 || param6 || param7 || param8;
+ }
+
+ Common::String toString() {
+ return Common::String::format("IIII: %d %d %d %d %d %d %d %d\n", param1, param2, param3, param4, param5, param6, param7, param8);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersIIII::update: invalid index (was: %d)", index);
+
+ case 0: param1 = 1; break;
+ case 1: param2 = 1; break;
+ case 2: param3 = 1; break;
+ case 3: param4 = 1; break;
+ case 4: param5 = 1; break;
+ case 5: param6 = 1; break;
+ case 6: param7 = 1; break;
+ case 7: param8 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(param1);
+ s.syncAsUint32LE(param2);
+ s.syncAsUint32LE(param3);
+ s.syncAsUint32LE(param4);
+ s.syncAsUint32LE(param5);
+ s.syncAsUint32LE(param6);
+ s.syncAsUint32LE(param7);
+ s.syncAsUint32LE(param8);
+ }
+ };
+
+ struct EntityParametersSIII : EntityParameters {
+ char seq[12];
+ uint param4;
+ uint param5;
+ uint param6;
+ uint param7;
+ uint param8;
+
+ EntityParametersSIII() {
+ memset(&seq, 0, 12);
+ param4 = 0;
+ param5 = 0;
+ param6 = 0;
+ param7 = 0;
+ param8 = 0;
+ }
+
+ Common::String toString() {
+ return Common::String::format("SIII: %s %d %d %d %d %d\n", seq, param4, param5, param6, param7, param8);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersSIII::update: invalid index (was: %d)", index);
+
+ case 3: param4 = 1; break;
+ case 4: param5 = 1; break;
+ case 5: param6 = 1; break;
+ case 6: param7 = 1; break;
+ case 7: param8 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncBytes((byte *)&seq, 12);
+ s.syncAsUint32LE(param4);
+ s.syncAsUint32LE(param5);
+ s.syncAsUint32LE(param6);
+ s.syncAsUint32LE(param7);
+ s.syncAsUint32LE(param8);
+ }
+ };
+
+ struct EntityParametersSIIS : EntityParameters {
+ char seq1[12];
+ uint param4;
+ uint param5;
+ char seq2[12];
+
+ EntityParametersSIIS() {
+ memset(&seq1, 0, 12);
+ param4 = 0;
+ param5 = 0;
+ memset(&seq2, 0, 12);
+ }
+
+ Common::String toString() {
+ return Common::String::format("SIIS: %s %d %d %s\n", seq1, param4, param5, seq2);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersSIIS::update: invalid index (was: %d)", index);
+
+ case 3: param4 = 1; break;
+ case 4: param5 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncBytes((byte *)&seq1, 12);
+ s.syncAsUint32LE(param4);
+ s.syncAsUint32LE(param5);
+ s.syncBytes((byte *)&seq2, 12);
+ }
+ };
+
+ struct EntityParametersISSI : EntityParameters {
+ uint param1;
+ char seq1[12];
+ char seq2[12];
+ uint param8;
+
+ EntityParametersISSI() {
+ param1 = 0;
+ memset(&seq1, 0, 12);
+ memset(&seq2, 0, 12);
+ param8 = 0;
+ }
+
+ Common::String toString() {
+ return Common::String::format("ISSI: %d %s %s %d\n", param1, seq1, seq2, param8);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersISSI::update: invalid index (was: %d)", index);
+
+ case 0: param1 = 1; break;
+ case 7: param8 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(param1);
+ s.syncBytes((byte *)&seq1, 12);
+ s.syncBytes((byte *)&seq2, 12);
+ s.syncAsUint32LE(param8);
+ }
+ };
+
+ struct EntityParametersISII : EntityParameters {
+ uint param1;
+ char seq[12];
+ uint param5;
+ uint param6;
+ uint param7;
+ uint param8;
+
+ EntityParametersISII() {
+ param1 = 0;
+ memset(&seq, 0, 12);
+ param5 = 0;
+ param6 = 0;
+ param7 = 0;
+ param8 = 0;
+ }
+
+ Common::String toString() {
+ return Common::String::format("ISII: %d %s %d %d %d %d\n", param1, seq, param5, param6, param7, param8);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersISII::update: invalid index (was: %d)", index);
+
+ case 0: param1 = 1; break;
+ case 4: param5 = 1; break;
+ case 5: param6 = 1; break;
+ case 6: param7 = 1; break;
+ case 7: param8 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(param1);
+ s.syncBytes((byte *)&seq, 12);
+ s.syncAsUint32LE(param5);
+ s.syncAsUint32LE(param6);
+ s.syncAsUint32LE(param7);
+ s.syncAsUint32LE(param8);
+ }
+ };
+
+ struct EntityParametersSSII : EntityParameters {
+ char seq1[12];
+ char seq2[12];
+ uint param7;
+ uint param8;
+
+ EntityParametersSSII() {
+ memset(&seq1, 0, 12);
+ memset(&seq2, 0, 12);
+ param7 = 0;
+ param8 = 0;
+ }
+
+ Common::String toString() {
+ return Common::String::format("SSII: %s %s %d %d\n", seq1, seq2, param7, param8);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersSSII::update: invalid index (was: %d)", index);
+
+ case 6: param7 = 1; break;
+ case 7: param8 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncBytes((byte *)&seq1, 12);
+ s.syncBytes((byte *)&seq2, 12);
+ s.syncAsUint32LE(param7);
+ s.syncAsUint32LE(param8);
+ }
+ };
+
+ struct EntityParametersSSS : EntityParameters {
+ char seq1[12];
+ char seq2[12];
+ char seq3[8];
+
+ EntityParametersSSS() {
+ memset(&seq1, 0, 12);
+ memset(&seq2, 0, 12);
+ memset(&seq3, 0, 8);
+ }
+
+ Common::String toString() {
+ return Common::String::format("SSS: %s %s %s\n", seq1, seq2, seq3);
+ }
+
+ void update(uint32) {
+ error("EntityParametersSSS::update: cannot update this type of parameters");
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncBytes((byte *)&seq1, 12);
+ s.syncBytes((byte *)&seq2, 12);
+ s.syncBytes((byte *)&seq3, 8);
+ }
+ };
+
+ struct EntityParametersIISS : EntityParameters {
+ uint param1;
+ uint param2;
+ char seq1[12];
+ char seq2[12];
+
+ EntityParametersIISS() {
+ param1 = 0;
+ param2 = 0;
+ memset(&seq1, 0, 12);
+ memset(&seq2, 0, 12);
+ }
+
+ Common::String toString() {
+ return Common::String::format("IISS: %d %d %s %s\n", param1, param2, seq1, seq2);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersIISS::update: invalid index (was: %d)", index);
+
+ case 0: param1 = 1; break;
+ case 1: param2 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(param1);
+ s.syncAsUint32LE(param2);
+ s.syncBytes((byte *)&seq1, 12);
+ s.syncBytes((byte *)&seq2, 12);
+ }
+ };
+
+ struct EntityParametersIISI : EntityParameters {
+ uint param1;
+ uint param2;
+ char seq[12];
+ uint param6;
+ uint param7;
+ uint param8;
+
+ EntityParametersIISI() {
+ param1 = 0;
+ param2 = 0;
+ memset(&seq, 0, 12);
+ param6 = 0;
+ param7 = 0;
+ param8 = 0;
+ }
+
+ Common::String toString() {
+ return Common::String::format("IISI: %d %d %s %d %d %d\n", param1, param2, seq, param6, param7, param8);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersIISI::update: invalid index (was: %d)", index);
+
+ case 0: param1 = 1; break;
+ case 1: param2 = 1; break;
+ case 5: param6 = 1; break;
+ case 6: param7 = 1; break;
+ case 7: param8 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(param1);
+ s.syncAsUint32LE(param2);
+ s.syncBytes((byte *)&seq, 12);
+ s.syncAsUint32LE(param6);
+ s.syncAsUint32LE(param7);
+ s.syncAsUint32LE(param8);
+ }
+ };
+
+ struct EntityParametersIIIS : EntityParameters {
+ uint param1;
+ uint param2;
+ uint param3;
+ char seq[12];
+ uint param7;
+ uint param8;
+
+ EntityParametersIIIS() {
+ param1 = 0;
+ param2 = 0;
+ param3 = 0;
+ memset(&seq, 0, 12);
+ param7 = 0;
+ param8 = 0;
+ }
+
+ Common::String toString() {
+ return Common::String::format("IIIS: %d %d %d %s %d %d\n", param1, param2, param3, seq, param7, param8);
+ }
+
+ void update(uint32 index) {
+ switch (index) {
+ default:
+ error("EntityParametersIIIS::update: invalid index (was: %d)", index);
+
+ case 0: param1 = 1; break;
+ case 1: param2 = 1; break;
+ case 2: param3 = 1; break;
+ case 6: param7 = 1; break;
+ case 7: param8 = 1; break;
+ }
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(param1);
+ s.syncAsUint32LE(param2);
+ s.syncAsUint32LE(param3);
+ s.syncBytes((byte *)&seq, 12);
+ s.syncAsUint32LE(param7);
+ s.syncAsUint32LE(param8);
+ }
+ };
+
+ struct EntityParametersI5S : EntityParameters {
+ uint param1;
+ uint param2;
+ uint param3;
+ uint param4;
+ uint param5;
+ char seq[12];
+
+ EntityParametersI5S() {
+ param1 = 0;
+ param2 = 0;
+ param3 = 0;
+ param4 = 0;
+ param5 = 0;
+ memset(&seq, 0, 12);
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(param1);
+ s.syncAsUint32LE(param2);
+ s.syncAsUint32LE(param3);
+ s.syncAsUint32LE(param4);
+ s.syncAsUint32LE(param5);
+ s.syncBytes((byte *)&seq, 12);
+ }
+ };
+
+ struct EntityCallParameters : Common::Serializable {
+ EntityParameters *parameters[4];
+
+ EntityCallParameters() {
+ // We default to int parameters
+ for (int i = 0; i < 4; i++)
+ parameters[i] = new EntityParametersIIII();
+ }
+
+ ~EntityCallParameters() {
+ clear();
+ }
+
+ void clear() {
+ for (int i = 0; i < 4; i++) {
+ if (parameters[i])
+ delete parameters[i];
+ parameters[i] = NULL;
+ }
+ }
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ for (uint i = 0; i < ARRAYSIZE(parameters); i++)
+ parameters[i]->saveLoadWithSerializer(s);
+ }
+ };
+
+ struct EntityCallData : Common::Serializable {
+ byte callbacks[16];
+ byte currentCall;
+ EntityPosition entityPosition; // word
+ Location location; // word
+ CarIndex car; // word
+ byte field_497;
+ EntityIndex entity; // byte
+ InventoryItem inventoryItem; // byte
+ EntityDirection direction; // byte
+ int16 field_49B;
+ int16 currentFrame;
+ int16 currentFrame2;
+ int16 field_4A1;
+ int16 field_4A3;
+ ClothesIndex clothes; // byte
+ Position position;
+ CarIndex car2; // byte
+ bool doProcessEntity; // byte
+ bool field_4A9; // byte
+ bool field_4AA; // byte
+ EntityDirection directionSwitch;
+ Common::String sequenceName; // char[13]
+ Common::String sequenceName2; // char[13]
+ Common::String sequenceNamePrefix; // char[7]
+ Common::String sequenceNameCopy; // char[13]
+ SequenceFrame *frame;
+ SequenceFrame *frame1;
+ Sequence *sequence;
+ Sequence *sequence2;
+ Sequence *sequence3;
+
+ /**
+ * Default constructor.
+ */
+ EntityCallData() {
+ memset(&callbacks, 0, 16 * sizeof(byte));
+ currentCall = 0;
+ entityPosition = kPositionNone;
+ location = kLocationOutsideCompartment;
+ car = kCarNone;
+ field_497 = 0;
+ entity = kEntityPlayer;
+ inventoryItem = kItemNone;
+ direction = kDirectionNone;
+ field_49B = 0;
+ currentFrame = 0;
+ currentFrame2 = 0;
+ field_4A1 = 0;
+ field_4A3 = 30;
+ clothes = kClothesDefault;
+ position = 0;
+ car2 = kCarNone;
+ doProcessEntity = false;
+ field_4A9 = false;
+ field_4AA = false;
+ directionSwitch = kDirectionNone;
+ frame = NULL;
+ frame1 = NULL;
+ sequence = NULL;
+ sequence2 = NULL;
+ sequence3 = NULL;
+ }
+
+ /**
+ * Convert this object into a string representation.
+ *
+ * @return A string representation of this object.
+ */
+ Common::String toString() {
+ Common::String str = "";
+
+ str += Common::String::format("Entity position: %d - Location: %d - Car: %d\n", entityPosition, location, car);
+ str += Common::String::format("Entity: %d - Item: %d - Direction: %d\n", entity, inventoryItem, direction);
+ str += Common::String::format("Clothes: %d - Position: %d - Direction switch: %d\n", clothes, position, directionSwitch);
+ str += "\n";
+ str += Common::String::format("field_497: %02d - field_49B: %i - field_4A1: %i\n", field_497, field_49B, field_4A1);
+ str += Common::String::format("field_4A9: %02d - field_4AA: %i - Car 2: %d\n", field_4A9, field_4AA, car2);
+ str += "\n";
+ str += "Sequence: " + sequenceName + " - Sequence 2: " + sequenceName2 + "\n";
+ str += "Sequence prefix: " + sequenceNamePrefix + " - Sequence copy: " + sequenceNameCopy + "\n";
+ str += Common::String::format("Current frame: %i - Current frame 2: %i - Process entity: %d\n", currentFrame, currentFrame2, doProcessEntity);
+ str += "\n";
+ str += Common::String::format("Current call: %d\n", currentCall);
+ str += Common::String::format("Functions: %d %d %d %d %d %d %d %d\n", callbacks[0], callbacks[1], callbacks[2], callbacks[3], callbacks[4], callbacks[5], callbacks[6], callbacks[7]);
+ str += Common::String::format("Callbacks: %d %d %d %d %d %d %d %d\n", callbacks[8], callbacks[9], callbacks[10], callbacks[11], callbacks[12], callbacks[13], callbacks[14], callbacks[15]);
+
+ return str;
+ }
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &s);
+ };
+
+ EntityData() {}
+
+ template<class T>
+ void resetCurrentParameters() {
+ EntityCallParameters *params = &_parameters[_data.currentCall];
+ params->clear();
+
+ for (int i = 0; i < 4; i++)
+ params->parameters[i] = new T();
+ }
+
+ EntityCallData *getCallData() { return &_data; }
+
+ EntityParameters *getParameters(uint callback, byte index) const;
+ EntityParameters *getCurrentParameters(byte index = 0) { return getParameters(_data.currentCall, index); }
+
+ int getCallback(uint callback) const;
+ int getCurrentCallback() { return getCallback(_data.currentCall); }
+ void setCallback(uint callback, byte index);
+ void setCurrentCallback(uint index) { setCallback(_data.currentCall, index); }
+
+ void updateParameters(uint32 index) const;
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &ser);
+
+private:
+
+ EntityCallData _data;
+ EntityCallParameters _parameters[9];
+};
+
+class Entity : Common::Serializable {
+public:
+
+ typedef Common::Functor1<const SavePoint&, void> Callback;
+
+ Entity(LastExpressEngine *engine, EntityIndex index);
+ virtual ~Entity();
+
+ // Accessors
+ EntityData *getParamData() { return _data; }
+ EntityData::EntityCallData *getData() { return _data->getCallData(); }
+
+ // Callbacks
+ byte getCallback() { return _data->getCallback(_data->getCallData()->currentCall + 8); }
+ void setCallback(byte index) { _data->setCallback(_data->getCallData()->currentCall + 8, index); getData()->currentCall++; }
+
+ // Setup
+ void setup(ChapterIndex index);
+
+ virtual void setup_chapter1() = 0;
+ virtual void setup_chapter2() = 0;
+ virtual void setup_chapter3() = 0;
+ virtual void setup_chapter4() = 0;
+ virtual void setup_chapter5() = 0;
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &ser) { _data->saveLoadWithSerializer(ser); }
+
+ void nullfunction(const SavePoint &savepoint) {}
+
+protected:
+ LastExpressEngine *_engine;
+
+ EntityIndex _entityIndex;
+ EntityData *_data;
+ Common::Array<Callback *> _callbacks;
+
+ /**
+ * Saves the game
+ *
+ * @param savepoint The savepoint
+ * - SavegameType
+ * - EventIndex
+ */
+ void savegame(const SavePoint &savepoint);
+
+ /**
+ * Play sound
+ *
+ * @param savepoint The savepoint
+ * - Sound filename
+ * @param resetItem true to reset item.
+ * @param flag sound flag
+ */
+ void playSound(const SavePoint &savepoint, bool resetItem = false, SoundManager::FlagType flag = SoundManager::kFlagInvalid);
+
+ /**
+ * Draws the entity
+ *
+ * @param savepoint The savepoint
+ * - Sequence
+ * - ExcuseMe flag
+ * @param handleExcuseMe true to handle excuseMeCath action
+ */
+ void draw(const SavePoint &savepoint, bool handleExcuseMe = false);
+
+ /**
+ * Draws the entity along with another one
+ *
+ * @param savepoint The savepoint.
+ * - Sequence 1
+ * - Sequence 2
+ * - EntityIndex
+ */
+ void draw2(const SavePoint &savepoint);
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param savepoint The savepoint
+ * - Number of ticks to add
+ */
+ void updateFromTicks(const SavePoint &savepoint);
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param savepoint The savepoint.
+ * - Time to add
+ */
+ void updateFromTime(const SavePoint &savepoint);
+
+ /**
+ * Resets an entity
+ *
+ * @param savepoint The savepoint.
+ * @param resetClothes true to reset clothes.
+ * @param resetItem true to reset inventoryItem to kItemInvalid
+ */
+ void reset(const SavePoint &savepoint, bool resetClothes = false, bool resetItem = false);
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ *
+ * @param savepoint The savepoint.
+ */
+ void callbackActionOnDirection(const SavePoint &savepoint);
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ *
+ * @param savepoint The savepoint.
+ */
+ void callbackActionRestaurantOrSalon(const SavePoint &savepoint);
+
+ /**
+ * Updates the entity
+ *
+ * @param savepoint The savepoint.
+ * - CarIndex
+ * - EntityPosition
+ * @param handleExcuseMe true to handle the kActionExcuseMe/kActionExcuseMeCath actions.
+ */
+ void updateEntity(const SavePoint &savepoint, bool handleExcuseMe = false);
+
+ /**
+ * Call a specific savepoint (or draw sequence in default case)
+ *
+ * @param savepoint The savepoint.
+ * - Sequence to draw in default case
+ * - EntityIndex
+ * - ActionIndex
+ * - Sequence for the savepoint
+ * @param handleExcuseMe true to handle excuse me.
+ */
+ void callSavepoint(const SavePoint &savepoint, bool handleExcuseMe = false);
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param savepoint The savepoint.
+ * @param position1 The first position.
+ * @param position2 The second position.
+ * @param car The car.
+ * @param compartment The compartment.
+ * @param alternate true to use the alternate version of SceneManager::loadSceneFromObject()
+ */
+ void enterExitCompartment(const SavePoint &savepoint, EntityPosition position1 = kPositionNone, EntityPosition position2 = kPositionNone, CarIndex car = kCarNone, ObjectIndex compartment = kObjectNone, bool alternate = false, bool updateLocation = false);
+
+ /**
+ * Updates the position
+ *
+ * @param savepoint The savepoint
+ * - Sequence name
+ * - CarIndex
+ * - Position
+ * @param handleExcuseMe true to handle excuseMe actions
+ */
+ void updatePosition(const SavePoint &savepoint, bool handleExcuseMe = false);
+};
+
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ENTITY_H
diff --git a/engines/lastexpress/entities/entity39.cpp b/engines/lastexpress/entities/entity39.cpp
new file mode 100644
index 0000000000..6d139094c7
--- /dev/null
+++ b/engines/lastexpress/entities/entity39.cpp
@@ -0,0 +1,103 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/entity39.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Entity39::Entity39(LastExpressEngine *engine) : Entity(engine, kEntity39) {
+ ADD_CALLBACK_FUNCTION(Entity39, chapter1);
+ ADD_CALLBACK_FUNCTION(Entity39, chapter2);
+ ADD_CALLBACK_FUNCTION(Entity39, chapter3);
+ ADD_CALLBACK_FUNCTION(Entity39, chapter4);
+ ADD_CALLBACK_FUNCTION(Entity39, chapter5);
+ ADD_CALLBACK_FUNCTION(Entity39, process);
+
+ memset(&_sequence, 0, 12);
+ _counter = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Entity39, chapter1)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(2, Entity39, chapter2)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(3, Entity39, chapter3)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Entity39, chapter4)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Entity39, chapter5)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Entity39, process)
+// TODO: _sequence & counter do not seem to be touched anywhere else in the code :(
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->drawSequenceRight(kEntity39, (char *)&_sequence);
+ break;
+
+ case kActionNone:
+ getData()->car = getEntityData(kEntityPlayer)->car;
+
+ if (*_sequence && !_counter) {
+ _counter++;
+ getEntities()->drawSequenceRight(kEntity39, (char *)&_sequence);
+ }
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/entity39.h b/engines/lastexpress/entities/entity39.h
new file mode 100644
index 0000000000..344cf5b494
--- /dev/null
+++ b/engines/lastexpress/entities/entity39.h
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ENTITY39_H
+#define LASTEXPRESS_ENTITY39_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Entity39 : public Entity {
+public:
+ Entity39(LastExpressEngine *engine);
+ ~Entity39() {}
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Process function
+ */
+ DECLARE_FUNCTION(process)
+
+private:
+ char _sequence[12];
+ int _counter;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_##define##_H
diff --git a/engines/lastexpress/entities/entity_intern.h b/engines/lastexpress/entities/entity_intern.h
new file mode 100644
index 0000000000..71607ed511
--- /dev/null
+++ b/engines/lastexpress/entities/entity_intern.h
@@ -0,0 +1,528 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ENTITY_INTERN_H
+#define LASTEXPRESS_ENTITY_INTERN_H
+
+namespace LastExpress {
+
+#define LOW_BYTE(w) ((unsigned char)(((unsigned long)(w)) & 0xff))
+
+//////////////////////////////////////////////////////////////////////////
+// Callbacks
+#define ENTITY_CALLBACK(class, name, pointer) \
+ Common::Functor1Mem<const SavePoint&, void, class>(pointer, &class::name)
+
+#define ADD_CALLBACK_FUNCTION(class, name) \
+ _callbacks.push_back(new ENTITY_CALLBACK(class, name, this));
+
+#define ADD_NULL_FUNCTION() \
+ _callbacks.push_back(new ENTITY_CALLBACK(Entity, nullfunction, this));
+
+//////////////////////////////////////////////////////////////////////////
+// Declaration
+//////////////////////////////////////////////////////////////////////////
+
+#define DECLARE_FUNCTION(name) \
+ void setup_##name(); \
+ void name(const SavePoint &savepoint);
+
+#define DECLARE_FUNCTION_1(name, param1) \
+ void setup_##name(param1); \
+ void name(const SavePoint &savepoint);
+
+#define DECLARE_FUNCTION_2(name, param1, param2) \
+ void setup_##name(param1, param2); \
+ void name(const SavePoint &savepoint);
+
+#define DECLARE_FUNCTION_3(name, param1, param2, param3) \
+ void setup_##name(param1, param2, param3); \
+ void name(const SavePoint &savepoint);
+
+#define DECLARE_FUNCTION_4(name, param1, param2, param3, param4) \
+ void setup_##name(param1, param2, param3, param4); \
+ void name(const SavePoint &savepoint);
+
+#define DECLARE_FUNCTION_NOSETUP(name) \
+ void name(const SavePoint &savepoint);
+
+#define DECLARE_NULL_FUNCTION() \
+ void setup_nullfunction();
+
+//////////////////////////////////////////////////////////////////////////
+// Setup
+//////////////////////////////////////////////////////////////////////////
+
+#define IMPLEMENT_SETUP(class, callback_class, name, index) \
+void class::setup_##name() { \
+ BEGIN_SETUP(callback_class, name, index, EntityData::EntityParametersIIII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::setup_" #name "()"); \
+ END_SETUP() \
+}
+
+#define BEGIN_SETUP(class, name, index, type) \
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, new ENTITY_CALLBACK(class, name, this)); \
+ _data->setCurrentCallback(index); \
+ _data->resetCurrentParameters<type>();
+
+#define END_SETUP() \
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+
+
+//////////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////////
+
+// Expose parameters and check validity
+#define EXPOSE_PARAMS(type) \
+ type *params = (type*)_data->getCurrentParameters(); \
+ if (!params) \
+ error("Trying to call an entity function with invalid parameters!"); \
+
+
+// function signature without setup (we keep the index for consistency but never use it)
+#define IMPLEMENT_FUNCTION_NOSETUP(index, class, name) \
+ void class::name(const SavePoint &savepoint) { \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(index=" #index ")");
+
+// simple setup with no parameters
+#define IMPLEMENT_FUNCTION(index, class, name) \
+ IMPLEMENT_SETUP(class, class, name, index) \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "() - action: %s", ACTION_NAME(savepoint.action));
+
+// nullfunction call
+#define IMPLEMENT_NULL_FUNCTION(index, class) \
+ IMPLEMENT_SETUP(class, Entity, nullfunction, index)
+
+// setup with one uint parameter
+#define IMPLEMENT_FUNCTION_I(index, class, name, paramType) \
+ void class::setup_##name(paramType param1) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersIIII) \
+ EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII*)_data->getCurrentParameters(); \
+ params->param1 = (unsigned int)param1; \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d) - action: %s", params->param1, ACTION_NAME(savepoint.action));
+
+// setup with two uint parameters
+#define IMPLEMENT_FUNCTION_II(index, class, name, paramType1, paramType2) \
+ void class::setup_##name(paramType1 param1, paramType2 param2) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersIIII) \
+ EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII*)_data->getCurrentParameters(); \
+ params->param1 = param1; \
+ params->param2 = param2; \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d) - action: %s", params->param1, params->param2, ACTION_NAME(savepoint.action));
+
+// setup with three uint parameters
+#define IMPLEMENT_FUNCTION_III(index, class, name, paramType1, paramType2, paramType3) \
+ void class::setup_##name(paramType1 param1, paramType2 param2, paramType3 param3) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersIIII) \
+ EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII*)_data->getCurrentParameters(); \
+ params->param1 = param1; \
+ params->param2 = param2; \
+ params->param3 = param3; \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %d) - action: %s", params->param1, params->param2, params->param3, ACTION_NAME(savepoint.action));
+
+// setup with one char *parameter
+#define IMPLEMENT_FUNCTION_S(index, class, name) \
+ void class::setup_##name(const char *seq1) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIIS) \
+ EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); \
+ strncpy((char *)&params->seq1, seq1, 12); \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s) - action: %s", (char *)&params->seq1, ACTION_NAME(savepoint.action));
+
+// setup with one char *parameter and one uint
+#define IMPLEMENT_FUNCTION_SI(index, class, name, paramType2) \
+ void class::setup_##name(const char *seq1, paramType2 param4) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIIS) \
+ EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); \
+ strncpy((char *)&params->seq1, seq1, 12); \
+ params->param4 = param4; \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d) - action: %s", (char *)&params->seq1, params->param4, ACTION_NAME(savepoint.action));
+
+// setup with one char *parameter and two uints
+#define IMPLEMENT_FUNCTION_SII(index, class, name, paramType2, paramType3) \
+ void class::setup_##name(const char *seq1, paramType2 param4, paramType3 param5) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIIS) \
+ EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); \
+ strncpy((char *)&params->seq1, seq1, 12); \
+ params->param4 = param4; \
+ params->param5 = param5; \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d) - action: %s", (char *)&params->seq1, params->param4, params->param5, ACTION_NAME(savepoint.action));
+
+// setup with one char *parameter and three uints
+#define IMPLEMENT_FUNCTION_SIII(index, class, name, paramType2, paramType3, paramType4) \
+ void class::setup_##name(const char *seq, paramType2 param4, paramType3 param5, paramType4 param6) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIII) \
+ EntityData::EntityParametersSIII *params = (EntityData::EntityParametersSIII*)_data->getCurrentParameters(); \
+ strncpy((char *)&params->seq, seq, 12); \
+ params->param4 = param4; \
+ params->param5 = param5; \
+ params->param6 = param6; \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersSIII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d, %d) - action: %s", (char *)&params->seq, params->param4, params->param5, params->param6, ACTION_NAME(savepoint.action));
+
+#define IMPLEMENT_FUNCTION_SIIS(index, class, name, paramType2, paramType3) \
+ void class::setup_##name(const char *seq1, paramType2 param4, paramType3 param5, const char *seq2) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIIS) \
+ EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); \
+ strncpy((char *)&params->seq1, seq1, 12); \
+ params->param4 = param4; \
+ params->param5 = param5; \
+ strncpy((char *)&params->seq2, seq2, 12); \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d, %s) - action: %s", (char *)&params->seq1, params->param4, params->param5, (char *)&params->seq2, ACTION_NAME(savepoint.action));
+
+#define IMPLEMENT_FUNCTION_SS(index, class, name) \
+ void class::setup_##name(const char *seq1, const char *seq2) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersSSII) \
+ EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII*)_data->getCurrentParameters(); \
+ strncpy((char *)&params->seq1, seq1, 12); \
+ strncpy((char *)&params->seq2, seq2, 12); \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersSSII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %s) - action: %s", (char *)&params->seq1, (char *)&params->seq2, ACTION_NAME(savepoint.action));
+
+#define IMPLEMENT_FUNCTION_SSI(index, class, name, paramType3) \
+ void class::setup_##name(const char *seq1, const char *seq2, paramType3 param7) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersSSII) \
+ EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII*)_data->getCurrentParameters(); \
+ strncpy((char *)&params->seq1, seq1, 12); \
+ strncpy((char *)&params->seq2, seq2, 12); \
+ params->param7 = param7; \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersSSII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %s, %d) - action: %s", (char *)&params->seq1, (char *)&params->seq2, params->param7, ACTION_NAME(savepoint.action));
+
+#define IMPLEMENT_FUNCTION_IS(index, class, name, paramType) \
+ void class::setup_##name(paramType param1, const char *seq) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersISII) \
+ EntityData::EntityParametersISII *params = (EntityData::EntityParametersISII*)_data->getCurrentParameters(); \
+ params->param1 = (unsigned int)param1; \
+ strncpy((char *)&params->seq, seq, 12); \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersISII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %s) - action: %s", params->param1, (char *)&params->seq, ACTION_NAME(savepoint.action));
+
+#define IMPLEMENT_FUNCTION_ISS(index, class, name, paramType) \
+ void class::setup_##name(paramType param1, const char *seq1, const char *seq2) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersISSI) \
+ EntityData::EntityParametersISSI *params = (EntityData::EntityParametersISSI*)_data->getCurrentParameters(); \
+ params->param1 = param1; \
+ strncpy((char *)&params->seq1, seq1, 12); \
+ strncpy((char *)&params->seq2, seq2, 12); \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersISSI) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %s, %s) - action: %s", params->param1, (char *)&params->seq1, (char *)&params->seq2, ACTION_NAME(savepoint.action));
+
+#define IMPLEMENT_FUNCTION_IIS(index, class, name, paramType1, paramType2) \
+ void class::setup_##name(paramType1 param1, paramType2 param2, const char *seq) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersIISI) \
+ EntityData::EntityParametersIISI *params = (EntityData::EntityParametersIISI*)_data->getCurrentParameters(); \
+ params->param1 = param1; \
+ params->param2 = param2; \
+ strncpy((char *)&params->seq, seq, 12); \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersIISI) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %s) - action: %s", params->param1, params->param2, (char *)&params->seq, ACTION_NAME(savepoint.action));
+
+#define IMPLEMENT_FUNCTION_IISS(index, class, name, paramType1, paramType2) \
+ void class::setup_##name(paramType1 param1, paramType2 param2, const char *seq1, const char *seq2) { \
+ BEGIN_SETUP(class, name, index, EntityData::EntityParametersIISS) \
+ EntityData::EntityParametersIISS *params = (EntityData::EntityParametersIISS*)_data->getCurrentParameters(); \
+ params->param1 = param1; \
+ params->param2 = param2; \
+ strncpy((char *)&params->seq1, seq1, 12); \
+ strncpy((char *)&params->seq2, seq2, 12); \
+ END_SETUP() \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersIISS) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %s, %s) - action: %s", params->param1, params->param2, (char *)&params->seq1, (char *)&params->seq2, ACTION_NAME(savepoint.action));
+
+
+//////////////////////////////////////////////////////////////////////////
+// Misc
+//////////////////////////////////////////////////////////////////////////
+#define RESET_ENTITY_STATE(entity, class, function) \
+ getEntities()->resetState(entity); \
+ ((class*)getEntities()->get(entity))->function();
+
+//////////////////////////////////////////////////////////////////////////
+// Parameters macros (for default IIII parameters)
+//////////////////////////////////////////////////////////////////////////
+#define CURRENT_PARAM(index, id) \
+ ((EntityData::EntityParametersIIII*)_data->getCurrentParameters(index))->param##id
+
+#define ENTITY_PARAM(index, id) \
+ ((EntityData::EntityParametersIIII*)_data->getParameters(8, index))->param##id
+
+//////////////////////////////////////////////////////////////////////////
+// Time check macros
+//////////////////////////////////////////////////////////////////////////
+#define TIME_CHECK(timeValue, parameter, function) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ function(); \
+ break; \
+ }
+
+#define TIME_CHECK_SAVEPOINT(timeValue, parameter, entity1, entity2, action) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ getSavePoints()->push(entity1, entity2, action); \
+ }
+
+#define TIME_CHECK_CALLBACK(timeValue, parameter, callback, function) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ setCallback(callback); \
+ function(); \
+ break; \
+ }
+
+#define TIME_CHECK_CALLBACK_1(timeValue, parameter, callback, function, param1) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ setCallback(callback); \
+ function(param1); \
+ break; \
+ }
+
+#define TIME_CHECK_CALLBACK_2(timeValue, parameter, callback, function, param1, param2) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ setCallback(callback); \
+ function(param1, param2); \
+ break; \
+ }
+
+#define TIME_CHECK_CALLBACK_3(timeValue, parameter, callback, function, param1, param2, param3) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ setCallback(callback); \
+ function(param1, param2, param3); \
+ break; \
+ }
+
+#define TIME_CHECK_CALLBACK_INVENTORY(timeValue, parameter, callback, function) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ getData()->inventoryItem = kItemNone; \
+ setCallback(callback); \
+ function(); \
+ break; \
+ }
+
+#define TIME_CHECK_CALLBACK_ACTION(timeValue, parameter) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ CALLBACK_ACTION(); \
+ break; \
+ }
+
+#define TIME_CHECK_PLAYSOUND_UPDATEPOSITION(timeValue, parameter, callback, sound, position) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ getData()->entityPosition = position; \
+ setCallback(callback); \
+ setup_playSound(sound); \
+ break; \
+ }
+
+#define TIME_CHECK_OBJECT(timeValue, parameter, object, location) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ getObjects()->updateLocation2(object, location); \
+ }
+
+#define TIME_CHECK_CAR(timeValue, parameter, callback, function) {\
+ if ((getState()->time <= timeValue && !getEntities()->isPlayerInCar(kCarGreenSleeping)) || !parameter) \
+ parameter = (uint)getState()->time + 75; \
+ if (getState()->time > timeValue || parameter < getState()->time) { \
+ parameter = kTimeInvalid; \
+ setCallback(callback); \
+ function(); \
+ break; \
+ } \
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Callback action
+//////////////////////////////////////////////////////////////////////////
+#define CALLBACK_ACTION() { \
+ if (getData()->currentCall == 0) \
+ error("CALLBACK_ACTION: currentCall is already 0, cannot proceed!"); \
+ getData()->currentCall--; \
+ getSavePoints()->setCallback(_entityIndex, _callbacks[_data->getCurrentCallback()]); \
+ getSavePoints()->call(_entityIndex, _entityIndex, kActionCallback); \
+ }
+
+//////////////////////////////////////////////////////////////////////////
+// Param update
+//////////////////////////////////////////////////////////////////////////
+#define UPDATE_PARAM(parameter, type, value) { \
+ if (!parameter) \
+ parameter = (uint)(type + value); \
+ if (parameter >= type) \
+ break; \
+ parameter = kTimeInvalid; \
+}
+
+// Todo: replace with UPDATE_PARAM_PROC as appropriate
+#define UPDATE_PARAM_GOTO(parameter, type, value, label) { \
+ if (!parameter) \
+ parameter = (uint)(type + value); \
+ if (parameter >= type) \
+ goto label; \
+ parameter = kTimeInvalid; \
+}
+
+// Updating parameter with code inside the check
+#define UPDATE_PARAM_PROC(parameter, type, value) \
+ if (!parameter) \
+ parameter = (uint)(type + value); \
+ if (parameter < type) { \
+ parameter = kTimeInvalid;
+
+#define UPDATE_PARAM_PROC_TIME(timeValue, test, parameter, value) \
+ if (getState()->time <= timeValue) { \
+ if (test || !parameter) \
+ parameter = (uint)(getState()->time + value); \
+ } \
+ if (parameter < getState()->time || getState()->time > timeValue) { \
+ parameter = kTimeInvalid;
+
+#define UPDATE_PARAM_PROC_END }
+
+// Updating parameter with an added check (and code inside the check)
+#define UPDATE_PARAM_CHECK(parameter, type, value) \
+ if (!parameter || parameter < type) { \
+ if (!parameter) \
+ parameter = (uint)(type + value);
+
+//////////////////////////////////////////////////////////////////////////
+// Compartments
+//////////////////////////////////////////////////////////////////////////
+// Go from one compartment to another (or the same one if no optional args are passed
+#define COMPARTMENT_TO(class, compartmentFrom, positionFrom, sequenceFrom, sequenceTo) \
+ switch (savepoint.action) { \
+ default: \
+ break; \
+ case kActionDefault: \
+ getData()->entityPosition = positionFrom; \
+ setCallback(1); \
+ setup_enterExitCompartment(sequenceFrom, compartmentFrom); \
+ break; \
+ case kActionCallback: \
+ switch (getCallback()) { \
+ default: \
+ break; \
+ case 1: \
+ setCallback(2); \
+ setup_enterExitCompartment(sequenceTo, compartmentFrom); \
+ break; \
+ case 2: \
+ getData()->entityPosition = positionFrom; \
+ getEntities()->clearSequences(_entityIndex); \
+ CALLBACK_ACTION(); \
+ } \
+ break; \
+ }
+
+#define COMPARTMENT_FROM_TO(class, compartmentFrom, positionFrom, sequenceFrom, compartmentTo, positionTo, sequenceTo) \
+ switch (savepoint.action) { \
+ default: \
+ break; \
+ case kActionDefault: \
+ getData()->entityPosition = positionFrom; \
+ getData()->location = kLocationOutsideCompartment; \
+ setCallback(1); \
+ setup_enterExitCompartment(sequenceFrom, compartmentFrom); \
+ break; \
+ case kActionCallback: \
+ switch (getCallback()) { \
+ default: \
+ break; \
+ case 1: \
+ setCallback(2); \
+ setup_updateEntity(kCarGreenSleeping, positionTo); \
+ break; \
+ case 2: \
+ setCallback(3); \
+ setup_enterExitCompartment(sequenceTo, compartmentTo); \
+ break; \
+ case 3: \
+ getData()->location = kLocationInsideCompartment; \
+ getEntities()->clearSequences(_entityIndex); \
+ CALLBACK_ACTION(); \
+ break; \
+ } \
+ break; \
+ }
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ENTITY_INTERN_H
diff --git a/engines/lastexpress/entities/francois.cpp b/engines/lastexpress/entities/francois.cpp
new file mode 100644
index 0000000000..bec164e116
--- /dev/null
+++ b/engines/lastexpress/entities/francois.cpp
@@ -0,0 +1,1295 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/francois.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Francois::Francois(LastExpressEngine *engine) : Entity(engine, kEntityFrancois) {
+ ADD_CALLBACK_FUNCTION(Francois, reset);
+ ADD_CALLBACK_FUNCTION(Francois, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Francois, draw);
+ ADD_CALLBACK_FUNCTION(Francois, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Francois, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Francois, playSound);
+ ADD_CALLBACK_FUNCTION(Francois, savegame);
+ ADD_CALLBACK_FUNCTION(Francois, updateEntity);
+ ADD_CALLBACK_FUNCTION(Francois, function9);
+ ADD_CALLBACK_FUNCTION(Francois, function10);
+ ADD_CALLBACK_FUNCTION(Francois, function11);
+ ADD_CALLBACK_FUNCTION(Francois, function12);
+ ADD_CALLBACK_FUNCTION(Francois, function13);
+ ADD_CALLBACK_FUNCTION(Francois, function14);
+ ADD_CALLBACK_FUNCTION(Francois, function15);
+ ADD_CALLBACK_FUNCTION(Francois, function16);
+ ADD_CALLBACK_FUNCTION(Francois, chapter1);
+ ADD_CALLBACK_FUNCTION(Francois, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Francois, function19);
+ ADD_CALLBACK_FUNCTION(Francois, function20);
+ ADD_CALLBACK_FUNCTION(Francois, chapter2);
+ ADD_CALLBACK_FUNCTION(Francois, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Francois, function23);
+ ADD_CALLBACK_FUNCTION(Francois, chapter3);
+ ADD_CALLBACK_FUNCTION(Francois, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Francois, chapter4);
+ ADD_CALLBACK_FUNCTION(Francois, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Francois, chapter5);
+ ADD_CALLBACK_FUNCTION(Francois, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Francois, function30);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Francois, reset)
+ Entity::reset(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(2, Francois, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Francois, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(4, Francois, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(5, Francois, enterExitCompartment2, ObjectIndex)
+ Entity::enterExitCompartment(savepoint, kPosition_5790, kPosition_6130, kCarRedSleeping, kObjectCompartmentD, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(6, Francois, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(7, Francois, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(8, Francois, updateEntity, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ } else {
+ if (!getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000)
+ || !getInventory()->hasItem(kItemFirebird)
+ || getEvent(kEventFrancoisShowEgg)
+ || getEvent(kEventFrancoisShowEggD)
+ || getEvent(kEventFrancoisShowEggNight)
+ || getEvent(kEventFrancoisShowEggNightD)) {
+ if (getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000)
+ && getInventory()->get(kItemBeetle)->location == kObjectLocation1
+ && !getEvent(kEventFrancoisShowBeetle)
+ && !getEvent(kEventFrancoisShowBeetleD))
+ getData()->inventoryItem = kItemMatchBox;
+ } else {
+ getData()->inventoryItem = kItemFirebird;
+ }
+
+ if (ENTITY_PARAM(0, 1)
+ && getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 1000)
+ && !getEntities()->isInsideCompartments(kEntityPlayer)
+ && !getEntities()->checkFields10(kEntityPlayer)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventFrancoisTradeWhistle);
+ }
+ }
+ break;
+
+ case kAction1:
+ switch (savepoint.param.intValue) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventFrancoisShowBeetle);
+ break;
+
+ case 18:
+ if (isNight())
+ getAction()->playAnimation(getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition ? kEventFrancoisShowEggNightD : kEventFrancoisShowEggNight);
+ else
+ getAction()->playAnimation(getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition ? kEventFrancoisShowEggD : kEventFrancoisShowEgg);
+
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ break;
+ }
+ break;
+
+ case kActionExcuseMeCath:
+ case kActionExcuseMe:
+ getSound()->excuseMe(_entityIndex);
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition ? kEventFrancoisTradeWhistleD : kEventFrancoisTradeWhistle);
+ getInventory()->addItem(kItemWhistle);
+ getInventory()->removeItem(kItemMatchBox);
+ getInventory()->get(kItemBeetle)->location = kObjectLocation2;
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ ENTITY_PARAM(0, 1) = 0;
+ break;
+
+ case 2:
+ getAction()->playAnimation(getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition ? kEventFrancoisShowBeetleD : kEventFrancoisShowBeetle);
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionUp ? -1 : 1))), getData()->direction == kDirectionUp);
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Francois, function9)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getObjects()->get(kObjectCompartmentD).location == kObjectLocation2) {
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getSavePoints()->push(kEntityFrancois, kEntityMmeBoutarel, kAction134289824);
+ setCallback(1);
+ setup_enterExitCompartment("605Cd", kObjectCompartmentD);
+ } else {
+ setCallback(2);
+ setup_enterExitCompartment("605Ed", kObjectCompartmentD);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Francois, function10)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getObjects()->get(kObjectCompartmentD).location == kObjectLocation2) {
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ setCallback(1);
+ setup_enterExitCompartment("605Bd", kObjectCompartmentD);
+ } else {
+ setCallback(2);
+ setup_enterExitCompartment("605Dd", kObjectCompartmentD);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getSavePoints()->push(kEntityFrancois, kEntityMmeBoutarel, kAction102484312);
+ break;
+
+ case 2:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityFrancois);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(11, Francois, function11, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getSound()->isBuffered(kEntityFrancois)) {
+
+ UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->timeTicks, params->param6)
+ switch (rnd(7)) {
+ default:
+ break;
+
+ case 0:
+ getSound()->playSound(kEntityFrancois, "Fra1002A");
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityFrancois, "Fra1002B");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityFrancois, "Fra1002C");
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityFrancois, "Fra1002D");
+ break;
+
+ case 4:
+ getSound()->playSound(kEntityFrancois, "Fra1002E");
+ break;
+
+ case 5:
+ case 6:
+ getSound()->playSound(kEntityFrancois, "Fra1002F");
+ break;
+ }
+
+ params->param6 = 15 * rnd(7);
+ CURRENT_PARAM(1, 1) = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (!getEntities()->hasValidFrame(kEntityFrancois) || !getEntities()->isWalkingOppositeToPlayer(kEntityFrancois))
+ getData()->inventoryItem = kItemNone;
+
+ if (getEntities()->updateEntity(kEntityFrancois, (CarIndex)params->param2, (EntityPosition)params->param3)) {
+ params->param5 = 0;
+
+ if (params->param3 == kPosition_540) {
+ params->param2 = (getProgress().chapter == kChapter1) ? kCarRedSleeping : kCarGreenSleeping;
+ params->param3 = kPosition_9460;
+ } else {
+ params->param2 = kCarGreenSleeping;
+ params->param3 = kPosition_540;
+ params->param7 = 0;
+ params->param8 = 0;
+
+ getSavePoints()->push(kEntityFrancois, kEntityCoudert, kAction225932896);
+ getSavePoints()->push(kEntityFrancois, kEntityMertens, kAction225932896);
+ }
+ }
+
+ if (getEntities()->checkDistanceFromPosition(kEntityFrancois, kPosition_2000, 500) && getData()->direction == kDirectionDown) {
+
+ if (getEntities()->isInsideTrainCar(kEntityFrancois, kCarRedSleeping) && params->param8) {
+ setCallback(2);
+ setup_draw("605A");
+ break;
+ }
+
+ if (getEntities()->isInsideTrainCar(kEntityFrancois, kCarGreenSleeping) && params->param7) {
+ setCallback(3);
+ setup_draw("605A");
+ break;
+ }
+ }
+
+label_callback:
+ if (getProgress().chapter == kChapter1) {
+
+ if (getEntities()->isInsideTrainCar(kEntityFrancois, kCarRedSleeping)
+ && (getEntities()->hasValidFrame(kEntityFrancois) || params->param1 < getState()->time || params->param4)
+ && !params->param5
+ && getData()->entityPosition < getEntityData(kEntityMmeBoutarel)->entityPosition) {
+
+ if (getData()->direction == kDirectionDown) {
+ getSavePoints()->push(kEntityFrancois, kEntityMmeBoutarel, kAction202221040);
+ params->param4 = 1;
+ params->param5 = 1;
+ } else if (params->param4 && getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityMmeBoutarel, 1000)) {
+ getSavePoints()->push(kEntityFrancois, kEntityMmeBoutarel, kAction168986720);
+ params->param5 = 1;
+ }
+ }
+ } else if (params->param1 < getState()->time) {
+ getData()->clothes = kClothesDefault;
+ getData()->field_4A3 = 30;
+ getData()->inventoryItem = kItemNone;
+
+ if (getSound()->isBuffered(kEntityFrancois))
+ getSound()->processEntry(kEntityFrancois);
+
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ if (getSound()->isBuffered(kEntityFrancois))
+ getSound()->processEntry(kEntityFrancois);
+
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventFrancoisWhistle);
+ break;
+
+ case kActionExcuseMeCath:
+ if (getProgress().jacket == kJacketGreen
+ && !getEvent(kEventFrancoisWhistle)
+ && !getEvent(kEventFrancoisWhistleD)
+ && !getEvent(kEventFrancoisWhistleNight)
+ && !getEvent(kEventFrancoisWhistleNightD))
+ getData()->inventoryItem = kItemInvalid;
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function9();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->clothes = kClothes1;
+ getData()->field_4A3 = 100;
+ getData()->inventoryItem = kItemNone;
+
+ params->param2 = kCarGreenSleeping;
+ params->param3 = kPosition_540;
+
+ getEntities()->updateEntity(kEntityFrancois, kCarGreenSleeping, kPosition_540);
+
+ params->param6 = 15 * rnd(7);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityFrancois, kEntityCoudert, kAction168253822);
+ // Fallback to next case
+
+ case 3:
+ params->param2 = kCarRedSleeping;
+ params->param3 = kPosition_9460;
+ params->param5 = 0;
+
+ getData()->entityPosition = kPosition_2088;
+
+ getEntities()->updateEntity(kEntityFrancois, kCarRedSleeping, kPosition_9460);
+ goto label_callback;
+
+ case 4:
+ setCallback(5);
+ setup_function10();
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ if (getProgress().jacket == kJacketGreen) {
+ if (isNight())
+ getAction()->playAnimation(getData()->entityPosition <= getEntityData(kEntityPlayer)->entityPosition ? kEventFrancoisWhistleNightD : kEventFrancoisWhistleNight);
+ else
+ getAction()->playAnimation(getData()->entityPosition <= getEntityData(kEntityPlayer)->entityPosition ? kEventFrancoisWhistleD : kEventFrancoisWhistleD);
+ }
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750 * (getData()->direction == kDirectionUp ? -1 : 1)), getData()->direction == kDirectionUp);
+ break;
+ }
+ break;
+
+ case kAction102752636:
+ getEntities()->clearSequences(kEntityFrancois);
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_5790;
+ getData()->clothes = kClothesDefault;
+ getData()->field_4A3 = 30;
+ getData()->inventoryItem = kItemNone;
+
+ CALLBACK_ACTION();
+ break;
+
+ case kAction205346192:
+ if (savepoint.entity2 == kEntityCoudert)
+ params->param8 = 1;
+ else if (savepoint.entity2 == kEntityMertens)
+ params->param7 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Francois, function12)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function9();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateFromTime(675);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_540);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_updateFromTime(675);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function10();
+ break;
+
+ case 7:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Francois, function13)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function9();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_540);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_4070);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment("605Df", kObjectCompartment6);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityFrancois);
+
+ setCallback(5);
+ setup_playSound("Har2010");
+ break;
+
+ case 5:
+ getSavePoints()->push(kEntityFrancois, kEntityAlouan, kAction189489753);
+ break;
+
+ case 6:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(7);
+ setup_updateEntity(kCarGreenSleeping, kPosition_4840);
+ break;
+
+ case 7:
+ if (getInventory()->hasItem(kItemWhistle) || getInventory()->get(kItemWhistle)->location == kObjectLocation3) {
+ setCallback(10);
+ setup_updateEntity(kCarGreenSleeping, kPosition_5790);
+ break;
+ }
+
+ getEntities()->drawSequenceLeft(kEntityFrancois, "605He");
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_updateFromTime(450);
+ break;
+
+ case 9:
+ getEntities()->exitCompartment(kEntityFrancois, kObjectCompartmentE, true);
+
+ setCallback(10);
+ setup_updateEntity(kCarGreenSleeping, kPosition_5790);
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_function10();
+ break;
+
+ case 11:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction190219584:
+ setCallback(6);
+ setup_enterExitCompartment("605Ef", kObjectCompartment6);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IIS(14, Francois, function14, ObjectIndex, EntityPosition)
+ // Expose parameters as IISS and ignore the default exposed parameters
+ EntityData::EntityParametersIISS *parameters = (EntityData::EntityParametersIISS*)_data->getCurrentParameters();
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ strcpy((char *)&parameters->seq2, "605H");
+ strcat((char *)&parameters->seq2, (char *)&parameters->seq1);
+
+ setCallback(1);
+ setup_function9();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, (EntityPosition)parameters->param2);
+ break;
+
+ case 2:
+ if (getInventory()->get(kItemBeetle)->location == kObjectLocation3) {
+ getEntities()->drawSequenceLeft(kEntityFrancois, (char *)&parameters->seq2);
+ getEntities()->enterCompartment(kEntityFrancois, (ObjectIndex)parameters->param1, true);
+
+ setCallback(3);
+ setup_playSound("Fra2005A");
+ } else {
+ if (parameters->param2 >= kPosition_5790) {
+ setCallback(10);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ } else {
+ setCallback(9);
+ setup_updateEntity(kCarRedSleeping, kPosition_540);
+ }
+ }
+ break;
+
+ case 3:
+ case 5:
+ setCallback(getCallback() + 1);
+ setup_updateFromTime(rnd(450));
+ break;
+
+ case 4:
+ case 6:
+ setCallback(getCallback() + 1);
+ setup_playSound(rnd(2) ? "Fra2005B" : "Fra2005C");
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_updateFromTime(rnd(150));
+ break;
+
+ case 8:
+ getEntities()->exitCompartment(kEntityFrancois, (ObjectIndex)parameters->param1);
+ // Fallback to next case
+
+ case 9:
+ setCallback(10);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_updateFromTime(900);
+ break;
+
+ case 11:
+ setCallback(12);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case 12:
+ setCallback(13);
+ setup_function10();
+ break;
+
+ case 13:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Francois, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function9();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getData()->entityPosition >= getEntityData(kEntityPlayer)->entityPosition) {
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_540);
+ } else {
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ }
+ break;
+
+ case 2:
+ case 3:
+ setCallback(4);
+ setup_updateFromTime(450);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function10();
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_updateFromTime(900);
+ break;
+
+ case 7:
+ if (!getEntities()->isInsideCompartment(kEntityMmeBoutarel, kCarRedSleeping, kPosition_5790)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ setCallback(8);
+ setup_playSound("Fra2012");
+ break;
+
+ case 8:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Francois, function16)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ getData()->entityPosition = getEntityData(kEntityBoutarel)->entityPosition;
+ getData()->location = getEntityData(kEntityBoutarel)->location;
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_enterExitCompartment("605Cd", kObjectCompartmentD);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getData()->entityPosition = kPosition_5890;
+
+ getSavePoints()->push(kEntityFrancois, kEntityMmeBoutarel, kAction101107728);
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityFrancois);
+ getSavePoints()->push(kEntityFrancois, kEntityBoutarel, kAction237889408);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment("605Id", kObjectCompartmentD);
+ break;
+
+ case 4:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getSavePoints()->push(kEntityFrancois, kEntityMmeBoutarel, kAction100957716);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction100901266:
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Francois, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Francois, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK_1(kTimeParisEpernay, params->param1, 1, setup_function11, kTime1093500);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function19();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Francois, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTime1161000, params->param1, 2, setup_function12);
+ break;
+
+ case kAction101107728:
+ setCallback(1);
+ setup_function16();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Francois, function20)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->clearSequences(kEntityFrancois);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Francois, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityFrancois);
+
+ getData()->entityPosition = kPosition_4689;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Francois, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("605Id", kObjectCompartmentD);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getSavePoints()->push(kEntityFrancois, kEntityMmeBoutarel, kAction100957716);
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityFrancois);
+ setup_function23();
+ break;
+ }
+ break;
+
+ case kAction100901266:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Francois, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEvent(kEventFrancoisShowBeetle) || getEvent(kEventFrancoisShowBeetleD))
+ if (!getEvent(kEventFrancoisTradeWhistle) && !getEvent(kEventFrancoisTradeWhistleD))
+ ENTITY_PARAM(0, 1) = 1;
+
+ if (ENTITY_PARAM(0, 1) && getEntities()->isPlayerInCar(kCarRedSleeping)) {
+ setCallback(1);
+ setup_function15();
+ break;
+ }
+
+label_callback_1:
+ TIME_CHECK_CALLBACK_1(kTime1764000, params->param1, 2, setup_playSound, "Fra2011");
+
+label_callback_2:
+ TIME_CHECK_CALLBACK(kTime1800000, params->param2, 3, setup_function13);
+
+label_callback_3:
+ if (!getInventory()->hasItem(kItemWhistle) && getInventory()->get(kItemWhistle)->location != kObjectLocation3) {
+ TIME_CHECK_CALLBACK_1(kTime1768500, params->param3, 4, setup_function11, kTime1773000);
+
+label_callback_4:
+ TIME_CHECK_CALLBACK_1(kTime1827000, params->param4, 5, setup_function11, kTime1831500);
+ }
+
+label_callback_5:
+ if (getInventory()->get(kItemWhistle)->location != kObjectLocation3) {
+ // TODO: do we also need to check if the whistle is in the inventory?
+ break;
+ }
+
+ if (params->param5 != kTimeInvalid) {
+ UPDATE_PARAM_PROC_TIME(kTimeEnd, !getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000), params->param5, 75);
+ setCallback(6);
+ setup_playSound("Fra2010");
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+label_callback_6:
+ TIME_CHECK_CALLBACK_3(kTime1782000, params->param6, 7, setup_function14, kObjectCompartmentC, kPosition_6470, "c");
+
+label_callback_7:
+ TIME_CHECK_CALLBACK_3(kTime1813500, params->param7, 8, setup_function14, kObjectCompartmentF, kPosition_4070, "f");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ getProgress().field_9C = 1;
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Francois, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityFrancois);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Francois, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEvent(kEventFrancoisShowBeetle) || getEvent(kEventFrancoisShowBeetleD))
+ if (!getEvent(kEventFrancoisTradeWhistle) && !getEvent(kEventFrancoisTradeWhistleD))
+ ENTITY_PARAM(0, 1) = 1;
+
+ if (params->param2 && getEntities()->isInsideCompartment(kEntityMmeBoutarel, kCarRedSleeping, kPosition_5790) && !params->param1) {
+
+ if (ENTITY_PARAM(0, 1) && getEntities()->isPlayerInCar(kCarRedSleeping)) {
+ setCallback(2);
+ setup_function15();
+ break;
+ }
+
+label_callback_2:
+ TIME_CHECK_CALLBACK(kTime2025000, params->param3, 3, setup_function12);
+
+label_callback_3:
+ TIME_CHECK_CALLBACK(kTime2052000, params->param4, 4, setup_function12);
+
+label_callback_4:
+ TIME_CHECK_CALLBACK(kTime2079000, params->param5, 5, setup_function12);
+
+label_callback_5:
+ TIME_CHECK_CALLBACK(kTime2092500, params->param6, 6, setup_function12);
+
+label_callback_6:
+ TIME_CHECK_CALLBACK(kTime2173500, params->param7, 7, setup_function12);
+
+label_callback_7:
+ TIME_CHECK_CALLBACK(kTime2182500, params->param8, 8, setup_function12);
+
+label_callback_8:
+ TIME_CHECK_CALLBACK(kTime2241000, CURRENT_PARAM(1, 1), 9, setup_function12);
+
+label_callback_9:
+ if (!getInventory()->hasItem(kItemWhistle) && getInventory()->get(kItemWhistle)->location != kObjectLocation3) {
+ TIME_CHECK_CALLBACK_1(kTime2011500, CURRENT_PARAM(1, 2), 10, setup_function11, kTime2016000);
+
+label_callback_10:
+ TIME_CHECK_CALLBACK_1(kTime2115000, CURRENT_PARAM(1, 3), 11, setup_function11, kTime2119500);
+ }
+
+label_callback_11:
+ if (getInventory()->get(kItemWhistle)->location == kObjectLocation3) {
+ if (getState()->time <= kTimeEnd)
+ if (!getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000) || !params->param4)
+ params->param4 = (uint)(getState()->time + 75);
+
+ if (params->param4 < getState()->time || getState()->time > kTimeEnd) {
+ params->param4 = kTimeInvalid;
+
+ setCallback(12);
+ setup_playSound("Fra2010");
+ break;
+ }
+
+label_callback_12:
+ TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 5), 13, setup_function14, kObjectCompartmentE, kPosition_4840, "e");
+
+label_callback_13:
+ TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 6), 14, setup_function14, kObjectCompartmentF, kPosition_4070, "f");
+
+label_callback_14:
+ TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 7), 15, setup_function14, kObjectCompartmentB, kPosition_7500, "b");
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param2 = 1;
+ break;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+
+ case 8:
+ goto label_callback_8;
+
+ case 9:
+ goto label_callback_9;
+
+ case 10:
+ goto label_callback_10;
+
+ case 11:
+ goto label_callback_11;
+
+ case 12:
+ getProgress().field_9C = 1;
+ goto label_callback_12;
+
+ case 13:
+ goto label_callback_13;
+
+ case 14:
+ goto label_callback_14;
+ }
+ break;
+
+ case kAction101107728:
+ setCallback(1);
+ setup_function16();
+ break;
+
+ case kAction189872836:
+ params->param1 = 1;
+ break;
+ case kAction190390860:
+ params->param1 = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Francois, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityFrancois);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Francois, chapter4Handler)
+ if (savepoint.action == kAction101107728) {
+ setCallback(1);
+ setup_function16();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Francois, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityFrancois);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Francois, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5) {
+ if (!getInventory()->hasItem(kItemWhistle)
+ && getInventory()->get(kItemWhistle)->location != kObjectLocation3)
+ getInventory()->setLocationAndProcess(kItemWhistle, kObjectLocation1);
+
+ setup_function30();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Francois, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(31, Francois)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/francois.h b/engines/lastexpress/entities/francois.h
new file mode 100644
index 0000000000..c924cf677b
--- /dev/null
+++ b/engines/lastexpress/entities/francois.h
@@ -0,0 +1,170 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_FRANCOIS_H
+#define LASTEXPRESS_FRANCOIS_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Francois : public Entity {
+public:
+ Francois(LastExpressEngine *engine);
+ ~Francois() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION(function9)
+ DECLARE_FUNCTION(function10)
+ DECLARE_FUNCTION_1(function11, TimeValue timeValue)
+ DECLARE_FUNCTION(function12)
+ DECLARE_FUNCTION(function13)
+ DECLARE_FUNCTION_3(function14, ObjectIndex compartment, EntityPosition entityPosition, const char *str)
+ DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION(function16)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function19)
+ DECLARE_FUNCTION(function20)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function23)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function30)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FRANCOIS_H
diff --git a/engines/lastexpress/entities/gendarmes.cpp b/engines/lastexpress/entities/gendarmes.cpp
new file mode 100644
index 0000000000..620a885a60
--- /dev/null
+++ b/engines/lastexpress/entities/gendarmes.cpp
@@ -0,0 +1,620 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/gendarmes.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Gendarmes::Gendarmes(LastExpressEngine *engine) : Entity(engine, kEntityGendarmes) {
+ ADD_CALLBACK_FUNCTION(Gendarmes, reset);
+ ADD_CALLBACK_FUNCTION(Gendarmes, chapter1);
+ ADD_CALLBACK_FUNCTION(Gendarmes, arrestDraw);
+ ADD_CALLBACK_FUNCTION(Gendarmes, arrestPlaysound);
+ ADD_CALLBACK_FUNCTION(Gendarmes, arrestPlaysound16);
+ ADD_CALLBACK_FUNCTION(Gendarmes, arrestCallback);
+ ADD_CALLBACK_FUNCTION(Gendarmes, savegame);
+ ADD_CALLBACK_FUNCTION(Gendarmes, arrestUpdateEntity);
+ ADD_CALLBACK_FUNCTION(Gendarmes, function9);
+ ADD_CALLBACK_FUNCTION(Gendarmes, function10);
+ ADD_CALLBACK_FUNCTION(Gendarmes, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Gendarmes, function12);
+ ADD_CALLBACK_FUNCTION(Gendarmes, function13);
+ ADD_CALLBACK_FUNCTION(Gendarmes, chapter2);
+ ADD_CALLBACK_FUNCTION(Gendarmes, chapter3);
+ ADD_CALLBACK_FUNCTION(Gendarmes, chapter4);
+ ADD_CALLBACK_FUNCTION(Gendarmes, chapter5);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Gendarmes, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(2, Gendarmes, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Gendarmes, arrestDraw)
+ arrest(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(4, Gendarmes, arrestPlaysound)
+ arrest(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(5, Gendarmes, arrestPlaysound16)
+ arrest(savepoint, true, SoundManager::kFlagDefault);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(6, Gendarmes, arrestCallback, uint32)
+ arrest(savepoint, true, SoundManager::kFlagInvalid, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(7, Gendarmes, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(8, Gendarmes, arrestUpdateEntity, CarIndex, EntityPosition)
+ arrest(savepoint, true, SoundManager::kFlagInvalid, false, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
+ EntityData::EntityParametersSSS *parameters1 = (EntityData::EntityParametersSSS*)_data->getCurrentParameters(1);
+ EntityData::EntityParametersISII *parameters2 = (EntityData::EntityParametersISII*)_data->getCurrentParameters(2);
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (params->param2 <= kPosition_3050) {
+ if (params->param2 != kPosition_3050) {
+ if (params->param2 == kPosition_2740)
+ parameters2->param5 = kObjectCompartment8;
+ } else {
+ parameters2->param5 = kObjectCompartment7;
+ parameters2->param6 = true;
+ }
+ } else if (params->param2 <= kPosition_4840) {
+ if (params->param2 != kPosition_4840) {
+ if (params->param2 == kPosition_4070) {
+ parameters2->param5 = kObjectCompartment6;
+ parameters2->param7 = kPosition_4455;
+ }
+ } else {
+ parameters2->param5 = kObjectCompartment5;
+ parameters2->param6 = true;
+ parameters2->param7 = kPosition_4455;
+ }
+ } else if (params->param2 <= kPosition_6470) {
+ if (params->param2 != kPosition_6470) {
+ if (params->param2 == kPosition_5790) {
+ parameters2->param5 = kObjectCompartment4;
+ parameters2->param7 = kPosition_6130;
+ }
+ } else {
+ parameters2->param5 = kObjectCompartment3;
+ parameters2->param6 = true;
+ parameters2->param7 = kPosition_6130;
+ }
+ } else if (params->param2 != kPosition_7500) {
+ if (params->param2 == kPosition_8200) {
+ parameters2->param5 = kObjectCompartment1;
+ parameters2->param6 = true;
+ parameters2->param7 = kPosition_7850;
+ }
+ } else {
+ parameters2->param5 = kObjectCompartment2;
+ parameters2->param7 = kPosition_7850;
+ }
+
+ if (params->param1 == kCarBaggageRear)
+ parameters2->param5 += 31; // Switch to next compartment car
+
+ if (parameters2->param6) {
+ strcpy((char *)&parameters1->seq1, "632A");
+ strcpy((char *)&parameters1->seq2, "632B");
+ strcpy((char *)&parameters1->seq3, "632C");
+ } else {
+ strcpy((char *)&parameters1->seq1, "632D");
+ strcpy((char *)&parameters1->seq2, "632E");
+ strcpy((char *)&parameters1->seq3, "632F");
+ }
+
+ strcat((char *)&parameters1->seq1, (char *)&params->seq1);
+ strcat((char *)&parameters1->seq2, (char *)&params->seq1);
+ strcat((char *)&parameters1->seq3, (char *)&params->seq1);
+
+ if ((getEntities()->isInsideCompartment(kEntityPlayer, (CarIndex)params->param1, (EntityPosition)params->param2)
+ || getEntities()->isInsideCompartment(kEntityPlayer, (CarIndex)params->param1, (EntityPosition)parameters2->param7)
+ || (params->param1 == kCarGreenSleeping && params->param2 == kPosition_8200 && getEntities()->isOutsideAlexeiWindow()))
+ && !getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_7850)) {
+ setCallback(1);
+ setup_function10((CarIndex)params->param1, (EntityPosition)params->param2, (ObjectIndex)parameters2->param5);
+ } else {
+ getEntities()->drawSequenceLeft(kEntityGendarmes, (char *)&parameters1->seq1);
+ getEntities()->enterCompartment(kEntityGendarmes, (ObjectIndex)CURRENT_PARAM(2, 5));
+
+ setCallback(parameters2->param6 ? 2 : 3);
+ setup_arrestPlaysound(parameters2->param6 ? "POL1044A" : "POL1044B");
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ CALLBACK_ACTION();
+ break;
+
+ case 2:
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityGendarmes, (char *)&parameters1->seq2);
+ if (getEntities()->isNobodyInCompartment((CarIndex)params->param1, (EntityPosition)params->param2) || !strcmp(params->seq2, "NODIALOG")) {
+ setCallback(4);
+ setup_arrestCallback(150);
+ } else {
+ char *arrestSound = (char *)&parameters2->seq;
+ strcpy(arrestSound, "POL1045");
+ strcat(arrestSound, (char *)&params->seq2);
+
+ setCallback(5);
+ setup_arrestPlaysound(arrestSound);
+ }
+ break;
+
+ case 4:
+ case 5:
+ if (!getEntities()->isNobodyInCompartment((CarIndex)params->param1, (EntityPosition)params->param2) && strcmp(params->seq2, "NODIALOG")) {
+ char *arrestSound = (char *)&parameters2->seq;
+ strcpy(arrestSound, "POL1043");
+ strcat(arrestSound, (char *)&params->seq2);
+
+ getSound()->playSound(kEntityGendarmes, arrestSound, SoundManager::kFlagInvalid, 30);
+ }
+
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(6);
+ setup_arrestDraw((char *)&parameters1->seq3);
+ break;
+
+ case 6:
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->exitCompartment(kEntityGendarmes, (ObjectIndex)parameters2->param5);
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, ObjectIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param5 || getState()->timeTicks > (uint32)params->param5) {
+ if (!params->param5)
+ params->param5 = getState()->timeTicks + 75;
+
+ if (!getEntities()->isOutsideAlexeiWindow() && getObjects()->get((ObjectIndex)params->param3).location != kObjectLocation1) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventGendarmesArrestation);
+ break;
+ }
+ }
+
+ if (!params->param6)
+ params->param6 = getState()->timeTicks + 150;
+
+ if (params->param6 == 0 || getState()->timeTicks > (uint32)params->param6) {
+ params->param6 = kTimeInvalid;
+
+ getSound()->playSound(kEntityGendarmes, "POL1046A", SoundManager::kFlagDefault);
+ }
+
+ UPDATE_PARAM(params->param7, getState()->timeTicks, 300);
+
+ if (!params->param4 && getEntities()->isOutsideAlexeiWindow()) {
+ getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ CALLBACK_ACTION();
+ } else {
+ if (getEntities()->isOutsideAlexeiWindow())
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ getSound()->playSound(kEntityGendarmes, "LIB017", SoundManager::kFlagDefault);
+
+ setCallback(getProgress().jacket == kJacketBlood ? 3 : 4);
+ setup_savegame(kSavegameTypeEvent, getProgress().jacket == kJacketBlood ? kEventMertensBloodJacket : kEventGendarmesArrestation);
+ }
+ break;
+
+ case kActionKnock:
+ getObjects()->update((ObjectIndex)params->param3, kEntityGendarmes, getObjects()->get((ObjectIndex)params->param3).location, kCursorNormal, kCursorNormal);
+
+ setCallback(5);
+ setup_arrestPlaysound16("POL1046B");
+ break;
+
+ case kActionOpenDoor:
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventGendarmesArrestation);
+ break;
+
+ case kActionDefault:
+ getObjects()->update((ObjectIndex)params->param3, kEntityGendarmes, getObjects()->get((ObjectIndex)params->param3).location, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_arrestPlaysound16("POL1046");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update((ObjectIndex)params->param3, kEntityGendarmes, getObjects()->get((ObjectIndex)params->param3).location, kCursorTalk, kCursorNormal);
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityGendarmes, "LIB014", SoundManager::kFlagDefault);
+ getAction()->playAnimation(kEventGendarmesArrestation);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
+ break;
+
+ case 3:
+ getAction()->playAnimation((params->param1 < kCarRedSleeping) ? kEventMertensBloodJacket : kEventCoudertBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+
+ getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ CALLBACK_ACTION();
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventGendarmesArrestation);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
+
+ getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ CALLBACK_ACTION();
+ break;
+
+ case 5:
+ getObjects()->update((ObjectIndex)params->param3, kEntityGendarmes, getObjects()->get((ObjectIndex)params->param3).location, kCursorNormal, kCursorHand);
+ break;
+
+ case 6:
+ getSound()->playSound(kEntityGendarmes, "LIB014", SoundManager::kFlagDefault);
+ getAction()->playAnimation(kEventGendarmesArrestation);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Gendarmes, chapter1Handler)
+ if (savepoint.action == kAction169499649) {
+ getSavePoints()->push(kEntityGendarmes, kEntityMertens, kAction190082817);
+ setup_function12();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Gendarmes, function12)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getProgress().field_14 = 29;
+
+ setCallback(1);
+ setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_5540);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function9(kCarGreenSleeping, kPosition_5790, "d", "A");
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_6220);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function9(kCarGreenSleeping, kPosition_6470, "c", "B");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_7250);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function9(kCarGreenSleeping, kPosition_7500, "b", "C");
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_7950);
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_function9(kCarGreenSleeping, kPosition_8200, "a", "NODIALOG");
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_9460);
+ break;
+
+ case 9:
+ if (getEntityData(kEntityPlayer)->car == kCarGreenSleeping) {
+ getProgress().field_14 = 0;
+ getEntities()->clearSequences(kEntityGendarmes);
+ getSavePoints()->push(kEntityGendarmes, kEntityVerges, kAction168710784);
+ setup_function13();
+ break;
+ }
+
+ setCallback(10);
+ setup_arrestUpdateEntity(kCarRedSleeping, kPosition_2490);
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_function9(kCarRedSleeping, kPosition_2740, "h", "NODIALOG");
+ break;
+
+ case 11:
+ setCallback(12);
+ setup_arrestUpdateEntity(kCarRedSleeping, kPosition_3820);
+ break;
+
+ case 12:
+ setCallback(13);
+ setup_function9(kCarRedSleeping, kPosition_4070, "f", "E");
+ break;
+
+ case 13:
+ setCallback(14);
+ setup_arrestUpdateEntity(kCarRedSleeping, kPosition_4590);
+ break;
+
+ case 14:
+ setCallback(15);
+ setup_function9(kCarRedSleeping, kPosition_4840, "e", "F");
+ break;
+
+ case 15:
+ setCallback(16);
+ setup_arrestUpdateEntity(kCarRedSleeping, kPosition_5540);
+ break;
+
+ case 16:
+ setCallback(17);
+ setup_function9(kCarRedSleeping, kPosition_5790, "d", "G");
+ break;
+
+ case 17:
+ setCallback(18);
+ setup_arrestUpdateEntity(kCarRedSleeping, kPosition_6220);
+ break;
+
+ case 18:
+ setCallback(19);
+ setup_function9(kCarRedSleeping, kPosition_6470, "c", "H");
+ break;
+
+ case 19:
+ setCallback(20);
+ setup_arrestUpdateEntity(kCarRedSleeping, kPosition_7250);
+ break;
+
+ case 20:
+ setCallback(21);
+ setup_function9(kCarRedSleeping, kPosition_7500, "b", "J");
+ break;
+
+ case 21:
+ setCallback(22);
+ setup_arrestUpdateEntity(kCarRedSleeping, kPosition_7950);
+ break;
+
+ case 22:
+ setCallback(23);
+ setup_function9(kCarRedSleeping, kPosition_8200, "a", "NODIALOG");
+ break;
+
+ case 23:
+ setCallback(24);
+ setup_arrestUpdateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 24:
+ getProgress().field_14 = 0;
+ getEntities()->clearSequences(kEntityGendarmes);
+ getSavePoints()->push(kEntityGendarmes, kEntityVerges, kAction168710784);
+ setup_function13();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Gendarmes, function13)
+ if (savepoint.action == kActionDefault)
+ getData()->car = kCarNone;
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Gendarmes, chapter2)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityGendarmes);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Gendarmes, chapter3)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityGendarmes);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Gendarmes, chapter4)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityGendarmes);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Gendarmes, chapter5)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityGendarmes);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions
+//////////////////////////////////////////////////////////////////////////
+void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundManager::FlagType flag, bool checkCallback, bool shouldUpdateEntity) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (checkCallback) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII);
+ TIME_CHECK_CALLBACK_ACTION(params->param1, params->param2);
+ }
+
+ if (shouldUpdateEntity) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII);
+ if (getEntities()->updateEntity(kEntityGendarmes, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+ }
+ // Fallback to next action
+
+ case kActionDrawScene:
+ if (!ENTITY_PARAM(0, 1) && getEntities()->hasValidFrame(kEntityGendarmes)) {
+ getSound()->playSound(kEntityPlayer, "MUS007");
+ ENTITY_PARAM(0, 1) = 1;
+ }
+
+ if (getEntities()->isDistanceBetweenEntities(kEntityGendarmes, kEntityPlayer, 1000) && !getEntityData(kEntityPlayer)->location) {
+
+ if (shouldUpdateEntity)
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 22) && !getEntities()->isDistanceBetweenEntities(kEntityGendarmes, kEntityPlayer, 250))
+ break;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventGendarmesArrestation);
+ }
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ // Only handle when passing SIIS params
+ if (!checkCallback) {
+ EXPOSE_PARAMS(EntityData::EntityParametersSIIS);
+
+ if (!shouldPlaySound)
+ getEntities()->drawSequenceRight(kEntityGendarmes, (char *)&params->seq1);
+ else
+ getSound()->playSound(kEntityGendarmes, (char *)&params->seq1, flag);
+ }
+
+ if (shouldUpdateEntity) {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII);
+ if (getEntities()->updateEntity(kEntityGendarmes, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventGendarmesArrestation);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
+ }
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/gendarmes.h b/engines/lastexpress/entities/gendarmes.h
new file mode 100644
index 0000000000..095a74fa44
--- /dev/null
+++ b/engines/lastexpress/entities/gendarmes.h
@@ -0,0 +1,99 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_GENDARMES_H
+#define LASTEXPRESS_GENDARMES_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+#include "lastexpress/game/sound.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Gendarmes : public Entity {
+public:
+ Gendarmes(LastExpressEngine *engine);
+ ~Gendarmes() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION_1(arrestDraw, const char *sequence)
+ DECLARE_FUNCTION_1(arrestPlaysound, const char *soundName)
+ DECLARE_FUNCTION_1(arrestPlaysound16, const char *soundName)
+ DECLARE_FUNCTION_1(arrestCallback, uint32 timeValue)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ DECLARE_FUNCTION_2(arrestUpdateEntity, CarIndex car, EntityPosition entityPosition)
+ DECLARE_FUNCTION_4(function9, CarIndex car, EntityPosition entityPosition, const char *sequence1, const char *sequence2)
+ DECLARE_FUNCTION_3(function10, CarIndex car, EntityPosition entityPosition, ObjectIndex object)
+ DECLARE_FUNCTION(chapter1Handler)
+ DECLARE_FUNCTION(function12)
+ DECLARE_FUNCTION(function13)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+private:
+ void arrest(const SavePoint &savepoint, bool playSound = false, SoundManager::FlagType flag = SoundManager::kFlagInvalid, bool checkCallback = false, bool shouldUpdateEntity = false);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_GENDARMES_H
diff --git a/engines/lastexpress/entities/hadija.cpp b/engines/lastexpress/entities/hadija.cpp
new file mode 100644
index 0000000000..5590c1b6fe
--- /dev/null
+++ b/engines/lastexpress/entities/hadija.cpp
@@ -0,0 +1,532 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/hadija.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Hadija::Hadija(LastExpressEngine *engine) : Entity(engine, kEntityHadija) {
+ ADD_CALLBACK_FUNCTION(Hadija, reset);
+ ADD_CALLBACK_FUNCTION(Hadija, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Hadija, playSound);
+ ADD_CALLBACK_FUNCTION(Hadija, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Hadija, updateEntity);
+ ADD_CALLBACK_FUNCTION(Hadija, compartment6);
+ ADD_CALLBACK_FUNCTION(Hadija, compartment8);
+ ADD_CALLBACK_FUNCTION(Hadija, compartment6to8);
+ ADD_CALLBACK_FUNCTION(Hadija, compartment8to6);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter1);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Hadija, function12);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter2);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter3);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter4);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Hadija, function19);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter5);
+ ADD_CALLBACK_FUNCTION(Hadija, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Hadija, function22);
+ ADD_CALLBACK_FUNCTION(Hadija, function23);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Hadija, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(2, Hadija, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Hadija, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(4, Hadija, updateFromTime)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(5, Hadija, updateEntity, CarIndex, EntityPosition)
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Hadija, compartment6)
+ COMPARTMENT_TO(Hadija, kObjectCompartment6, kPosition_4070, "619Cf", "619Df");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Hadija, compartment8)
+ COMPARTMENT_TO(Hadija, kObjectCompartment8, kPosition_2740, "619Ch", "619Dh");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Hadija, compartment6to8)
+ COMPARTMENT_FROM_TO(Hadija, kObjectCompartment6, kPosition_4070, "619Bf", kObjectCompartment8, kPosition_2740, "619Ah");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Hadija, compartment8to6)
+ COMPARTMENT_FROM_TO(Hadija, kObjectCompartment8, kPosition_2740, "619Bh", kObjectCompartment6, kPosition_4070, "619Af");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Hadija, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Hadija, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_PLAYSOUND_UPDATEPOSITION(kTimeParisEpernay, params->param1, 1, "Har1100", kPosition_4840);
+
+label_callback1:
+ TIME_CHECK_CALLBACK(kTime1084500, params->param2, 2, setup_compartment6to8);
+
+label_callback2:
+ if (params->param3 != kTimeInvalid && getState()->time > kTime1093500) {
+
+ if (getState()->time <= kTime1134000) {
+
+ if (!getEntities()->isPlayerInCar(kCarGreenSleeping) || !getEntities()->isInsideCompartment(kEntityMahmud, kCarGreenSleeping, kPosition_5790) || !params->param3) {
+ params->param3 = (uint)getState()->time + 75;
+
+ if (!params->param3) {
+ setCallback(3);
+ setup_compartment8();
+ return;
+ }
+ }
+
+ if (params->param3 >= getState()->time)
+ return;
+ }
+
+ params->param3 = kTimeInvalid;
+
+ setCallback(3);
+ setup_compartment8();
+ }
+
+label_callback3:
+ TIME_CHECK_CALLBACK(kTime1156500, params->param4, 4, setup_compartment8to6);
+
+label_callback4:
+ if (params->param5 != kTimeInvalid && getState()->time > kTime1165500) {
+ if (getState()->time <= kTime1188000) {
+
+ if (!getEntities()->isPlayerInCar(kCarGreenSleeping) || !getEntities()->isInsideCompartment(kEntityMahmud, kCarGreenSleeping, kPosition_5790) || !params->param5) {
+ params->param5 = (uint)getState()->time + 75;
+
+ if (!params->param5) {
+ setCallback(5);
+ setup_compartment6();
+ return;
+ }
+ }
+
+ if (params->param5 >= getState()->time)
+ return;
+ }
+
+ params->param5 = kTimeInvalid;
+
+ setCallback(5);
+ setup_compartment6();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 3:
+ goto label_callback3;
+
+ case 4:
+ goto label_callback4;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Hadija, function12)
+ if (savepoint.action == kActionDefault) {
+ getObjects()->update(kObjectCompartment8, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getEntities()->clearSequences(kEntityHadija);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Hadija, chapter2)
+ if (savepoint.action == kActionDefault) {
+
+ getEntities()->clearSequences(kEntityHadija);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ setup_chapter2Handler();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime1782000 && !params->param1) {
+ params->param1 = 1;
+ getData()->entityPosition = kPosition_2740;
+ }
+
+ if (params->param2 == kTimeInvalid || getState()->time <= kTime1786500) {
+ TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6);
+ break;
+ }
+
+ if (getState()->time <= kTime1818000) {
+
+ if (!getEntities()->isPlayerInCar(kCarGreenSleeping) || !params->param2)
+ params->param2 = (uint)getState()->time + 75;
+
+ if (params->param2 >= getState()->time) {
+ TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6);
+ break;
+ }
+ }
+
+ params->param2 = kTimeInvalid;
+
+ setCallback(1);
+ setup_compartment8();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_playSound("Har2012");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Hadija, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityHadija);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Hadija, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTime1998000, params->param1, 1, setup_compartment6to8);
+
+label_callback1:
+ TIME_CHECK_CALLBACK(kTime2020500, params->param2, 2, setup_compartment8to6);
+
+label_callback2:
+ TIME_CHECK_CALLBACK(kTime2079000, params->param3, 3, setup_compartment6to8);
+
+label_callback3:
+ TIME_CHECK_CALLBACK(kTime2187000, params->param4, 4, setup_compartment8to6);
+
+label_callback4:
+ if (params->param5 != kTimeInvalid && getState()->time > kTime2196000)
+ TIME_CHECK_CAR(kTime2254500, params->param5, 5, setup_compartment6);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityAlouan, kEntityTrain, kAction191070912, kPosition_4840);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 3:
+ goto label_callback3;
+
+ case 4:
+ goto label_callback4;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Hadija, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Hadija, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 != kTimeInvalid)
+ TIME_CHECK_CAR(kTime1714500, params->param1, 1, setup_compartment6);
+
+label_callback1:
+ TIME_CHECK_CALLBACK(kTime2367000, params->param2, 2, setup_compartment6to8);
+
+label_callback2:
+ TIME_CHECK_CALLBACK(kTime2421000, params->param3, 3, setup_compartment8to6);
+
+label_callback3:
+ if (params->param4 != kTimeInvalid && getState()->time > kTime2425500)
+ TIME_CHECK_CAR(kTime2484000, params->param4, 4, setup_compartment6);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 3:
+ goto label_callback3;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Hadija, function19)
+ if (savepoint.action == kActionDefault) {
+ getObjects()->update(kObjectCompartment8, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getEntities()->clearSequences(kEntityHadija);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Hadija, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityHadija);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Hadija, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function22();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Hadija, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->time, 2700);
+ setup_function23();
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
+ setup_function23();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Hadija, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_4070);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("619AF", kObjectCompartment6);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityHadija);
+
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+
+ getObjects()->update(kObjectCompartment5, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(24, Hadija)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/hadija.h b/engines/lastexpress/entities/hadija.h
new file mode 100644
index 0000000000..bd37a205d9
--- /dev/null
+++ b/engines/lastexpress/entities/hadija.h
@@ -0,0 +1,144 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_HADIJA_H
+#define LASTEXPRESS_HADIJA_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Hadija : public Entity {
+public:
+ Hadija(LastExpressEngine *engine);
+ ~Hadija() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param savepoint The savepoint
+ * - Time to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTime)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION(compartment6)
+ DECLARE_FUNCTION(compartment8)
+ DECLARE_FUNCTION(compartment6to8)
+ DECLARE_FUNCTION(compartment8to6)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function12)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function19)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_HADIJA_H
diff --git a/engines/lastexpress/entities/ivo.cpp b/engines/lastexpress/entities/ivo.cpp
new file mode 100644
index 0000000000..6bee62f003
--- /dev/null
+++ b/engines/lastexpress/entities/ivo.cpp
@@ -0,0 +1,829 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/ivo.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/fight.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Ivo::Ivo(LastExpressEngine *engine) : Entity(engine, kEntityIvo) {
+ ADD_CALLBACK_FUNCTION(Ivo, reset);
+ ADD_CALLBACK_FUNCTION(Ivo, draw);
+ ADD_CALLBACK_FUNCTION(Ivo, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Ivo, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Ivo, updateFromTicks);
+ ADD_CALLBACK_FUNCTION(Ivo, updateEntity);
+ ADD_CALLBACK_FUNCTION(Ivo, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Ivo, playSound);
+ ADD_CALLBACK_FUNCTION(Ivo, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Ivo, savegame);
+ ADD_CALLBACK_FUNCTION(Ivo, function11);
+ ADD_CALLBACK_FUNCTION(Ivo, sitAtTableWithSalko);
+ ADD_CALLBACK_FUNCTION(Ivo, leaveTableWithSalko);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter1);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Ivo, function16);
+ ADD_CALLBACK_FUNCTION(Ivo, function17);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter2);
+ ADD_CALLBACK_FUNCTION(Ivo, function19);
+ ADD_CALLBACK_FUNCTION(Ivo, function20);
+ ADD_CALLBACK_FUNCTION(Ivo, function21);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter3);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter4);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Ivo, function26);
+ ADD_CALLBACK_FUNCTION(Ivo, function27);
+ ADD_CALLBACK_FUNCTION(Ivo, function28);
+ ADD_CALLBACK_FUNCTION(Ivo, function29);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter5);
+ ADD_CALLBACK_FUNCTION(Ivo, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Ivo, fight);
+ ADD_CALLBACK_FUNCTION(Ivo, function33);
+ ADD_CALLBACK_FUNCTION(Ivo, function34);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Ivo, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Ivo, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(3, Ivo, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(4, Ivo, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(5, Ivo, updateFromTicks, uint32)
+ Entity::updateFromTicks(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(6, Ivo, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath || savepoint.action == kActionExcuseMe) {
+ getSound()->playSound(kEntityPlayer, "CAT1127A");
+ return;
+ }
+
+ Entity::updateEntity(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Ivo, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(8, Ivo, playSound)
+ Entity::playSound(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Ivo, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Ivo, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Ivo, function11)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isDistanceBetweenEntities(kEntityIvo, kEntitySalko, 750) || getEntities()->checkDistanceFromPosition(kEntitySalko, kPosition_2740, 500)) {
+ getSavePoints()->push(kEntityIvo, kEntitySalko, kAction123668192);
+
+ setCallback(4);
+ setup_enterExitCompartment("613Ah", kObjectCompartmentH);
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityIvo, "809DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityIvo);
+
+ setCallback(1);
+ setup_callbackActionOnDirection();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityIvo, kEntitySalko, kAction125242096);
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_2740);
+ break;
+
+ case 2:
+ if (getEntities()->isDistanceBetweenEntities(kEntityIvo, kEntitySalko, 750) || getEntities()->checkDistanceFromPosition(kEntitySalko, kPosition_2740, 500)) {
+ getSavePoints()->push(kEntityIvo, kEntitySalko, kAction123668192);
+
+ setCallback(3);
+ setup_enterExitCompartment("613Ah", kObjectCompartmentH);
+ } else {
+ getEntities()->drawSequenceLeft(kEntityIvo, "613Hh");
+ getEntities()->enterCompartment(kEntityIvo, kObjectCompartmentH, true);
+ }
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityIvo);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 4:
+ getEntities()->exitCompartment(kEntityIvo, kObjectCompartmentH, true);
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityIvo);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Ivo, sitAtTableWithSalko)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->clearSequences(kEntitySalko);
+ getSavePoints()->push(kEntityIvo, kEntityTables2, kAction136455232);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityIvo, "023A1");
+ getEntities()->drawSequenceRight(kEntitySalko, "023A2");
+ getEntities()->drawSequenceRight(kEntityTables2, "023A3");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Ivo, leaveTableWithSalko)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getSavePoints()->push(kEntityIvo, kEntityTables2, kActionDrawTablesWithChairs, "009E");
+ getEntities()->clearSequences(kEntitySalko);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityIvo, "023D1");
+ getEntities()->drawSequenceRight(kEntitySalko, "023D2");
+ getEntities()->drawSequenceRight(kEntityTables2, "023D3");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Ivo, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject47, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getData()->entityPosition = kPosition_4691;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Ivo, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ getData()->entityPosition = getEntityData(kEntityMilos)->entityPosition;
+ getData()->location = getEntityData(kEntityMilos)->location;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function11();
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityIvo, kEntityMilos, kAction135024800);
+ setup_function16();
+ break;
+ }
+ break;
+
+ case kAction125242096:
+ setCallback(1);
+ setup_updateFromTicks(75);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Ivo, function16)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getEntities()->clearSequences(kEntityIvo);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityIvo, "613Ch");
+ getEntities()->enterCompartment(kEntityIvo, kObjectCompartmentH);
+ getSavePoints()->push(kEntityIvo, kEntityCoudert, kAction88652208);
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->clearSequences(kEntityIvo);
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+
+ case kAction122865568:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_enterExitCompartment("613Bh", kObjectCompartmentH);
+ break;
+
+ case kAction123852928:
+ getEntities()->exitCompartment(kEntityIvo, kObjectCompartmentH, true);
+
+ setCallback(2);
+ setup_enterExitCompartment("613Dh", kObjectCompartmentH);
+ break;
+
+ case kAction221683008:
+ getSavePoints()->push(kEntityIvo, kEntityCoudert, kAction123199584);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Ivo, function17)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->clearSequences(kEntityIvo);
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Ivo, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTime1777500, params->param1, setup_function19);
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityIvo);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject47, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Ivo, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("613FH", kObjectCompartmentH);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ if (getData()->entityPosition < kPosition_2087)
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityIvo, kEntitySalko, kAction136184016);
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("809US");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_sitAtTableWithSalko();
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ setup_function20();
+ break;
+ }
+ break;
+
+ case kAction102675536:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Ivo, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime1809000 && params->param1) {
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_leaveTableWithSalko();
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityIvo, kEntityServers1, kAction189688608);
+ getEntities()->drawSequenceLeft(kEntityIvo, "023B");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityIvo, kEntityServers1, kAction101106391);
+ getEntities()->drawSequenceLeft(kEntityIvo, "023B");
+ params->param1 = 1;
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function11();
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityIvo, kEntityServers1, kAction236237423);
+ setup_function21();
+ break;
+ }
+ break;
+
+ case kAction123712592:
+ getEntities()->drawSequenceLeft(kEntityIvo, "023C2");
+
+ setCallback(1);
+ setup_updateFromTime(450);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Ivo, function21)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Ivo, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityIvo);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Ivo, chapter3Handler)
+ if (savepoint.action == kActionDefault)
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Ivo, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Ivo, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2361600 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->location = kLocationOutsideCompartment;
+ setup_function26();
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityIvo, kEntityTables2, kAction136455232);
+ getEntities()->drawSequenceLeft(kEntityIvo, "023B");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Ivo, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_leaveTableWithSalko();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function11();
+ break;
+
+ case 2:
+ setup_function27();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Ivo, function27)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ if (getData()->entityPosition < kPosition_2087)
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityIvo);
+ setup_function28();
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityIvo, "613Ch");
+ getEntities()->enterCompartment(kEntityIvo, kObjectCompartmentH, true);
+ getSavePoints()->push(kEntityIvo, kEntityCoudert, kAction88652208);
+ break;
+
+ case 4:
+ getEntities()->exitCompartment(kEntityIvo, kObjectCompartmentH, true);
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityIvo);
+ break;
+ }
+ break;
+
+ case kAction55996766:
+ setCallback(1);
+ setup_enterExitCompartment("613FH", kObjectCompartmentH);
+ break;
+
+ case kAction122865568:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_enterExitCompartment("613Bh", kObjectCompartmentH);
+ break;
+
+ case kAction123852928:
+ setCallback(4);
+ setup_enterExitCompartment("613Dh", kObjectCompartmentH);
+ break;
+
+ case kAction221683008:
+ getSavePoints()->push(kEntityIvo, kEntityCoudert, kAction123199584);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Ivo, function28)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2425500 && !params->param1) {
+ params->param1 = 1;
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_2740);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("613EH", kObjectCompartmentH);
+ break;
+
+ case 2:
+ setup_function29();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Ivo, function29)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityIvo);
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->inventoryItem = kItemNone;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Ivo, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityIvo);
+
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarBaggageRear;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Ivo, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_fight();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Ivo, fight)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+ getData()->entityPosition = kPosition_540;
+ getData()->car = kCarBaggageRear;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventCathIvoFight);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityPlayer, "LIB090");
+ getAction()->playAnimation(kEventCathIvoFight);
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case 2:
+ params->param1 = getFight()->setup(kFightIvo);
+ if (params->param1) {
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, true);
+ } else {
+ getScenes()->loadSceneFromPosition(kCarBaggageRear, 96);
+ setup_function33();
+ }
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Ivo, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getState()->time = (TimeValue)(getState()->time + 1800);
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ getObjects()->update(kObject94, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+
+ break;
+
+ case kAction135800432:
+ setup_function34();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Ivo, function34)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityIvo);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/ivo.h b/engines/lastexpress/entities/ivo.h
new file mode 100644
index 0000000000..e726c95af0
--- /dev/null
+++ b/engines/lastexpress/entities/ivo.h
@@ -0,0 +1,177 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_IVO_H
+#define LASTEXPRESS_IVO_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Ivo : public Entity {
+public:
+ Ivo(LastExpressEngine *engine);
+ ~Ivo() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param ticks The number of ticks to add
+ */
+ DECLARE_FUNCTION_1(updateFromTicks, uint32 ticks)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Plays sound
+ *
+ * @param savepoint The savepoint
+ * - the sound filename
+ */
+ DECLARE_FUNCTION_NOSETUP(playSound)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ DECLARE_FUNCTION(function11)
+ DECLARE_FUNCTION(sitAtTableWithSalko)
+ DECLARE_FUNCTION(leaveTableWithSalko)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function16)
+ DECLARE_FUNCTION(function17)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ DECLARE_FUNCTION(function19)
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(function28)
+ DECLARE_FUNCTION(function29)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(fight)
+ DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(function34)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_IVO_H
diff --git a/engines/lastexpress/entities/kahina.cpp b/engines/lastexpress/entities/kahina.cpp
new file mode 100644
index 0000000000..89c685cfe9
--- /dev/null
+++ b/engines/lastexpress/entities/kahina.cpp
@@ -0,0 +1,1528 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/kahina.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Kahina::Kahina(LastExpressEngine *engine) : Entity(engine, kEntityKahina) {
+ ADD_CALLBACK_FUNCTION(Kahina, reset);
+ ADD_CALLBACK_FUNCTION(Kahina, playSound);
+ ADD_CALLBACK_FUNCTION(Kahina, savegame);
+ ADD_CALLBACK_FUNCTION(Kahina, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Kahina, updateFromTicks);
+ ADD_CALLBACK_FUNCTION(Kahina, function6);
+ ADD_CALLBACK_FUNCTION(Kahina, updateEntity2);
+ ADD_CALLBACK_FUNCTION(Kahina, updateEntity);
+ ADD_CALLBACK_FUNCTION(Kahina, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Kahina, chapter1);
+ ADD_CALLBACK_FUNCTION(Kahina, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Kahina, function12);
+ ADD_CALLBACK_FUNCTION(Kahina, function13);
+ ADD_CALLBACK_FUNCTION(Kahina, function14);
+ ADD_CALLBACK_FUNCTION(Kahina, function15);
+ ADD_CALLBACK_FUNCTION(Kahina, chapter2);
+ ADD_CALLBACK_FUNCTION(Kahina, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Kahina, chapter3);
+ ADD_CALLBACK_FUNCTION(Kahina, function19);
+ ADD_CALLBACK_FUNCTION(Kahina, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Kahina, function21);
+ ADD_CALLBACK_FUNCTION(Kahina, function22);
+ ADD_CALLBACK_FUNCTION(Kahina, function23);
+ ADD_CALLBACK_FUNCTION(Kahina, function24);
+ ADD_CALLBACK_FUNCTION(Kahina, function25);
+ ADD_CALLBACK_FUNCTION(Kahina, function26);
+ ADD_CALLBACK_FUNCTION(Kahina, function27);
+ ADD_CALLBACK_FUNCTION(Kahina, chapter4);
+ ADD_CALLBACK_FUNCTION(Kahina, chapter5);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Kahina, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Kahina, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(3, Kahina, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(4, Kahina, updateFromTime, uint32)
+ if (savepoint.action == kAction137503360) {
+ ENTITY_PARAM(0, 2) = 1;
+ CALLBACK_ACTION();
+ }
+
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(5, Kahina, updateFromTicks)
+ Entity::updateFromTicks(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 < getState()->time && !params->param2) {
+ params->param2 = 1;
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (getEntities()->isPlayerInCar(kCarGreenSleeping) || getEntities()->isPlayerInCar(kCarRedSleeping)) {
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
+ setCallback(2);
+ setup_updateEntity2(kCarGreenSleeping, kPosition_540);
+ } else {
+ setCallback(3);
+ setup_updateEntity2(kCarRedSleeping, kPosition_9460);
+ }
+ }
+ break;
+
+ case kActionDefault:
+ ENTITY_PARAM(0, 1) = 0;
+ ENTITY_PARAM(0, 2) = 0;
+
+ setCallback(1);
+ setup_updateEntity2(kCarRedSleeping, kPosition_540);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityKahina);
+ break;
+
+ case 2:
+ case 3:
+ if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityKahina);
+
+ setCallback(4);
+ setup_updateFromTime(450);
+ break;
+
+ case 4:
+ if (ENTITY_PARAM(0, 2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ setCallback(5);
+ setup_updateEntity2(kCarRedSleeping, kPosition_540);
+ break;
+
+ case 5:
+ if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityKahina);
+ break;
+ }
+ break;
+
+ case kAction137503360:
+ ENTITY_PARAM(0, 2) = 1;
+
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(7, Kahina, updateEntity2, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ } else if (getEntities()->isDistanceBetweenEntities(kEntityKahina, kEntityPlayer, 1000)
+ && !getEntities()->isInGreenCarEntrance(kEntityPlayer)
+ && !getEntities()->isInsideCompartments(kEntityPlayer)
+ && !getEntities()->checkFields10(kEntityPlayer)) {
+
+ if (getData()->car == kCarGreenSleeping || getData()->car == kCarRedSleeping) {
+ ENTITY_PARAM(0, 1) = 1;
+ CALLBACK_ACTION();
+ }
+ }
+ break;
+
+ case kAction137503360:
+ ENTITY_PARAM(0, 2) = 1;
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(8, Kahina, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ if (getEvent(kEventKronosConversation) || getEvent(kEventKronosConversationFirebird)) {
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1019" : "CAT1019A");
+ } else {
+ getSound()->excuseMeCath();
+ }
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(9, Kahina, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Kahina, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarKronos;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Kahina, chapter1Handler)
+ if (savepoint.action != kActionNone)
+ return;
+
+ if (getProgress().jacket != kJacketOriginal)
+ TIME_CHECK_SAVEPOINT(kTime1107000, params->param1, kEntityKahina, kEntityMertens, kAction238732837);
+
+ if (getProgress().eventMertensKronosInvitation)
+ setup_function12();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Kahina, function12)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTime1485000, params->param2, setup_function13);
+ break;
+
+ case kActionKnock:
+ getSound()->playSound(kEntityPlayer, "LIB012");
+ // Fallback to next action
+
+ case kActionOpenDoor:
+ if (!getEvent(kEventKronosGoingToInvitation)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKronosGoingToInvitation);
+ break;
+ }
+
+ if (savepoint.action == kActionOpenDoor)
+ getSound()->playSound(kEntityPlayer, "LIB014");
+
+ getScenes()->loadSceneFromPosition(kCarKronos, 80);
+ getSavePoints()->push(kEntityKahina, kEntityKronos, kAction171849314);
+ params->param1 = 1;
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventKronosGoingToInvitation);
+ getScenes()->loadSceneFromPosition(kCarKronos, 80);
+ getSavePoints()->push(kEntityKahina, kEntityKronos, kAction171849314);
+ params->param1 = 1;
+ }
+ break;
+
+ case kAction137685712:
+ setup_function13();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Kahina, function13)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().field_14 || getState()->time >= kTime1201500 || params->param2 == kTimeInvalid || params->param1 >= getState()->time)
+ break;
+
+ if (getState()->time <= kTime1197000) {
+ if (!getEntities()->isPlayerInCar(kCarGreenSleeping) || !params->param2) {
+ params->param2 = (uint)getState()->time;
+
+ if (!getState()->time)
+ goto label_callback;
+ }
+
+ if (params->param2 >= getState()->time)
+ break;
+ }
+
+ params->param2 = kTimeInvalid;
+
+label_callback:
+ setCallback(1);
+ setup_function15();
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarKronos;
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param1 = (uint)getState()->time + 1800;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Kahina, function14)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->exitCompartment(kEntityKahina, kObjectCompartmentF);
+ CALLBACK_ACTION();
+ break;
+
+ case kAction4:
+ getEntities()->exitCompartment(kEntityKahina, kObjectCompartmentF);
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityKahina, "616Cf");
+ getEntities()->enterCompartment(kEntityKahina, kObjectCompartmentF);
+ getSavePoints()->push(kEntityKahina, kEntityMax, kAction158007856);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Kahina, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2 != kTimeInvalid) {
+ UPDATE_PARAM_PROC_TIME(params->param1, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param2, 0)
+ setCallback(9);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ UPDATE_PARAM_PROC_END
+ }
+ break;
+
+ case kActionDefault:
+ getProgress().field_14 = 19;
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEntities()->hasValidFrame(kEntityKahina)) {
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+ }
+ // Fallback to next case
+
+ case 4:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_8200)
+ || getEntities()->isOutsideAlexeiWindow()
+ || getEntities()->isDistanceBetweenEntities(kEntityKahina, kEntityPlayer, 2000)) {
+ if (getProgress().field_14 == 19)
+ getProgress().field_14 = 0;
+
+ setCallback(8);
+ setup_updateEntity(kCarGreenSleeping, kPosition_9460);
+ } else {
+ setCallback(5);
+ setup_enterExitCompartment("616Aa", kObjectCompartment1);
+ }
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateFromTime(1800);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityKahina);
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObjectHandleBathroom, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(6);
+ setup_updateFromTime(900);
+ break;
+
+ case 6:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleBathroom, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(7);
+ setup_enterExitCompartment("616Ba", kObjectCompartment1);
+ break;
+
+ case 7:
+ getData()->location = kLocationOutsideCompartment;
+
+ if (getProgress().field_14 == 19)
+ getProgress().field_14 = 0;
+
+ setCallback(8);
+ setup_updateEntity(kCarGreenSleeping, kPosition_9460);
+ break;
+
+ case 8:
+ getEntities()->clearSequences(kEntityKahina);
+ params->param1 = (uint)getState()->time + 4500;
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_function14();
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_updateEntity(kCarRedSleeping, kPosition_6470);
+ break;
+
+ case 11:
+ if (getEntities()->checkFields19(kEntityPlayer, kCarRedSleeping, kPosition_6130)) {
+ setCallback(15);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ } else {
+ setCallback(12);
+ setup_enterExitCompartment("616Ac", kObjectCompartmentC);
+ }
+ break;
+
+ case 12:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityKahina);
+
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, getObjects()->get(kObjectCompartmentC).location, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject50, kEntityPlayer, getObjects()->get(kObject50).location, kCursorNormal, kCursorNormal);
+
+ setCallback(13);
+ setup_updateFromTime(900);
+ break;
+
+ case 13:
+ getObjects()->update(kObjectCompartmentC, kEntityPlayer, getObjects()->get(kObjectCompartmentC).location, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject50, kEntityPlayer, getObjects()->get(kObject50).location, kCursorHandKnock, kCursorHand);
+
+ setCallback(14);
+ setup_enterExitCompartment("616Bc", kObjectCompartmentC);
+ break;
+
+ case 14:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(15);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 15:
+ getEntities()->clearSequences(kEntityKahina);
+
+ setCallback(16);
+ setup_updateFromTime(900);
+ break;
+
+ case 16:
+ setCallback(17);
+ setup_updateEntity(kCarKronos, kPosition_9270);
+ break;
+
+ case 17:
+ getEntities()->clearSequences(kEntityKahina);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Kahina, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityKahina);
+
+ getData()->entityPosition = kPosition_6000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarKronos;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Kahina, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM_PROC(params->param2, getState()->time, 9000)
+ params->param1 = 1;
+ params->param2 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (getEvent(kEventKahinaAskSpeakFirebird) && getEvent(kEventKronosConversationFirebird) && getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)) {
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 900)
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird);
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+label_callback_3:
+ if (getState()->time > kTime1845000 && getEvent(kEventKronosConversationFirebird) && getEntities()->isInKronosSalon(kEntityPlayer)) {
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getScenes()->loadSceneFromPosition(kCarKronos, 87);
+ }
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (getEvent(kEventKronosConversationFirebird))
+ break;
+
+ if (getEvent(kEventKahinaAskSpeakFirebird)) {
+ if (getSound()->isBuffered(kEntityKahina))
+ getSound()->processEntry(kEntityKahina);
+
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird);
+ break;
+ }
+
+ if (getEvent(kEventMilosCompartmentVisitAugust) || getEvent(kEventTatianaGivePoem) || getEvent(kEventTatianaBreakfastGivePoem)) {
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ setCallback(7);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaAskSpeakFirebird);
+ break;
+ }
+
+ if (params->param1) {
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ getAction()->playAnimation(kEventKahinaAskSpeak);
+ getScenes()->processScene();
+
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(8);
+ setup_playSound("KRO3003");
+ } else {
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 9 : 10);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 1;
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 4:
+ getAction()->playAnimation(kEventKronosConversationFirebird);
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getScenes()->loadSceneFromPosition(kCarKronos, 80, 1);
+
+ setCallback(getCallback() + 1);
+ setup_updateFromTime(900);
+ break;
+
+ case 2:
+ case 5:
+ setCallback(getCallback() + 1);
+ setup_playSound("KRO3005");
+ break;
+
+ case 3:
+ goto label_callback_3;
+
+ case 7:
+ getAction()->playAnimation(kEventKahinaAskSpeakFirebird);
+ getScenes()->loadSceneFromPosition(kCarKronos, 81);
+ getSound()->playSound(kEntityKahina, "KRO3004");
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ if (getCallback() == 8)
+ params->param1 = 0;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Kahina, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityKahina);
+
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarKronos;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEvent(kEventAnnaBaggageArgument))
+ RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function22);
+
+ if (getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMeCath:
+ if (getEvent(kEventKronosConversation) || getEvent(kEventKronosConversationFirebird))
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1019" : "CAT1019A");
+ else
+ getSound()->excuseMeCath();
+ break;
+
+ case kActionExcuseMe:
+ getSound()->excuseMe(kEntityKahina);
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Kahina, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEvent(kEventKronosVisit))
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ if (getEntities()->isInKronosSanctum(kEntityPlayer)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaPunchSuite4);
+ break;
+ }
+
+label_callback_1:
+ if (getState()->time > kTime2079000 && !params->param2) {
+ params->param2 = 1;
+
+ if (getEvent(kEventKahinaAskSpeakFirebird)
+ && !getEvent(kEventKronosConversationFirebird)
+ && getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird);
+ break;
+ }
+
+label_callback_2:
+ if (getEntities()->isInKronosSalon(kEntityPlayer))
+ getScenes()->loadSceneFromPosition(kCarKronos, 87);
+
+ setup_function21();
+ break;
+ }
+
+ if (!params->param1) {
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 9000)
+ params->param1 = 1;
+ params->param3 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (getEvent(kEventKahinaAskSpeakFirebird)
+ && !getEvent(kEventKronosConversationFirebird)
+ && getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)) {
+ UPDATE_PARAM(params->param4, getState()->time, 900);
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird);
+ }
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (!getEvent(kEventKronosConversationFirebird)) {
+
+ if (getEvent(kEventKahinaAskSpeakFirebird)) {
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird);
+ break;
+ }
+
+ if (getEvent(kEventMilosCompartmentVisitAugust) || getEvent(kEventTatianaGivePoem) || getEvent(kEventTatianaBreakfastGivePoem)) {
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ setCallback(9);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaAskSpeakFirebird);
+ break;
+ }
+
+ if (params->param1) {
+ if (savepoint.action == kActionKnock)
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ getAction()->playAnimation(kEventKahinaAskSpeak);
+ getScenes()->processScene();
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(10);
+ setup_playSound("KRO3003");
+ break;
+ }
+
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 11 : 12);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ if (getEvent(kEventKronosConversationFirebird)) {
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ } else {
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ params->param1 = 1;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventKahinaPunchSuite4);
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventCathJumpDownCeiling, kSceneNone, false);
+ goto label_callback_1;
+
+ case 2:
+ getAction()->playAnimation(kEventKronosConversationFirebird);
+ getScenes()->loadSceneFromPosition(kCarKronos, 87);
+ goto label_callback_2;
+
+ case 3:
+ getAction()->playAnimation(kEventKronosConversationFirebird);
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getScenes()->loadSceneFromPosition(kCarKronos, 80, 1);
+
+ setCallback(4);
+ setup_updateFromTime(900);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_playSound("KRO3005");
+ break;
+
+ case 6:
+ getAction()->playAnimation(kEventKronosConversationFirebird);
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getScenes()->loadSceneFromPosition(kCarKronos, 80, 1);
+
+ setCallback(7);
+ setup_updateFromTime(900);
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_playSound("KRO3005");
+ break;
+
+ case 9:
+ getAction()->playAnimation(kEventKahinaAskSpeakFirebird);
+ getScenes()->loadSceneFromPosition(kCarKronos, 81);
+ getSound()->playSound(kEntityKahina, "KRO3004");
+ break;
+
+ case 10:
+ params->param1 = 0;
+ // Fallback to next case
+
+ case 11:
+ case 12:
+ getObjects()->update(kObjectCompartmentKronos, kEntityKahina, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Kahina, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ if (!params->param3)
+ params->param3 = (uint)getState()->time + 4500;
+
+ if (params->param6 != kTimeInvalid) {
+ UPDATE_PARAM_PROC_TIME(params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param5, 0)
+ setCallback(2);
+ setup_function23();
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+ }
+
+label_callback_2:
+ if (params->param2) {
+
+ if (!params->param4)
+ params->param4 = (uint)getState()->time + 4500;
+
+ if (params->param6 != kTimeInvalid) {
+ UPDATE_PARAM_PROC_TIME(params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param6, 0)
+ getSound()->playSound(kEntityPlayer, "LIB014", getSound()->getSoundFlag(kEntityKahina));
+ getSound()->playSound(kEntityPlayer, "LIB015", getSound()->getSoundFlag(kEntityKahina));
+
+ getEntities()->drawSequenceLeft(kEntityKahina, "202a");
+
+ params->param2 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+ }
+
+ if (!getProgress().field_44
+ && getState()->time > kTime2214000) {
+
+ ObjectLocation location = getInventory()->get(kItemFirebird)->location;
+
+ if (location == kObjectLocation3 || location == kObjectLocation7) {
+ setCallback(3);
+ setup_function25();
+ } else if (location == kObjectLocation1 || location == kObjectLocation2) {
+ setCallback(4);
+ setup_function26();
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarKronos;
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->drawSequenceLeft(kEntityKahina, "202a");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param1 = 0;
+ params->param2 = 1;
+ break;
+
+ case 2:
+ params->param1 = 0;
+ params->param2 = 1;
+ goto label_callback_2;
+ }
+ break;
+
+ case kAction92186062:
+ if (params->param1) {
+ setCallback(1);
+ setup_function23();
+ }
+ break;
+
+ case kAction134611040:
+ if (getEvent(kEventConcertLeaveWithBriefcase))
+ setup_function24();
+ break;
+
+ case kAction137503360:
+ setup_function22();
+ break;
+
+ case kAction237555748:
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Kahina, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ ObjectLocation location = getInventory()->get(kItemFirebird)->location;
+
+ if (ENTITY_PARAM(0, 3) || location == kObjectLocation3 || location == kObjectLocation7) {
+ setCallback(1);
+ setup_function25();
+ } else if (location == kObjectLocation2 || location == kObjectLocation1) {
+ setCallback(2);
+ setup_function26();
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarKronos;
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+ break;
+
+ case kActionDrawScene:
+ if (getData()->car > kCarGreenSleeping || (getData()->car == kCarGreenSleeping && getData()->entityPosition > kPosition_2740))
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Kahina, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityPlayer, "LIB014", getSound()->getSoundFlag(kEntityKahina));
+ getSound()->playSound(kEntityPlayer, "LIB015", getSound()->getSoundFlag(kEntityKahina), 15);
+
+ getEntities()->clearSequences(kEntityKahina);
+
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_540;
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEntities()->checkFields19(kEntityPlayer, kCarRedSleeping, kPosition_4455) || getEntities()->isOutsideAnnaWindow()) {
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+ } else {
+ setCallback(2);
+ setup_enterExitCompartment("616Cf", kObjectCompartmentF);
+ }
+ break;
+
+ case 2:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityKahina);
+
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, getObjects()->get(kObjectCompartmentF).location, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityPlayer, getObjects()->get(kObject53).location, kCursorNormal, kCursorNormal);
+
+ setCallback(3);
+ setup_updateFromTime(900);
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, getObjects()->get(kObjectCompartmentF).location, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityPlayer, getObjects()->get(kObject53).location, kCursorHandKnock, kCursorHand);
+
+ setCallback(4);
+ setup_enterExitCompartment("616Df", kObjectCompartmentF);
+ break;
+
+ case 4:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 5:
+ getEntities()->clearSequences(kEntityKahina);
+
+ setCallback(6);
+ setup_updateFromTime(900);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_updateEntity(kCarKronos, kPosition_9270);
+ break;
+
+ case 7:
+ getEntities()->clearSequences(kEntityKahina);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Kahina, function24)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 && getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param2, (EntityPosition)params->param3)) {
+ getEntities()->clearSequences(kEntityKahina);
+ params->param1 = 0;
+ }
+ break;
+
+ case kActionEndSound:
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos))
+ getSavePoints()->push(kEntityKahina, kEntityKronos, kActionOpenDoor);
+ else
+ setup_function27();
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function6(kTime2241000);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (ENTITY_PARAM(0, 2)) {
+ getEntities()->clearSequences(kEntityKahina);
+ if (getSound()->isBuffered(kEntityKahina))
+ getSound()->processEntry(kEntityKahina);
+
+ getProgress().field_44 = 0;
+
+ setup_function22();
+ } else if (ENTITY_PARAM(0, 1)) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaGunYellow);
+ } else {
+ setup_function27();
+ }
+ break;
+
+ case 2:
+ if (getEntityData(kEntityPlayer)->entityPosition >= getData()->entityPosition)
+ getAction()->playAnimation(getData()->car < kCarRedSleeping ? kEventKahinaGunYellow : kEventKahinaGunBlue);
+ else
+ getAction()->playAnimation(kEventKahinaGun);
+
+ getEntities()->updateEntity(kEntityKahina, kCarKronos, kPosition_9270);
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750));
+ getSavePoints()->push(kEntityKahina, kEntityKronos, kAction235599361);
+ getSound()->playSound(kEntityKahina, "MUS016", SoundManager::kFlagDefault);
+ getProgress().field_44 = 1;
+
+ params->param1 = true;
+ params->param2 = kCarKronos;
+ params->param3 = kPosition_9270;
+ break;
+ }
+ break;
+
+ case kAction137503360:
+ getEntities()->clearSequences(kEntityKahina);
+ if (getSound()->isBuffered(kEntityKahina))
+ getSound()->processEntry(kEntityKahina);
+
+ getProgress().field_44 = 0;
+
+ setup_function22();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Kahina, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 == kTimeInvalid)
+ break;
+
+ if (getState()->time <= kTime2263500) {
+ if (!getEntities()->isPlayerInCar(kCarGreenSleeping) || !params->param1)
+ params->param1 = (uint)getState()->time;
+
+ if (params->param1 >= getState()->time)
+ break;
+ }
+
+ params->param1 = kTimeInvalid;
+
+ setCallback(12);
+ setup_enterExitCompartment("616Ba", kObjectCompartment1);
+ break;
+
+ case kActionDefault:
+ if (!getEvent(kEventAnnaBaggageArgument)) {
+ setCallback(1);
+ setup_function19(kCarGreenSleeping, kPosition_8200);
+ break;
+ }
+
+ switch (getInventory()->get(kItemFirebird)->location) {
+ default:
+ break;
+
+ case kObjectLocation3:
+ case kObjectLocation7:
+ if (getInventory()->get(kItemFirebird)->location == kObjectLocation3)
+ getProgress().field_7C = 1;
+ else
+ getProgress().field_80 = 1;
+
+ getScenes()->loadSceneFromItemPosition(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation5;
+ getSavePoints()->push(kEntityKahina, kEntityKronos, kAction138085344);
+ break;
+ }
+
+ getInventory()->setLocationAndProcess(kItemBriefcase, kObjectLocation2);
+ getProgress().field_78 = 1;
+ ENTITY_PARAM(0, 3) = 0;
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 4:
+ if (getEntities()->isPlayerInCar(kCarGreenSleeping)) {
+ setCallback(getCallback() + 1);
+ setup_function19(getCallback() == 1 ? kCarGreenSleeping : kCarKronos, getCallback() == 1 ? kPosition_9460 : kPosition_9270);
+ break;
+ } else {
+ if (getEntities()->checkFields19(kEntityPlayer, kCarGreenSleeping, kPosition_7850) || getEntities()->isOutsideAlexeiWindow()) {
+ setCallback(6);
+ setup_playSound("LIB013");
+ } else {
+ setCallback(8);
+ setup_enterExitCompartment("616Aa", kObjectCompartment1);
+ }
+ }
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateFromTime(1800);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function19(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 5:
+ case 7:
+ case 11:
+ case 13:
+ getEntities()->clearSequences(kEntityKahina);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function19(kCarKronos, kPosition_9270);
+ break;
+
+ case 8:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityKahina);
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObjectHandleBathroom, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(9);
+ setup_updateFromTime(900);
+ break;
+
+ case 9:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectHandleBathroom, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ switch (getInventory()->get(kItemFirebird)->location) {
+ default:
+ if (ENTITY_PARAM(0, 3))
+ getInventory()->setLocationAndProcess(kItemBriefcase, kObjectLocation2);
+ break;
+
+ case kObjectLocation3:
+ case kObjectLocation7:
+ if (getInventory()->get(kItemFirebird)->location == kObjectLocation3)
+ getProgress().field_7C = 1;
+ else
+ getProgress().field_80 = 1;
+
+ getScenes()->loadSceneFromItemPosition(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation5;
+ getSavePoints()->push(kEntityKahina, kEntityKronos, kAction138085344);
+ getInventory()->setLocationAndProcess(kItemBriefcase, kObjectLocation2);
+ getProgress().field_C0 = (uint)getState()->time;
+ getProgress().field_78 = 1;
+ break;
+ }
+
+ getProgress().field_78 = 1;
+ ENTITY_PARAM(0, 3) = 0;
+
+ if (getInventory()->get(kItemFirebird)->location != kObjectLocation18) {
+ setCallback(10);
+ setup_enterExitCompartment("616Ba", kObjectCompartment1);
+ }
+ break;
+
+ case 10:
+ case 12:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(getCallback() + 1);
+ setup_updateEntity(kCarKronos, kPosition_9270);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Kahina, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (!getEvent(kEventAnnaBaggageArgument)) {
+ setCallback(1);
+ setup_function19(kCarRedSleeping, kPosition_8200);
+ break;
+ }
+
+ getScenes()->loadSceneFromItemPosition(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation5;
+ getSavePoints()->push(kEntityKahina, kEntityKronos, kAction138085344);
+ getInventory()->setLocationAndProcess(kItemBriefcase, kObjectLocation2);
+ getProgress().field_78 = 1;
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEntities()->checkFields19(kEntityPlayer, kCarGreenSleeping, kPosition_7850)) {
+ setCallback(2);
+ setup_function19(kCarRedSleeping, kPosition_9460);
+ } else {
+ setCallback(6);
+ setup_enterExitCompartment("616Aa", kObjectCompartmentA);
+ }
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateFromTime(1800);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function19(kCarRedSleeping, kPosition_8200);
+ break;
+
+ case 4:
+ if (getEntities()->checkFields19(kEntityPlayer, kCarGreenSleeping, kPosition_7850)) {
+ setCallback(5);
+ setup_function19(kCarRedSleeping, kPosition_9270);
+ } else {
+ setCallback(6);
+ setup_enterExitCompartment("616Aa", kObjectCompartmentA);
+ }
+ break;
+
+ case 5:
+ case 9:
+ getEntities()->clearSequences(kEntityKahina);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityKahina);
+
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, getObjects()->get(kObjectCompartmentA).location, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject48, kEntityPlayer, getObjects()->get(kObject48).location, kCursorNormal, kCursorNormal);
+
+ setCallback(7);
+ setup_updateFromTime(900);
+ break;
+
+ case 7:
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, getObjects()->get(kObjectCompartmentA).location, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject48, kEntityPlayer, getObjects()->get(kObject48).location, kCursorHandKnock, kCursorHand);
+
+ if (getInventory()->get(kItemFirebird)->location == kObjectLocation1 || getInventory()->get(kItemFirebird)->location == kObjectLocation2) {
+ getScenes()->loadSceneFromItemPosition(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation5;
+ getSavePoints()->push(kEntityKahina, kEntityKronos, kAction138085344);
+ ENTITY_PARAM(0, 3) = 1;
+ }
+
+ setCallback(8);
+ setup_enterExitCompartment("616Ba", kObjectCompartmentA);
+ break;
+
+ case 8:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(9);
+ setup_updateEntity(kCarKronos, kPosition_9270);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Kahina, function27)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer))
+ params->param1 = kEventKahinaPunchCar;
+ else if (getEntities()->isPlayerInCar(kCarGreenSleeping))
+ params->param1 = kEventKahinaPunchBlue;
+ else if (getEntities()->isPlayerInCar(kCarRedSleeping))
+ params->param1 = kEventKahinaPunchYellow;
+ else if (getEntities()->isInSalon(kEntityPlayer))
+ params->param1 = kEventKahinaPunchSalon;
+ else if (getEntities()->isInRestaurant(kEntityPlayer))
+ params->param1 = kEventKahinaPunchRestaurant;
+ else if (getEntities()->isInKitchen(kEntityPlayer))
+ params->param1 = kEventKahinaPunchKitchen;
+ else if (getEntities()->isInBaggageCarEntrance(kEntityPlayer))
+ params->param1 = kEventKahinaPunchBaggageCarEntrance;
+ else if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarBaggage))
+ params->param1 = kEventKahinaPunchBaggageCar;
+
+ if (params->param1) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kSceneGameOverAlarm2);
+ }
+ break;
+
+ case kActionDefault:
+ getState()->timeDelta = 0;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation((EventIndex)params->param1);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Kahina, chapter4)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityKahina);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Kahina, chapter5)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityKahina);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/kahina.h b/engines/lastexpress/entities/kahina.h
new file mode 100644
index 0000000000..4be9d9fb27
--- /dev/null
+++ b/engines/lastexpress/entities/kahina.h
@@ -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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_KAHINA_H
+#define LASTEXPRESS_KAHINA_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Kahina : public Entity {
+public:
+ Kahina(LastExpressEngine *engine);
+ ~Kahina() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param savepoint The savepoint
+ * - ticks to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTicks)
+
+ DECLARE_FUNCTION_1(function6, TimeValue timeValue)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity2, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function12)
+ DECLARE_FUNCTION(function13)
+ DECLARE_FUNCTION(function14)
+ DECLARE_FUNCTION(function15)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Update the entity, handling excuse me events and resetting the entity state after the argument with Anna in the baggage car
+ *
+ * @param car The car index
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(function19, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_KAHINA_H
diff --git a/engines/lastexpress/entities/kronos.cpp b/engines/lastexpress/entities/kronos.cpp
new file mode 100644
index 0000000000..3335edb2fb
--- /dev/null
+++ b/engines/lastexpress/entities/kronos.cpp
@@ -0,0 +1,892 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/kronos.h"
+
+#include "lastexpress/entities/anna.h"
+#include "lastexpress/entities/august.h"
+#include "lastexpress/entities/kahina.h"
+#include "lastexpress/entities/rebecca.h"
+#include "lastexpress/entities/sophie.h"
+#include "lastexpress/entities/tatiana.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+static const struct {
+ uint32 time;
+ const char *sequence;
+} concertData[54] = {
+ {735, "201d"}, {1395, "201a"}, {1965, "201d"}, {2205, "201a"}, {3405, "201d"},
+ {3750, "201a"}, {3975, "201d"}, {4365, "201a"}, {4650, "201d"}, {4770, "201a"},
+ {4995, "201e"}, {5085, "201d"}, {5430, "201a"}, {5685, "201d"}, {5850, "201a"},
+ {7515, "201d"}, {7620, "201a"}, {7785, "201d"}, {7875, "201a"}, {8235, "201d"},
+ {8340, "201a"}, {8745, "201d"}, {8805, "201a"}, {8925, "201d"}, {8985, "201a"},
+ {9765, "201d"}, {9930, "201a"}, {12375, "201e"}, {12450, "201d"}, {12705, "201c"},
+ {13140, "201d"}, {13305, "201a"}, {13380, "201d"}, {13560, "201a"}, {14145, "201d"},
+ {14385, "201a"}, {14445, "201c"}, {14805, "201a"}, {16485, "201d"}, {16560, "201a"},
+ {16755, "201d"}, {16845, "201a"}, {17700, "201d"}, {17865, "201a"}, {18645, "201d"},
+ {18720, "201a"}, {19410, "201e"}, {19500, "201a"}, {22020, "201d"}, {22185, "201a"},
+ {22590, "201d"}, {22785, "201a"}, {23085, "201d"}, {23265, "201a"}
+};
+
+Kronos::Kronos(LastExpressEngine *engine) : Entity(engine, kEntityKronos) {
+ ADD_CALLBACK_FUNCTION(Kronos, reset);
+ ADD_CALLBACK_FUNCTION(Kronos, savegame);
+ ADD_CALLBACK_FUNCTION(Kronos, updateEntity);
+ ADD_CALLBACK_FUNCTION(Kronos, playSound);
+ ADD_CALLBACK_FUNCTION(Kronos, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Kronos, updateFromTicks);
+ ADD_CALLBACK_FUNCTION(Kronos, chapter1);
+ ADD_CALLBACK_FUNCTION(Kronos, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Kronos, function9);
+ ADD_CALLBACK_FUNCTION(Kronos, function10);
+ ADD_CALLBACK_FUNCTION(Kronos, function11);
+ ADD_CALLBACK_FUNCTION(Kronos, chapter2);
+ ADD_CALLBACK_FUNCTION(Kronos, chapter3);
+ ADD_CALLBACK_FUNCTION(Kronos, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Kronos, function15);
+ ADD_CALLBACK_FUNCTION(Kronos, function16);
+ ADD_CALLBACK_FUNCTION(Kronos, function17);
+ ADD_CALLBACK_FUNCTION(Kronos, function18);
+ ADD_CALLBACK_FUNCTION(Kronos, function19);
+ ADD_CALLBACK_FUNCTION(Kronos, function20);
+ ADD_CALLBACK_FUNCTION(Kronos, function21);
+ ADD_CALLBACK_FUNCTION(Kronos, function22);
+ ADD_CALLBACK_FUNCTION(Kronos, function23);
+ ADD_CALLBACK_FUNCTION(Kronos, chapter4);
+ ADD_CALLBACK_FUNCTION(Kronos, chapter5);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Kronos, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(2, Kronos, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(3, Kronos, updateEntity, CarIndex, EntityPosition)
+ Entity::updateEntity(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(4, Kronos, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(5, Kronos, updateFromTime)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(6, Kronos, updateFromTicks)
+ Entity::updateFromTicks(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Kronos, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6000;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarKronos;
+
+ getObjects()->update(kObjectCeiling, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Kronos, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTime1489500, params->param2, setup_function11);
+ break;
+
+ case kAction171849314:
+ params->param1 = 1;
+ break;
+
+ case kAction202621266:
+ setup_function9();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Kronos, function9)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKronosConversation);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventKronosConversation);
+ getScenes()->loadSceneFromPosition(kCarKronos, 87);
+ getSavePoints()->push(kEntityKronos, kEntityKahina, kAction137685712);
+ setup_function10();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Kronos, function10)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTime1489500, params->param1, setup_function11);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarKronos;
+
+ getEntities()->clearSequences(kEntityKronos);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Kronos, function11)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ params->param1++;
+ getSound()->playSound(kEntityKronos, (params->param1 & 1) ? "KRO1001" : "KRO1002");
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_7000;
+
+ if (!getSound()->isBuffered(kEntityKronos))
+ getSound()->playSound(kEntityKronos, "KRO1001");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Kronos, chapter2)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityKronos);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Kronos, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityKronos);
+
+ getData()->entityPosition = kPosition_6000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarKronos;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCeiling, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Kronos, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime1993500 && !params->param1 && !params->param2 && !params->param3)
+ setup_function15();
+ break;
+
+ case kAction157159392:
+ switch (savepoint.entity2) {
+ case kEntityAnna:
+ params->param1 = 1;
+ break;
+
+ case kEntityTatiana:
+ params->param2 = 1;
+ break;
+
+ case kEntityAbbot:
+ params->param3 = 1;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Kronos, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 && !getEntities()->isInSalon(kEntityBoutarel)) {
+ UPDATE_PARAM_PROC(params->param2, getState()->timeTicks, 75)
+ setup_function16();
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param3 != kTimeInvalid && getState()->time > kTime2002500) {
+ if (getState()->time <= kTime2052000) {
+ if (!getEntities()->isInSalon(kEntityPlayer) || getEntities()->isInSalon(kEntityPlayer) || !params->param3)
+ params->param3 = (uint)getState()->time + 900;
+
+ if (params->param3 >= getState()->time)
+ break;
+ }
+
+ params->param3 = kTimeInvalid;
+
+ if (getEntities()->isInSalon(kEntityPlayer)) {
+ setup_function16();
+ } else {
+ getSavePoints()->push(kEntityKronos, kEntityAnna, kAction101169422);
+ getSavePoints()->push(kEntityKronos, kEntityTatiana, kAction101169422);
+ getSavePoints()->push(kEntityKronos, kEntityAbbot, kAction101169422);
+
+ setup_function18();
+ }
+ }
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 60)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 59)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 83)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 81)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 87))
+ params->param1 = 1;
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 && getEntities()->isPlayerPosition(kCarRestaurant, 51) && !getEntities()->isInSalon(kEntityBoutarel))
+ setup_function16();
+ else
+ params->param1 = getEntities()->isPlayerPosition(kCarRestaurant, 60)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 59)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 83)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 81)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 87);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Kronos, function16)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKronosVisit);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventKronosVisit);
+ getSavePoints()->push(kEntityKronos, kEntityAnna, kAction101169422);
+ getSavePoints()->push(kEntityKronos, kEntityTatiana, kAction101169422);
+ getSavePoints()->push(kEntityKronos, kEntityAbbot, kAction101169422);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 60);
+
+ setup_function17();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Kronos, function17)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_9270);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function18();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Kronos, function18)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2079000 && !params->param2) {
+ getObjects()->updateLocation2(kObjectCompartmentKronos, kObjectLocation3);
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param1 = 1;
+ params->param2 = 1;
+ }
+
+ TIME_CHECK(kTime2106000, params->param3, setup_function19)
+ else {
+ if (params->param1 && getEntities()->isInKronosSanctum(kEntityPlayer)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaPunchSuite4);
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6000;
+ getData()->car = kCarKronos;
+ getData()->location = kLocationOutsideCompartment;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventKahinaPunchSuite4);
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventCathJumpDownCeiling, kSceneNone, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Kronos, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ break;
+
+ case kActionDrawScene:
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventKahinaPunchSuite4);
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventCathJumpDownCeiling, kSceneNone, true);
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventConcertStart);
+ getSound()->setupEntry(SoundManager::kSoundType7, kEntityKronos);
+ getScenes()->loadSceneFromPosition(kCarKronos, 83);
+
+ RESET_ENTITY_STATE(kEntityRebecca, Rebecca, setup_function39);
+ RESET_ENTITY_STATE(kEntitySophie, Sophie, setup_chaptersHandler);
+ RESET_ENTITY_STATE(kEntityAugust, August, setup_function50);
+ RESET_ENTITY_STATE(kEntityAnna, Anna, setup_function56);
+ RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function35);
+
+ setup_function20();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Kronos, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ params->param5 = getSound()->getEntryTime(kEntityKronos)* 2;
+
+ if (params->param6 < ARRAYSIZE(concertData) && params->param5 > concertData[params->param6].time) {
+
+ getEntities()->drawSequenceLeft(kEntityKronos, concertData[params->param6].sequence);
+
+ if (scumm_stricmp(concertData[params->param6].sequence, "201e")) {
+
+ if (scumm_stricmp(concertData[params->param6].sequence, "201c")) {
+
+ if (!scumm_stricmp(concertData[params->param6].sequence, "201d")) {
+ if (getEntities()->isPlayerPosition(kCarKronos, 86))
+ getScenes()->loadSceneFromPosition(kCarKronos, 83);
+
+ getEntities()->updatePositionEnter(kEntityKronos, kCarKronos, 86);
+ getEntities()->updatePositionExit(kEntityKronos, kCarKronos, 85);
+ } else {
+ getEntities()->updatePositionExit(kEntityKronos, kCarKronos, 85);
+ getEntities()->updatePositionExit(kEntityKronos, kCarKronos, 86);
+ }
+ } else {
+ if (getEntities()->isPlayerPosition(kCarKronos, 85))
+ getScenes()->loadSceneFromPosition(kCarKronos, 83);
+
+ getEntities()->updatePositionEnter(kEntityKronos, kCarKronos, 85);
+ getEntities()->updatePositionExit(kEntityKronos, kCarKronos, 86);
+ }
+ } else {
+ if (getEntities()->isPlayerPosition(kCarKronos, 85) || getEntities()->isPlayerPosition(kCarKronos, 86))
+ getScenes()->loadSceneFromPosition(kCarKronos, 83);
+
+ getEntities()->updatePositionEnter(kEntityKronos, kCarKronos, 85);
+ getEntities()->updatePositionEnter(kEntityKronos, kCarKronos, 86);
+ }
+
+ ++params->param6;
+ }
+
+ getObjects()->update(kObject76, kEntityKronos, kObjectLocationNone, kCursorNormal, getInventory()->hasItem(kItemBriefcase) ? kCursorHand : kCursorNormal);
+
+ if (!params->param7) {
+ params->param7 = (uint)getState()->time + 2700;
+ params->param8 = (uint)getState()->time + 13500;
+ }
+
+ if (CURRENT_PARAM(1, 2) != kTimeInvalid && params->param7 < getState()->time) {
+ UPDATE_PARAM_PROC_TIME(params->param8, !params->param1, CURRENT_PARAM(1, 2), 450)
+ getSavePoints()->push(kEntityKronos, kEntityKahina, kAction237555748);
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (!params->param1)
+ params->param2 = params->param3;
+
+ params->param2 -= getState()->timeDelta;
+
+ if (params->param2 < getState()->timeDelta) {
+
+ getSavePoints()->push(kEntityKronos, kEntityKahina, kAction92186062);
+
+ ++params->param4;
+ switch (params->param4) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventCathWakingUp);
+ getScenes()->processScene();
+ params->param3 = 1800;
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventCathWakingUp);
+ getScenes()->processScene();
+ params->param3 = 3600;
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventCathFallingAsleep);
+
+ while (getSound()->isBuffered("1919.LNK"))
+ getSound()->updateQueue();
+
+ getAction()->playAnimation(kEventCathWakingUp);
+ getScenes()->processScene();
+ params->param3 = 162000;
+ break;
+ }
+ params->param2 = params->param3;
+ }
+
+ if (params->param5 > 23400 || CURRENT_PARAM(1, 1)) {
+ if (getEntities()->isInKronosSanctum(kEntityPlayer)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaWrongDoor);
+ }
+ }
+ break;
+
+ case kActionEndSound:
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ if (CURRENT_PARAM(1, 1)) {
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 26);
+
+ setup_function21();
+ break;
+ }
+
+ if (getEntities()->isInKronosSalon(kEntityPlayer)) {
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventConcertEnd);
+ break;
+ }
+
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)) {
+ getSound()->playSound(kEntityKronos, "Kro3001");
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorNormal, kCursorNormal);
+ CURRENT_PARAM(1, 1) = 1;
+ break;
+ }
+
+ setup_function21();
+ break;
+
+ case kActionOpenDoor:
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventConcertLeaveWithBriefcase);
+ break;
+
+ case kActionDefault:
+ getState()->time = kTime2115000;
+ getState()->timeDelta = 3;
+
+ params->param1 = (getEntities()->isPlayerPosition(kCarKronos, 88)
+ || getEntities()->isPlayerPosition(kCarKronos, 84)
+ || getEntities()->isPlayerPosition(kCarKronos, 85)
+ || getEntities()->isPlayerPosition(kCarKronos, 86)
+ || getEntities()->isPlayerPosition(kCarKronos, 83));
+
+ if (getInventory()->hasItem(kItemFirebird))
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+ else
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getObjects()->update(kObject76, kEntityKronos, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getProgress().field_40 = 1;
+ getEntities()->drawSequenceLeft(kEntityKronos, "201a");
+
+ params->param2 = 2700;
+ params->param3 = 2700;
+ break;
+
+ case kActionDrawScene:
+ params->param1 = (getEntities()->isPlayerPosition(kCarKronos, 88)
+ || getEntities()->isPlayerPosition(kCarKronos, 84)
+ || getEntities()->isPlayerPosition(kCarKronos, 85)
+ || getEntities()->isPlayerPosition(kCarKronos, 86)
+ || getEntities()->isPlayerPosition(kCarKronos, 83));
+
+ if (getInventory()->hasItem(kItemFirebird))
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorNormal, kCursorNormal);
+ else
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventKahinaWrongDoor);
+
+ if (getInventory()->hasItem(kItemBriefcase))
+ getInventory()->removeItem(kItemBriefcase);
+
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarKronos, 81);
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorNormal, kCursorNormal);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_6000;
+ getAction()->playAnimation(kEventConcertLeaveWithBriefcase);
+
+ RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function21);
+
+ getScenes()->loadSceneFromPosition(kCarKronos, 87);
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventConcertEnd);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 26);
+
+ setup_function21();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Kronos, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInKronosSanctum(kEntityPlayer)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaWrongDoor);
+ }
+ break;
+
+ case kActionDefault:
+ getProgress().field_40 = 0;
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorNormal, kCursorNormal);
+ getSavePoints()->push(kEntityKronos, kEntityRebecca, kAction191668032);
+ if (!getEvent(kEventConcertLeaveWithBriefcase))
+ setup_function22();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventKahinaWrongDoor);
+
+ if (getInventory()->hasItem(kItemBriefcase))
+ getInventory()->removeItem(kItemBriefcase);
+
+ getSound()->playSound(kEntityPlayer, "BUMP");
+
+ getScenes()->loadSceneFromPosition(kCarKronos, 81);
+
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ }
+ break;
+
+ case kAction235599361:
+ setup_function22();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Kronos, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().field_44) {
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaPunchBaggageCarEntrance);
+ } else {
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaWrongDoor);
+ }
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (!getSound()->isBuffered(savepoint.action == kActionKnock ? "LIB012" : "LIB013", true))
+ getSound()->playSound(kEntityPlayer, savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+
+ if (getEvent(kEventConcertLeaveWithBriefcase))
+ getSavePoints()->call(kEntityKronos, kEntityKahina, kAction137503360);
+
+ if (getInventory()->hasItem(kItemBriefcase)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKronosReturnBriefcase);
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemFirebird) && getEvent(kEventConcertLeaveWithBriefcase)) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventKronosBringEggCeiling);
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemFirebird)) {
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventKronosBringEggCeiling);
+ break;
+ }
+
+ if (getEvent(kEventConcertLeaveWithBriefcase)) {
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventKronosBringNothing);
+ break;
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentKronos, kEntityKronos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventKronosReturnBriefcase);
+ getScenes()->loadSceneFromPosition(kCarKronos, 87);
+ getInventory()->removeItem(kItemFirebird);
+ getInventory()->removeItem(kItemScarf);
+
+ setup_function23();
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventKronosBringEggCeiling);
+ getScenes()->loadSceneFromPosition(kCarKronos, 87);
+ getInventory()->removeItem(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation5;
+
+ setup_function23();
+ break;
+
+ case 3:
+ getInventory()->removeItem(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation5;
+ getAction()->playAnimation(kEventKronosBringEgg);
+ getScenes()->loadSceneFromPosition(kCarKronos, 87);
+ getInventory()->addItem(kItemBriefcase);
+ setup_function23();
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventKronosBringNothing);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ break;
+
+ case 5:
+ getAction()->playAnimation(kEventKahinaPunchSuite4);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ break;
+
+ case 6:
+ getAction()->playAnimation(kEventKahinaWrongDoor);
+ if (getInventory()->hasItem(kItemBriefcase))
+ getInventory()->removeItem(kItemBriefcase);
+
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarKronos, 81);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ break;
+ }
+ break;
+
+ case kAction138085344:
+ setup_function23();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Kronos, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInKronosSanctum(kEntityPlayer)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventKahinaWrongDoor);
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventKahinaWrongDoor);
+
+ if (getInventory()->hasItem(kItemBriefcase))
+ getInventory()->removeItem(kItemBriefcase);
+
+ getSound()->playSound(kEntityPlayer, "BUMP");
+
+ getScenes()->loadSceneFromPosition(kCarKronos, 81);
+
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Kronos, chapter4)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityKronos);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Kronos, chapter5)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityKronos);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/kronos.h b/engines/lastexpress/entities/kronos.h
new file mode 100644
index 0000000000..f73c245347
--- /dev/null
+++ b/engines/lastexpress/entities/kronos.h
@@ -0,0 +1,138 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_KRONOS_H
+#define LASTEXPRESS_KRONOS_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Kronos : public Entity {
+public:
+ Kronos(LastExpressEngine *engine);
+ ~Kronos() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Plays sound
+ *
+ * @param savepoint The savepoint
+ * - the sound filename
+ */
+ DECLARE_FUNCTION_NOSETUP(playSound)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param savepoint The savepoint
+ * - Time to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTime)
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param savepoint The savepoint
+ * - ticks to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTicks)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function9)
+ DECLARE_FUNCTION(function10)
+ DECLARE_FUNCTION(function11)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION(function16)
+ DECLARE_FUNCTION(function17)
+ DECLARE_FUNCTION(function18)
+ DECLARE_FUNCTION(function19)
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_KRONOS_H
diff --git a/engines/lastexpress/entities/mahmud.cpp b/engines/lastexpress/entities/mahmud.cpp
new file mode 100644
index 0000000000..0b4dc1b138
--- /dev/null
+++ b/engines/lastexpress/entities/mahmud.cpp
@@ -0,0 +1,839 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/data/scene.h"
+
+#include "lastexpress/entities/mahmud.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Mahmud::Mahmud(LastExpressEngine *engine) : Entity(engine, kEntityMahmud) {
+ ADD_CALLBACK_FUNCTION(Mahmud, reset);
+ ADD_CALLBACK_FUNCTION(Mahmud, draw);
+ ADD_CALLBACK_FUNCTION(Mahmud, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Mahmud, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Mahmud, playSound);
+ ADD_CALLBACK_FUNCTION(Mahmud, playSoundMertens);
+ ADD_CALLBACK_FUNCTION(Mahmud, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Mahmud, savegame);
+ ADD_CALLBACK_FUNCTION(Mahmud, updateEntity);
+ ADD_CALLBACK_FUNCTION(Mahmud, function10);
+ ADD_CALLBACK_FUNCTION(Mahmud, function11);
+ ADD_CALLBACK_FUNCTION(Mahmud, function12);
+ ADD_CALLBACK_FUNCTION(Mahmud, function13);
+ ADD_CALLBACK_FUNCTION(Mahmud, chaptersHandler);
+ ADD_CALLBACK_FUNCTION(Mahmud, chapter1);
+ ADD_CALLBACK_FUNCTION(Mahmud, resetChapter);
+ ADD_CALLBACK_FUNCTION(Mahmud, chapter2);
+ ADD_CALLBACK_FUNCTION(Mahmud, chapter3);
+ ADD_CALLBACK_FUNCTION(Mahmud, chapter4);
+ ADD_CALLBACK_FUNCTION(Mahmud, chapter5);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Mahmud, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(2, Mahmud, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(3, Mahmud, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIII(4, Mahmud, enterExitCompartment2, ObjectIndex, uint32, ObjectIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param7, getState()->timeTicks, params->param5);
+
+ if (!getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp))
+ getScenes()->loadSceneFromObject((ObjectIndex)params->param6, true);
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->exitCompartment(kEntityMahmud, (ObjectIndex)params->param4);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityMahmud, (char *)&params->seq);
+ getEntities()->enterCompartment(kEntityMahmud, (ObjectIndex)params->param4);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(5, Mahmud, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(6, Mahmud, playSoundMertens)
+ Entity::playSound(savepoint, false, getSound()->getSoundFlag(kEntityMertens));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(7, Mahmud, updateFromTime)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(8, Mahmud, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(9, Mahmud, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ if (getInventory()->hasItem(kItemPassengerList))
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1025" : "CAT1025Q");
+ else
+ getSound()->excuseMeCath();
+
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Mahmud, function10, ObjectIndex, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param6, getState()->time, 13500);
+
+ getObjects()->update(kObjectCompartment5, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment6, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment7, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment8, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_enterExitCompartment("614Ed", kObjectCompartment4);
+ break;
+
+ case kActionEndSound:
+ case kActionDrawScene:
+ if (!getSound()->isBuffered(kEntityMahmud)) {
+ EntityPosition position = getEntityData(kEntityPlayer)->entityPosition;
+ if (position < kPosition_1500 || position >= kPosition_5790 || (position > kPosition_4455 && params->param5 != 5)) {
+ getObjects()->update(kObjectCompartment5, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment6, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment7, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment8, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ setCallback(3);
+ setup_enterExitCompartment("614Ed", kObjectCompartment4);
+ }
+ }
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (!getSound()->isBuffered((savepoint.action == kActionKnock) ? "LIB012" : "LIB013", true))
+ getSound()->playSound(kEntityPlayer, (savepoint.action == kActionKnock) ? "LIB012" : "LIB013");
+
+ params->param5 = savepoint.param.intValue;
+
+ if (!getSound()->isBuffered(kEntityMahmud)) {
+ params->param3++;
+
+ switch(params->param3) {
+ default:
+ params->param4 = 1;
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityMahmud, "MAH1174");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityMahmud, "MAH1173B");
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityMahmud, params->param2 ? "MAH1170E" : "MAH1173A");
+ break;
+ }
+ }
+
+ if (params->param4) {
+ if (getState()->time >= kTimeCityGalanta) {
+ params->param3 = 0;
+ } else {
+ getSound()->playSound(kEntityTrain, "LIB050", SoundManager::kFlagDefault);
+ getLogic()->gameOver(kSavegameTypeIndex, 0, (getProgress().chapter == kChapter1) ? kSceneGameOverPolice1 : kSceneGameOverPolice2, true);
+ }
+ break;
+ }
+
+ getAction()->handleOtherCompartment((ObjectIndex)savepoint.param.intValue, false, false);
+
+ switch (getScenes()->get(getState()->scene)->position) {
+ default:
+ break;
+
+ case 55:
+ getScenes()->loadSceneFromObject(kObjectCompartment5, true);
+ break;
+
+ case 56:
+ getScenes()->loadSceneFromObject(kObjectCompartment6, true);
+ break;
+
+ case 57:
+ getScenes()->loadSceneFromObject(kObjectCompartment7, true);
+ break;
+
+ case 58:
+ getScenes()->loadSceneFromObject(kObjectCompartment8, true);
+ break;
+ }
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityMahmud, params->param2 ? "MAH1170A" : "MAH1173", SoundManager::kFlagInvalid, 45);
+ getProgress().field_C4 = 1;
+
+ setCallback(1);
+ setup_enterExitCompartment2("614Dd", kObjectCompartment4, 30, (ObjectIndex)params->param1);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartment5, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment6, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment7, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment8, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->drawSequenceLeft(kEntityMahmud, "614Md");
+ getEntities()->enterCompartment(kEntityMahmud, kObjectCompartment4, true);
+ break;
+
+ case 2:
+ case 3:
+ getEntities()->exitCompartment(kEntityMahmud, kObjectCompartment4, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMahmud);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Mahmud, function11)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor: {
+ getSound()->playSound(kEntityPlayer, (savepoint.action == kActionKnock ? "LIB012" : "LIB013"));
+
+ if (!getSound()->isBuffered(kEntityMahmud)) {
+ params->param1++;
+
+ getSound()->playSound(kEntityMahmud, (params->param1 == 1 ? "MAH1170E" : (params->param1 == 2 ? "MAH1173B" : "MAH1174")));
+ }
+
+ switch (getScenes()->get(getState()->scene)->position) {
+ default:
+ break;
+
+ case 55:
+ getScenes()->loadSceneFromObject(kObjectCompartment5, true);
+ break;
+
+ case 56:
+ getScenes()->loadSceneFromObject(kObjectCompartment6, true);
+ break;
+
+ case 57:
+ getScenes()->loadSceneFromObject(kObjectCompartment7, true);
+ break;
+
+ case 58:
+ getScenes()->loadSceneFromObject(kObjectCompartment8, true);
+ break;
+ }
+ break;
+ }
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityMahmud, kEntityMertens, kAction102227384);
+ setCallback(1);
+ setup_enterExitCompartment("614Ad", kObjectCompartment4);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartment4, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getEntities()->drawSequenceLeft(kEntityMahmud, "614Kd");
+ getEntities()->enterCompartment(kEntityMahmud, kObjectCompartment4, true);
+
+ setCallback(2);
+ setup_playSound("MAH1170A");
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_playSoundMertens("MAH1170B");
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_playSound("MAH1170C");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_playSoundMertens("MAH1170D");
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_playSound("MAH1170E");
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_playSoundMertens("MAH1170F");
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_enterExitCompartment("614Ld", kObjectCompartment4);
+ break;
+
+ case 8:
+ getSavePoints()->push(kEntityMahmud, kEntityMertens, kAction156567128);
+ getEntities()->drawSequenceLeft(kEntityMahmud, "614Bd");
+ getEntities()->enterCompartment(kEntityMahmud, kObjectCompartment4, true);
+
+ setCallback(9);
+ setup_playSound("MAH1170G");
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_playSoundMertens("MAH1170H");
+ break;
+
+ case 10:
+ getObjects()->update(kObjectCompartment5, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment6, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment7, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment8, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 11:
+ getEntities()->exitCompartment(kEntityMahmud, kObjectCompartment4, true);
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->clearSequences(kEntityMahmud);
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction123852928:
+ if (getSound()->isBuffered(kEntityMahmud))
+ getSound()->processEntry(kEntityMahmud);
+
+ getObjects()->update(kObjectCompartment5, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment6, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment7, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment8, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ setCallback(11);
+ setup_enterExitCompartment("614Cd", kObjectCompartment4);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// TODO: factorize code between function12 & function13
+IMPLEMENT_FUNCTION(12, Mahmud, function12)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("614Gd", kObjectCompartment4);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartment4, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment("614Ff", kObjectCompartment6);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMahmud);
+
+ setCallback(4);
+ setup_playSound("Har1105");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("614Gf", kObjectCompartment6);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(6);
+ setup_updateEntity(kCarGreenSleeping, kPosition_5790);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_enterExitCompartment("614Fd", kObjectCompartment4);
+ break;
+
+ case 7:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMahmud);
+
+ CALLBACK_ACTION();
+ break;
+
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Mahmud, function13)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("614Gd", kObjectCompartment4);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartment4, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2740);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment("614Fh", kObjectCompartment8);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMahmud);
+
+ setCallback(4);
+ setup_playSound("Har1107");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("614Gh", kObjectCompartment8);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(6);
+ setup_updateEntity(kCarGreenSleeping, kPosition_5790);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_enterExitCompartment("614Fd", kObjectCompartment4);
+ break;
+
+ case 7:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMahmud);
+
+ CALLBACK_ACTION();
+ break;
+
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Mahmud, chaptersHandler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(0, 1)) {
+ params->param2 = 1;
+ getSavePoints()->push(kEntityMahmud, kEntityMertens, kAction204379649);
+ ENTITY_PARAM(0, 1) = 0;
+ }
+
+ if (!params->param2 && getProgress().chapter == kChapter1) {
+
+ TIME_CHECK_CALLBACK(kTime1098000, params->param6, 1, setup_function13);
+
+ if (!getSound()->isBuffered("HAR1104") && getState()->time > kTime1167300 && !params->param7) {
+ params->param7 = 1;
+
+ setCallback(2);
+ setup_function12();
+ break;
+ }
+ }
+
+ if (params->param5) {
+ UPDATE_PARAM(params->param8, getState()->timeTicks, 75);
+
+ params->param4 = 1;
+ params->param5 = 0;
+
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorNormal, kCursorNormal);
+ }
+
+ params->param8 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (params->param5) {
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ if (getProgress().jacket == kJacketBlood || getEvent(kEventMahmudWrongDoor) || getEvent(kEventMahmudWrongDoorOriginalJacket) || getEvent(kEventMahmudWrongDoorDay)) {
+ // Check if we have the passenger list
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(6);
+ setup_playSound(rnd(2) == 0 ? "CAT1501" : getSound()->wrongDoorCath());
+ } else {
+ setCallback(7);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 8 : 9);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ } else {
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 3 : 4);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getEntities()->clearSequences(kEntityMahmud);
+ params->param3 = 1;
+
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param4 || params->param5) {
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param4 = 0;
+ params->param5 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ return;
+
+ case 1:
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param4 = 0;
+ params->param5 = 0;
+
+ if (!getSound()->isBuffered("HAR1104") && getState()->time > kTime1167300 && !params->param7) {
+ params->param7 = 1;
+ setCallback(2);
+ setup_function12();
+ break;
+ }
+
+ params->param8 = 0;
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param4 = 0;
+ params->param5 = 0;
+ params->param8 = 0;
+ break;
+
+ case 3:
+ case 4:
+ setCallback(5);
+ setup_playSound("MAH1175");
+ break;
+
+ case 5: {
+ CursorStyle cursor = kCursorHand;
+ CursorStyle cursor2 = kCursorHandKnock;
+
+ if (getProgress().jacket == kJacketBlood
+ || getEvent(kEventMahmudWrongDoor)
+ || getEvent(kEventMahmudWrongDoorOriginalJacket)
+ || getEvent(kEventMahmudWrongDoorDay)) {
+ cursor = kCursorNormal;
+ cursor2 = kCursorTalk;
+ }
+
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation1, cursor, cursor2);
+ params->param5 = 1;
+ break;
+ }
+
+ case 6:
+ case 7:
+ params->param4 = 1;
+ break;
+
+ case 8:
+ case 9:
+ setCallback(10);
+ setup_savegame(kSavegameTypeEvent, kEventMahmudWrongDoor);
+ return;
+
+ case 10:
+ getAction()->playAnimation((getProgress().jacket == kJacketGreen) ? (isNight() ? kEventMahmudWrongDoor : kEventMahmudWrongDoorDay) : kEventMahmudWrongDoorOriginalJacket);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->processScene();
+
+ params->param4 = 1;
+ break;
+
+ case 11:
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param4 = 0;
+ params->param5 = 0;
+ break;
+
+ case 12:
+ getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param2 = 0;
+ params->param4 = 0;
+ params->param5 = 0;
+ break;
+ }
+ break;
+
+ case kAction225563840:
+ setCallback(12);
+ setup_function11();
+ break;
+
+ case kAction290410610:
+ params->param3 = (params->param3 < 1) ? 1 : 0;
+ setCallback(11);
+ setup_function10((ObjectIndex)savepoint.param.intValue, (bool)params->param3);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Mahmud, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chaptersHandler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityMahmud, kAction170483072, 0);
+
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getObjects()->update(kObjectCompartment4, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject20, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Mahmud, resetChapter)
+ if (savepoint.action != kActionDefault)
+ return;
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getObjects()->update(kObjectCompartment4, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getEntities()->clearSequences(kEntityMahmud);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Mahmud, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chaptersHandler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMahmud);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Mahmud, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chaptersHandler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMahmud);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Mahmud, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chaptersHandler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMahmud);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Mahmud, chapter5)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityMahmud);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/mahmud.h b/engines/lastexpress/entities/mahmud.h
new file mode 100644
index 0000000000..647d48b8ed
--- /dev/null
+++ b/engines/lastexpress/entities/mahmud.h
@@ -0,0 +1,153 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_MAHMUD_H
+#define LASTEXPRESS_MAHMUD_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Mahmud : public Entity {
+public:
+ Mahmud(LastExpressEngine *engine);
+ ~Mahmud() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Draws the entity
+ *
+ * @param savepoint The savepoint
+ * - The sequence to draw
+ */
+ DECLARE_FUNCTION_NOSETUP(draw)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ * @param ticks The time ticks
+ * @param object The object for loading the scene
+ */
+ DECLARE_FUNCTION_4(enterExitCompartment2, const char *sequence, ObjectIndex compartment, uint32 ticks, ObjectIndex object)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSoundMertens, const char *filename)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param savepoint The savepoint
+ * - Time to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTime)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION_2(function10, ObjectIndex, bool)
+ DECLARE_FUNCTION(function11)
+ DECLARE_FUNCTION(function12)
+ DECLARE_FUNCTION(function13)
+
+ /**
+ * Handle chapters events
+ */
+ DECLARE_FUNCTION(chaptersHandler)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Reset chapter data
+ */
+ DECLARE_FUNCTION(resetChapter)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_MAHMUD_H
diff --git a/engines/lastexpress/entities/max.cpp b/engines/lastexpress/entities/max.cpp
new file mode 100644
index 0000000000..a846f7b6dd
--- /dev/null
+++ b/engines/lastexpress/entities/max.cpp
@@ -0,0 +1,628 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/max.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Max::Max(LastExpressEngine *engine) : Entity(engine, kEntityMax) {
+ ADD_CALLBACK_FUNCTION(Max, reset);
+ ADD_CALLBACK_FUNCTION(Max, playSound);
+ ADD_CALLBACK_FUNCTION(Max, draw);
+ ADD_CALLBACK_FUNCTION(Max, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Max, savegame);
+ ADD_CALLBACK_FUNCTION(Max, chapter12_handler);
+ ADD_CALLBACK_FUNCTION(Max, function7);
+ ADD_CALLBACK_FUNCTION(Max, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Max, function9);
+ ADD_CALLBACK_FUNCTION(Max, chapter1);
+ ADD_CALLBACK_FUNCTION(Max, chapter2);
+ ADD_CALLBACK_FUNCTION(Max, chapter3);
+ ADD_CALLBACK_FUNCTION(Max, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Max, freeFromCage);
+ ADD_CALLBACK_FUNCTION(Max, function15);
+ ADD_CALLBACK_FUNCTION(Max, chapter4);
+ ADD_CALLBACK_FUNCTION(Max, function17);
+ ADD_CALLBACK_FUNCTION(Max, chapter5);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Max, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Max, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(3, Max, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(4, Max, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(5, Max, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Max, chapter12_handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param2, getState()->time, params->param1);
+
+ if (!getSound()->isBuffered(kEntityMax))
+ getSound()->playSound(kEntityMax, "Max1122");
+
+ params->param1 = 255 * (4 * rnd(20) + 40);
+ params->param2 = 0;
+ break;
+
+ case kActionDefault:
+ params->param1 = 255 * (4 * rnd(20) + 40);
+ break;
+
+ case kAction71277948:
+ setCallback(1);
+ setup_function7();
+ break;
+
+ case kAction158007856:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ getSound()->playSound(kEntityMax, "Max1122");
+ params->param1 = 255 * (4 * rnd(20) + 40);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Max, function7)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param2, getState()->time, params->param1)
+
+ if (!getSound()->isBuffered(kEntityMax))
+ getSound()->playSound(kEntityMax, "Max1122");
+
+ params->param1 = 255 * (4 * rnd(20) + 40);
+ params->param2 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentF, kEntityMax, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject53, kEntityMax, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (getSound()->isBuffered(kEntityMax))
+ getSound()->processEntry(kEntityMax);
+
+ setCallback((savepoint.action == kActionKnock) ? 1 : 2);
+ setup_playSound((savepoint.action == kActionKnock) ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ params->param1 = 255 * (4 * rnd(20) + 40);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentF, kEntityMax, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityMax, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 56) || getEntities()->isPlayerPosition(kCarRedSleeping, 78))
+ getSound()->playSound(kEntityMax, "Max1120");
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ case 0:
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound("Max1122");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentF, kEntityMax, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityMax, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+
+ case kAction101687594:
+ getEntities()->clearSequences(kEntityMax);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kAction122358304:
+ case kActionMaxFreeFromCage:
+ getSavePoints()->push(kEntityMax, kEntityMax, kActionMaxFreeFromCage);
+ getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject53, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kAction158007856:
+ if (!getSound()->isBuffered(kEntityMax)) {
+ getSound()->playSound(kEntityMax, "Max1122");
+ params->param1 = 255 * (4 * rnd(20) + 40);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Max, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param3, getState()->time, params->param2);
+
+ if (!getSound()->isBuffered(kEntityMax))
+ getSound()->playSound(kEntityMax, "Max3101");
+
+ params->param2 = 255 * (4 * rnd(20) + 40);
+ params->param3 = 0;
+ break;
+
+ case kActionOpenDoor:
+ if (params->param1) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventCathMaxLickHand);
+ break;
+ }
+
+ if (getSound()->isBuffered(kEntityMax))
+ getSound()->processEntry(kEntityMax);
+
+ getAction()->playAnimation(kEventCathMaxLickHand);
+ getScenes()->processScene();
+
+ params->param1 = 1;
+ break;
+
+ case kActionDefault:
+ params->param2 = 255 * (4 * rnd(20) + 40);
+
+ getObjects()->update(kObjectCageMax, kEntityMax, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getEntities()->clearSequences(kEntityMax);
+
+ getData()->entityPosition = kPosition_8000;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarBaggage;
+
+ if (!getSound()->isBuffered(kEntityMax))
+ getSound()->playSound(kEntityMax, "Max3101");
+ break;
+
+ case kActionCallback:
+ if (getCallback() != 1)
+ break;
+
+ if (getSound()->isBuffered(kEntityMax))
+ getSound()->processEntry(kEntityMax);
+
+ getSound()->playSound(kEntityPlayer, "LIB026");
+ getAction()->playAnimation(kEventCathMaxFree);
+ getScenes()->loadSceneFromPosition(kCarBaggage, 92);
+ getObjects()->update(kObjectCageMax, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ setup_function9();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Max, function9)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2 == kTimeInvalid || !getState()->time)
+ break;
+
+ if (params->param1 >= getState()->time) {
+ if (!getEntities()->hasValidFrame(kEntityMax) || !params->param2) {
+
+ params->param2 = (uint)getState()->time;
+ if (!params->param2)
+ goto setup_functions;
+ }
+
+ if (params->param2 >= getState()->time)
+ break;
+ }
+
+ params->param2 = kTimeInvalid;
+
+setup_functions:
+ if (getProgress().chapter == kChapter3)
+ setup_function15();
+
+ if (getProgress().chapter == kChapter4)
+ setup_function17();
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Draw Max outside of cage
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->drawSequenceLeft(kEntityMax, "630Af");
+ getEntities()->enterCompartment(kEntityMax, kObjectCompartmentF, true);
+
+ params->param1 = (uint)(getState()->time + 2700);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Max, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter12_handler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Max, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter12_handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMax);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Max, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMax);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Max, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2) {
+ getData()->entityPosition = getEntityData(kEntityCoudert)->entityPosition;
+ break;
+ }
+
+ UPDATE_PARAM(params->param3, getState()->time, params->param1);
+
+ if (!getSound()->isBuffered(kEntityMax))
+ getSound()->playSound(kEntityMax, "Max1122");
+
+ params->param1 = 255 * (4 * rnd(20) + 40);
+ params->param3 = 0;
+ break;
+
+ case kActionDefault:
+ params->param1 = 255 * (4 * rnd(20) + 40);
+
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ break;
+
+ case kAction71277948:
+ setCallback(1);
+ setup_function7();
+ break;
+
+ case kAction122358304:
+ params->param2 = 1;
+ break;
+
+ case kActionMaxFreeFromCage:
+ setup_freeFromCage();
+ break;
+
+ case kAction158007856:
+ if (params->param2)
+ break;
+
+ if (!getSound()->isBuffered(kEntityMax)) {
+ getSound()->playSound(kEntityMax, "Max1122");
+ params->param1 = 255 * (4 * rnd(20) + 40);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Max, freeFromCage)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ break;
+
+ case kActionEndSound:
+ getSound()->playSound(kEntityMax, "Max1122");
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Save game after freeing Max from his cage
+ case kActionOpenDoor:
+ if (getEvent(kEventCathMaxCage)) {
+ if (getEvent(kEventCathMaxFree)) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventCathMaxFree);
+ }
+
+ } else {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventCathMaxCage);
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCageMax, kEntityMax, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ getData()->entityPosition = kPosition_8000;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarBaggage;
+
+ if (!getSound()->isBuffered(kEntityMax))
+ getSound()->playSound(kEntityMax, "Max1122");
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Play animation for Max in the cage and after opening it
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getSound()->isBuffered(kEntityMax))
+ getSound()->removeFromQueue(kEntityMax);
+
+ getAction()->playAnimation(kEventCathMaxCage);
+ getSound()->setupEntry(SoundManager::kSoundType7, kEntityMax);
+ getScenes()->processScene();
+ break;
+
+ case 2:
+ if (getSound()->isBuffered(kEntityMax))
+ getSound()->processEntry(kEntityMax);
+
+ getSound()->playSound(kEntityPlayer, "LIB026");
+ getAction()->playAnimation(kEventCathMaxFree);
+ getScenes()->loadSceneFromPosition(kCarBaggage, 92);
+ getObjects()->update(kObjectCageMax, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ setup_function9();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Max, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2) {
+ getData()->entityPosition = getEntityData(kEntityCoudert)->entityPosition;
+ getData()->car = getEntityData(kEntityCoudert)->car;
+ }
+
+ if (!params->param1) {
+ UPDATE_PARAM(params->param3, getState()->time, 900);
+
+ getSavePoints()->push(kEntityMax, kEntityCoudert, kAction157026693);
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ if (!getSound()->isBuffered(kEntityMax))
+ getSound()->playSound(kEntityMax, "Max3010");
+
+ setCallback(1);
+ setup_enterExitCompartment("630Bf", kObjectCompartment4);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->drawSequenceLeft(kEntityMax, "630Af");
+ getEntities()->enterCompartment(kEntityMax, kObjectCompartmentF, true);
+ getSavePoints()->push(kEntityMax, kEntityAnna, kAction156622016);
+ }
+ break;
+
+ case kAction122358304:
+ (savepoint.entity2 == kEntityAnna) ? (params->param1 = 1) : (params->param2 = 1);
+ getEntities()->exitCompartment(kEntityMax, kObjectCompartmentF, true);
+ getEntities()->drawSequenceLeft(kEntityMax, "BLANK");
+ break;
+
+ case kActionMaxFreeFromCage:
+ getEntities()->exitCompartment(kEntityMax, kObjectCompartmentF, true);
+ setup_chapter4Handler();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Max, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMax);
+
+ getData()->entityPosition = kPosition_8000;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarBaggage;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Max, function17)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ getData()->entityPosition = getEntityData(kEntityCoudert)->entityPosition;
+ getData()->car = getEntityData(kEntityCoudert)->car;
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4070;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->drawSequenceLeft(kEntityMax, "630Af");
+ getSavePoints()->push(kEntityMax, kEntityCoudert, kAction157026693);
+ break;
+
+ case kAction122358304:
+ params->param1 = 1;
+ getEntities()->exitCompartment(kEntityMax, kObjectCompartmentF, true);
+ getEntities()->drawSequenceLeft(kEntityMax, "BLANK");
+ break;
+
+ case kActionMaxFreeFromCage:
+ getEntities()->exitCompartment(kEntityMax, kObjectCompartmentF, true);
+ setup_chapter4Handler();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Max, chapter5)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityMax);
+
+ getData()->entityPosition = kPositionNone;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarNone;
+
+ getObjects()->update(kObjectCageMax, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/max.h b/engines/lastexpress/entities/max.h
new file mode 100644
index 0000000000..93eb165a0f
--- /dev/null
+++ b/engines/lastexpress/entities/max.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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_MAX_H
+#define LASTEXPRESS_MAX_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Max : public Entity {
+public:
+ Max(LastExpressEngine *engine);
+ ~Max() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Draws the entity
+ *
+ * @param savepoint The savepoint
+ * - The sequence to draw
+ */
+ DECLARE_FUNCTION_NOSETUP(draw)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Handle Chapter 1 & 2 events
+ */
+ DECLARE_FUNCTION(chapter12_handler)
+
+ DECLARE_FUNCTION(function7)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function9)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(freeFromCage)
+ DECLARE_FUNCTION(function15)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ DECLARE_FUNCTION(function17)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_MAX_H
diff --git a/engines/lastexpress/entities/mertens.cpp b/engines/lastexpress/entities/mertens.cpp
new file mode 100644
index 0000000000..d204c204f1
--- /dev/null
+++ b/engines/lastexpress/entities/mertens.cpp
@@ -0,0 +1,4113 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/mertens.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/state.h"
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+#define SAVEGAME_BLOOD_JACKET() \
+ if (getProgress().jacket == kJacketBlood \
+ && getEntities()->isDistanceBetweenEntities(kEntityMertens, kEntityPlayer, 1000) \
+ && !getEntities()->isInsideCompartments(kEntityPlayer) \
+ && !getEntities()->checkFields10(kEntityPlayer)) { \
+ setCallback(1); \
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket); \
+ }
+
+Mertens::Mertens(LastExpressEngine *engine) : Entity(engine, kEntityMertens) {
+ ADD_CALLBACK_FUNCTION(Mertens, reset);
+ ADD_CALLBACK_FUNCTION(Mertens, bloodJacket);
+ ADD_CALLBACK_FUNCTION(Mertens, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Mertens, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Mertens, enterExitCompartment3);
+ ADD_CALLBACK_FUNCTION(Mertens, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Mertens, playSound);
+ ADD_CALLBACK_FUNCTION(Mertens, playSound16);
+ ADD_CALLBACK_FUNCTION(Mertens, savegame);
+ ADD_CALLBACK_FUNCTION(Mertens, updateEntity);
+ ADD_CALLBACK_FUNCTION(Mertens, function11);
+ ADD_CALLBACK_FUNCTION(Mertens, bonsoir);
+ ADD_CALLBACK_FUNCTION(Mertens, function13);
+ ADD_CALLBACK_FUNCTION(Mertens, function14);
+ ADD_CALLBACK_FUNCTION(Mertens, function15);
+ ADD_CALLBACK_FUNCTION(Mertens, function16);
+ ADD_CALLBACK_FUNCTION(Mertens, function17);
+ ADD_CALLBACK_FUNCTION(Mertens, function18);
+ ADD_CALLBACK_FUNCTION(Mertens, function19);
+ ADD_CALLBACK_FUNCTION(Mertens, function20);
+ ADD_CALLBACK_FUNCTION(Mertens, function21);
+ ADD_CALLBACK_FUNCTION(Mertens, function22);
+ ADD_CALLBACK_FUNCTION(Mertens, function23);
+ ADD_CALLBACK_FUNCTION(Mertens, function24);
+ ADD_CALLBACK_FUNCTION(Mertens, function25);
+ ADD_CALLBACK_FUNCTION(Mertens, function26);
+ ADD_CALLBACK_FUNCTION(Mertens, tylerCompartment);
+ ADD_CALLBACK_FUNCTION(Mertens, function28);
+ ADD_CALLBACK_FUNCTION(Mertens, function29);
+ ADD_CALLBACK_FUNCTION(Mertens, function30);
+ ADD_CALLBACK_FUNCTION(Mertens, function31);
+ ADD_CALLBACK_FUNCTION(Mertens, function32);
+ ADD_CALLBACK_FUNCTION(Mertens, function33);
+ ADD_CALLBACK_FUNCTION(Mertens, chapter1);
+ ADD_CALLBACK_FUNCTION(Mertens, function35);
+ ADD_CALLBACK_FUNCTION(Mertens, function36);
+ ADD_CALLBACK_FUNCTION(Mertens, function37);
+ ADD_CALLBACK_FUNCTION(Mertens, function38);
+ ADD_CALLBACK_FUNCTION(Mertens, function39);
+ ADD_CALLBACK_FUNCTION(Mertens, function40);
+ ADD_CALLBACK_FUNCTION(Mertens, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Mertens, function42);
+ ADD_CALLBACK_FUNCTION(Mertens, chapter2);
+ ADD_CALLBACK_FUNCTION(Mertens, function44);
+ ADD_CALLBACK_FUNCTION(Mertens, chapter3);
+ ADD_CALLBACK_FUNCTION(Mertens, function46);
+ ADD_CALLBACK_FUNCTION(Mertens, chapter4);
+ ADD_CALLBACK_FUNCTION(Mertens, function48);
+ ADD_CALLBACK_FUNCTION(Mertens, function49);
+ ADD_CALLBACK_FUNCTION(Mertens, chapter5);
+ ADD_CALLBACK_FUNCTION(Mertens, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Mertens, function52);
+ ADD_CALLBACK_FUNCTION(Mertens, function53);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Mertens, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Mertens, bloodJacket)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityMertens, (char *)&params->seq1);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(3, Mertens, enterExitCompartment, ObjectIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ return;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ return;
+ }
+
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(4, Mertens, enterExitCompartment2, ObjectIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ return;
+
+ case kAction4:
+ getEntities()->exitCompartment(kEntityMertens, (ObjectIndex)params->param4);
+ CALLBACK_ACTION();
+ return;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ return;
+ }
+
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIII(5, Mertens, enterExitCompartment3, ObjectIndex, EntityPosition, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->exitCompartment(_entityIndex, (ObjectIndex)params->param4);
+ getData()->entityPosition = (EntityPosition)params->param5;
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(_entityIndex, (char *)&params->seq);
+ getEntities()->enterCompartment(_entityIndex, (ObjectIndex)params->param4);
+ getData()->entityPosition = (EntityPosition)params->param5;
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, (EntityPosition)params->param5) || getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, (EntityPosition)params->param6)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject((ObjectIndex)params->param4);
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Mertens, callbackActionOnDirection)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getData()->direction != kDirectionRight) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(7, Mertens, playSound)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionEndSound:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityMertens, (char *)&params->seq1);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(8, Mertens, playSound16)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionEndSound:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityMertens, (char *)&params->seq1, SoundManager::kFlagDefault);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(9, Mertens, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition)
+
+#define LOADSCENE_FROM_POSITION() \
+ if (getData()->direction != kDirectionUp) { \
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750)); \
+ } else { \
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition - 750), true); \
+ }
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param3 && getEntities()->isDistanceBetweenEntities(kEntityMertens, kEntityPlayer, 2000))
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem | kItemInvalid);
+ else
+ getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem & kItemToggleHigh);
+
+ if (!getEntities()->isDistanceBetweenEntities(kEntityMertens, kEntityPlayer, 1000)
+ || getEntities()->isInsideCompartments(kEntityPlayer)
+ || getEntities()->checkFields10(kEntityPlayer)) {
+ if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ getData()->inventoryItem = kItemNone;
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+
+ if (getProgress().jacket == kJacketBlood) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
+ break;
+ }
+
+ if ((ENTITY_PARAM(0, 6) || ENTITY_PARAM(0, 7)) && (!getEvent(kEventKronosConversation) && getProgress().jacket == kJacketGreen)) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventMertensKronosInvitation);
+ break;
+ }
+
+ if (ENTITY_PARAM(1, 2) && getProgress().jacket == kJacketGreen && !getProgress().eventMetAugust) {
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventMertensAugustWaiting);
+ break;
+ }
+
+ if (ENTITY_PARAM(2, 4) && getState()->time < kTime2133000) {
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventMertensKronosConcertInvitation);
+ break;
+ }
+
+ if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ getData()->inventoryItem = kItemNone;
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kAction1:
+ params->param3 = 0;
+ if (getProgress().eventCorpseFound || getEvent(kEventMertensAskTylerCompartment) || getEvent(kEventMertensAskTylerCompartmentD)) {
+ if (ENTITY_PARAM(0, 4) && getProgress().jacket == kJacketGreen && !getEvent(kEventMertensDontMakeBed) && !getProgress().eventCorpseThrown) {
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventMertensDontMakeBed);
+ }
+ } else {
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventMertensAskTylerCompartment);
+ }
+ break;
+
+ case kActionExcuseMeCath:
+ getSound()->playSound(kEntityMertens, "CON1110B");
+ break;
+
+ case kActionExcuseMe:
+ getSound()->excuseMe(kEntityMertens);
+ break;
+
+ case kActionDefault:
+ if ((!getProgress().eventCorpseFound && !getEvent(kEventMertensAskTylerCompartment) && !getEvent(kEventMertensAskTylerCompartment))
+ || (ENTITY_PARAM(0, 4) && getProgress().jacket == kJacketGreen && !getEvent(kEventMertensDontMakeBed) && !getProgress().eventCorpseThrown))
+ params->param3 = 1;
+
+ if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ break;
+
+ case 2:
+ getAction()->playAnimation(getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition ? kEventMertensKronosInvitation : kEventMertensKronosInvitationClosedWindows);
+ getProgress().eventMertensKronosInvitation = true;
+
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+
+ if (params->param1 != 3 || (params->param2 != kPosition_8200 && params->param2 != kPosition_9510)) {
+ LOADSCENE_FROM_POSITION();
+ break;
+ }
+
+ getData()->inventoryItem = kItemNone;
+
+ if (getData()->car == kCarGreenSleeping && getEntities()->checkDistanceFromPosition(kEntityMertens, kPosition_2000, 500))
+ getData()->entityPosition = kPosition_2500;
+
+ getEntities()->updateEntity(kEntityMertens, kCarGreenSleeping, kPosition_2000);
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750));
+
+ CALLBACK_ACTION();
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventMertensAugustWaiting);
+ getProgress().eventMertensAugustWaiting = true;
+
+ ENTITY_PARAM(1, 2) = 0;
+
+ if (params->param1 == 3 && params->param2 == kPosition_8200) {
+ if (getData()->car == kCarGreenSleeping && getEntities()->checkDistanceFromPosition(kEntityMertens, kPosition_2000, 500))
+ getData()->entityPosition = kPosition_2500;
+
+ getEntities()->updateEntity(kEntityMertens, kCarGreenSleeping, kPosition_2000);
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750));
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ LOADSCENE_FROM_POSITION();
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventMertensKronosConcertInvitation);
+ ENTITY_PARAM(2, 4) = 0;
+
+ LOADSCENE_FROM_POSITION();
+ break;
+
+ case 5:
+ getAction()->playAnimation(getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition ? kEventMertensAskTylerCompartmentD : kEventMertensAskTylerCompartment);
+ LOADSCENE_FROM_POSITION();
+ break;
+
+ case 6:
+ getAction()->playAnimation(kEventMertensDontMakeBed);
+ LOADSCENE_FROM_POSITION();
+ ENTITY_PARAM(0, 4) = 0;
+ break;
+ }
+ break;
+ }
+
+#undef LOADSCENE_FROM_POSITION
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(11, Mertens, function11, uint32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+
+ UPDATE_PARAM(params->param2, getState()->time, params->param1)
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(12, Mertens, bonsoir, EntityIndex)
+ EntityIndex entity = (EntityIndex)params->param1;
+
+ if (savepoint.action == kActionDefault)
+ return;
+
+ if (getSound()->isBuffered(kEntityMertens)) {
+ CALLBACK_ACTION();
+ return;
+ }
+
+ if (isNight()) {
+ if (Entities::isFemale(entity)) {
+ getSound()->playSound(kEntityMertens, rnd(2) ? "CON1112" : "CON1112A");
+ } else {
+ if (entity || getProgress().field_18 != 2) {
+ getSound()->playSound(kEntityMertens, "CON1112F");
+ } else {
+ switch (rnd(3)) {
+ default:
+ case 0:
+ getSound()->playSound(kEntityMertens, "CON1061");
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityMertens, "CON1110G");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityMertens, "CON1110H");
+ break;
+ }
+ }
+ }
+ } else {
+ if (Entities::isFemale(entity))
+ getSound()->playSound(kEntityMertens, rnd(2) ? "CON1112B" : "CON1112C");
+ else
+ getSound()->playSound(kEntityMertens, "CON1112G");
+ }
+
+ CALLBACK_ACTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(13, Mertens, function13, bool, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+
+ if (!params->param2 && !params->param3) {
+ UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, 75)
+ getData()->inventoryItem = kItemNone;
+ setCallback(5);
+ setup_function18();
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+ UPDATE_PARAM_PROC(params->param5, getState()->timeTicks, 225)
+ getData()->inventoryItem = kItemNone;
+ setCallback(6);
+ setup_function18();
+ break;
+ UPDATE_PARAM_PROC_END
+
+ getData()->inventoryItem = (getProgress().chapter == kChapter1
+ && !ENTITY_PARAM(2, 1)
+ && !getProgress().eventCorpseFound
+ && !getEvent(kEventMertensAskTylerCompartment)
+ && !getEvent(kEventMertensAskTylerCompartmentD)) ? kItemMatchBox : kItemNone;
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ setCallback(7);
+ setup_savegame(kSavegameTypeEvent, kEventMertensAskTylerCompartmentD);
+ break;
+
+ case kAction11:
+ params->param3++;
+ setCallback(11);
+ setup_bonsoir(savepoint.entity2);
+ break;
+
+ case kActionDefault:
+ if (params->param2)
+ params->param3 = 1;
+
+ if (!getSound()->isBuffered(kEntityMertens)) {
+
+ }
+
+ setCallback(3);
+ setup_function20();
+ break;
+
+ case kAction16:
+ params->param3--;
+
+ if (params->param2 && !params->param3) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(10);
+ setup_function18();
+ }
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 23) && ENTITY_PARAM(0, 7) && !getEvent(kEventKronosConversation)) {
+ setCallback(8);
+ setup_savegame(kSavegameTypeEvent, kEventMertensKronosInvitation);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_function20();
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntityMertens, params->param1 ? "601I" : "601H");
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ break;
+
+ case 5:
+ case 6:
+ case 9:
+ case 10:
+ CALLBACK_ACTION();
+ break;
+
+ case 7:
+ getAction()->playAnimation(kEventMertensAskTylerCompartmentD);
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 25);
+ break;
+
+ case 8:
+ getAction()->playAnimation(kEventMertensKronosInvitation);
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+ getScenes()->processScene();
+
+ if (!params->param3) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(10);
+ setup_function18();
+ }
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(14, Mertens, function14, EntityIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ SAVEGAME_BLOOD_JACKET();
+ break;
+
+ case kActionDefault:
+ getData()->inventoryItem = kItemNone;
+
+ if (ENTITY_PARAM(2, 1)) {
+ ENTITY_PARAM(2, 1) = 0;
+
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_1500);
+ } else {
+ setCallback(1);
+ setup_function11(15);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityMertens, (EntityIndex)params->param1, kAction202558662);
+
+ setCallback(2);
+ setup_function20();
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityMertens, (EntityIndex)params->param1, kAction155853632);
+ getEntities()->drawSequenceLeft(kEntityMertens, "601K");
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityMertens, (EntityIndex)params->param1, kAction202558662);
+ getSavePoints()->push(kEntityMertens, (EntityIndex)params->param1, kAction155853632);
+ getEntities()->drawSequenceLeft(kEntityMertens, "601K");
+ getScenes()->loadSceneFromItemPosition(kItem7);
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction125499160:
+ if (params->param1 == kEntityVerges)
+ ENTITY_PARAM(0, 8) = 0;
+
+ setCallback(5);
+ setup_function18();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(15, Mertens, function15, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ ENTITY_PARAM(1, 4) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityMertens, params->param1 ? "CON1059A" : "CON1059");
+
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_7500);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment("601Xb", kObjectCompartment2);
+ break;
+
+ case 4:
+ getSavePoints()->push(kEntityMertens, kEntityAlexei, kAction135664192);
+
+ setCallback(5);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function17();
+ break;
+
+ case 6:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(16, Mertens, function16, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ switch (rnd(4)) {
+ default:
+ break;
+
+ case 0:
+ getSound()->playSound(kEntityMertens, "AUG2095A");
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityMertens, "AUG2096A");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityMertens, "AUG2094B");
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityMertens, "AUG2094C");
+ break;
+ }
+
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityMertens, params->param1 ? "AUG2097" : "AUG2098");
+
+ setCallback(4);
+ setup_enterExitCompartment("601Xc", kObjectCompartment3);
+ break;
+
+ case 4:
+ getSavePoints()->push(kEntityMertens, kEntityAugust, kAction69239528);
+
+ setCallback(5);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function17();
+ break;
+
+ case 6:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Mertens, function17)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ // FIXME: Check that we are using the correct parameter struct
+ if (ENTITY_PARAM(0, 6) || ((EntityData::EntityParametersIIII*)_data->getParameters(8, 1))->hasNonNullParameter()) {
+ getInventory()->setLocationAndProcess(kItem7, kObjectLocation1);
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 8)) {
+ getEntities()->drawSequenceLeft(kEntityMertens, "601K");
+ getScenes()->loadSceneFromItemPosition(kItem7);
+ ENTITY_PARAM(2, 1) = 1;
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ // Mertens sits on his chair at the back of the train
+ if (!getInventory()->hasItem(kItemPassengerList) || ENTITY_PARAM(0, 2)) {
+ getEntities()->drawSequenceRight(kEntityMertens, "601A");
+ } else {
+ // Got the passenger list, Mertens is looking for it before sitting
+ ENTITY_PARAM(0, 2) = 1;
+ getSound()->playSound(kEntityMertens, "CON1058", SoundManager::kFlagInvalid, 75);
+ getEntities()->drawSequenceRight(kEntityMertens, "601D");
+ }
+
+ getScenes()->loadSceneFromItemPosition(kItem7);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 68)) {
+ getSound()->playSound(kEntityPlayer, "CON1110");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 25);
+ }
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityMertens);
+ ENTITY_PARAM(2, 1) = 1;
+ setCallback(2);
+ setup_function11(75);
+ break;
+
+ case 2:
+ CALLBACK_ACTION();
+ break;
+
+ case 3:
+ if (!ENTITY_PARAM(0, 3)
+ && !getInventory()->hasItem(kItemPassengerList)
+ && ENTITY_PARAM(0, 2)) {
+ getSavePoints()->push(kEntityMertens, kEntityVerges, kAction158617345);
+ ENTITY_PARAM(0, 3) = 1;
+ }
+
+ getEntities()->drawSequenceLeft(kEntityMertens, "601B");
+
+ ENTITY_PARAM(0, 1) = 0;
+ getData()->inventoryItem = kItemNone;
+
+ getSavePoints()->push(kEntityMertens, kEntityMertens, kActionDrawScene);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Mertens, function18)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (ENTITY_PARAM(0, 6)
+ || ENTITY_PARAM(1, 1)
+ || ENTITY_PARAM(1, 2)
+ || ENTITY_PARAM(1, 3)
+ || ENTITY_PARAM(1, 4)
+ || ENTITY_PARAM(1, 5)
+ || ENTITY_PARAM(1, 6)
+ || ENTITY_PARAM(1, 7)
+ || ENTITY_PARAM(1, 8)) {
+ getInventory()->setLocationAndProcess(kItem7, kObjectLocation1);
+ ENTITY_PARAM(2, 1) = 1;
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 8)) {
+ getScenes()->loadSceneFromItemPosition(kItem7);
+ ENTITY_PARAM(2, 1) = 1;
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (!getInventory()->hasItem(kItemPassengerList) || ENTITY_PARAM(0, 2)) {
+ getEntities()->drawSequenceRight(kEntityMertens, "601A");
+ } else {
+ ENTITY_PARAM(0, 2) = 1;
+ getSound()->playSound(kEntityMertens, "CON1058", SoundManager::kFlagInvalid, 75);
+ getEntities()->drawSequenceRight(kEntityMertens, "601D");
+ }
+
+ getScenes()->loadSceneFromItemPosition(kItem7);
+
+ setCallback(1);
+ setup_callbackActionOnDirection();
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (!ENTITY_PARAM(0, 3)
+ && !getInventory()->hasItem(kItemPassengerList)
+ && ENTITY_PARAM(0, 2)) {
+ getSavePoints()->push(kEntityMertens, kEntityVerges, kAction158617345);
+ ENTITY_PARAM(0, 3) = 1;
+ }
+
+ getEntities()->drawSequenceLeft(kEntityMertens, "601B");
+ ENTITY_PARAM(0, 1) = 0;
+ getData()->inventoryItem = kItemNone;
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Mertens, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (ENTITY_PARAM(2, 1)) {
+ getInventory()->setLocationAndProcess(kItem7, kObjectLocation1);
+ ENTITY_PARAM(2, 1) = 0;
+ CALLBACK_ACTION();
+ } else {
+ setCallback(1);
+ setup_bloodJacket("601C");
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getInventory()->setLocationAndProcess(kItem7, kObjectLocation1);
+
+ if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2))
+ getData()->entityPosition = kPosition_2088;
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Mertens, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getScenes()->loadSceneFromItemPosition(kItem7);
+
+ if (ENTITY_PARAM(2, 1)) {
+ ENTITY_PARAM(2, 1) = 0;
+
+ CALLBACK_ACTION();
+ } else {
+ setCallback(1);
+ setup_bloodJacket("601C");
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(21, Mertens, function21, ObjectIndex, ObjectIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_PROC(CURRENT_PARAM(1, 4), getState()->time, 300)
+ getSound()->playSound(kEntityPlayer, "ZFX1004", getSound()->getSoundFlag(kEntityMertens));
+ UPDATE_PARAM_PROC_END
+
+ UPDATE_PARAM(CURRENT_PARAM(1, 5), getState()->time, 900);
+
+ // Update objects
+ getObjects()->updateLocation2((ObjectIndex)params->param1, kObjectLocation1);
+ if (params->param5 != kObjectLocation2)
+ getObjects()->update((ObjectIndex)params->param1, (EntityIndex)params->param4, (ObjectLocation)params->param5, (CursorStyle)params->param6, (CursorStyle)params->param7);
+
+ if (params->param2)
+ getObjects()->update((ObjectIndex)params->param2, (EntityIndex)params->param8, (ObjectLocation)CURRENT_PARAM(1, 1), (CursorStyle)CURRENT_PARAM(1, 2), (CursorStyle)CURRENT_PARAM(1, 3));
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update((ObjectIndex)params->param1, kEntityMertens, kObjectLocation1, kCursorNormal, kCursorNormal);
+ if (params->param2)
+ getObjects()->update((ObjectIndex)params->param2, kEntityMertens, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ params->param3 = 1;
+ params->param4 = getObjects()->get((ObjectIndex)params->param1).entity;
+ params->param5 = getObjects()->get((ObjectIndex)params->param1).location;
+ params->param6 = getObjects()->get((ObjectIndex)params->param1).cursor;
+ params->param7 = getObjects()->get((ObjectIndex)params->param1).cursor2;
+
+ if (params->param2) {
+ params->param8 = getObjects()->get((ObjectIndex)params->param2).entity;
+ CURRENT_PARAM(1, 1) = getObjects()->get((ObjectIndex)params->param2).location;
+ CURRENT_PARAM(1, 2) = getObjects()->get((ObjectIndex)params->param2).cursor;
+ CURRENT_PARAM(1, 3) = getObjects()->get((ObjectIndex)params->param2).cursor2;
+
+ getObjects()->update((ObjectIndex)params->param2, kEntityMertens, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+
+ if (params->param5 != kObjectLocation2)
+ getObjects()->update((ObjectIndex)params->param1, kEntityMertens, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(params->param3 ? 3 : 4);
+ setup_playSound(params->param3 ? "Con1017" : "Con1017A");
+ break;
+
+ case 3:
+ case 4:
+ params->param3 = 0;
+ getObjects()->update((ObjectIndex)params->param1, kEntityMertens, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ if (params->param2)
+ getObjects()->update((ObjectIndex)params->param2, kEntityMertens, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Mertens, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2740);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("601Mh", kObjectCompartment8);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601Nh");
+ getEntities()->enterCompartment(kEntityMertens, kObjectCompartment8, true);
+
+ setCallback(3);
+ setup_function11(150);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment("601Mh", kObjectCompartment8);
+ break;
+
+ case 4:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601Nh");
+ getEntities()->enterCompartment(kEntityMertens, kObjectCompartment8);
+ getSavePoints()->push(kEntityMertens, kEntityMahmud, kAction225563840);
+ break;
+
+ case 5:
+ if (!getSound()->isBuffered(kEntityMertens))
+ getSound()->playSound(kEntityMertens, "MAH1170I");
+
+ setCallback(6);
+ setup_enterExitCompartment("601Zd", kObjectCompartment4);
+ break;
+
+ case 6:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+ if (!getSound()->isBuffered(kEntityMertens))
+ getSound()->playSound(kEntityMertens, "MAH1172", SoundManager::kFlagInvalid, 225);
+
+ setCallback(7);
+ setup_function21(kObjectCompartment4, kObject20);
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_enterExitCompartment("671Ad", kObjectCompartment4);
+ break;
+
+ case 8:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityMertens, kEntityMahmud, kAction123852928);
+
+ setCallback(9);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+
+ break;
+
+ case 9:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction102227384:
+ getEntities()->drawSequenceLeft(kEntityMertens, "671Dh");
+ break;
+
+ case kAction156567128:
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment8, true);
+
+ setCallback(5);
+ setup_updateEntity(kCarGreenSleeping, kPosition_5790);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Mertens, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_5790);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("601Vd", kObjectCompartment4);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601Wd");
+ getEntities()->enterCompartment(kEntityMertens, kObjectCompartment4, true);
+
+ setCallback(3);
+ setup_function11(150);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment("601Zd", kObjectCompartment4);
+ break;
+
+ case 4:
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment4);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+
+ setCallback(5);
+ setup_function21(kObjectCompartment4, kObject20);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_enterExitCompartment("671Ad", kObjectCompartment4);
+ break;
+
+ case 6:
+ getData()->location = kLocationOutsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Mertens, function24)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+
+ setCallback(3);
+ setup_enterExitCompartment3("601Rc", kObjectCompartment3, kPosition_6470, kPosition_6130);
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_6470);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("601Mc", kObjectCompartment3);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityMertens, kEntityAugust, kAction221617184);
+ getEntities()->drawSequenceLeft(kEntityMertens, "601Nc");
+ getEntities()->enterCompartment(kEntityMertens, kObjectCompartment3, true);
+ break;
+
+ case 3:
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment3, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+
+ setCallback(4);
+ setup_function21(kObjectCompartment3, kObjectKitchen);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("601Sc", kObjectCompartment3);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment3, true);
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+
+ setCallback(7);
+ setup_function21(kObjectCompartment3, kObjectKitchen);
+ break;
+
+ case 7:
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(8);
+ setup_enterExitCompartment("601Uc", kObjectCompartment3);
+ break;
+
+ case 8:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityMertens, kEntityAugust, kAction124697504);
+
+ setCallback(9);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+ break;
+
+ case 9:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction100906246:
+ getSavePoints()->push(kEntityMertens, kEntityAugust, kAction192849856);
+ getEntities()->drawSequenceLeft(kEntityMertens, "601Qc");
+ break;
+
+ case kAction102675536:
+ params->param1 = 1;
+ break;
+
+ case kAction156567128:
+ setCallback(6);
+ setup_enterExitCompartment("601Tc", kObjectCompartment3);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Mertens, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+
+ setCallback(3);
+ setup_enterExitCompartment3("601Zb", kObjectCompartment2, kPosition_7500, kPositionNone);
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_7500);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("601Vb", kObjectCompartment2);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityMertens, kEntityAlexei, kAction221617184);
+ getEntities()->drawSequenceLeft(kEntityMertens, "601Wb");
+ getEntities()->enterCompartment(kEntityMertens, kObjectCompartment2, true);
+ break;
+
+ case 3:
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment2, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+
+ if (getProgress().chapter == kChapter1 && ENTITY_PARAM(0, 4))
+ if (getProgress().field_14 != 29)
+ getProgress().field_14 = 3;
+
+ setCallback(4);
+ setup_function21(kObjectCompartment2, kObjectHandleInsideBathroom);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("671Ab", kObjectCompartment2);
+ break;
+
+ case 5:
+ getData()->location = kLocationOutsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment2, true);
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+
+ if (getProgress().chapter == kChapter1 && ENTITY_PARAM(0, 4))
+ if (getProgress().field_14 != 29)
+ getProgress().field_14 = 3;
+
+ setCallback(7);
+ setup_function21(kObjectCompartment2, kObjectHandleInsideBathroom);
+ break;
+
+ case 7:
+ getSound()->playSound(kEntityMertens, "CON1024A");
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(8);
+ setup_enterExitCompartment("641Ub", kObjectCompartment2);
+ break;
+
+ case 8:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityMertens, kEntityAlexei, kAction124697504);
+
+ setCallback(9);
+ setup_updateEntity(kCarGreenSleeping, kPosition_9460);
+ break;
+
+ case 9:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction100906246:
+ params->param1 = 1;
+ break;
+
+ case kAction156567128:
+ setCallback(6);
+ setup_enterExitCompartment("641Tb", kObjectCompartment2);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(26, Mertens, function26, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getProgress().eventCorpseThrown
+ || !params->param1
+ || getProgress().chapter != kChapter1
+ || getProgress().jacket != kJacketGreen) {
+
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ setCallback(3);
+ setup_playSound16("ZNU1001");
+ } else {
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ setCallback(2);
+ setup_playSound16("CON1062");
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 3:
+ if (getProgress().jacket == kJacketBlood) {
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
+ } else if (getProgress().eventCorpseMovedFromFloor) {
+ getEntities()->enterCompartment(kEntityMertens, kObjectCompartment1);
+ getEntities()->drawSequenceRight(kEntityMertens, "601Ra");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 16);
+
+ setCallback(6);
+ setup_callbackActionOnDirection();
+ } else {
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventMertensCorpseFloor);
+ }
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ break;
+
+ case 5:
+ getAction()->playAnimation(kEventMertensCorpseFloor);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, getProgress().eventCorpseFound ? kSceneGameOverStopPolice : kSceneGameOverPolice, true);
+ break;
+
+ case 6:
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment1);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+
+ setCallback(7);
+ setup_function21(kObjectCompartment1, kObjectHandleBathroom);
+ break;
+
+ case 7:
+ if (getProgress().eventCorpseThrown || getProgress().chapter != kChapter1) {
+ if (getEntities()->isDistanceBetweenEntities(kEntityMertens, kEntityPlayer, 1000)) {
+ if (!getEntities()->checkFields10(kEntityPlayer))
+ getSound()->playSound(kEntityMertens, "CON1061");
+ }
+
+ setCallback(9);
+ setup_enterExitCompartment("601Sa", kObjectCompartment1);
+ } else {
+ if (!getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping))
+ getScenes()->loadSceneFromPosition(kCarNone, 1);
+
+ setCallback(8);
+ setup_savegame(kSavegameTypeEvent, kEventMertensCorpseBed);
+ }
+ break;
+
+ case 8:
+ getAction()->playAnimation(kEventMertensCorpseBed);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
+ break;
+
+ case 9:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(27, Mertens, tylerCompartment, MertensActionType)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().field_14 == 29) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ UPDATE_PARAM_PROC(params->param2, getState()->timeTicks, 150)
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ setCallback(10);
+ setup_playSound16("CON1018A");
+ break;
+ UPDATE_PARAM_PROC_END
+
+label_callback10:
+ if (!params->param3)
+ params->param3 = getState()->timeTicks + 300;
+
+ if (params->param3 >= getState()->timeTicks) {
+label_callback11:
+ UPDATE_PARAM(params->param4, getState()->timeTicks, 375);
+
+ getSound()->playSound(kEntityPlayer, "LIB033");
+
+ if (getProgress().eventCorpseMovedFromFloor) {
+
+ if (getProgress().jacket == kJacketBlood) {
+ setCallback(18);
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
+ break;
+ }
+
+ if (params->param1) {
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ switch (params->param1) {
+ case 1:
+ setCallback(20);
+ setup_savegame(kSavegameTypeEvent, kEventMertensAugustWaitingCompartment);
+ break;
+
+ case 2:
+ setCallback(21);
+ setup_savegame(kSavegameTypeEvent, kEventMertensKronosInvitationCompartment);
+ break;
+
+ case 3:
+ getAction()->playAnimation(isNight() ? kEventMertensPushCallNight : kEventMertensPushCall);
+ // fallback to default case
+
+ default:
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadScene(kScene41);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ } else {
+ setCallback(26);
+ setup_function26(false);
+ }
+
+ } else {
+ if (!getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping))
+ getScenes()->loadSceneFromPosition(kCarNone, 1);
+
+ setCallback(17);
+ setup_savegame(kSavegameTypeEvent, kEventMertensCorpseFloor);
+ }
+ } else {
+ params->param3 = kTimeInvalid;
+
+ if (getObjects()->get(kObjectCompartment1).location == kObjectLocation1) {
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(11);
+ setup_playSound16("CON1018B");
+ break;
+ }
+
+ getSound()->playSound(kEntityPlayer, "LIB014");
+
+ if (getProgress().eventCorpseMovedFromFloor) {
+
+ if (getProgress().jacket == kJacketBlood) {
+ setCallback(13);
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
+ break;
+ }
+
+ if (params->param1) {
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ switch (params->param1) {
+ case 1:
+ setCallback(15);
+ setup_savegame(kSavegameTypeEvent, kEventMertensAugustWaitingCompartment);
+ break;
+
+ case 2:
+ setCallback(16);
+ setup_savegame(kSavegameTypeEvent, kEventMertensKronosInvitationCompartment);
+ break;
+
+ case 3:
+ getAction()->playAnimation(isNight() ? kEventMertensPushCallNight : kEventMertensPushCall);
+ // fallback to default case
+
+ default:
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadScene(kScene41);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ } else {
+ setCallback(14);
+ setup_function26(false);
+ }
+ } else {
+ if (!getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping))
+ getScenes()->loadSceneFromPosition(kCarNone, 1);
+
+ setCallback(12);
+ setup_savegame(kSavegameTypeEvent, kEventMertensCorpseFloor);
+ }
+ }
+ break;
+
+ case kActionKnock:
+ if (params->param1) {
+ getObjects()->update(kObjectCompartment1, kEntityMertens, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ switch (params->param1) {
+ default:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 1:
+ setCallback(23);
+ setup_playSound16("CON1018D");
+ break;
+
+ case 2:
+ setCallback(24);
+ setup_playSound16("CON1018E");
+ break;
+
+ case 3:
+ setCallback(25);
+ setup_playSound16("CON1025");
+ break;
+ }
+
+ } else {
+ setCallback(22);
+ setup_function26(true);
+ }
+ break;
+
+ case kActionOpenDoor:
+ getSound()->playSound(kEntityPlayer, getObjects()->get(kObjectCompartment1).location == kObjectLocation1 ? "LIB012" : "LIB014");
+
+ if (getProgress().eventCorpseMovedFromFloor) {
+
+ if (getProgress().jacket == kJacketBlood) {
+ setCallback(27);
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
+ break;
+ }
+
+ if (params->param1) {
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ switch (params->param1) {
+ case 1:
+ setCallback(29);
+ setup_savegame(kSavegameTypeEvent, kEventMertensAugustWaitingCompartment);
+ break;
+
+ case 2:
+ setCallback(30);
+ setup_savegame(kSavegameTypeEvent, kEventMertensKronosInvitationCompartment);
+ break;
+
+ case 3:
+ getAction()->playAnimation(isNight() ? kEventMertensPushCallNight : kEventMertensPushCall);
+ // fallback to default case
+
+ default:
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadScene(kScene41);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ } else {
+ setCallback(28);
+ setup_function26(false);
+ }
+ } else {
+ if (!getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping))
+ getScenes()->loadSceneFromPosition(kCarNone, 1);
+
+ setCallback(26);
+ setup_savegame(kSavegameTypeEvent, kEventMertensCorpseFloor);
+ }
+ break;
+
+ case kActionDefault:
+ getData()->inventoryItem = kItemNone;
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_8200)
+ || getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_7850)
+ || getEntities()->isOutsideAlexeiWindow()) {
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ if (getEntities()->isOutsideAlexeiWindow())
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ setCallback(params->param1 ? 9 : 8);
+ setup_playSound16(params->param1 ? "CON1018" : "CON1060");
+ } else {
+ getSound()->playSound(kEntityMertens, "CON1019");
+
+ setCallback(1);
+ setup_enterExitCompartment("601Ma", kObjectCompartment1);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getProgress().eventCorpseMovedFromFloor) {
+ setCallback(4);
+ setup_enterExitCompartment("601Ra", kObjectCompartment1);
+ } else {
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
+ setCallback(2);
+ setup_enterExitCompartment("601Ra", kObjectCompartment1);
+ } else {
+ getScenes()->loadSceneFromPosition(kCarNone, 1);
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventMertensCorpseFloor);
+ }
+ }
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventMertensCorpseFloor);
+ break;
+
+ case 3:
+ case 12:
+ case 17:
+ case 26:
+ getAction()->playAnimation(kEventMertensCorpseFloor);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, getProgress().eventCorpseFound ? kSceneGameOverStopPolice : kSceneGameOverPolice, true);
+ break;
+
+ case 4:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMertens);
+
+ if (params->param1) {
+ setCallback(7);
+ setup_enterExitCompartment("601Sa", kObjectCompartment1);
+ break;
+ }
+
+ if (getProgress().eventCorpseThrown || getProgress().chapter != kChapter1) {
+ setCallback(6);
+ setup_function21(kObjectCompartment1, kObjectHandleBathroom);
+ } else {
+ if (!getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping))
+ getScenes()->loadSceneFromPosition(kCarNone, 1);
+
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventMertensCorpseBed);
+ }
+ break;
+
+ case 5:
+ getAction()->playAnimation(kEventMertensCorpseBed);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_enterExitCompartment("601Sa", kObjectCompartment1);
+ break;
+
+ case 7:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 8:
+ case 9:
+ getObjects()->update(kObjectCompartment1, kEntityMertens, getObjects()->get(kObjectCompartment1).location, kCursorTalk, kCursorHand);
+ break;
+
+ case 10:
+ getObjects()->update(kObjectCompartment1, kEntityMertens, getObjects()->get(kObjectCompartment1).location, kCursorTalk, kCursorHand);
+ goto label_callback10;
+
+ case 11:
+ getObjects()->update(kObjectCompartment1, kEntityMertens, getObjects()->get(kObjectCompartment1).location, kCursorTalk, kCursorHand);
+ goto label_callback11;
+
+ case 13:
+ case 18:
+ case 27:
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ break;
+
+ case 14:
+ case 19:
+ case 22:
+ case 28:
+ CALLBACK_ACTION();
+ break;
+
+ case 15:
+ case 20:
+ case 29:
+ getAction()->playAnimation(kEventMertensAugustWaitingCompartment);
+ getProgress().eventMertensAugustWaiting = true;
+
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadScene(kScene41);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 16:
+ case 21:
+ case 30:
+ getAction()->playAnimation(kEventMertensKronosInvitationCompartment);
+ getProgress().eventMertensKronosInvitation = true;
+
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadScene(kScene41);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 23:
+ getProgress().eventMertensAugustWaiting = true;
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 24:
+ getProgress().eventMertensKronosInvitation = true;
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 25:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(28, Mertens, function28)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param4 && params->param5) {
+ getSavePoints()->push(kEntityMertens, kEntityCoudert, kAction125499160);
+
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ }
+ break;
+
+ case kActionEndSound:
+ params->param4 = 1;
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_1500);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601O");
+ getSavePoints()->push(kEntityMertens, kEntityCoudert, kAction154005632);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function17();
+ break;
+
+ case 4:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction155853632:
+ params->param5 = 1;
+ break;
+
+ case kAction202558662:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601L");
+ getSound()->playSound(kEntityMertens, (char *)&params->seq1);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SS(29, Mertens, function29)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param7 > 1 && params->param8) {
+ getSavePoints()->push(kEntityMertens, kEntityCoudert, kAction125499160);
+
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ }
+ break;
+
+ case kActionEndSound:
+ params->param7++;
+ if (params->param7 == 1)
+ getSound()->playSound(kEntityMertens, (char *)&params->seq2);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_1500);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601O");
+ getSavePoints()->push(kEntityMertens, kEntityCoudert, kAction154005632);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function17();
+ break;
+
+ case 4:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction155853632:
+ params->param8 = 1;
+ break;
+
+ case kAction202558662:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601L");
+ getSound()->playSound(kEntityMertens, (char *)&params->seq1);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(30, Mertens, function30, MertensActionType)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ switch (params->param1) {
+ default:
+ CALLBACK_ACTION();
+ return;
+
+ case 1:
+ params->param2 = kPosition_8200;
+
+ if (getProgress().field_14) {
+ CALLBACK_ACTION();
+ return;
+ }
+
+ getProgress().field_14 = 3;
+ break;
+
+ case 2:
+ params->param2 = kPosition_7500;
+ break;
+
+ case 3:
+ params->param2 = kPosition_6470;
+ break;
+ }
+
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, (EntityPosition)params->param2);
+ break;
+
+ case 2:
+ switch (params->param1) {
+ default:
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ setCallback(8);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 1:
+ if (getProgress().chapter == kChapter4)
+ getSavePoints()->push(kEntityMertens, kEntityTatiana, kAction238790488);
+
+ setCallback(3);
+ setup_tylerCompartment(kMertensAction3);
+ break;
+
+ case 2:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_7500)) {
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, getObjects()->get(kObjectCompartment2).location, kCursorNormal, kCursorNormal);
+ params->param3 = 1;
+ }
+
+ setCallback(4);
+ setup_enterExitCompartment("601Vb", kObjectCompartment2);
+ break;
+
+ case 3:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_6470)) {
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, getObjects()->get(kObjectCompartment3).location, kCursorNormal, kCursorNormal);
+ params->param3 = 1;
+ }
+
+ setCallback(6);
+ setup_enterExitCompartment("601Mc", kObjectCompartment3);
+ break;
+ }
+ break;
+
+ case 3:
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ setCallback(8);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 4:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601Wb");
+ getEntities()->enterCompartment(kEntityMertens, kObjectCompartment2, true);
+
+ setCallback(5);
+ setup_playSound("CON3020");
+ break;
+
+ case 5:
+ if (params->param3)
+ getObjects()->update(kObjectCompartment2, kEntityPlayer, getObjects()->get(kObjectCompartment2).location, kCursorHandKnock, kCursorHand);
+
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment2);
+
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ setCallback(8);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 6:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601Nc");
+ getEntities()->enterCompartment(kEntityMertens, kObjectCompartment3, true);
+
+ setCallback(7);
+ setup_playSound("CON3020");
+ break;
+
+ case 7:
+ if (params->param3)
+ getObjects()->update(kObjectCompartment3, kEntityPlayer, getObjects()->get(kObjectCompartment3).location, kCursorHandKnock, kCursorHand);
+
+ getEntities()->exitCompartment(kEntityMertens, kObjectCompartment3);
+
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ setCallback(8);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_function17();
+ break;
+
+ case 9:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(31, Mertens, function31, MertensActionType)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ setCallback(3);
+ setup_function17();
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_bloodJacket("601G");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getSound()->isBuffered(kEntityMertens)) {
+ getEntities()->drawSequenceLeft(kEntityMertens, "601J");
+ } else {
+ setCallback(2);
+ setup_function17();
+ }
+ break;
+
+ case 2:
+ case 3:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Mertens, function32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_9510);
+ break;
+
+ case 2:
+ if (getData()->entityPosition >= kPosition_9460) {
+ getEntities()->clearSequences(kEntityMertens);
+ setCallback(3);
+ setup_function11(900);
+ break;
+ }
+ // Fallback to next case
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function17();
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Mertens, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (ENTITY_PARAM(0, 8) || ENTITY_PARAM(0, 6)
+ || ENTITY_PARAM(1, 1) || ENTITY_PARAM(1, 2) || ENTITY_PARAM(1, 3) || ENTITY_PARAM(1, 4) || ENTITY_PARAM(1, 5) || ENTITY_PARAM(1, 6) || ENTITY_PARAM(1, 7)
+ || ENTITY_PARAM(2, 2)) {
+ ENTITY_PARAM(1, 8) = 1;
+
+ setCallback(ENTITY_PARAM(0, 8) ? 1 : 3);
+ setup_updateEntity(kCarGreenSleeping, ENTITY_PARAM(0, 8) ? kPosition_1500 : kPosition_540);
+ } else {
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ ENTITY_PARAM(2, 1) = 1;
+
+ setCallback(2);
+ setup_function14(kEntityVerges);
+ break;
+
+ case 2:
+ ENTITY_PARAM(1, 8) = 0;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityMertens);
+
+ setCallback(4);
+ setup_function11(75);
+ break;
+
+ case 4:
+ if (ENTITY_PARAM(1, 6)) {
+ setCallback(5);
+ setup_function16(true);
+ break;
+ }
+ // Fallback to next case
+
+ case 5:
+ if (ENTITY_PARAM(1, 7)) {
+ setCallback(6);
+ setup_function16(false);
+ break;
+ }
+ // Fallback to next case
+
+ case 6:
+ if (ENTITY_PARAM(1, 5)) {
+ setCallback(7);
+ setup_function15(true);
+ break;
+ }
+ // Fallback to next case
+
+ case 7:
+ if (ENTITY_PARAM(1, 4)) {
+ setCallback(8);
+ setup_function15(false);
+ break;
+ }
+ // Fallback to next case
+
+ case 8:
+ if (ENTITY_PARAM(1, 2)) {
+ setCallback(9);
+ setup_function35();
+ break;
+ }
+ // Fallback to next case
+
+ case 9:
+ if (ENTITY_PARAM(0, 6)) {
+ setCallback(10);
+ setup_function36();
+ break;
+ }
+ // Fallback to next case
+
+ case 10:
+ if (ENTITY_PARAM(1, 3)) {
+ setCallback(11);
+ setup_function40();
+ break;
+ }
+ // Fallback to next case
+
+ case 11:
+ if (ENTITY_PARAM(1, 1)) {
+ setCallback(12);
+ setup_function28("CON1200");
+ break;
+ }
+
+ if (ENTITY_PARAM(2, 2)) {
+ setCallback(13);
+ setup_function37();
+ break;
+ }
+
+ CALLBACK_ACTION();
+ break;
+
+ case 12:
+ getSavePoints()->push(kEntityMertens, kEntityCoudert, kAction168254872);
+ ENTITY_PARAM(1, 1) = 0;
+
+ if (ENTITY_PARAM(2, 2)) {
+ setCallback(13);
+ setup_function37();
+ break;
+ }
+
+ CALLBACK_ACTION();
+ break;
+
+ case 13:
+ ENTITY_PARAM(2, 2) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Mertens, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityMertens, kAction171394341, 7);
+ getSavePoints()->addData(kEntityMertens, kAction169633856, 9);
+ getSavePoints()->addData(kEntityMertens, kAction238732837, 10);
+ getSavePoints()->addData(kEntityMertens, kAction269624833, 12);
+ getSavePoints()->addData(kEntityMertens, kAction302614416, 11);
+ getSavePoints()->addData(kEntityMertens, kAction190082817, 8);
+ getSavePoints()->addData(kEntityMertens, kAction269436673, 13);
+ getSavePoints()->addData(kEntityMertens, kAction303343617, 14);
+ getSavePoints()->addData(kEntityMertens, kAction224122407, 17);
+ getSavePoints()->addData(kEntityMertens, kAction201431954, 18);
+ getSavePoints()->addData(kEntityMertens, kAction188635520, 19);
+ getSavePoints()->addData(kEntityMertens, kAction204379649, 4);
+
+ ENTITY_PARAM(0, 1) = 0;
+
+ getData()->entityPosition = kPosition_9460;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ break;
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Mertens, function35)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getProgress().field_14 == 29) {
+ CALLBACK_ACTION();
+ break;
+ } else {
+ getProgress().field_14 = 3;
+
+ setCallback(1);
+ setup_function19();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 2:
+ if (!ENTITY_PARAM(1, 2) || getProgress().eventMetAugust) {
+ ENTITY_PARAM(1, 2) = 0;
+
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ } else {
+ setCallback(5);
+ setup_tylerCompartment(kMertensAction1);
+ }
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function17();
+ break;
+
+ case 4:
+ CALLBACK_ACTION();
+ break;
+
+ case 5:
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ if (getProgress().eventMertensAugustWaiting)
+ ENTITY_PARAM(1, 2) = 0;
+
+ setCallback(6);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 6:
+ ENTITY_PARAM(1, 2) = 0;
+
+ setCallback(7);
+ setup_function17();
+ break;
+
+ case 7:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Mertens, function36)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getProgress().field_14 == 29) {
+ CALLBACK_ACTION();
+ } else {
+ getProgress().field_14 = 3;
+
+ setCallback(1);
+ setup_function19();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 2:
+ if (ENTITY_PARAM(0, 6)) {
+ if (getEntities()->isPlayerInCar(kCarGreenSleeping) && getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition) {
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_9460);
+ } else {
+ setCallback(7);
+ setup_tylerCompartment(kMertensAction2);
+ }
+ } else {
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ setCallback(5);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ }
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 4:
+ if (ENTITY_PARAM(0, 6)) {
+ setCallback(7);
+ setup_tylerCompartment(kMertensAction2);
+ } else {
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ setCallback(5);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ }
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function17();
+ break;
+
+ case 7:
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ if (!getProgress().eventMertensKronosInvitation)
+ ENTITY_PARAM(0, 7) = 1;
+
+ ENTITY_PARAM(0, 6) = 0;
+
+ setCallback(8);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_function17();
+ break;
+
+ case 6:
+ case 9:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Mertens, function37)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 >= 2 && params->param2) {
+ getSavePoints()->push(kEntityMertens, kEntityCoudert, kAction125499160);
+
+ setCallback(3);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ }
+ break;
+
+ case kActionEndSound:
+ ++params->param6;
+
+ if (params->param6 == 1)
+ getSound()->playSound(kEntityMertens, getEntities()->isDistanceBetweenEntities(kEntityMertens, kEntityPlayer, 2000) ? "CON1152" : "CON1151");
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_1500);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601O");
+ getSavePoints()->push(kEntityMertens, kEntityCoudert, kAction154005632);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function17();
+ break;
+
+ case 4:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction155853632:
+ params->param2 = 1;
+ break;
+
+ case kAction202558662:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601L");
+ getSound()->playSound(kEntityMertens, "CON1150");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Mertens, function38)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (!ENTITY_PARAM(0, 4)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (getProgress().field_14 == 29) {
+ CALLBACK_ACTION();
+ } else {
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (!ENTITY_PARAM(0, 4)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ setCallback(2);
+ setup_tylerCompartment(kMertensActionNone);
+ break;
+
+ case 2:
+ ENTITY_PARAM(0, 4) = 0;
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(39, Mertens, function39)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ ENTITY_PARAM(0, 4) = 1;
+
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function22();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function33();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function24();
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function33();
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function25();
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function33();
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_function38();
+ break;
+
+ case 8:
+ if (getProgress().field_14 == 3)
+ getProgress().field_14 = 0;
+
+ setCallback(9);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_function17();
+ break;
+
+ case 10:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(40, Mertens, function40)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ ENTITY_PARAM(1, 3) = 0;
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarKronos, kPosition_9460);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function11(1800);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_1500);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function17();
+ break;
+
+ case 5:
+ ENTITY_PARAM(0, 6) = 1;
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(41, Mertens, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function17();
+ break;
+
+ case 2:
+ setup_function42();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(42, Mertens, function42)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(2, 3)) {
+ ENTITY_PARAM(0, 1) = 1;
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+
+ ENTITY_PARAM(2, 1) = 0; // BUG: is set twice. Maybe a bug?
+ ENTITY_PARAM(2, 2) = 0;
+ ENTITY_PARAM(2, 3) = 0;
+
+ params->param1 = 1;
+ params->param2 = 1;
+
+ getEntities()->drawSequenceLeft(kEntityMertens, "601E");
+ }
+
+ if (ENTITY_PARAM(2, 1) || getProgress().eventCorpseFound || getEvent(kEventMertensAskTylerCompartmentD) || getEvent(kEventMertensAskTylerCompartment))
+ getData()->inventoryItem = kItemNone;
+ else
+ getData()->inventoryItem = kItemInvalid;
+
+ if (!params->param2) {
+ TIME_CHECK_SAVEPOINT(kTime1125000, params->param3, kEntityMertens, kEntityMahmud, kAction170483072);
+
+ if (params->param4 != kTimeInvalid && getState()->time > kTimeCityChalons) {
+
+ if (getState()->time <= kTime1188000) {
+ if ((!getEntities()->isPlayerInCar(kCarGreenSleeping) && !getEntities()->isPlayerInCar(kCarRedSleeping))
+ || getSound()->isBuffered("REB1205")
+ || !getEntities()->isInsideCompartment(kEntityMmeBoutarel, kCarRedSleeping, kPosition_5790)
+ || !params->param4) {
+ params->param4 = (uint)getState()->time;
+ }
+
+ if (params->param4 >= getState()->time)
+ break;
+ }
+
+ ENTITY_PARAM(0, 4) = kTimeInvalid;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(8);
+ setup_function29("CON1210", "CON1210A");
+ break;
+ }
+ }
+
+label_callback_8:
+ if (getState()->time > kTime1215000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
+ UPDATE_PARAM_PROC(params->param5, getState()->time, 2700)
+ getEntities()->drawSequenceLeft(kEntityMertens, "601E");
+ ENTITY_PARAM(0, 1) = 1;
+ params->param5 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (ENTITY_PARAM(0, 8)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(9);
+ setup_function14(kEntityVerges);
+ break;
+ }
+
+ if (getProgress().field_14 == 29)
+ goto label_callback_13;
+
+label_callback_9:
+ if (ENTITY_PARAM(1, 6)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(10);
+ setup_function16(true);
+ break;
+ }
+
+label_callback_10:
+ if (ENTITY_PARAM(1, 7)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(11);
+ setup_function16(false);
+ break;
+ }
+
+label_callback_11:
+ if (ENTITY_PARAM(1, 5)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(12);
+ setup_function15(true);
+ break;
+ }
+
+label_callback_12:
+ if (ENTITY_PARAM(1, 4)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(13);
+ setup_function15(false);
+ break;
+ }
+
+label_callback_13:
+ if (ENTITY_PARAM(1, 2)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(14);
+ setup_function35();
+ break;
+ }
+
+label_callback_14:
+ if (ENTITY_PARAM(0, 6)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(15);
+ setup_function36();
+ break;
+ }
+
+label_callback_15:
+ if (ENTITY_PARAM(1, 3)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(16);
+ setup_function40();
+ break;
+ }
+
+label_callback_16:
+ if (ENTITY_PARAM(1, 1)) {
+ ENTITY_PARAM(1, 1) = 0;
+ getData()->inventoryItem = kItemNone;
+ setCallback(17);
+ setup_function28("CON1200");
+ break;
+ }
+
+label_callback_17:
+ if (ENTITY_PARAM(2, 2)) {
+ ENTITY_PARAM(2, 2) = 0;
+ getData()->inventoryItem = kItemNone;
+ setCallback(18);
+ setup_function37();
+ break;
+ }
+
+label_callback_18:
+ if (!params->param1 && ENTITY_PARAM(0, 5)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(19);
+ setup_function39();
+ break;
+ }
+
+label_callback_19:
+ if (ENTITY_PARAM(0, 1) && !getSound()->isBuffered(kEntityMertens)) {
+ if (getProgress().field_18 != 4)
+ getSound()->playSound(kEntityMertens, "CON1505");
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ setCallback(21);
+ setup_savegame(kSavegameTypeEvent, kEventMertensAskTylerCompartmentD);
+ break;
+
+ case kAction11:
+ if (!ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(20);
+ setup_function13((bool)savepoint.param.intValue, (bool)savepoint.entity2);
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+ getScenes()->loadSceneFromItemPosition(kItem7);
+ break;
+
+ case kActionDrawScene:
+ if (ENTITY_PARAM(2, 1))
+ break;
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 23) && ENTITY_PARAM(0, 7) && !getEvent(kEventKronosConversation)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventMertensKronosInvitation);
+ break;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 23) && !getProgress().eventMertensKronosInvitation && !getEvent(kEventMertensLastCar) && !getEvent(kEventMertensLastCarOriginalJacket)) {
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventMertensLastCar);
+ break;
+ }
+
+label_callback_2_4:
+ if ((getEntities()->isPlayerPosition(kCarGreenSleeping, 1) || getEntities()->isPlayerPosition(kCarGreenSleeping, 23)) && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(getEntities()->isPlayerPosition(kCarGreenSleeping, 1) ? 5 : 6);
+ setup_function13(getEntities()->isPlayerPosition(kCarGreenSleeping, 1), false);
+ break;
+ }
+
+label_callback_5_6:
+ if (getEntities()->isPlayerInCar(kCarGreenSleeping) && getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition) {
+ if (getProgress().jacket == kJacketOriginal || ENTITY_PARAM(0, 7)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(7);
+ setup_function32();
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(kEventMertensKronosInvitation);
+ getProgress().eventMertensKronosInvitation = true;
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+ getEntities()->drawSequenceRight(kEntityMertens, "601A");
+ getScenes()->loadSceneFromItemPosition(kItem7);
+ ENTITY_PARAM(0, 1) = 0;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ case 4:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601B");
+ goto label_callback_2_4;
+
+ case 3:
+ getAction()->playAnimation(getProgress().jacket == kJacketOriginal ? kEventMertensLastCarOriginalJacket : kEventMertensLastCar);
+ getEntities()->drawSequenceRight(kEntityMertens, "601A");
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 6);
+ getScenes()->loadSceneFromItemPosition(kItem7);
+ ENTITY_PARAM(0, 1) = 0;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(4);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 5:
+ case 6:
+ goto label_callback_5_6;
+
+ case 8:
+ goto label_callback_8;
+
+ case 9:
+ goto label_callback_9;
+
+ case 10:
+ goto label_callback_10;
+
+ case 11:
+ goto label_callback_11;
+
+ case 12:
+ goto label_callback_12;
+
+ case 13:
+ goto label_callback_13;
+
+ case 14:
+ goto label_callback_14;
+
+ case 15:
+ goto label_callback_15;
+
+ case 16:
+ goto label_callback_16;
+
+ case 17:
+ goto label_callback_17;
+
+ case 18:
+ goto label_callback_18;
+
+ case 19:
+ params->param1 = 1;
+ goto label_callback_19;
+
+ case 21:
+ getAction()->playAnimation(kEventMertensAskTylerCompartmentD);
+ getEntities()->drawSequenceRight(kEntityMertens, "601A");
+ getInventory()->get(kItem7)->location = kObjectLocationNone;
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 25);
+
+ setCallback(22);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 22:
+ getEntities()->drawSequenceLeft(kEntityMertens, "601B");
+ break;
+ }
+ break;
+
+ case kAction225358684:
+ if (!ENTITY_PARAM(0, 1)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(23);
+ setup_function30((MertensActionType)savepoint.param.intValue);
+ }
+ break;
+
+ case kAction225932896:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1))
+ getSavePoints()->push(kEntityMertens, kEntityFrancois, kAction205346192);
+ break;
+
+ case kAction305159806:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ getData()->inventoryItem = kItemNone;
+ setCallback(24);
+ setup_function31((MertensActionType)savepoint.param.intValue);
+ }
+ break;
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(43, Mertens, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_function17();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMertens);
+
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(0, 1) = 0;
+ ENTITY_PARAM(0, 2) = 0;
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(0, 4) = 0;
+ ENTITY_PARAM(0, 5) = 0;
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function44();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(44, Mertens, function44)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(1, 6)) {
+ setCallback(1);
+ setup_function16(true);
+ break;
+ }
+
+label_callback1:
+ if (ENTITY_PARAM(1, 7)) {
+ setCallback(2);
+ setup_function16(false);
+ break;
+ }
+
+label_callback2:
+ if (ENTITY_PARAM(1, 5)) {
+ setCallback(3);
+ setup_function15(true);
+ break;
+ }
+
+label_callback3:
+ if (ENTITY_PARAM(1, 4)) {
+ setCallback(4);
+ setup_function15(false);
+ break;
+ }
+
+ break;
+
+ case kAction11:
+ if (!ENTITY_PARAM(2, 1)) {
+ setCallback(5);
+ setup_function13((bool)savepoint.param.intValue, (bool)savepoint.entity2);
+ }
+ break;
+
+ case kActionDrawScene:
+ if (ENTITY_PARAM(2, 1))
+ break;
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 1)) {
+ setCallback(6);
+ setup_function13(true, false);
+
+ } else if (getEntities()->isPlayerPosition(kCarGreenSleeping, 23)) {
+ setCallback(7);
+ setup_function13(false, false);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 3:
+ goto label_callback3;
+ }
+ break;
+
+ case kAction225358684:
+ if (!ENTITY_PARAM(0, 1)) {
+ setCallback(9);
+ setup_function30((MertensActionType)savepoint.param.intValue);
+ }
+ break;
+
+ case kAction225932896:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1))
+ getSavePoints()->push(kEntityMertens, kEntityFrancois, kAction205346192);
+ break;
+
+ case kAction226078300:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(8);
+ setup_playSound("CON2020");
+ }
+ break;
+
+ case kAction305159806:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(10);
+ setup_function31((MertensActionType)savepoint.param.intValue);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(45, Mertens, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_function17();
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+
+ ENTITY_PARAM(2, 3) = 0;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function46();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(46, Mertens, function46)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(1, 6)) {
+ setCallback(1);
+ setup_function16(true);
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(1, 7)) {
+ setCallback(2);
+ setup_function16(false);
+ break;
+ }
+
+label_callback_2:
+ if (ENTITY_PARAM(1, 5)) {
+ setCallback(3);
+ setup_function15(true);
+ break;
+ }
+
+label_callback_3:
+ if (ENTITY_PARAM(1, 4)) {
+ setCallback(4);
+ setup_function15(false);
+ break;
+ }
+
+label_callback_4:
+ if (ENTITY_PARAM(0, 8)) {
+ setCallback(5);
+ setup_function14(kEntityVerges);
+ break;
+ }
+
+label_callback_5:
+ if (ENTITY_PARAM(2, 4)
+ && (getEvent(kEventKronosVisit) || getState()->time > kTime2052000)
+ && getState()->time < kTime2133000
+ && getEntities()->isPlayerInCar(kCarGreenSleeping)) {
+ setCallback(6);
+ setup_function32();
+ break;
+ }
+
+label_callback_6:
+ TIME_CHECK_CALLBACK_1(kTime1971000, params->param1, 7, setup_function28, "CON3012");
+
+label_callback_7:
+ TIME_CHECK_CALLBACK(kTime2117700, params->param2, 8, setup_function32);
+
+label_callback_8:
+ TIME_CHECK_CALLBACK_1(kTime2124000, params->param3, 9, setup_function28, "CON2010");
+
+label_callback_9:
+ TIME_CHECK_CALLBACK(kTime2146500, params->param4, 10, setup_function32);
+
+label_callback_10:
+ TIME_CHECK_CALLBACK(kTime2169000, params->param5, 11, setup_function32);
+ break;
+
+ case kAction11:
+ if (!ENTITY_PARAM(2, 1)) {
+ setCallback(12);
+ setup_function13((bool)savepoint.param.intValue, savepoint.entity2 != kEntityPlayer);
+ }
+ break;
+
+ case kActionDefault:
+ break;
+
+ case kActionDrawScene:
+ if (!ENTITY_PARAM(2, 1)) {
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 1)) {
+ setCallback(13);
+ setup_function13(true, false);
+ } else if (getEntities()->isPlayerPosition(kCarGreenSleeping, 23)) {
+ setCallback(14);
+ setup_function13(false, false);
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+
+ case 8:
+ goto label_callback_8;
+
+ case 9:
+ goto label_callback_9;
+
+ case 10:
+ goto label_callback_10;
+ }
+ break;
+
+ case kAction225358684:
+ if (!ENTITY_PARAM(0, 1)) {
+ setCallback(16);
+ setup_function30((MertensActionType)savepoint.param.intValue);
+ }
+ break;
+
+ case kAction225932896:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1))
+ getSavePoints()->push(kEntityMertens, kEntityFrancois, kAction205346192);
+ break;
+
+ case kAction226078300:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(15);
+ setup_playSound("CON2020");
+ }
+ break;
+
+ case kAction305159806:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(17);
+ setup_function31((MertensActionType)savepoint.param.intValue);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(47, Mertens, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_function17();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMertens);
+
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+
+ ENTITY_PARAM(2, 4) = 0;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function48();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(48, Mertens, function48)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(2, 3)) {
+ params->param1 = 1;
+
+ getObjects()->updateLocation2(kObjectCompartment2, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartment3, kObjectLocation1);
+ getObjects()->updateLocation2(kObjectCompartment4, kObjectLocation1);
+
+ ENTITY_PARAM(1, 4) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+
+ getEntities()->drawSequenceLeft(kEntityMertens, "601E");
+
+ ENTITY_PARAM(2, 3) = 0;
+ }
+
+ if (ENTITY_PARAM(1, 6)) {
+ setCallback(1);
+ setup_function16(true);
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(1, 7)) {
+ setCallback(2);
+ setup_function16(false);
+ break;
+ }
+
+label_callback_2:
+ if (ENTITY_PARAM(1, 5)) {
+ setCallback(3);
+ setup_function15(true);
+ break;
+ }
+
+label_callback_3:
+ if (ENTITY_PARAM(1, 4)) {
+ setCallback(4);
+ setup_function15(false);
+ break;
+ }
+
+label_callback_4:
+ if (!params->param1) {
+ TIME_CHECK_CALLBACK(kTime2403000, params->param2, 5, setup_function49);
+
+label_callback_5:
+ TIME_CHECK_CALLBACK(kTime2430000, params->param3, 6, setup_function32);
+
+label_callback_6:
+ TIME_CHECK_CALLBACK(kTime2439000, params->param4, 7, setup_function32);
+
+label_callback_7:
+ TIME_CHECK_CALLBACK(kTime2448000, params->param5, 8, setup_function32);
+ }
+
+label_callback_8:
+ if (getState()->time > kTime2538000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
+ UPDATE_PARAM(params->param6, getState()->time, 2700);
+
+ getEntities()->drawSequenceLeft(kEntityMertens, "601E");
+
+ ENTITY_PARAM(0, 1) = 1;
+ params->param6 = 0;
+ }
+ break;
+
+ case kAction11:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(9);
+ setup_function13((bool)savepoint.param.intValue, savepoint.entity2 != kEntityPlayer);
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_1500;
+ getData()->location = kLocationOutsideCompartment;
+
+ getScenes()->loadSceneFromItemPosition(kItem7);
+ break;
+
+ case kActionDrawScene:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 1)) {
+ setCallback(10);
+ setup_function13(true, false);
+ } else if (getEntities()->isPlayerPosition(kCarGreenSleeping, 23)) {
+ setCallback(11);
+ setup_function13(false, false);
+ }
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+
+ case 8:
+ goto label_callback_8;
+ }
+ break;
+
+ case kAction225358684:
+ if (!ENTITY_PARAM(0, 1)) {
+ setCallback(13);
+ setup_function30((MertensActionType)savepoint.param.intValue);
+ }
+ break;
+
+ case kAction226078300:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(12);
+ setup_playSound("CON2020");
+ }
+ break;
+
+ case kAction305159806:
+ if (!ENTITY_PARAM(2, 1) && !ENTITY_PARAM(0, 1)) {
+ setCallback(14);
+ setup_function31((MertensActionType)savepoint.param.intValue);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(49, Mertens, function49)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function19();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_tylerCompartment(kMertensActionNone);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function33();
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function25();
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function33();
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function24();
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_function33();
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_function23();
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_function17();
+ break;
+
+ case 11:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(50, Mertens, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMertens);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(51, Mertens, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function52();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(52, Mertens, function52)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2 == kTimeInvalid)
+ break;
+
+ if (params->param1 >= getState()->time) {
+
+ if (!getEntities()->isPlayerInCar(kCarRedSleeping) || !params->param2)
+ params->param2 = (uint)getState()->time;
+
+ if (params->param2 >= getState()->time)
+ break;
+ }
+
+ params->param2 = kTimeInvalid;
+
+ setCallback(1);
+ setup_playSound("Mme5010");
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ params->param1 = (uint)(getState()->time + 4500);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("671Ad", kObjectCompartmentD);
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityMertens, kEntityMmeBoutarel, kAction155604840);
+ setup_function53();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(53, Mertens, function53)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM(params->param4, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 0;
+
+ getObjects()->update(kObjectCompartment4, kEntityMertens, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param4 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (params->param1) {
+ getObjects()->update(kObjectCompartment4, kEntityMertens, kObjectLocation1, kCursorNormal, kCursorNormal);
+ params->param1 = 0;
+
+ setCallback(3);
+ setup_playSound(getSound()->justCheckingCath());
+ }
+
+ setCallback(savepoint.action == kActionKnock ? 4 : 5);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_5790);
+ break;
+
+ case kActionDrawScene:
+ if (params->param2 || params->param1) {
+ params->param1 = 0;
+ params->param2 = 0;
+ params->param3 = 0;
+
+ getObjects()->update(kObjectCompartment4, kEntityMertens, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("601ZD", kObjectCompartment4);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityMertens);
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_5790;
+ // Fallback to next case
+
+ case 3:
+ getObjects()->update(kObjectCompartment4, kEntityMertens, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 4:
+ case 5:
+ params->param3++;
+
+ if (params->param3 == 1) {
+ getObjects()->update(kObjectCompartment4, kEntityMertens, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(6);
+ setup_playSound("Con5002");
+
+ } else if (params->param3 == 2) {
+ getObjects()->update(kObjectCompartment4, kEntityMertens, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(7);
+ setup_playSound("Con5002A");
+ }
+ break;
+
+ case 6:
+ params->param1 = 1;
+ getObjects()->update(kObjectCompartment4, kEntityMertens, kObjectLocation1, kCursorTalk, kCursorNormal);
+ break;
+
+ case 7:
+ params->param2 = 1;
+ break;
+ }
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(54, Mertens)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/mertens.h b/engines/lastexpress/entities/mertens.h
new file mode 100644
index 0000000000..ccce17795c
--- /dev/null
+++ b/engines/lastexpress/entities/mertens.h
@@ -0,0 +1,220 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_MERTENS_H
+#define LASTEXPRESS_MERTENS_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Mertens : public Entity {
+private:
+ // The type of action when entering Tyler compartment
+ enum MertensActionType {
+ kMertensActionNone = 0,
+ kMertensAction1 = 1,
+ kMertensAction2 = 2,
+ kMertensAction3 = 3
+ };
+
+public:
+ Mertens(LastExpressEngine *engine);
+ ~Mertens() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Handle meeting Coudert with the blooded jacket
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(bloodJacket, const char *sequence)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ * @param entityPosition1 The entity position
+ * @param entityPosition1 The entity position to check
+ *
+ * @note We are not using the shared function due to too many differences
+ */
+ DECLARE_FUNCTION_4(enterExitCompartment3, const char *sequence, ObjectIndex compartment, EntityPosition entityPosition1, EntityPosition entityPosition2)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound16, const char *filename)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION_1(function11, uint32 time)
+
+ /**
+ * Says "Bonsoir" to another character
+ *
+ * @param entity The entity
+ */
+ DECLARE_FUNCTION_1(bonsoir, EntityIndex entity)
+ DECLARE_FUNCTION_2(function13, bool, bool)
+ DECLARE_FUNCTION_1(function14, EntityIndex entity)
+ DECLARE_FUNCTION_1(function15, bool)
+ DECLARE_FUNCTION_1(function16, bool)
+ DECLARE_FUNCTION(function17)
+ DECLARE_FUNCTION(function18)
+ DECLARE_FUNCTION(function19)
+ DECLARE_FUNCTION(function20)
+
+ /**
+ * ???
+ *
+ * @param object1 First object index
+ * @param object2 Second object index
+ */
+ DECLARE_FUNCTION_2(function21, ObjectIndex object1, ObjectIndex object2)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION_1(function26, bool)
+ DECLARE_FUNCTION_1(tylerCompartment, MertensActionType action)
+ DECLARE_FUNCTION_1(function28, const char *soundName)
+ DECLARE_FUNCTION_2(function29, const char *soundName1, const char *soundName2)
+ DECLARE_FUNCTION_1(function30, MertensActionType action)
+ DECLARE_FUNCTION_1(function31, MertensActionType action)
+ DECLARE_FUNCTION(function32)
+ DECLARE_FUNCTION(function33)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+ DECLARE_FUNCTION(function35)
+ DECLARE_FUNCTION(function36)
+ DECLARE_FUNCTION(function37)
+ DECLARE_FUNCTION(function38)
+ DECLARE_FUNCTION(function39)
+ DECLARE_FUNCTION(function40)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function42)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ DECLARE_FUNCTION(function44)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ DECLARE_FUNCTION(function46)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ DECLARE_FUNCTION(function48)
+ DECLARE_FUNCTION(function49)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function52)
+ DECLARE_FUNCTION(function53)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_MERTENS_H
diff --git a/engines/lastexpress/entities/milos.cpp b/engines/lastexpress/entities/milos.cpp
new file mode 100644
index 0000000000..50b0c04f45
--- /dev/null
+++ b/engines/lastexpress/entities/milos.cpp
@@ -0,0 +1,1805 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/milos.h"
+
+#include "lastexpress/entities/vesna.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/fight.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Milos::Milos(LastExpressEngine *engine) : Entity(engine, kEntityMilos) {
+ ADD_CALLBACK_FUNCTION(Milos, reset);
+ ADD_CALLBACK_FUNCTION(Milos, draw);
+ ADD_CALLBACK_FUNCTION(Milos, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Milos, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Milos, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Milos, playSound);
+ ADD_CALLBACK_FUNCTION(Milos, playSound16);
+ ADD_CALLBACK_FUNCTION(Milos, savegame);
+ ADD_CALLBACK_FUNCTION(Milos, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Milos, enterCompartmentDialog);
+ ADD_CALLBACK_FUNCTION(Milos, function11);
+ ADD_CALLBACK_FUNCTION(Milos, chapter1);
+ ADD_CALLBACK_FUNCTION(Milos, function13);
+ ADD_CALLBACK_FUNCTION(Milos, function14);
+ ADD_CALLBACK_FUNCTION(Milos, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Milos, function16);
+ ADD_CALLBACK_FUNCTION(Milos, function17);
+ ADD_CALLBACK_FUNCTION(Milos, function18);
+ ADD_CALLBACK_FUNCTION(Milos, chapter2);
+ ADD_CALLBACK_FUNCTION(Milos, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Milos, function21);
+ ADD_CALLBACK_FUNCTION(Milos, chapter3);
+ ADD_CALLBACK_FUNCTION(Milos, function23);
+ ADD_CALLBACK_FUNCTION(Milos, function24);
+ ADD_CALLBACK_FUNCTION(Milos, function25);
+ ADD_CALLBACK_FUNCTION(Milos, function26);
+ ADD_CALLBACK_FUNCTION(Milos, function27);
+ ADD_CALLBACK_FUNCTION(Milos, chapter4);
+ ADD_CALLBACK_FUNCTION(Milos, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Milos, function30);
+ ADD_CALLBACK_FUNCTION(Milos, function31);
+ ADD_CALLBACK_FUNCTION(Milos, function32);
+ ADD_CALLBACK_FUNCTION(Milos, chapter5);
+ ADD_CALLBACK_FUNCTION(Milos, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Milos, function35);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Milos, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Milos, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(3, Milos, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(4, Milos, enterExitCompartment2, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Milos, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(6, Milos, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(7, Milos, playSound16)
+ Entity::playSound(savepoint, false, SoundManager::kFlagDefault);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(8, Milos, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(9, Milos, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Milos, enterCompartmentDialog, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMeCath:
+ case kActionExcuseMe:
+ if (getEvent(kEventMilosTylerCompartmentDefeat)) {
+ // Robert saying: "Milos"
+ switch(rnd(3)) {
+ default:
+ case 0:
+ getSound()->playSound(kEntityPlayer, "CAT1014");
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityPlayer, "CAT1014A");
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityPlayer, "CAT1014B");
+ break;
+ }
+ } else {
+ getSound()->excuseMeCath();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(11, Milos, function11, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param5 && params->param1 < getState()->time && !params->param7) {
+ params->param7 = 1;
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param2) {
+ UPDATE_PARAM_PROC(params->param8, getState()->timeTicks, 75)
+ params->param2 = 0;
+ params->param3 = 1;
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation1, kCursorNormal, kCursorNormal);
+ UPDATE_PARAM_PROC_END
+ }
+
+ params->param8 = 0;
+
+ if (getProgress().chapter != kChapter1 || params->param5)
+ break;
+
+ if (params->param6) {
+ UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->time, 4500)
+ params->param6 = 0;
+ CURRENT_PARAM(1, 1) = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (!getProgress().field_CC) {
+
+ if (ENTITY_PARAM(0, 3) && !getProgress().field_14 && !params->param6) {
+ getProgress().field_14 = 14;
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction190412928);
+
+ setCallback(1);
+ setup_enterExitCompartment("609Cg", kObjectCompartmentG);
+ }
+ break;
+ }
+
+ if (!params->param4)
+ params->param4 = (uint)getState()->time + 18000;
+
+ if (CURRENT_PARAM(1, 2) != kTimeInvalid) {
+ if (params->param4 >= getState()->time) {
+ if (!getEntities()->isDistanceBetweenEntities(kEntityPlayer, kEntityMilos, 2000) || !CURRENT_PARAM(1, 2))
+ CURRENT_PARAM(1, 2) = (uint)getState()->time + 150;
+
+ if (CURRENT_PARAM(1, 2) >= getState()->time)
+ break;
+ }
+
+ CURRENT_PARAM(1, 2) = kTimeInvalid;
+
+ if (getEntities()->isDistanceBetweenEntities(kEntityPlayer, kEntityMilos, 2000))
+ getProgress().field_98 = 1;
+
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ setCallback(6);
+ setup_playSound("MIL1012");
+ }
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ if (params->param2) {
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(10);
+ setup_playSound((rnd(2) ? "CAT1504" : getSound()->wrongDoorCath()));
+ } else {
+ setCallback(11);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 7 : 8);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param3 || params->param2) {
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param3 = 0;
+ params->param2 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch(getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ setCallback(2);
+ setup_enterCompartmentDialog(kCarGreenSleeping, kPosition_8200);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function14();
+ break;
+
+ case 3:
+ if (getProgress().field_14 == 14)
+ getProgress().field_14 = 0;
+
+ params->param6 = 1;
+ setCallback(4);
+ setup_enterCompartmentDialog(kCarRedSleeping, kPosition_3050);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("609Bg", kObjectCompartmentG);
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMilos);
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction101687594);
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 6:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 7:
+ case 8:
+ setCallback(9);
+ // Milos asking: "Yeah? Who is it?"
+ setup_playSound("MIL1117A");
+ break;
+
+ case 9:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorTalk, kCursorNormal);
+ params->param2 = 1;
+ break;
+
+ case 10:
+ case 11:
+ params->param2 = 0;
+ params->param3 = 1;
+ break;
+
+ case 12:
+ getEntities()->drawSequenceLeft(kEntityMilos, "611Cg");
+ getEntities()->enterCompartment(kEntityMilos, kObjectCompartmentG, true);
+ getSavePoints()->push(kEntityMilos, kEntityCoudert, kAction88652208);
+ break;
+
+ case 13:
+ getEntities()->exitCompartment(kEntityMilos, kObjectCompartmentG, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMilos);
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param5 = 0;
+ break;
+
+ }
+ break;
+
+ case kAction122865568:
+ getData()->location = kLocationOutsideCompartment;
+ setCallback(12);
+ setup_enterExitCompartment("611Bg", kObjectCompartmentG);
+ break;
+
+ case kAction123852928:
+ params->param1 = 13;
+ setup_enterExitCompartment("611Dg", kObjectCompartmentG);
+ break;
+
+ case kAction221683008:
+ params->param5 = 1;
+ getSavePoints()->push(kEntityMilos, kEntityCoudert, kAction123199584);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Milos, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject46, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getData()->entityPosition = kPosition_4689;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+
+ getSavePoints()->addData(kEntityMilos, kAction157691176, 0);
+ getSavePoints()->addData(kEntityMilos, kAction208228224, 2);
+ getSavePoints()->addData(kEntityMilos, kAction259125998, 3);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Milos, function13)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getSavePoints()->push(kEntityMilos, kEntityTables2, kActionDrawTablesWithChairs, "009E");
+ getEntities()->clearSequences(kEntityVesna);
+ getEntities()->clearSequences(kEntityIvo);
+ getEntities()->clearSequences(kEntitySalko);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntitySalko, "009D5");
+ getEntities()->drawSequenceRight(kEntityTables2, "009D4");
+ getEntities()->drawSequenceRight(kEntityIvo, "009D3");
+ getEntities()->drawSequenceRight(kEntityVesna, "009D2");
+ getEntities()->drawSequenceRight(kEntityMilos, "009D1");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Milos, function14)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().field_14 == 29 || getProgress().field_14 == 3) {
+ if (params->param2) {
+ setCallback(1);
+ setup_enterExitCompartment("609Ca", kObjectCompartment1);
+ } else {
+ getEntities()->exitCompartment(kEntityMilos, kObjectCompartment1, true);
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+
+ if (params->param1) {
+
+ // TODO replace with UPDATE_PARAM_PROC (without the kTimeInvalid part)
+ if (!CURRENT_PARAM(1, 1))
+ CURRENT_PARAM(1, 1) = getState()->timeTicks + 45;
+
+ if (CURRENT_PARAM(1, 1) < getState()->timeTicks) {
+
+ if (getObjects()->get(kObjectCompartment1).location == kObjectLocation1) {
+ UPDATE_PARAM(CURRENT_PARAM(1, 2), getState()->timeTicks, 75);
+
+ getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ ++params->param5;
+ switch (params->param5) {
+ default:
+ getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, params->param3 < 1 ? kCursorTalk : kCursorNormal, kCursorHand);
+ CURRENT_PARAM(1, 2) = 0;
+ break;
+
+ case 1:
+ setCallback(6);
+ setup_playSound("LIB013");
+ break;
+
+ case 2:
+ setCallback(8);
+ setup_playSound("LIB012");
+ break;
+
+ case 3:
+ setCallback(10);
+ setup_playSound("LIB012");
+ break;
+
+ case 4:
+ ++params->param7;
+
+ if (params->param7 < 3) {
+ params->param5 = 1;
+ getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, params->param3 < 1 ? kCursorTalk : kCursorNormal, kCursorHand);
+ CURRENT_PARAM(1, 2) = 0;
+ break;
+ }
+
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ } else {
+ if (getProgress().eventCorpseMovedFromFloor && getProgress().jacket != kJacketBlood) {
+ params->param6 = (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) ? kEventMilosTylerCompartmentBedVisit : kEventMilosTylerCompartmentVisit;
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventMilosTylerCompartmentVisit);
+ } else {
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventMilosCorpseFloor);
+ }
+ }
+ }
+ break;
+ }
+
+ // TODO replace with UPDATE_PARAM_PROC (without the kTimeInvalid part)
+ if (!CURRENT_PARAM(1, 3))
+ CURRENT_PARAM(1, 3) = getState()->timeTicks + 75;
+
+ if (CURRENT_PARAM(1, 3) < getState()->timeTicks) {
+
+ if (!params->param4) {
+ setCallback(12);
+ setup_playSound("MIL1030C");
+ break;
+ }
+
+label_callback_12:
+ UPDATE_PARAM(CURRENT_PARAM(1, 4), getState()->timeTicks, 75);
+
+ getEntities()->exitCompartment(kEntityMilos, kObjectCompartment1, true);
+
+ if (getProgress().eventCorpseMovedFromFloor) {
+ setCallback(13);
+ setup_enterExitCompartment("609Ba", kObjectCompartment1);
+ break;
+ }
+
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
+ setCallback(14);
+ setup_enterExitCompartment2("609Ba", kObjectCompartment1);
+ break;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarNone, 1);
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(15);
+ setup_savegame(kSavegameTypeEvent, kEventMilosCorpseFloor);
+ }
+ break;
+
+ case kActionKnock:
+ if (params->param2) {
+ getObjects()->update(kObjectCompartment1, kEntityMilos, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(20);
+ setup_playSound("LIB012");
+ } else if (!params->param3) {
+ getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ setCallback(22);
+ setup_playSound16("MIL1032");
+ }
+ break;
+
+ case kActionOpenDoor:
+ if (getProgress().eventCorpseMovedFromFloor && getProgress().jacket != kJacketBlood) {
+ if (params->param2) {
+ getEntityData(kEntityPlayer)->location = kLocationInsideCompartment;
+ params->param6 = (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) ? kEventMilosTylerCompartmentBed : kEventMilosTylerCompartment;
+ } else {
+ params->param6 = (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) ? kEventMilosTylerCompartmentBedVisit : kEventMilosTylerCompartmentVisit;
+ }
+
+ setCallback(17);
+ setup_savegame(kSavegameTypeEvent, kEventMilosTylerCompartmentVisit);
+ } else {
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(16);
+ setup_savegame(kSavegameTypeEvent, kEventMilosCorpseFloor);
+ }
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_8200)
+ || getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_7850)
+ || getEntities()->isOutsideAlexeiWindow()) {
+ getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
+
+ if (getEntities()->isOutsideAlexeiWindow())
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
+
+ getSound()->playSound(kEntityPlayer, "LIB012");
+
+ getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, kCursorTalk, kCursorHand);
+
+ params->param1 = 1;
+ } else {
+ getEntities()->drawSequenceLeft(kEntityMilos, "609Aa");
+ getEntities()->enterCompartment(kEntityMilos, kObjectCompartment1, true);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityPlayer, "LIB014");
+ getAction()->playAnimation(kEventMilosCorpseFloor);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, getProgress().eventCorpseMovedFromFloor ? kSceneGameOverBloodJacket : kSceneGameOverPolice1, true);
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getSound()->playSound(kEntityPlayer, "LIB014");
+ getAction()->playAnimation((EventIndex)params->param6);
+
+ setCallback(4);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case 4:
+ case 18:
+ params->param8 = getFight()->setup(kFightMilos);
+ if (params->param8) {
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, params->param8 == Fight::kFightEndLost);
+ } else {
+ getState()->time = (TimeValue)(getState()->time + 1800);
+ getProgress().field_CC = 1;
+
+ setCallback(getCallback() + 1);
+ setup_savegame(kSavegameTypeEvent, kEventMilosTylerCompartmentDefeat);
+ }
+ break;
+
+ case 5:
+ case 19:
+ getAction()->playAnimation(kEventMilosTylerCompartmentDefeat);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadScene(kScene41);
+ getData()->location = kLocationOutsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_playSound16("MIL1031C");
+ break;
+
+ case 7:
+ case 9:
+ case 11:
+ getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, params->param3 < 1 ? kCursorTalk : kCursorNormal, kCursorHand);
+ CURRENT_PARAM(1, 2) = 0;
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_playSound16("MIL1031A");
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_playSound16("MIL1031B");
+ break;
+
+ case 12:
+ params->param4 = 1;
+ goto label_callback_12;
+
+ case 13:
+ params->param2 = 1;
+ getEntities()->clearSequences(kEntityMilos);
+ getData()->location = kLocationInsideCompartment;
+ getObjects()->update(kObjectCompartment1, kEntityMilos, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 14:
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(15);
+ setup_savegame(kSavegameTypeEvent, kEventMilosCorpseFloor);
+ break;
+
+ case 15:
+ getAction()->playAnimation(kEventMilosCorpseFloor);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
+ break;
+
+ case 16:
+ getSound()->playSound(kEntityPlayer, getObjects()->get(kObjectCompartment1).location == kObjectLocation1 ? "LIB032" : "LIB014");
+ getAction()->playAnimation(kEventMilosCorpseFloor);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, getProgress().eventCorpseMovedFromFloor ? kSceneGameOverBloodJacket : kSceneGameOverPolice1, true);
+ break;
+
+ case 17:
+ getSound()->playSound(kEntityPlayer, getObjects()->get(kObjectCompartment1).location == kObjectLocation1 ? "LIB032" : "LIB014");
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getAction()->playAnimation((EventIndex)params->param6);
+
+ setCallback(18);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case 20:
+ setCallback(21);
+ setup_playSound("MIL1117A");
+ break;
+
+ case 21:
+ getObjects()->update(kObjectCompartment1, kEntityMilos, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 22:
+ params->param3 = 1;
+ getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorHand);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Milos, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_SAVEPOINT(kTime1071000, params->param3, kEntityMilos, kEntityServers1, kAction223002560);
+
+ if (getState()->time > kTime1089000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ setup_function16();
+ break;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 61) && !params->param1) {
+ UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, 45)
+ setCallback(1);
+ setup_draw("009C");
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 70) && !params->param2) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 45);
+
+ setCallback(2);
+ setup_draw("009C");
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityMilos, kEntityTables2, kAction136455232);
+ getEntities()->drawSequenceLeft(kEntityMilos, "009A");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityMilos, "009A");
+ params->param1 = 1;
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMilos, "009A");
+ params->param2 = 1;
+ break;
+ }
+ break;
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Milos, function16)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ if (getEntities()->isDistanceBetweenEntities(kEntityMilos, kEntityVesna, 750)
+ || getEntities()->checkDistanceFromPosition(kEntityVesna, kPosition_3050, 500)) {
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction123668192);
+
+ setCallback(5);
+ setup_enterExitCompartment("611Ag", kObjectCompartmentG);
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_function13();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityMilos, kEntityServers1, kAction269485588);
+ getSavePoints()->push(kEntityMilos, kEntityIvo, kAction125242096);
+ getEntities()->drawSequenceRight(kEntityMilos, "807DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityMilos);
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityMilos);
+ break;
+
+ case 3:
+ if (getEntities()->isDistanceBetweenEntities(kEntityMilos, kEntityVesna, 750)
+ || getEntities()->checkDistanceFromPosition(kEntityVesna, kPosition_3050, 500)) {
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction123668192);
+
+ setCallback(4);
+ setup_enterExitCompartment("611Ag", kObjectCompartmentG);
+ } else {
+ params->param1 = 1;
+
+ getEntities()->drawSequenceLeft(kEntityMilos, "609Dg");
+ getEntities()->enterCompartment(kEntityMilos, kObjectCompartmentG, true);
+ }
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMilos);
+
+ setup_function17();
+ break;
+
+ case 5:
+ getEntities()->exitCompartment(kEntityMilos, kObjectCompartmentG, true);
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMilos);
+
+ setup_function17();
+ break;
+ }
+ break;
+
+ case kAction135024800:
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction204832737);
+
+ setCallback(3);
+ setup_enterCompartmentDialog(kCarRedSleeping, kPosition_3050);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Milos, function17)
+ if (savepoint.action == kActionDefault) {
+ setCallback(1);
+ setup_function11(kTimeBedTime);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Milos, function18)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->clearSequences(kEntityMilos);
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Milos, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMilos);
+
+ getData()->entityPosition = kPosition_4689;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject46, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Milos, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationOutsideCompartment;
+
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction137165825);
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerInCar(kCarRedSleeping) && !getEntities()->isPlayerPosition(kCarRedSleeping, 1)) {
+ setCallback(1);
+ setup_enterCompartmentDialog(kCarRedSleeping, kPosition_3050);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("609Bg", kObjectCompartmentG);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityMilos);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction101687594);
+
+ setup_function21();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Milos, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param2, getState()->time, 4500);
+
+ params->param1 = 1;
+ break;
+
+ case kActionKnock:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_playSound("LIB012");
+ break;
+
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventMilosCompartmentVisitAugust);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (!getEvent(kEventMilosCompartmentVisitAugust)
+ && !getEntities()->isInsideTrainCar(kEntityPlayer, kCarRedSleeping)
+ && params->param1)
+ setup_chapter2Handler();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_playSound("Mil1118");
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventMilosCompartmentVisitAugust);
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 5);
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction135024800);
+
+ setCallback(4);
+ setup_function11(kTimeEnd);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Milos, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->events[kEventMilosCompartmentVisitAugust])
+ setup_function24();
+ else
+ setup_function23();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMilos);
+
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ ENTITY_PARAM(0, 1) = 0;
+ ENTITY_PARAM(0, 4) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Milos, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2106000 && !params->param1) {
+ params->param1 = 1;
+
+ setCallback(1);
+ setup_enterCompartmentDialog(kCarRedSleeping, kPosition_3050);
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction137165825);
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerInCar(kCarRedSleeping)
+ && !getEntities()->isPlayerPosition(kCarRedSleeping, 1)) {
+ setCallback(3);
+ setup_enterCompartmentDialog(kCarRedSleeping, kPosition_3050);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("609Bg", kObjectCompartmentG);
+ break;
+
+ case 2:
+ case 4:
+ getEntities()->clearSequences(kEntityMilos);
+ getData()->location = kLocationInsideCompartment;
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction101687594);
+
+ setup_function24();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment("609Bg", kObjectCompartmentG);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Milos, function24)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param4)
+ params->param4 = (uint)getState()->time + 4500;
+
+ if (params->param4 < getState()->time) {
+ params->param4 = kTimeInvalid;
+ params->param3 = 1;
+ }
+
+ if (ENTITY_PARAM(0, 1)) {
+ setCallback(1);
+ setup_enterExitCompartment("609Cg", kObjectCompartmentG);
+ break;
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 1;
+
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param5 = 0;
+ break;
+
+ case kActionKnock:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ if (params->param1) {
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(9);
+ setup_playSound(rnd(2) ? "CAT1504" : getSound()->wrongDoorCath());
+ } else {
+ setCallback(10);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ setCallback(6);
+ setup_playSound("LIB012");
+ }
+ break;
+
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ if (getEvent(kEventMilosCompartmentVisitAugust) || getState()->time >= kTime2106000) {
+ setCallback(12);
+ setup_playSound("LIB013");
+ } else {
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(11);
+ setup_savegame(kSavegameTypeEvent, kEventMilosCompartmentVisitAugust);
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (getEvent(kEventMilosCompartmentVisitAugust)
+ || getEntities()->isInsideTrainCar(kEntityPlayer, kCarRedSleeping)
+ || !params->param3
+ || getState()->time >= kTime2106000) {
+ if (params->param1 || params->param2) {
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ params->param1 = 0;
+ params->param2 = 0;
+ }
+ break;
+ }
+
+ setup_function23();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction203663744);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_function26(kTime2223000);
+ break;
+
+ case 2:
+ if (ENTITY_PARAM(0, 2)) {
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventMilosCorridorThanksD);
+ } else {
+ setCallback(4);
+ setup_enterCompartmentDialog(kCarRedSleeping, kPosition_3050);
+ }
+ break;
+
+ case 3:
+ getAction()->playAnimation((getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition) ? kEventMilosCorridorThanksD : kEventMilosCorridorThanks);
+
+ if (getData()->car == kCarRedSleeping && getEntities()->checkDistanceFromPosition(kEntityMilos, kPosition_3050, 500))
+ getData()->entityPosition = kPosition_3550;
+
+ getEntities()->updateEntity(kEntityMilos, kCarRedSleeping, kPosition_3050);
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + (750 * (getData()->direction == kDirectionDown ? 1 : -1))), getData()->direction != kDirectionDown);
+
+ setCallback(4);
+ setup_enterCompartmentDialog(kCarRedSleeping, kPosition_3050);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("609BG", kObjectCompartmentG);
+ break;
+
+ case 5:
+ getEntities()->clearSequences(kEntityMilos);
+ getData()->location = kLocationInsideCompartment;
+ ENTITY_PARAM(0, 1) = 0;
+
+ setup_function25();
+ break;
+
+ case 6:
+ if (getEvent(kEventMilosCompartmentVisitAugust) || getState()->time >= kTime2106000) {
+ setCallback(8);
+ setup_playSound("Mil1117A");
+ } else {
+ setCallback(7);
+ setup_playSound("Mil1118");
+ }
+ break;
+
+ case 7:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 8:
+ case 13:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorTalk, kCursorNormal);
+ params->param1 = 1;
+ break;
+
+ case 9:
+ case 10:
+ params->param1 = 0;
+ params->param2 = 1;
+ break;
+
+ case 11:
+ getAction()->playAnimation(kEventMilosCompartmentVisitAugust);
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 5);
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction135024800);
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 12:
+ setCallback(13);
+ setup_playSound("MIL1117A");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Milos, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getEvent(kEventMilosCompartmentVisitTyler) && !getProgress().field_54 && !ENTITY_PARAM(0, 4)) {
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 13500)
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction155913424);
+ params->param3 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param4, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 1;
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param4 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, params->param1 ? kObjectLocation3 : kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param1) {
+ setCallback(5);
+ setup_playSound(rnd(2) ? "CAT1505" : "CAT1505A");
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ if (!getEvent(kEventMilosCompartmentVisitTyler) && !getProgress().field_54 && !ENTITY_PARAM(0, 4))
+ getSavePoints()->push(kEntityMilos, kEntityVesna, kAction155913424);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ params->param1 = 0;
+ params->param2 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ if (getEntities()->isInsideCompartment(kEntityVesna, kCarRedSleeping, kPosition_3050)) {
+ setCallback(3);
+ setup_playSound("VES1015A");
+ break;
+ }
+
+ if (getEvent(kEventMilosCompartmentVisitTyler) || ENTITY_PARAM(0, 4)) {
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+
+ RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_chapter3Handler);
+
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventMilosCompartmentVisitTyler);
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param1 = 1;
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventMilosCompartmentVisitTyler);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 5);
+ getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 5:
+ params->param1 = 0;
+ params->param2 = 1;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 < getState()->time && !params->param2) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (getEntities()->isPlayerInCar(kCarGreenSleeping) || getEntities()->isPlayerInCar(kCarRedSleeping)) {
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
+ setCallback(2);
+ setup_function27(kCarGreenSleeping, kPosition_540);
+ } else {
+ setCallback(3);
+ setup_function27(kCarRedSleeping, kPosition_9460);
+ }
+ }
+ break;
+
+ case kActionDefault:
+ ENTITY_PARAM(0, 2) = 0;
+
+ setCallback(1);
+ setup_function27(kCarRedSleeping, kPosition_540);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (ENTITY_PARAM(0, 2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityMilos);
+ break;
+
+ case 2:
+ case 3:
+ if (ENTITY_PARAM(0, 2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityMilos);
+
+ setCallback(4);
+ setup_updateFromTime(450);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function27(kCarRedSleeping, kPosition_540);
+ break;
+
+ case 5:
+ if (ENTITY_PARAM(0, 2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityMilos);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(27, Milos, function27, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (getEntities()->isDistanceBetweenEntities(kEntityMilos, kEntityPlayer, 1000)
+ && !getEntities()->isInGreenCarEntrance(kEntityPlayer)
+ && !getEntities()->isInsideCompartments(kEntityPlayer)
+ && !getEntities()->checkFields10(kEntityPlayer)) {
+ if (getData()->car == kCarRedSleeping || getData()->car == kCarGreenSleeping) {
+ ENTITY_PARAM(0, 2) = 1;
+
+ CALLBACK_ACTION();
+ }
+ }
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Milos, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMilos);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Milos, chapter4Handler)
+#define TIME_CHECK_PLAYSOUND_MILOS(timeValue, parameter, sound) \
+ if (getState()->time > timeValue && !parameter) { \
+ parameter = 1; \
+ getSound()->playSound(kEntityMilos, sound); \
+ if (getEntities()->isDistanceBetweenEntities(kEntityMilos, kEntityPlayer, 2000)) \
+ getProgress().field_94 = 1; \
+ break; \
+ }
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1)
+ break;
+
+ if (params->param2) {
+ setup_function30();
+ break;
+ }
+
+ TIME_CHECK_PLAYSOUND_MILOS(kTime2356200, params->param3, "Mil4013");
+
+ TIME_CHECK_PLAYSOUND_MILOS(kTime2360700, params->param4, "Mil4014");
+
+ TIME_CHECK_PLAYSOUND_MILOS(kTime2370600, params->param5, "Mil4015");
+
+ TIME_CHECK_SAVEPOINT(kTime2407500, params->param6, kEntityMilos, kEntityVesna, kAction55996766);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityMilos, "611Cg");
+ getEntities()->enterCompartment(kEntityMilos, kObjectCompartmentG, true);
+ getSavePoints()->push(kEntityMilos, kEntityCoudert, kAction88652208);
+ break;
+
+ case 2:
+ getEntities()->exitCompartment(kEntityMilos, kObjectCompartmentG);
+
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_3050;
+
+ getEntities()->clearSequences(kEntityMilos);
+
+ params->param1 = 0;
+ break;
+ }
+ break;
+
+ case kAction122865568:
+ setCallback(1);
+ setup_enterExitCompartment("611Bg", kObjectCompartmentG);
+ break;
+
+ case kAction123852928:
+ setCallback(2);
+ setup_enterExitCompartment("611Dg", kObjectCompartmentG);
+ break;
+
+ case kAction135600432:
+ params->param2 = 1;
+ break;
+
+ case kAction221683008:
+ if (getSound()->isBuffered(kEntityMilos))
+ getSound()->processEntry(kEntityMilos);
+
+ params->param1 = 1;
+ getSavePoints()->push(kEntityMilos, kEntityCoudert, kAction123199584);
+ break;
+ }
+
+#undef TIME_CHECK_PLAYSOUND_MILOS
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Milos, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_function11(kTime2410200);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityMilos, kEntityIvo, kAction55996766);
+
+ setCallback(2);
+ setup_function11(kTime2412000);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityMilos, kEntitySalko, kAction55996766);
+
+ setCallback(3);
+ setup_function11(kTime2415600);
+ break;
+
+ case 3:
+ setup_function31();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Milos, function31)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_enterExitCompartment("609CG", kObjectCompartmentG);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_enterCompartmentDialog(kCarGreenSleeping, kPosition_540);
+ break;
+
+ case 2:
+ setup_function32();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Milos, function32)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityMilos);
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarCoalTender;
+ getData()->inventoryItem = kItemNone;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Milos, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMilos);
+
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarCoalTender;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Milos, chapter5Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ if (!getProgress().isNightTime) {
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventTrainStopped);
+ break;
+ }
+
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneGameOverTrainStopped2, true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getAction()->playAnimation(isNight() ? kEventLocomotiveMilosShovelingNight : kEventLocomotiveMilosShovelingDay);
+ getScenes()->processScene();
+ break;
+
+ case 2:
+ if (getSound()->isBuffered("MUS050"))
+ getSound()->processEntry("MUS050");
+
+ if (getSound()->isBuffered("ARRIVE"))
+ getSound()->removeFromQueue("ARRIVE");
+
+ getSound()->processEntries();
+ getAction()->playAnimation(isNight() ? kEventLocomotiveMilosNight : kEventLocomotiveMilosDay);
+ getSound()->setupEntry(SoundManager::kSoundType7, kEntityMilos);
+ getScenes()->loadSceneFromPosition(kCarCoalTender, 1);
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventLocomotiveAnnaStopsTrain);
+ getLogic()->gameOver(kSavegameTypeEvent2, kEventLocomotiveMilosDay, kSceneGameOverTrainStopped, true);
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventLocomotiveRestartTrain);
+ getAction()->playAnimation(kEventLocomotiveOldBridge);
+ getSound()->resetState();
+ getState()->time = kTime2983500;
+
+ setCallback(5);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case 5:
+ getScenes()->loadSceneFromPosition(kCarCoalTender, 2, 1);
+ getSavePoints()->push(kEntityMilos, kEntityAbbot, kAction135600432);
+
+ setup_function35();
+ break;
+
+ case 6:
+ getAction()->playAnimation(kEventTrainStopped);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverTrainStopped, true);
+ break;
+ }
+ break;
+
+ case kAction168646401:
+ if (!getEvent(kEventLocomotiveMilosShovelingDay) && !getEvent(kEventLocomotiveMilosShovelingNight)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventLocomotiveMilosShovelingDay);
+ break;
+ }
+
+ if (!getEvent(kEventLocomotiveMilosDay) && !getEvent(kEventLocomotiveMilosNight)) {
+ if (getProgress().isNightTime && getState()->time < kTimeTrainStopped2)
+ getState()->time = kTimeTrainStopped2;
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventLocomotiveMilosDay);
+ }
+ break;
+
+ case kAction169773228:
+ if (!getProgress().isNightTime) {
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventLocomotiveAnnaStopsTrain);
+ }
+
+ getSound()->processEntry(kEntityMilos);
+ if (getState()->time < kTimeTrainStopped2)
+ getState()->time = kTimeTrainStopped2;
+
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventLocomotiveRestartTrain);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Milos, function35)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityMilos);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/milos.h b/engines/lastexpress/entities/milos.h
new file mode 100644
index 0000000000..6d44d1c4d9
--- /dev/null
+++ b/engines/lastexpress/entities/milos.h
@@ -0,0 +1,175 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_MILOS_H
+#define LASTEXPRESS_MILOS_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Milos : public Entity {
+public:
+ Milos(LastExpressEngine *engine);
+ ~Milos() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound16, const char *filename)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ DECLARE_FUNCTION_2(enterCompartmentDialog, CarIndex car, EntityPosition entityPosition)
+ DECLARE_FUNCTION_1(function11, TimeValue timeValue)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION(function13)
+ DECLARE_FUNCTION(function14)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function16)
+ DECLARE_FUNCTION(function17)
+ DECLARE_FUNCTION(function18)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function21)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION_1(function26, TimeValue timeValue)
+ DECLARE_FUNCTION_2(function27, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function30)
+ DECLARE_FUNCTION(function31)
+ DECLARE_FUNCTION(function32)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function35)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_MILOS_H
diff --git a/engines/lastexpress/entities/mmeboutarel.cpp b/engines/lastexpress/entities/mmeboutarel.cpp
new file mode 100644
index 0000000000..aeaa1e631e
--- /dev/null
+++ b/engines/lastexpress/entities/mmeboutarel.cpp
@@ -0,0 +1,1301 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/mmeboutarel.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+MmeBoutarel::MmeBoutarel(LastExpressEngine *engine) : Entity(engine, kEntityMmeBoutarel) {
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, reset);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, playSound);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, draw);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, updateFromTime);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, updateEntity);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function8);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function9);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter1);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function11);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function13);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function14);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function15);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function16);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter2);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function19);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter3);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter4);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function24);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function25);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter5);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(MmeBoutarel, function28);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, MmeBoutarel, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, MmeBoutarel, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, MmeBoutarel, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(4, MmeBoutarel, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(5, MmeBoutarel, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(6, MmeBoutarel, enterExitCompartment2, ObjectIndex)
+ Entity::enterExitCompartment(savepoint, kPosition_5790, kPosition_6130, kCarRedSleeping, kObjectCompartmentD, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(7, MmeBoutarel, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ getInventory()->hasItem(kItemPassengerList) ? getSound()->playSound(kEntityPlayer, "CAT1021") : getSound()->excuseMeCath();
+
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(8, MmeBoutarel, function8)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param4 && params->param5) {
+ getSavePoints()->push(kEntityMmeBoutarel, kEntityCoudert, kAction125499160);
+
+ if (!getEntities()->isPlayerPosition(kCarRedSleeping, 2))
+ getData()->entityPosition = kPosition_2088;
+
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionEndSound:
+ params->param5 = 1;
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "606U");
+ getSavePoints()->push(kEntityMmeBoutarel, kEntityCoudert, kAction169557824);
+ break;
+
+ case kAction155853632:
+ params->param4 = 1;
+ break;
+
+ case kAction202558662:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "606L");
+ getSound()->playSound(kEntityMmeBoutarel, (char *)&params->seq1);
+
+ if (getEntities()->hasValidFrame(kEntityMmeBoutarel) || getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 2000)) {
+ if (getProgress().chapter == kChapter1)
+ getProgress().field_A8 = 1;
+ else if (getProgress().chapter == kChapter3)
+ getProgress().field_A4 = 1;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, MmeBoutarel, function9)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ getData()->entityPosition = getEntityData(kEntityBoutarel)->entityPosition;
+ getData()->location = getEntityData(kEntityBoutarel)->location;
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(1);
+ setup_enterExitCompartment("606Rd", kObjectCompartmentD);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+ getSavePoints()->push(kEntityMmeBoutarel, kEntityBoutarel, kAction203520448);
+ break;
+
+ case 3:
+ if (getEntities()->isInsideCompartment(kEntityFrancois, kCarRedSleeping, kPosition_5790)) {
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(4);
+ setup_enterExitCompartment2("606Ad", kObjectCompartmentD);
+ } else {
+ params->param1 = 1;
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "606Md");
+ getEntities()->enterCompartment(kEntityMmeBoutarel, kObjectCompartmentD, true);
+ }
+ break;
+
+ case 4:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 5:
+ getEntities()->exitCompartment(kEntityMmeBoutarel, kObjectCompartmentD, true);
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction100901266:
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case kAction100957716:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(5);
+ setup_enterExitCompartment2("606Ad", kObjectCompartmentD);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, MmeBoutarel, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityMmeBoutarel, kAction242526416, 0);
+
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, MmeBoutarel, function11)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2 == kTimeInvalid)
+ break;
+
+ if (params->param1 >= getState()->time) {
+ if (!getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 1000) || !params->param2)
+ params->param2 = (uint)getState()->time + 150;
+
+ if (params->param2 >= getState()->time)
+ break;
+ }
+
+ params->param2 = kTimeInvalid;
+
+ setCallback(1);
+ setup_playSound("MME1040");
+ break;
+
+ case kActionDefault:
+ params->param1 = (uint)getState()->time + 1800;
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_playSound("MME1040A");
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_playSound("MME1041");
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateFromTime(900);
+ break;
+
+ case 4:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, MmeBoutarel, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ params->param1 = 1;
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 44)) {
+ setCallback(1);
+ setup_draw("502B");
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "502A");
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "606Qd");
+ getEntities()->enterCompartment(kEntityMmeBoutarel, kObjectCompartmentD, true);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ params->param1 = 1;
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+ setup_function13();
+ break;
+ }
+ break;
+
+ case kAction102484312:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ params->param1 = 1;
+ break;
+
+ case kAction134289824:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "502A");
+ params->param1 = 0;
+ break;
+
+ case kAction168986720:
+ getSavePoints()->push(kEntityMmeBoutarel, kEntityFrancois, kAction102752636);
+ getSound()->playSound(kEntityMmeBoutarel, "MME1036");
+ getEntities()->exitCompartment(kEntityMmeBoutarel, kObjectCompartmentD, true);
+
+ setCallback(3);
+ setup_enterExitCompartment("606Fd", kObjectCompartmentD);
+ break;
+
+ case kAction202221040:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationOutsideCompartment;
+
+ getSound()->playSound(kEntityMmeBoutarel, "MME1035A");
+
+ if (getEntities()->hasValidFrame(kEntityMmeBoutarel) || getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 2000) )
+ getProgress().field_AC = 1;
+
+ setCallback(2);
+ setup_enterExitCompartment("606Ed", kObjectCompartmentD);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, MmeBoutarel, function13)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getSound()->isBuffered(kEntityMmeBoutarel) && params->param6 != kTimeInvalid) {
+ UPDATE_PARAM_PROC_TIME(params->param1, !getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 2000), params->param6, 0)
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 2000))
+ getProgress().field_A0 = 1;
+
+ params->param5 = 1;
+
+ setCallback(1);
+ setup_playSound("MME1037");
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+label_callback_1:
+ if (getProgress().field_24 && params->param7 != kTimeInvalid) {
+ UPDATE_PARAM_PROC_TIME(kTime1093500, (!params->param5 || !getEntities()->isPlayerInCar(kCarRedSleeping)), params->param7, 0)
+ setCallback(2);
+ setup_function11();
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+ TIME_CHECK(kTime1094400, params->param8, setup_function14);
+
+ if (params->param4) {
+ UPDATE_PARAM(CURRENT_PARAM(1, 1), getState()->timeTicks, 75);
+
+ params->param3 = 1;
+ params->param4 = 0;
+
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ CURRENT_PARAM(1, 1) = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param4) {
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(7);
+ setup_playSound(rnd(2) ? "CAT1510" : getSound()->wrongDoorCath());
+ } else {
+ setCallback(8);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ ++params->param2;
+
+ setCallback(savepoint.action == kActionKnock ? 4 : 3);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = (uint)getState()->time + 900;
+ getData()->entityPosition = kPosition_5790;
+
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param3 || params->param4) {
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param2 = 0;
+ params->param3 = 0;
+ params->param4 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ goto label_callback_1;
+
+ case 2:
+ setup_function14();
+ break;
+
+ case 3:
+ case 4:
+ setCallback(params->param2 <= 1 ? 6 : 5);
+ setup_playSound(params->param2 <= 1 ? "MME1038" : "MME1038C");
+ break;
+
+ case 5:
+ case 6:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param4 = 1;
+ break;
+
+ case 7:
+ case 8:
+ params->param3 = 1;
+ params->param4 = 0;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, MmeBoutarel, function14)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("606Dd", kObjectCompartmentD);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "503");
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "503");
+
+ setCallback(3);
+ setup_playSound("MRB1080");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(4);
+ setup_enterExitCompartment("606Cd", kObjectCompartmentD);
+ break;
+
+ case 4:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ setup_function15();
+ break;
+ }
+ break;
+
+ case kAction101107728:
+ setCallback(2);
+ setup_function9();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, MmeBoutarel, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTimeEnterChalons && !params->param4) {
+ params->param4 = 1;
+
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(1);
+ setup_enterExitCompartment("606Rd", kObjectCompartmentD);
+ break;
+ }
+
+label_callback_5:
+ if (params->param2) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+
+ params->param1 = 1;
+ params->param2 = 0;
+
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param5 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param2) {
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(10);
+ setup_playSound(rnd(2) ? "CAT1510" : getSound()->wrongDoorCath());
+ } else {
+ setCallback(11);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ break;
+ }
+
+ ++params->param3;
+
+ setCallback(savepoint.action == kActionKnock ? 7 : 6);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->car = kCarRedSleeping;
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_5790;
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param1 = 0;
+ params->param3 = 0; // BUG" why param3 when it's always param2?
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function8("MME1101");
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment2("606Td", kObjectCompartmentD);
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_5790;
+
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ goto label_callback_5;
+
+ case 6:
+ case 7:
+ if (params->param3 <= 1) {
+ setCallback(9);
+ setup_playSound("MME1038");
+ } else {
+ setCallback(8);
+ setup_playSound("MME1038C");
+ }
+ break;
+
+ case 8:
+ case 9:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param2 = 1;
+ break;
+
+ case 10:
+ case 11:
+ params->param1 = 1;
+ params->param2 = 0;
+ break;
+
+ case 12:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+
+ case kAction223068211:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(12);
+ setup_playSound("MME1151B");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, MmeBoutarel, function16)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, MmeBoutarel, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ getData()->entityPosition = kPosition_4689;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject43, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, MmeBoutarel, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEntities()->isInsideCompartment(kEntityFrancois, kCarRedSleeping, kPosition_5790)) {
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(2);
+ setup_enterExitCompartment2("606Ad", kObjectCompartmentD);
+ } else {
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "606Md");
+ getEntities()->enterCompartment(kEntityMmeBoutarel, kObjectCompartmentD, true);
+ }
+ break;
+
+ case 2:
+ case 3:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getData()->location = kLocationInsideCompartment;
+ setup_function19();
+ break;
+ }
+ break;
+
+ case kAction100901266:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case kAction100957716:
+ getEntities()->exitCompartment(kEntityMmeBoutarel, kObjectCompartmentD, true);
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorNormal);
+
+ setCallback(3);
+ setup_enterExitCompartment2("606Ad", kObjectCompartmentD);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, MmeBoutarel, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 44) && !params->param2) {
+ if (params->param1) {
+ setCallback(1);
+ setup_draw("502B");
+ } else {
+ params->param1 = 1;
+ }
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ params->param2 = 1;
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (getEntities()->isPlayerPosition(kCarRedSleeping , 44))
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 11);
+ }
+ break;
+
+ case kAction102484312:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ params->param2 = 1;
+ break;
+
+ case kAction134289824:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "502A");
+ params->param2 = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, MmeBoutarel, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, MmeBoutarel, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(0, 1) && params->param2 != kTimeInvalid) {
+
+ if (getState()->time <= kTime2038500) {
+ if (!getEntities()->isPlayerInCar(kCarRedSleeping)
+ || !params->param1
+ || getSound()->isBuffered("FRA2012")
+ || getSound()->isBuffered("FRA2010")
+ ||!params->param2)
+ params->param2 = (uint)getState()->time;
+
+ if (params->param2 >= getState()->time)
+ break;
+ }
+
+ params->param2 = kTimeInvalid;
+
+ getSavePoints()->push(kEntityMmeBoutarel, kEntityFrancois, kAction189872836);
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(1);
+ setup_enterExitCompartment("606Cd", kObjectCompartmentD);
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 1;
+
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject43, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("606Rd", kObjectCompartmentD);
+ break;
+
+ case 2:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function8("MME3001");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_5790);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_enterExitCompartment2("606Td", kObjectCompartmentD);
+ break;
+
+ case 6:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setCallback(7);
+ setup_updateFromTime(150);
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_enterExitCompartment("606Dd", kObjectCompartmentD);
+ break;
+
+ case 8:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ getSavePoints()->push(kEntityMmeBoutarel, kEntityFrancois, kAction190390860);
+ break;
+
+ case 9:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ params->param1 = 1;
+ break;
+ }
+ break;
+
+ case kAction101107728:
+ setCallback(9);
+ setup_function9();
+ break;
+
+ case kAction102484312:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ params->param1 = 1;
+ break;
+
+ case kAction134289824:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "502A");
+ params->param1 = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, MmeBoutarel, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, MmeBoutarel, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM(params->param2, getState()->time, 900);
+
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
+
+ setCallback(1);
+ setup_enterExitCompartment("606Cd", kObjectCompartmentD);
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+ setup_function24();
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMmeBoutarel, "501");
+ params->param1 = 1;
+ break;
+ }
+ break;
+
+ case kAction101107728:
+ setCallback(2);
+ setup_function9();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, MmeBoutarel, function24)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTime2470500, params->param4, setup_function25);
+
+ if (params->param2) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+
+ params->param1 = 1;
+ params->param2 = 0;
+
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+
+ params->param5 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param2) {
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(5);
+ setup_playSound(rnd(2) ? "CAT1510" : getSound()->wrongDoorCath());
+ } else {
+ setCallback(6);
+ setup_playSound(getSound()->wrongDoorCath());
+ }
+ } else {
+ ++params->param3;
+
+ setCallback(savepoint.action == kActionKnock ? 2 : 1);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ params->param1 = 0;
+ params->param2 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(params->param3 > 1 ? 3 : 4);
+ setup_playSound(params->param3 > 1 ? "MME1038C" : "MME1038");
+ break;
+
+ case 3:
+ case 4:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param2 = 1;
+ break;
+
+ case 5:
+ case 6:
+ params->param1 = 1;
+ params->param2 = 0;
+ break;
+
+ case 7:
+ getSavePoints()->push(kEntityMmeBoutarel, kEntityCoudert, kAction123199584);
+ break;
+
+ case 8:
+ getSavePoints()->push(kEntityMmeBoutarel, kEntityCoudert, kAction88652208);
+ break;
+ }
+ break;
+
+ case kAction122865568:
+ setCallback(8);
+ setup_playSound("Mme1151A");
+ break;
+
+ case kAction221683008:
+ setCallback(7);
+ setup_playSound("Mme1038");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, MmeBoutarel, function25)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, MmeBoutarel, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, MmeBoutarel, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function28();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, MmeBoutarel, function28)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM(params->param3, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 1;
+
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param3 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (params->param1) {
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ params->param1 = 0;
+
+ setCallback(1);
+ setup_playSound(getSound()->justCheckingCath());
+ break;
+ }
+
+ setCallback(savepoint.action == kActionKnock ? 2 : 3);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_5790;
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->clearSequences(kEntityMmeBoutarel);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ params->param1 = 0;
+ params->param2 = 0;
+
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 2:
+ case 3:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(4);
+ setup_playSound("Mme5001");
+ break;
+
+ case 4:
+ params->param1 = 1;
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorTalk, kCursorNormal);
+ break;
+ }
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+
+ case kAction155604840:
+ getObjects()->update(kObjectCompartmentD, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject51, kEntityMmeBoutarel, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(29, MmeBoutarel)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/mmeboutarel.h b/engines/lastexpress/entities/mmeboutarel.h
new file mode 100644
index 0000000000..1f1d762dd9
--- /dev/null
+++ b/engines/lastexpress/entities/mmeboutarel.h
@@ -0,0 +1,164 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_MMEBOUTAREL_H
+#define LASTEXPRESS_MMEBOUTAREL_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class MmeBoutarel : public Entity {
+public:
+ MmeBoutarel(LastExpressEngine *engine);
+ ~MmeBoutarel() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION_1(function8, const char *soundName)
+
+ DECLARE_FUNCTION(function9)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION(function11)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function13)
+ DECLARE_FUNCTION(function14)
+ DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION(function16)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function19)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(function25)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function28)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_MMEBOUTAREL_H
diff --git a/engines/lastexpress/entities/pascale.cpp b/engines/lastexpress/entities/pascale.cpp
new file mode 100644
index 0000000000..2c8c29177b
--- /dev/null
+++ b/engines/lastexpress/entities/pascale.cpp
@@ -0,0 +1,1232 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/pascale.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Pascale::Pascale(LastExpressEngine *engine) : Entity(engine, kEntityPascale) {
+ ADD_CALLBACK_FUNCTION(Pascale, draw);
+ ADD_CALLBACK_FUNCTION(Pascale, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Pascale, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Pascale, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Pascale, updatePosition);
+ ADD_CALLBACK_FUNCTION(Pascale, playSound);
+ ADD_CALLBACK_FUNCTION(Pascale, draw2);
+ ADD_CALLBACK_FUNCTION(Pascale, welcomeSophieAndRebecca);
+ ADD_CALLBACK_FUNCTION(Pascale, sitSophieAndRebecca);
+ ADD_CALLBACK_FUNCTION(Pascale, welcomeCath);
+ ADD_CALLBACK_FUNCTION(Pascale, function11);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter1);
+ ADD_CALLBACK_FUNCTION(Pascale, getMessageFromAugustToTyler);
+ ADD_CALLBACK_FUNCTION(Pascale, sitAnna);
+ ADD_CALLBACK_FUNCTION(Pascale, welcomeAnna);
+ ADD_CALLBACK_FUNCTION(Pascale, serveTatianaVassili);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Pascale, function18);
+ ADD_CALLBACK_FUNCTION(Pascale, function19);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter2);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter3);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Pascale, function23);
+ ADD_CALLBACK_FUNCTION(Pascale, welcomeAbbot);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter4);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Pascale, function27);
+ ADD_CALLBACK_FUNCTION(Pascale, messageFromAnna);
+ ADD_CALLBACK_FUNCTION(Pascale, function29);
+ ADD_CALLBACK_FUNCTION(Pascale, function30);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter5);
+ ADD_CALLBACK_FUNCTION(Pascale, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Pascale, function33);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(1, Pascale, draw)
+ Entity::draw(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(2, Pascale, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(3, Pascale, callbackActionOnDirection)
+ if (savepoint.action == kActionExcuseMeCath) {
+ if (!params->param1) {
+ getSound()->excuseMe(kEntityPascale);
+ params->param1 = 1;
+ }
+
+ return;
+ }
+
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(4, Pascale, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(5, Pascale, updatePosition)
+ Entity::updatePosition(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(6, Pascale, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(7, Pascale, draw2)
+ Entity::draw2(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Pascale, welcomeSophieAndRebecca)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_850;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("901");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ getSound()->playSound(kEntityPascale, "REB1198", SoundManager::kFlagInvalid, 30);
+ break;
+
+ case kChapter3:
+ getSound()->playSound(kEntityPascale, "REB3001", SoundManager::kFlagInvalid, 30);
+ break;
+
+ case kChapter4:
+ getSound()->playSound(kEntityPascale, "REB4001", SoundManager::kFlagInvalid, 30);
+ break;
+ }
+
+ setCallback(2);
+ setup_sitSophieAndRebecca();
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityPascale, kEntityRebecca, kAction157370960);
+
+ setCallback(3);
+ setup_draw("905");
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityPascale);
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(0, 4) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Pascale, sitSophieAndRebecca)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityPascale, "012C1");
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012C2");
+ getEntities()->drawSequenceLeft(kEntityTables3, "012C3");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Pascale, welcomeCath)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 && !getSound()->isBuffered(kEntityPascale))
+ getEntities()->updatePositionExit(kEntityPascale, kCarRestaurant, 64);
+ break;
+
+ case kActionExitCompartment:
+ if (!params->param2) {
+ params->param2 = 1;
+
+ getSound()->playSound(kEntityPascale, "HED1001A");
+ getSound()->playSound(kEntityPlayer, "LIB004");
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 69);
+ }
+
+ CALLBACK_ACTION();
+ break;
+
+ case kAction4:
+ if (!params->param1) {
+ params->param1 = 1;
+ getSound()->playSound(kEntityPascale, "HED1001");
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->updatePositionEnter(kEntityPascale, kCarRestaurant, 64);
+ getEntities()->drawSequenceRight(kEntityPascale, "035A");
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 && getEntities()->isPlayerPosition(kCarRestaurant, 64)) {
+ getSound()->playSound(kEntityPascale, "HED1001A");
+ getSound()->playSound(kEntityPlayer, "LIB004");
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 69);
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Pascale, function11)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ getSavePoints()->push(kEntityPascale, kEntityAugust, kAction168046720);
+ getSavePoints()->push(kEntityPascale, kEntityAnna, kAction168046720);
+ getSavePoints()->push(kEntityPascale, kEntityAlexei, kAction168046720);
+ getEntities()->updatePositionEnter(kEntityPascale, kCarRestaurant, 55);
+
+ setCallback(1);
+ setup_welcomeCath();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityPascale, kEntityAugust, kAction168627977);
+ getSavePoints()->push(kEntityPascale, kEntityAnna, kAction168627977);
+ getSavePoints()->push(kEntityPascale, kEntityAlexei, kAction168627977);
+ getEntities()->updatePositionExit(kEntityPascale, kCarRestaurant, 55);
+
+ setCallback(2);
+ setup_draw("905");
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityPascale);
+ getData()->entityPosition = kPosition_5900;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Pascale, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter1Handler();
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityPascale, kAction239072064, 0);
+ getSavePoints()->addData(kEntityPascale, kAction257489762, 2);
+ getSavePoints()->addData(kEntityPascale, kAction207769280, 6);
+ getSavePoints()->addData(kEntityPascale, kAction101824388, 7);
+ getSavePoints()->addData(kEntityPascale, kAction136059947, 8);
+ getSavePoints()->addData(kEntityPascale, kAction223262556, 1);
+ getSavePoints()->addData(kEntityPascale, kAction269479296, 3);
+ getSavePoints()->addData(kEntityPascale, kAction352703104, 4);
+ getSavePoints()->addData(kEntityPascale, kAction352768896, 5);
+ getSavePoints()->addData(kEntityPascale, kAction191604416, 10);
+ getSavePoints()->addData(kEntityPascale, kAction190605184, 11);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Pascale, getMessageFromAugustToTyler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("902");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (!ENTITY_PARAM(1, 3)) {
+ getEntities()->drawSequenceLeft(kEntityPascale, "010E");
+ getEntities()->drawSequenceLeft(kEntityAugust, "BLANK");
+
+ setCallback(2);
+ setup_playSound("AUG1001");
+ break;
+ }
+
+ setCallback(3);
+ setup_draw("905");
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityPascale, "010B");
+
+ setCallback(3);
+ setup_draw("905");
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_5900;
+ getEntities()->clearSequences(kEntityPascale);
+ getSavePoints()->push(kEntityPascale, kEntityVerges, kActionDeliverMessageToTyler);
+ ENTITY_PARAM(0, 1) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Pascale, sitAnna)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExitCompartment:
+ getEntities()->updatePositionExit(kEntityPascale, kCarRestaurant, 62);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceRight(kEntityTables0, "001C3");
+ getEntities()->drawSequenceRight(kEntityAnna, "001C2");
+ getEntities()->drawSequenceRight(kEntityPascale, "001C1");
+
+ getEntities()->updatePositionEnter(kEntityPascale, kCarRestaurant, 62);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("901");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityPascale, "ANN1047");
+
+ setCallback(2);
+ setup_sitAnna();
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityPascale, kEntityAnna, kAction157370960);
+
+ setCallback(3);
+ setup_draw("904");
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityPascale);
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(0, 2) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Pascale, serveTatianaVassili)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("903");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityPascale, kEntityTatiana, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityPascale, "014B");
+ getEntities()->updatePositionEnter(kEntityPascale, kCarRestaurant, 67);
+
+ if (getSound()->isBuffered("TAT1069A"))
+ getSound()->processEntry("TAT1069A");
+ else if (getSound()->isBuffered("TAT1069B"))
+ getSound()->processEntry("TAT1069B");
+
+ setCallback(2);
+ setup_playSound("TAT1066");
+ break;
+
+ case 2:
+ getEntities()->updatePositionExit(kEntityPascale, kCarRestaurant, 67);
+ getSavePoints()->push(kEntityPascale, kEntityTatiana, kAction122288808);
+
+ setCallback(3);
+ setup_draw("906");
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityPascale);
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(0, 3) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Pascale, chapter1Handler)
+switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param2) {
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 69)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 70)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 71))
+ params->param2 = 1;
+
+ if (!params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 61))
+ params->param1 = 1;
+ }
+
+ if (!getEntities()->isInKitchen(kEntityPascale))
+ break;
+
+ if (ENTITY_PARAM(0, 5) && ENTITY_PARAM(0, 6)) {
+ setup_function18();
+ break;
+ }
+
+ if (!getEntities()->isSomebodyInsideRestaurantOrSalon())
+ goto label_callback3;
+
+ if (params->param1 && !params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 61)) {
+ setCallback(1);
+ setup_function11();
+ break;
+ }
+
+label_callback1:
+ if (ENTITY_PARAM(0, 1) && !ENTITY_PARAM(1, 3)) {
+ setCallback(2);
+ setup_getMessageFromAugustToTyler();
+ break;
+ }
+
+label_callback2:
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(3);
+ setup_serveTatianaVassili();
+ break;
+ }
+
+label_callback3:
+ if (ENTITY_PARAM(0, 2)) {
+ setCallback(4);
+ setup_welcomeAnna();
+ break;
+ }
+
+label_callback4:
+ if (ENTITY_PARAM(0, 4)) {
+ setCallback(5);
+ setup_welcomeSophieAndRebecca();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param1 = 0;
+ params->param2 = 1;
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 3:
+ goto label_callback3;
+
+ case 4:
+ goto label_callback4;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Pascale, function18)
+ if (savepoint.action != kActionNone)
+ return;
+
+ if (getState()->time > kTime1242000 && !params->param1) {
+ params->param1 = 1;
+
+ getSavePoints()->push(kEntityPascale, kEntityServers0, kAction101632192);
+ getSavePoints()->push(kEntityPascale, kEntityServers1, kAction101632192);
+ getSavePoints()->push(kEntityPascale, kEntityCooks, kAction101632192);
+ getSavePoints()->push(kEntityPascale, kEntityVerges, kAction101632192);
+
+ setup_function19();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Pascale, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1 && getEntityData(kEntityPlayer)->entityPosition < kPosition_3650) {
+ getObjects()->update(kObject65, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getSavePoints()->push(kEntityPascale, kEntityTables0, kActionDrawTablesWithChairs, "001P");
+ getSavePoints()->push(kEntityPascale, kEntityTables1, kActionDrawTablesWithChairs, "005J");
+ getSavePoints()->push(kEntityPascale, kEntityTables2, kActionDrawTablesWithChairs, "009G");
+ getSavePoints()->push(kEntityPascale, kEntityTables3, kActionDrawTablesWithChairs, "010M");
+ getSavePoints()->push(kEntityPascale, kEntityTables4, kActionDrawTablesWithChairs, "014F");
+ getSavePoints()->push(kEntityPascale, kEntityTables5, kActionDrawTablesWithChairs, "024D");
+
+ params->param1 = 1;
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRestaurant;
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->clearSequences(kEntityPascale);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Pascale, chapter2)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityPascale);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes1;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObject65, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Pascale, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityPascale);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 4) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Pascale, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getEntities()->isInKitchen(kEntityPascale))
+ break;
+
+ if (ENTITY_PARAM(0, 7)) {
+ setCallback(1);
+ setup_function23();
+ break;
+ }
+
+label_callback:
+ if (ENTITY_PARAM(0, 4)) {
+ setCallback(2);
+ setup_welcomeSophieAndRebecca();
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ goto label_callback;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Pascale, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->updatePositionEnter(kEntityPascale, kCarRestaurant, 67);
+
+ setCallback(1);
+ setup_welcomeAbbot();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->updatePositionExit(kEntityPascale, kCarRestaurant, 67);
+ getSavePoints()->push(kEntityPascale, kEntityAbbot, kAction122288808);
+
+ setCallback(2);
+ setup_draw("906");
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(0, 7) = 0;
+ getEntities()->clearSequences(kEntityPascale);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Pascale, welcomeAbbot)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ getSound()->playSound(kEntityPascale, "ABB3015A");
+ params->param1 = 1;
+ }
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kAction10:
+ getSavePoints()->push(kEntityPascale, kEntityTables4, kAction136455232);
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityPascale, "ABB3015", SoundManager::kFlagInvalid, 105);
+ getEntities()->drawSequenceRight(kEntityPascale, "029A1");
+ getEntities()->drawSequenceRight(kEntityAbbot, "029A2");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Pascale, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityPascale);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 4) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 2) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Pascale, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2511000 && !params->param4) {
+ params->param2 = 1;
+ params->param4 = 1;
+ }
+
+ if (!getEntities()->isInKitchen(kEntityPascale))
+ break;
+
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ if (ENTITY_PARAM(0, 8)) {
+ setCallback(1);
+ setup_function27();
+ break;
+ }
+
+label_callback1:
+ if (ENTITY_PARAM(1, 2) && ENTITY_PARAM(1, 4)) {
+ if (!params->param3)
+ params->param3 = (uint)(getState()->time + 9000);
+
+ if (params->param5 != kTimeInvalid) {
+
+ if (params->param3 < getState()->time) {
+ params->param5 = kTimeInvalid;
+ setCallback(2);
+ setup_messageFromAnna();
+ break;
+ }
+
+ if (!getEntities()->isInRestaurant(kEntityPlayer) || !params->param5)
+ params->param5 = (uint)getState()->time;
+
+ if (params->param5 < getState()->time) {
+ params->param5 = kTimeInvalid;
+ setCallback(2);
+ setup_messageFromAnna();
+ break;
+ }
+ }
+ }
+
+label_callback2:
+ if (params->param1 && !params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 61)) {
+ setCallback(3);
+ setup_function11();
+ break;
+ }
+ }
+
+label_callback3:
+ if (ENTITY_PARAM(0, 4)) {
+ setCallback(4);
+ setup_welcomeSophieAndRebecca();
+ }
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 69)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 70)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 71))
+ params->param2 = 1;
+ break;
+
+ case kActionDrawScene:
+ if (!params->param2) {
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 69)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 70)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 71))
+ params->param2 = 1;
+
+ if (!params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 61))
+ params->param1 = 1;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 3:
+ params->param1 = 0;
+ params->param2 = 1;
+ goto label_callback3;
+ }
+ break;
+
+ case kAction201431954:
+ ENTITY_PARAM(0, 4) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+
+ getSavePoints()->push(kEntityPascale, kEntityTables0, kActionDrawTablesWithChairs, "001P");
+ getSavePoints()->push(kEntityPascale, kEntityTables1, kActionDrawTablesWithChairs, "005J");
+ getSavePoints()->push(kEntityPascale, kEntityTables2, kActionDrawTablesWithChairs, "009G");
+ getSavePoints()->push(kEntityPascale, kEntityTables3, kActionDrawTablesWithChairs, "010M");
+ getSavePoints()->push(kEntityPascale, kEntityTables4, kActionDrawTablesWithChairs, "014F");
+ getSavePoints()->push(kEntityPascale, kEntityTables5, kActionDrawTablesWithChairs, "024D");
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Pascale, function27)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(1, 1)) {
+ setCallback(2);
+ setup_updateFromTime(450);
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function29();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityPascale);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityPascale, kEntityCoudert, kAction123712592);
+
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function30();
+ break;
+
+ case 4:
+ getEntities()->clearSequences(kEntityPascale);
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(0, 8) = 0;
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 2) = 1;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Pascale, messageFromAnna)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("902");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityPascale, kEntityAugust, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityPascale, "010E2");
+
+ setCallback(2);
+ setup_playSound("Aug4001");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityPascale, kEntityAugust, kAction123793792);
+
+ setCallback(3);
+ setup_draw("905");
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityPascale);
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(1, 2) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Pascale, function29)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("817DD");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceRight(kEntityPascale, "817DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityPascale);
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_850;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Pascale, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_9270;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("817US");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceRight(kEntityPascale, "817UD");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityPascale);
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_5900;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Pascale, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityPascale);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Pascale, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function33();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Pascale, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param4) {
+ UPDATE_PARAM_PROC(params->param5, getState()->time, 4500)
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_playSound("Wat5010");
+ break;
+ UPDATE_PARAM_PROC_END
+ }
+
+label_callback1:
+ if (params->param1) {
+ UPDATE_PARAM(params->param6, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 2;
+
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param6 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (params->param1) {
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorNormal, kCursorNormal);
+ params->param1 = 0;
+
+ setCallback(2);
+ setup_playSound(getSound()->justCheckingCath());
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 3 : 4);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param2 || params->param1) {
+ params->param1 = 0;
+ params->param2 = 0;
+ params->param3 = 0;
+
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ goto label_callback1;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 3:
+ case 4:
+ params->param3++;
+
+ if (params->param3 == 1 || params->param3 == 2) {
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorNormal, kCursorNormal);
+ setCallback(params->param3 == 1 ? 5 : 6);
+ setup_playSound(params->param3 == 1 ? "Wat5001" : "Wat5002");
+ }
+ break;
+
+ case 5:
+ params->param1 = 1;
+ getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorTalk, kCursorNormal);
+ break;
+
+ case 6:
+ params->param2 = 1;
+ break;
+
+ case 7:
+ params->param4 = 1;
+ break;
+ }
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+
+ case kAction169750080:
+ if (getSound()->isBuffered(kEntityPascale)) {
+ params->param4 = 1;
+ } else {
+ setCallback(7);
+ setup_playSound("Wat5002");
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(34, Pascale)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/pascale.h b/engines/lastexpress/entities/pascale.h
new file mode 100644
index 0000000000..d0098dcf0b
--- /dev/null
+++ b/engines/lastexpress/entities/pascale.h
@@ -0,0 +1,165 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_PASCALE_H
+#define LASTEXPRESS_PASCALE_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Pascale : public Entity {
+public:
+ Pascale(LastExpressEngine *engine);
+ ~Pascale() {}
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Updates the position
+ *
+ * @param savepoint The savepoint
+ * - The sequence to draw
+ * - The car
+ * - The position
+ */
+ DECLARE_FUNCTION_NOSETUP(updatePosition)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Draws the entity along with another one
+ *
+ * @param savepoint The savepoint
+ * - The sequence to draw
+ * - The sequence to draw for the second entity
+ * - The EntityIndex of the second entity
+ */
+ DECLARE_FUNCTION_NOSETUP(draw2)
+
+ DECLARE_FUNCTION(welcomeSophieAndRebecca)
+ DECLARE_FUNCTION(sitSophieAndRebecca)
+ DECLARE_FUNCTION(welcomeCath)
+ DECLARE_FUNCTION(function11)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION(getMessageFromAugustToTyler)
+ DECLARE_FUNCTION(sitAnna)
+ DECLARE_FUNCTION(welcomeAnna)
+ DECLARE_FUNCTION(serveTatianaVassili)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function18)
+ DECLARE_FUNCTION(function19)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(welcomeAbbot)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(messageFromAnna)
+ DECLARE_FUNCTION(function29)
+ DECLARE_FUNCTION(function30)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function33)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_PASCALE_H
diff --git a/engines/lastexpress/entities/rebecca.cpp b/engines/lastexpress/entities/rebecca.cpp
new file mode 100644
index 0000000000..e902c5f37b
--- /dev/null
+++ b/engines/lastexpress/entities/rebecca.cpp
@@ -0,0 +1,1838 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/rebecca.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Rebecca::Rebecca(LastExpressEngine *engine) : Entity(engine, kEntityRebecca) {
+ ADD_CALLBACK_FUNCTION(Rebecca, reset);
+ ADD_CALLBACK_FUNCTION(Rebecca, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Rebecca, playSound);
+ ADD_CALLBACK_FUNCTION(Rebecca, playSound16);
+ ADD_CALLBACK_FUNCTION(Rebecca, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Rebecca, draw);
+ ADD_CALLBACK_FUNCTION(Rebecca, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Rebecca, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Rebecca, enterExitCompartment3);
+ ADD_CALLBACK_FUNCTION(Rebecca, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Rebecca, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Rebecca, updateEntity);
+ ADD_CALLBACK_FUNCTION(Rebecca, updatePosition);
+ ADD_CALLBACK_FUNCTION(Rebecca, draw2);
+ ADD_CALLBACK_FUNCTION(Rebecca, function15);
+ ADD_CALLBACK_FUNCTION(Rebecca, function16);
+ ADD_CALLBACK_FUNCTION(Rebecca, function17);
+ ADD_CALLBACK_FUNCTION(Rebecca, function18);
+ ADD_CALLBACK_FUNCTION(Rebecca, function19);
+ ADD_CALLBACK_FUNCTION(Rebecca, function20);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter1);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Rebecca, function23);
+ ADD_CALLBACK_FUNCTION(Rebecca, function24);
+ ADD_CALLBACK_FUNCTION(Rebecca, function25);
+ ADD_CALLBACK_FUNCTION(Rebecca, function26);
+ ADD_CALLBACK_FUNCTION(Rebecca, function27);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter2);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Rebecca, function30);
+ ADD_CALLBACK_FUNCTION(Rebecca, function31);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter3);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Rebecca, function34);
+ ADD_CALLBACK_FUNCTION(Rebecca, function35);
+ ADD_CALLBACK_FUNCTION(Rebecca, function36);
+ ADD_CALLBACK_FUNCTION(Rebecca, function37);
+ ADD_CALLBACK_FUNCTION(Rebecca, function38);
+ ADD_CALLBACK_FUNCTION(Rebecca, function39);
+ ADD_CALLBACK_FUNCTION(Rebecca, function40);
+ ADD_CALLBACK_FUNCTION(Rebecca, function41);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter4);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Rebecca, function44);
+ ADD_CALLBACK_FUNCTION(Rebecca, function45);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter5);
+ ADD_CALLBACK_FUNCTION(Rebecca, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Rebecca, function48);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Rebecca, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(2, Rebecca, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Rebecca, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(4, Rebecca, playSound16)
+ Entity::playSound(savepoint, false, getSound()->getSoundFlag(kEntityCoudert));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIIS(5, Rebecca, callSavepoint, EntityIndex, ActionIndex)
+ Entity::callSavepoint(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(6, Rebecca, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(7, Rebecca, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(8, Rebecca, enterExitCompartment2, ObjectIndex)
+ Entity::enterExitCompartment(savepoint, kPosition_4840, kPosition_4455, kCarRedSleeping, kObjectCompartmentE, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(9, Rebecca, enterExitCompartment3, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Rebecca, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Rebecca, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(12, Rebecca, updateEntity, CarIndex, EntityPosition)
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SII(13, Rebecca, updatePosition, CarIndex, Position)
+ Entity::updatePosition(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SSI(14, Rebecca, draw2, EntityIndex)
+ Entity::draw2(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Rebecca, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isOutsideAnnaWindow())
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+
+ setCallback(1);
+ setup_enterExitCompartment2("624Ae", kObjectCompartmentE);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getObjects()->update(kObjectOutsideBetweenCompartments, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityRebecca);
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(16, Rebecca, function16, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param2) {
+ if (getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntitySophie, 750)) {
+ if (!getEntities()->hasValidFrame(kEntitySophie)) {
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction123668192);
+
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ }
+ }
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment(params->param1 ? "624Be" : "623Ee", kObjectCompartmentE);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction125242096);
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityRebecca);
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("810US");
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityRebecca, "012B");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityRebecca);
+
+ setCallback(4);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 5:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012A");
+ if (getProgress().chapter == kChapter3)
+ getSound()->playSound(kEntityRebecca, "REB3000");
+
+ getSavePoints()->push(kEntityRebecca, kEntityPascale, kAction269479296);
+
+ params->param2 = 1;
+ break;
+ }
+ break;
+
+ case kAction157370960:
+ getSavePoints()->push(kEntityRebecca, kEntityTables3, kAction136455232);
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(17, Rebecca, function17, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntitySophie, 750)
+ && !getEntities()->hasValidFrame(kEntitySophie)) {
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction123668192);
+
+ setCallback(3);
+ setup_updateFromTime(0);
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("624Be", kObjectCompartmentE);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getData()->location = kLocationOutsideCompartment;
+
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction125242096);
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntitySophie);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ if (getProgress().chapter == kChapter3)
+ getSound()->playSound(kEntityRebecca, "Reb3005", SoundManager::kFlagInvalid, 75);
+
+ if (params->param1) {
+ setCallback(5);
+ setup_updatePosition("118A", kCarRestaurant, 52);
+ } else {
+ getEntities()->updatePositionEnter(kEntityRebecca, kCarRestaurant, 57);
+
+ setCallback(6);
+ setup_draw2("107A1", "107A2", kEntitySophie);
+ }
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ getEntities()->updatePositionExit(kEntityRebecca, kCarRestaurant, 57);
+ getEntities()->clearSequences(kEntitySophie);
+
+ getData()->location = kLocationInsideCompartment;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Rebecca, function18)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntitySophie, 750)
+ || getEntities()->checkDistanceFromPosition(kEntitySophie, kPosition_4840, 500)) {
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction123668192);
+ getEntities()->exitCompartment(kEntityRebecca, kObjectCompartmentE, true);
+
+ setCallback(3);
+ setup_function15();
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_9270;
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction136654208);
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_4840);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntitySophie, 750)
+ || getEntities()->checkDistanceFromPosition(kEntitySophie, kPosition_4840, 500)) {
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction123668192);
+
+ setCallback(2);
+ setup_function15();
+ } else {
+ getEntities()->drawSequenceLeft(kEntityRebecca, "623Ge");
+ getEntities()->enterCompartment(kEntityRebecca, kObjectCompartmentE, true);
+ }
+ break;
+
+ case 2:
+ case 3:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Rebecca, function19)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntitySophie, 750)
+ || getEntities()->checkDistanceFromPosition(kEntitySophie, kPosition_4840, 500)) {
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction123668192);
+ getEntities()->exitCompartment(kEntityRebecca, kObjectCompartmentE, true);
+
+ setCallback(6);
+ setup_function15();
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_callSavepoint("012H", kEntityTables3, kActionDrawTablesWithChairs, "010M");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction337548856);
+ getEntities()->drawSequenceRight(kEntityRebecca, "810DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityRebecca);
+
+ setCallback(4);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_9270;
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction136654208);
+
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_4840);
+ break;
+
+ case 4:
+ if (getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntitySophie, 750)
+ || getEntities()->checkDistanceFromPosition(kEntitySophie, kPosition_4840, 500)) {
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction123668192);
+
+ setCallback(5);
+ setup_function15();
+ } else {
+ getEntities()->drawSequenceLeft(kEntityRebecca, "623Ge");
+ getEntities()->enterCompartment(kEntityRebecca, kObjectCompartmentE, true);
+ }
+ break;
+
+ case 5:
+ case 6:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(20, Rebecca, function20, TimeValue)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 < getState()->time && !params->param5) {
+ params->param5 = 1;
+
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (!params->param2) {
+ params->param6 = 0;
+ } else {
+ UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, 75)
+ params->param2 = 0;
+ params->param3 = 1;
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ params->param6 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (getProgress().chapter == kChapter1 && !ENTITY_PARAM(0, 3)) {
+ if (params->param7 != kTimeInvalid && getState()->time > kTime1174500) {
+ if (getState()->time <= kTime1183500) {
+ if (!getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntityPlayer, 2000) || getSound()->isBuffered("CON1210") || !params->param7)
+ params->param7 = (uint)(getState()->time);
+
+ if (params->param7 >= getState()->time)
+ goto label_callback;
+ }
+
+ params->param7 = kTimeInvalid;
+ ENTITY_PARAM(0, 3) = 1;
+
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_playSound("REB1205");
+ break;
+ }
+ goto label_callback;
+ }
+
+ if (getProgress().chapter == kChapter3 && !ENTITY_PARAM(0, 4) && params->param8 != kTimeInvalid && getState()->time > kTime2097000) {
+ if (getState()->time <= kTime2106000) {
+ if (!getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntityPlayer, 1000) || !params->param8)
+ params->param8 = (uint)getState()->time;
+
+ if (params->param8 >= getState()->time)
+ goto label_callback;
+ }
+
+ params->param8 = kTimeInvalid;
+ ENTITY_PARAM(0, 4) = 1;
+
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(2);
+ setup_playSound("REB3010");
+ break;
+ }
+
+label_callback:
+ if (ENTITY_PARAM(0, 2) && getEntities()->isDistanceBetweenEntities(kEntityRebecca, kEntityPlayer, 1000)) {
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(3);
+ setup_playSound("REB1040");
+ }
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ break;
+
+ case kActionDrawScene:
+ if (params->param3 || params->param2) {
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param2 = 0;
+ params->param3 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ if (getCallback() != 2)
+ ENTITY_PARAM(0, 2) = 0;
+
+ if (getCallback() != 3)
+ goto label_callback;
+ break;
+
+ case 4:
+ case 5:
+ if (rnd(2)) {
+ setCallback(6);
+ setup_playSound("REB1039");
+ } else {
+ setCallback(7);
+ setup_playSound(rnd(2) ? "SOP1039" : "SOP1039A");
+ }
+ break;
+
+ case 6:
+ case 7:
+ params->param4 = (getCallback() == 6 ? 0 : 1);
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param2 = 1;
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ params->param2 = 0;
+ params->param3 = 1;
+ break;
+
+ case 12:
+ setCallback(13);
+ setup_playSound16("JAC1012B");
+ break;
+
+ case 13:
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+
+ case kAction254915200:
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(12);
+ setup_playSound("REB1039A");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Rebecca, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityRebecca, kAction224253538, 0);
+
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectOutsideBetweenCompartments, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getObjects()->updateLocation2(kObject110, kObjectLocation1);
+
+ getData()->entityPosition = kPosition_2830;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+
+ ENTITY_PARAM(0, 2) = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Rebecca, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK_1(kTime1084500, params->param3, 1, setup_playSound, "REB1015");
+
+ if (params->param4 == kTimeInvalid)
+ goto label_callback_4;
+
+ if (getState()->time > kTime1080000)
+ goto label_playConversation;
+
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param4)
+ params->param4 = (uint)(getState()->time + 150);
+
+ if (params->param4 >= getState()->time) {
+label_callback_4:
+ if (params->param1) {
+ UPDATE_PARAM_CHECK(params->param5, getState()->time, 900)
+ if (getEntities()->isInSalon(kEntityPlayer)) {
+ setCallback(5);
+ setup_playSound("REB1013");
+ break;
+ }
+ }
+ }
+
+label_callback_5:
+ if (params->param2) {
+ UPDATE_PARAM(params->param6, getState()->timeTicks, 90);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
+ } else {
+ params->param6 = 0;
+ }
+ } else {
+label_playConversation:
+ params->param4 = kTimeInvalid;
+
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getProgress().field_B8 = 1;
+
+ setCallback(4);
+ setup_playSound("REB1012");
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "107B");
+ break;
+
+ case kActionDrawScene:
+ params->param2 = (getEntities()->isPlayerPosition(kCarRestaurant, 57) ? 1 : 0);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updatePosition("107C", kCarRestaurant, 57);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function18();
+ break;
+
+ case 3:
+ setup_function23();
+ break;
+
+ case 4:
+ params->param1 = 1;
+ goto label_callback_4;
+
+ case 5:
+ getProgress().field_B4 = 1;
+ params->param1 = 0;
+ goto label_callback_5;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Rebecca, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK_2(kTime1111500, params->param2, 3, setup_enterExitCompartment, "623De", kObjectCompartmentE);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateFromTime(900);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("623Ce", kObjectCompartmentE);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getEntities()->drawSequenceLeft(kEntityRebecca, "504");
+ break;
+
+ case 3:
+ case 6:
+ getEntities()->clearSequences(kEntityRebecca);
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback((byte)(getCallback() + 1));
+ setup_function20(kTime1120500);
+ break;
+
+ case 4:
+ case 5:
+ if (ENTITY_PARAM(0, 1)) {
+ setup_function24();
+ } else {
+ setCallback(5);
+ setup_function20((TimeValue)(getState()->time + 900));
+ }
+ break;
+
+ case 7:
+ case 8:
+ if (ENTITY_PARAM(0, 1)) {
+ setup_function24();
+ } else {
+ setCallback(8);
+ setup_function20((TimeValue)(getState()->time + 900));
+ }
+ break;
+ }
+ break;
+
+ case kAction285528346:
+ setCallback(6);
+ setup_enterExitCompartment("623De", kObjectCompartmentE);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Rebecca, function24)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_SAVEPOINT(kTime1134000, params->param2, kEntityRebecca, kEntityServers0, kAction223712416);
+
+ if (!params->param1)
+ break;
+
+ TIME_CHECK_CALLBACK(kTime1165500, params->param3, 6, setup_function19);
+
+ if (params->param4 != kTimeInvalid) {
+ if (getState()->time <= kTime1161000) {
+ if (!getEntities()->isInRestaurant(kEntityPlayer) || !params->param4)
+ params->param4 = (uint)getState()->time + 150;
+
+ if (params->param4 >= getState()->time)
+ break;
+ }
+
+ params->param4 = kTimeInvalid;
+
+ setCallback(7);
+ setup_playSound("REB1200A");
+ }
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16(true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012D");
+
+ setCallback(2);
+ setup_playSound("REB1199");
+ break;
+
+ case 2:
+ if (getEntities()->isInRestaurant(kEntityPlayer)) {
+ setCallback(3);
+ setup_playSound("REB1199A");
+ break;
+ }
+ // Fallback to next case
+
+ case 3:
+ if (getCallback() == 3)
+ getProgress().field_BC = 1;
+
+ if (getEntities()->isInRestaurant(kEntityAnna)) {
+ setCallback(4);
+ setup_playSound("REB1199B");
+ break;
+ }
+ // Fallback to next case
+
+ case 4:
+ setCallback(5);
+ setup_playSound("REB1199C");
+ break;
+
+ case 6:
+ setup_function25();
+ break;
+
+ case 8:
+ getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400);
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012G");
+ params->param1 = 1;
+ break;
+ }
+ break;
+
+ case kAction123712592:
+ getEntities()->drawSequenceLeft(kEntityServers0, "BLANK");
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012E");
+
+ setCallback(8);
+ setup_playSound("REB1200");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Rebecca, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(kTime1184400);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function17(false);
+ break;
+
+ case 2:
+ setup_function26();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Rebecca, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK_3(kTime1224000, params->param2, 1, setup_updatePosition, "118H", kCarRestaurant, 52);
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param3, getState()->timeTicks, 90);
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 51);
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "118D");
+ break;
+
+ case kActionDrawScene:
+ params->param1 = getEntities()->isPlayerPosition(kCarRestaurant, 52);
+ params->param3 = 0;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function18();
+ break;
+
+ case 2:
+ setup_function27();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Rebecca, function27)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getEntities()->clearSequences(kEntityRebecca);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Rebecca, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityRebecca);
+
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getObjects()->updateLocation2(kObject110, kObjectLocation2);
+
+ ENTITY_PARAM(0, 2) = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Rebecca, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(kTime1764000);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function17(false);
+ break;
+
+ case 2:
+ setup_function30();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Rebecca, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1 && params->param4 != kTimeInvalid) {
+
+ if (getState()->time <= kTimeEnd)
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param4)
+ params->param4 = (uint)getState()->time + 450;
+
+ if (params->param4 < getState()->time || getState()->time > kTimeEnd) {
+ params->param4 = kTimeInvalid;
+
+ getSound()->playSound(kEntityRebecca, "Reb2001");
+ getProgress().field_B0 = 1;
+ params->param2 = 1;
+ }
+ }
+
+ if (!params->param3 && !params->param2 && params->param5 != kTimeInvalid) {
+
+ if (getState()->time <= kTime10881000) {
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param5)
+ params->param5 = (uint)getState()->time + 450;
+
+ if (params->param5 >= getState()->time)
+ break;
+ }
+
+ params->param5 = kTimeInvalid;
+
+ getSavePoints()->push(kEntityRebecca, kEntityAugust, kAction169358379);
+ }
+ break;
+
+ case kActionEndSound:
+ params->param2 = 0;
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "107B");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function31();
+ break;
+
+ case kAction125496184:
+ setCallback(1);
+ setup_function18();
+ break;
+
+ case kAction155465152:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "BLANK");
+ break;
+
+ case kAction155980128:
+ params->param1 = 1;
+ params->param3 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Rebecca, function31)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateFromTime(900);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("623CE", kObjectCompartmentE);
+ break;
+
+ case 2:
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocation2, kCursorNormal, kCursorNormal);
+ getEntities()->drawSequenceLeft(kEntityRebecca, "504");
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Rebecca, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityRebecca);
+
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Rebecca, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(kTime2016000);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function34();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Rebecca, function34)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2 == kTimeInvalid) {
+ if (getState()->time <= kTime1386000) {
+ if (!getEntities()->isInRestaurant(kEntityPlayer) || !params->param2)
+ params->param2 = (uint)getState()->time;
+
+ if (params->param2 >= getState()->time) {
+ TIME_CHECK_CALLBACK(kTime2052000, params->param3, 1, setup_function19);
+ break;
+ }
+ }
+
+ params->param2 = kTimeInvalid;
+
+ getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction223712416);
+ }
+
+ TIME_CHECK_CALLBACK(kTime2052000, params->param3, 1, setup_function19);
+ break;
+
+ case kActionEndSound:
+ setCallback(5);
+ setup_playSound("Reb3004");
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_function16(true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012D");
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(2);
+ setup_playSound("Reb3002");
+ break;
+
+ case 3:
+ setup_function35();
+ break;
+
+ case 4:
+ getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400);
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012G");
+ params->param1 = 1;
+ break;
+ }
+ break;
+
+ case kAction123712592:
+ getEntities()->drawSequenceLeft(kEntityServers0, "BLANK");
+ getSound()->playSound(kEntityRebecca, "Reb3003");
+
+ setCallback(4);
+ setup_draw("012E");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Rebecca, function35)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(kTime2070000);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function36();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Rebecca, function36)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param2)
+ params->param2 = (uint)getState()->time + 1800;
+
+ if (params->param4 != kTimeInvalid && params->param2 < getState()->time) {
+
+ if (getState()->time <= kTime2083500) {
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param4)
+ params->param4 = (uint)getState()->time + 300;
+ }
+
+ if (params->param4 < getState()->time || getState()->time > kTime2083500) {
+ params->param4 = kTimeInvalid;
+ getSound()->playSound(kEntityRebecca, "Reb3007");
+
+ setCallback(2);
+ setup_updatePosition("118E", kCarRedSleeping, 52);
+ break;
+ }
+ }
+
+ // TODO rewrite using proper if/else blocks instead of goto
+label_callback_2:
+ if (!params->param1)
+ goto label_callback_3;
+
+ if (!params->param3)
+ params->param3 = (uint)getState()->time + 9000;
+
+ if (params->param5 == kTimeInvalid || params->param3 >= getState()->time)
+ goto label_callback_3;
+
+ if (getState()->time <= kTime2092500) {
+ if (!getEntities()->isInSalon(kEntityPlayer) || !params->param5)
+ params->param5 = (uint)getState()->time + 300;
+
+ if (params->param5 >= getState()->time) {
+label_callback_3:
+ if (getState()->time > kTime2097000 && !params->param6) {
+ params->param6 = 1;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(4);
+ setup_updatePosition("118H", kCarRestaurant, 52);
+ }
+ break;
+ }
+ }
+
+ params->param5 = kTimeInvalid;
+
+ getData()->inventoryItem = kItemNone;
+ getSound()->playSound(kEntityRebecca, "Reb3008", SoundManager::kFlagInvalid, 60);
+ getEntities()->updatePositionEnter(kEntityRebecca, kCarRestaurant, 52);
+
+ setCallback(3);
+ setup_draw2("118G1", "118G2", kEntitySophie);
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(6);
+ setup_playSound("SOP3008");
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function17(true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "118D");
+ break;
+
+ case 2:
+ params->param1 = 1;
+ getData()->inventoryItem = kItemInvalid;
+ getEntities()->drawSequenceLeft(kEntityRebecca, "118F");
+ goto label_callback_2;
+
+ case 3:
+ getEntities()->clearSequences(kEntitySophie);
+ getEntities()->updatePositionExit(kEntityRebecca, kCarRestaurant, 52);
+ getEntities()->drawSequenceLeft(kEntityRebecca, "118D");
+ goto label_callback_3;
+
+ case 4:
+ setCallback(5);
+ setup_function18();
+ break;
+
+ case 5:
+ setup_function37();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Rebecca, function37)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(kTime2110500);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function38();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Rebecca, function38)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_enterExitCompartment3("624Be", kObjectCompartmentE);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction259921280);
+
+ setCallback(2);
+ setup_updateEntity(kCarKronos, kPosition_9270);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction123668192);
+ setup_function39();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(39, Rebecca, function39)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityRebecca);
+
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_6000;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarKronos;
+ break;
+
+ case kAction191668032:
+ setup_function40();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(40, Rebecca, function40)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_9270;
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2740);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction292775040);
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_2740);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityRebecca, kEntityAnna, kAction191668032);
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_4840);
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityRebecca, kEntitySophie, kAction123668192);
+ setCallback(4);
+ setup_function15();
+ break;
+
+ case 4:
+ setup_function41();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(41, Rebecca, function41)
+ if (savepoint.action == kActionDefault) {
+ ENTITY_PARAM(0, 2) = 1;
+
+ setCallback(1);
+ setup_function20(kTimeEnd);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(42, Rebecca, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityRebecca);
+
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->updateLocation2(kObject110, kObjectLocation3);
+
+ ENTITY_PARAM(0, 1) = 0;
+ ENTITY_PARAM(0, 2) = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(43, Rebecca, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function20(kTime2385000);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1 || getCallback() == 2) {
+ if (ENTITY_PARAM(0, 1)) {
+ setup_function44();
+ } else {
+ setCallback(2);
+ setup_function20((TimeValue)(getState()->time + 900));
+ }
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(44, Rebecca, function44)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param3 != kTimeInvalid) {
+ if (getState()->time <= kTime2412000) {
+ if (!getEntities()->isInRestaurant(kEntityPlayer) || !params->param3)
+ params->param3 = (uint)getState()->time;
+
+ if (params->param3 >= getState()->time)
+ goto label_next;
+ }
+
+ params->param3 = kTimeInvalid;
+
+ getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction223712416);
+ }
+
+label_next:
+ if (params->param1 && params->param4 != kTimeInvalid) {
+ if (getState()->time <= kTime2430000) {
+ if (!getEntities()->isInRestaurant(kEntityPlayer) || !params->param4)
+ params->param4 = (uint)getState()->time + 150;
+
+ if (params->param4 >= getState()->time)
+ goto label_callback_2;
+ }
+
+ params->param4 = kTimeInvalid;
+
+ setCallback(2);
+ setup_playSound("Reb4004");
+ break;
+ }
+
+label_callback_2:
+ if (params->param2)
+ TIME_CHECK_CALLBACK(kTime2443500, params->param5, 3, setup_function19);
+ break;
+
+ case kActionEndSound:
+ if (getEntities()->isInRestaurant(kEntityPlayer)) {
+ setCallback(5);
+ setup_playSound("Reb4004");
+ break;
+ }
+
+ params->param1 = 1;
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_function16(true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012D");
+ getData()->location = kLocationInsideCompartment;
+ break;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ setup_function45();
+ break;
+
+ case 4:
+ getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400);
+ getEntities()->drawSequenceLeft(kEntityRebecca, "012G");
+ params->param2 = 1;
+ break;
+ }
+ break;
+
+ case kAction123712592:
+ getEntities()->drawSequenceLeft(kEntityRebecca, "BLANK");
+ getSound()->playSound(kEntityRebecca, "Reb4003");
+
+ setCallback(4);
+ setup_draw("012E");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(45, Rebecca, function45)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject52, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getEntities()->clearSequences(kEntityRebecca);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ params->param1 = 1;
+ break;
+
+ case kAction205034665:
+ if (!params->param1 && getState()->time < kTime2511000) {
+ setCallback(1);
+ setup_playSound("Reb6969");
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(46, Rebecca, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityRebecca);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->updateLocation2(kObject110, kObjectLocation4);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(47, Rebecca, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function48();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(48, Rebecca, function48)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ UPDATE_PARAM(params->param3, getState()->timeTicks, 75);
+
+ params->param1 = 0;
+ params->param2 = 1;
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param3 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (params->param1) {
+ params->param1 = 0;
+
+ setCallback(2);
+ setup_playSound(getSound()->justCheckingCath());
+ } else {
+ setCallback(savepoint.action == kActionKnock ? 3 : 4);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+
+ setCallback(1);
+ setup_enterExitCompartment("624AE", kObjectCompartmentE);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ params->param1 = 0;
+ params->param2 = 0;
+
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityRebecca);
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_4840;
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case 3:
+ case 4:
+ setCallback(5);
+ setup_playSound("Reb5001");
+ break;
+
+ case 5:
+ params->param1 = 1;
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorTalk, kCursorNormal);
+ break;
+ }
+ break;
+
+ case kAction135800432:
+ setup_nullfunction();
+ break;
+
+ case kAction155604840:
+ getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(49, Rebecca)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/rebecca.h b/engines/lastexpress/entities/rebecca.h
new file mode 100644
index 0000000000..bdc9fe1d3b
--- /dev/null
+++ b/engines/lastexpress/entities/rebecca.h
@@ -0,0 +1,230 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_REBECCA_H
+#define LASTEXPRESS_REBECCA_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Rebecca : public Entity {
+public:
+ Rebecca(LastExpressEngine *engine);
+ ~Rebecca() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound16, const char *filename)
+
+ /**
+ * Call a savepoint (or draw sequence in default case)
+ *
+ * @param sequence1 The sequence to draw in the default case
+ * @param entity The entity
+ * @param action The action
+ * @param sequence2 The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_4(callSavepoint, const char *sequence1, EntityIndex entity, ActionIndex action, const char *sequence2)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment3, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence1, CarIndex car, Position position)
+
+ /**
+ * Draws the entity along with another one
+ *
+ * @param sequence1 The sequence to draw
+ * @param sequence2 The sequence to draw for the second entity
+ * @param entity The EntityIndex of the second entity
+ */
+ DECLARE_FUNCTION_3(draw2, const char *sequence1, const char *sequence2, EntityIndex entity)
+
+ DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION_1(function16, bool)
+ DECLARE_FUNCTION_1(function17, bool)
+ DECLARE_FUNCTION(function18)
+ DECLARE_FUNCTION(function19)
+ DECLARE_FUNCTION_1(function20, TimeValue timeValue)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function30)
+ DECLARE_FUNCTION(function31)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function34)
+ DECLARE_FUNCTION(function35)
+ DECLARE_FUNCTION(function36)
+ DECLARE_FUNCTION(function37)
+ DECLARE_FUNCTION(function38)
+ DECLARE_FUNCTION(function39)
+ DECLARE_FUNCTION(function40)
+ DECLARE_FUNCTION(function41)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function44)
+ DECLARE_FUNCTION(function45)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function48)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_REBECCA_H
diff --git a/engines/lastexpress/entities/salko.cpp b/engines/lastexpress/entities/salko.cpp
new file mode 100644
index 0000000000..cddbc9005d
--- /dev/null
+++ b/engines/lastexpress/entities/salko.cpp
@@ -0,0 +1,642 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/salko.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/fight.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Salko::Salko(LastExpressEngine *engine) : Entity(engine, kEntitySalko) {
+ ADD_CALLBACK_FUNCTION(Salko, reset);
+ ADD_CALLBACK_FUNCTION(Salko, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Salko, draw);
+ ADD_CALLBACK_FUNCTION(Salko, updateEntity);
+ ADD_CALLBACK_FUNCTION(Salko, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Salko, savegame);
+ ADD_CALLBACK_FUNCTION(Salko, function7);
+ ADD_CALLBACK_FUNCTION(Salko, function8);
+ ADD_CALLBACK_FUNCTION(Salko, chapter1);
+ ADD_CALLBACK_FUNCTION(Salko, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Salko, function11);
+ ADD_CALLBACK_FUNCTION(Salko, chapter2);
+ ADD_CALLBACK_FUNCTION(Salko, function13);
+ ADD_CALLBACK_FUNCTION(Salko, chapter3);
+ ADD_CALLBACK_FUNCTION(Salko, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Salko, function16);
+ ADD_CALLBACK_FUNCTION(Salko, function17);
+ ADD_CALLBACK_FUNCTION(Salko, chapter4);
+ ADD_CALLBACK_FUNCTION(Salko, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Salko, function20);
+ ADD_CALLBACK_FUNCTION(Salko, function21);
+ ADD_CALLBACK_FUNCTION(Salko, function22);
+ ADD_CALLBACK_FUNCTION(Salko, chapter5);
+ ADD_CALLBACK_FUNCTION(Salko, chapter5Handler);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Salko, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(2, Salko, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(3, Salko, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(4, Salko, updateEntity, CarIndex, EntityPosition)
+ Entity::updateEntity(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(5, Salko, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(6, Salko, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(7, Salko, function7, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone: {
+ params->param3 = 0;
+
+ EntityDirection direction = getData()->direction;
+ CarIndex carSalko = getData()->car;
+ CarIndex carIvo = getEntityData(kEntityIvo)->car;
+ EntityPosition positionSalko = getData()->entityPosition;
+ EntityPosition positionIvo = getEntityData(kEntityIvo)->entityPosition;
+
+ if (getEntities()->isDistanceBetweenEntities(kEntitySalko, kEntityIvo, 500)
+ || (direction == kDirectionUp && (carSalko > carIvo || (carSalko == carIvo && positionSalko > positionIvo)))
+ || (direction == kDirectionDown && (carSalko < carIvo || (carSalko == carIvo && positionSalko < positionIvo)))) {
+ getData()->field_49B = 0;
+ params->param3 = 1;
+ }
+
+ if (!params->param3)
+ getEntities()->updateEntity(kEntitySalko, (CarIndex)params->param1, (EntityPosition)params->param2);
+
+ }
+ break;
+
+ case kActionExcuseMeCath:
+ case kActionExcuseMe:
+ getSound()->playSound(kEntityPlayer, "ZFX1002", getSound()->getSoundFlag(kEntitySalko));
+ getSound()->playSound(kEntityPlayer, "CAT1127A");
+ break;
+
+ case kActionDefault:
+ getEntities()->updateEntity(kEntitySalko, (CarIndex)params->param1, (EntityPosition)params->param2);
+ break;
+
+ case kAction123668192:
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Salko, function8)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Salko, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4691;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Salko, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ getData()->entityPosition = getEntityData(kEntityIvo)->entityPosition;
+ getData()->location = getEntityData(kEntityIvo)->location;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->clearSequences(kEntitySalko);
+ setup_function8();
+ }
+ break;
+
+ case kAction125242096:
+ setCallback(1);
+ setup_function7(kCarRedSleeping, kPosition_2740);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Salko, function11)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->clearSequences(kEntitySalko);
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Salko, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntitySalko);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+
+ case kAction136184016:
+ setCallback(1);
+ setup_function13();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Salko, function13)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("612DH", kObjectCompartmentH);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntitySalko, kEntityIvo, kAction102675536);
+ getEntities()->clearSequences(kEntitySalko);
+ break;
+
+ case 3:
+ getEntities()->drawSequenceLeft(kEntitySalko, "BLANK");
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function8();
+ break;
+ }
+ break;
+
+ case kAction125242096:
+ setCallback(3);
+ setup_function7(kCarRedSleeping, kPosition_2740);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Salko, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntitySalko);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Salko, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time < kTime2200500) {
+ UPDATE_PARAM(params->param1, getState()->time, 81000);
+
+ setCallback(1);
+ setup_function16();
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ params->param1 = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Salko, function16)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->hasValidFrame(kEntitySalko) && getEntities()->isDistanceBetweenEntities(kEntitySalko, kEntityPlayer, 5000)) {
+ getSavePoints()->push(kEntitySalko, kEntityMax, kAction158007856);
+
+ setCallback(3);
+ setup_updateFromTime(75);
+ break;
+ }
+
+label_callback3:
+ UPDATE_PARAM(params->param1, getState()->time, 4500);
+
+ getSavePoints()->push(kEntitySalko, kEntitySalko, kAction101169464);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("612DH", kObjectCompartmentH);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+
+ if (getData()->entityPosition < kPosition_2087)
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntitySalko, kEntitySalko, kAction101169464);
+ goto label_callback3;
+
+ case 4:
+ getEntities()->exitCompartment(kEntitySalko, kObjectCompartmentF, true);
+
+ setCallback(5);
+ setup_updateEntity(kCarRedSleeping, kPosition_9460);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_updateFromTime(4500);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_updateEntity(kCarRedSleeping, kPosition_2740);
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_enterExitCompartment("612Ch", kObjectCompartmentH);
+ break;
+
+ case 8:
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_2740;
+ getEntities()->clearSequences(kEntitySalko);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction101169464:
+ setCallback(4);
+ setup_enterExitCompartment("612Bf", kObjectCompartmentF);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Salko, function17)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_6470;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2740);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("612Ch", kObjectCompartmentH);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntitySalko);
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getSavePoints()->push(kEntitySalko, kEntityMilos, kAction157691176);
+
+ setup_chapter3Handler();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Salko, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntitySalko);
+
+ getData()->entityPosition = kPosition_5420;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Salko, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->drawSequenceLeft(kEntitySalko, "BLANK");
+
+ getData()->location = kLocationInsideCompartment;
+
+ setup_function20();
+ }
+ break;
+
+ case kAction125242096:
+ setCallback(1);
+ setup_function7(kCarRedSleeping, kPosition_2740);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Salko, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ if (getData()->entityPosition < kPosition_2087)
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntitySalko);
+ setup_function21();
+ break;
+ }
+ break;
+
+ case kAction55996766:
+ setCallback(1);
+ setup_enterExitCompartment("612Dh", kObjectCompartmentH);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Salko, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2422800 && !params->param1) {
+ params->param1 = 1;
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_2740);
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment("612Ch", kObjectCompartmentH);
+ break;
+
+ case 2:
+ setup_function22();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Salko, function22)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntitySalko);
+ getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_2740;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->inventoryItem = kItemNone;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Salko, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntitySalko);
+
+ getData()->entityPosition = kPosition_9460;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Salko, chapter5Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (getSound()->isBuffered("MUS050"))
+ getSound()->processEntry("MUS050");
+
+ getAction()->playAnimation(kEventCathSalkoTrainTopFight);
+
+ setCallback(2);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case 2:
+ params->param1 = getFight()->setup(kFightSalko);
+
+ if (params->param1 == Fight::kFightEndWin) {
+ getState()->time = (TimeValue)(getState()->time + 1800);
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventCathSalkoTrainTopWin);
+ } else {
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, params->param1 == Fight::kFightEndLost);
+ }
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventCathSalkoTrainTopWin);
+ getSavePoints()->push(kEntitySalko, kEntityVesna, kAction134427424);
+
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 10);
+ setup_nullfunction();
+ break;
+ }
+ break;
+
+ case kAction167992577:
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventCathSalkoTrainTopFight);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(25, Salko)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/salko.h b/engines/lastexpress/entities/salko.h
new file mode 100644
index 0000000000..f21724d88a
--- /dev/null
+++ b/engines/lastexpress/entities/salko.h
@@ -0,0 +1,149 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SALKO_H
+#define LASTEXPRESS_SALKO_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Salko : public Entity {
+public:
+ Salko(LastExpressEngine *engine);
+ ~Salko() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Draws the entity
+ *
+ * @param savepoint The savepoint
+ * - The sequence to draw
+ */
+ DECLARE_FUNCTION_NOSETUP(draw)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ DECLARE_FUNCTION_2(function7, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION(function8)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function11)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+ DECLARE_FUNCTION(function13)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function16)
+ DECLARE_FUNCTION(function17)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SALKO_H
diff --git a/engines/lastexpress/entities/servers0.cpp b/engines/lastexpress/entities/servers0.cpp
new file mode 100644
index 0000000000..1f3f85bb8f
--- /dev/null
+++ b/engines/lastexpress/entities/servers0.cpp
@@ -0,0 +1,1039 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/servers0.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+#define HANDLE_TABLE(index, param, callback, function) \
+ if (ENTITY_PARAM(index, param)) { \
+ setCallback(callback); \
+ function(); \
+ break; \
+ }
+
+Servers0::Servers0(LastExpressEngine *engine) : Entity(engine, kEntityServers0) {
+ ADD_CALLBACK_FUNCTION(Servers0, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Servers0, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Servers0, draw);
+ ADD_CALLBACK_FUNCTION(Servers0, updatePosition);
+ ADD_CALLBACK_FUNCTION(Servers0, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Servers0, playSound);
+ ADD_CALLBACK_FUNCTION(Servers0, function7);
+ ADD_CALLBACK_FUNCTION(Servers0, function8);
+ ADD_CALLBACK_FUNCTION(Servers0, function9);
+ ADD_CALLBACK_FUNCTION(Servers0, function10);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter1);
+ ADD_CALLBACK_FUNCTION(Servers0, function12);
+ ADD_CALLBACK_FUNCTION(Servers0, function13);
+ ADD_CALLBACK_FUNCTION(Servers0, function14);
+ ADD_CALLBACK_FUNCTION(Servers0, function15);
+ ADD_CALLBACK_FUNCTION(Servers0, function16);
+ ADD_CALLBACK_FUNCTION(Servers0, function17);
+ ADD_CALLBACK_FUNCTION(Servers0, function18);
+ ADD_CALLBACK_FUNCTION(Servers0, function19);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Servers0, function21);
+ ADD_CALLBACK_FUNCTION(Servers0, function22);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter2);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Servers0, function25);
+ ADD_CALLBACK_FUNCTION(Servers0, function26);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter3);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Servers0, augustAnnaDateOrder);
+ ADD_CALLBACK_FUNCTION(Servers0, function30);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter4);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Servers0, augustOrderSteak);
+ ADD_CALLBACK_FUNCTION(Servers0, augustServeDuck);
+ ADD_CALLBACK_FUNCTION(Servers0, function35);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter5);
+ ADD_CALLBACK_FUNCTION(Servers0, chapter5Handler);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIIS(1, Servers0, callSavepoint, EntityIndex, ActionIndex)
+ Entity::callSavepoint(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(2, Servers0, updateFromTime)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Servers0, draw)
+ Entity::draw(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(4, Servers0, updatePosition)
+ Entity::updatePosition(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection)
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII);
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getData()->direction != kDirectionRight)
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMeCath:
+ if (!params->param1) {
+ getSound()->excuseMe(kEntityServers0);
+ params->param1 = 1;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(6, Servers0, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Servers0, function7)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ ENTITY_PARAM(0, 3) = 0;
+
+ setCallback(1);
+ setup_draw("911");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityServers0);
+ getSavePoints()->push(kEntityServers0, kEntityRebecca, kAction123712592);
+ break;
+
+ case 2:
+ getEntities()->clearSequences(kEntityServers0);
+ getData()->entityPosition = kPosition_5900;
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction136702400:
+ setCallback(2);
+ setup_draw("913");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Servers0, function8)
+ serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "913", &ENTITY_PARAM(1, 2));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Servers0, function9)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("915");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityServers0, "029D");
+
+ setCallback(2);
+ setup_playSound(getProgress().chapter == kChapter3 ? "Abb3016" : "Abb4001");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122288808);
+
+ setCallback(3);
+ setup_draw("917");
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_5900;
+ getEntities()->clearSequences(kEntityServers0);
+ ENTITY_PARAM(2, 2) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Servers0, function10)
+ serveTable(savepoint, "916", kEntityTables4, "014E", "014F", "918", &ENTITY_PARAM(2, 3), false);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Servers0, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter1Handler();
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityServers0, kAction270410280, 0);
+ getSavePoints()->addData(kEntityServers0, kAction304061224, 1);
+ getSavePoints()->addData(kEntityServers0, kAction252568704, 10);
+ getSavePoints()->addData(kEntityServers0, kAction286534136, 11);
+ getSavePoints()->addData(kEntityServers0, kAction218983616, 12);
+ getSavePoints()->addData(kEntityServers0, kAction218586752, 13);
+ getSavePoints()->addData(kEntityServers0, kAction207330561, 14);
+ getSavePoints()->addData(kEntityServers0, kAction286403504, 16);
+ getSavePoints()->addData(kEntityServers0, kAction218128129, 17);
+ getSavePoints()->addData(kEntityServers0, kAction270068760, 18);
+ getSavePoints()->addData(kEntityServers0, kAction223712416, 2);
+ getSavePoints()->addData(kEntityServers0, kAction237485916, 5);
+ getSavePoints()->addData(kEntityServers0, kAction188893625, 8);
+ getSavePoints()->addData(kEntityServers0, kAction204704037, 6);
+ getSavePoints()->addData(kEntityServers0, kAction292758554, 7);
+ getSavePoints()->addData(kEntityServers0, kAction337548856, 9);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Servers0, function12)
+ handleServer(savepoint, "907", kEntityAnna, kAction268773672, &ENTITY_PARAM(0, 1));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Servers0, function13)
+ handleServer(savepoint, "911", kEntityAugust, kAction268773672, &ENTITY_PARAM(0, 2), "010F");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Servers0, function14)
+ handleServer(savepoint, "908", kEntityAnna, kAction170016384, &ENTITY_PARAM(0, 4));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Servers0, function15)
+ handleServer(savepoint, "912", kEntityAugust, kAction170016384, &ENTITY_PARAM(0, 5));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Servers0, function16)
+ serveTable(savepoint, "907", kEntityTables0, "001N", "001P", "909", &ENTITY_PARAM(0, 6));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Servers0, function17)
+ serveTable(savepoint, "915", kEntityTables4, "014E", "014F", "917", &ENTITY_PARAM(1, 1), true, false, 67);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Servers0, function18)
+ serveTable(savepoint, "911", kEntityTables3, "010L", "010H", "913", &ENTITY_PARAM(0, 7));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Servers0, function19)
+ serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "913", &ENTITY_PARAM(0, 8), true, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2) {
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 2700);
+ ENTITY_PARAM(0, 4) = 1;
+ params->param2 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM_PROC(params->param4, getState()->time, 4500)
+ ENTITY_PARAM(0, 5) = 1;
+ params->param1 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (!getEntities()->isInKitchen(kEntityServers0) && !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ break;
+
+ HANDLE_TABLE(0, 1, 1, setup_function12);
+ HANDLE_TABLE(0, 2, 2, setup_function13);
+ HANDLE_TABLE(0, 3, 3, setup_function7);
+ HANDLE_TABLE(0, 4, 4, setup_function14);
+ HANDLE_TABLE(0, 5, 5, setup_function15);
+ HANDLE_TABLE(0, 6, 6, setup_function16);
+ HANDLE_TABLE(1, 1, 7, setup_function17);
+ HANDLE_TABLE(0, 7, 8, setup_function18);
+ HANDLE_TABLE(0, 8, 9, setup_function19);
+ HANDLE_TABLE(1, 2, 10, setup_function8);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 10:
+ getSavePoints()->push(kEntityServers0, kEntityPascale, kAction352703104);
+ setup_function21();
+ break;
+
+ case 11:
+ case 12:
+ getEntities()->clearSequences(kEntityServers0);
+ getData()->entityPosition = kPosition_5900;
+
+ if (getCallback() == 11)
+ params->param2 = 1;
+ else
+ params->param1 = 1;
+ break;
+
+ case 13:
+ case 14:
+ getEntities()->clearSequences(kEntityServers0);
+ getData()->entityPosition = kPosition_5900;
+ break;
+ }
+ break;
+
+ case kAction136702400:
+ setCallback(savepoint.entity2 == kEntityAnna ? 13 : 14);
+ setup_draw(savepoint.entity2 == kEntityAnna ? "909" : "913");
+ break;
+
+ case kAction203859488:
+ setCallback(savepoint.entity2 == kEntityAnna ? 11 : 12);
+ setup_draw(savepoint.entity2 == kEntityAnna ? "910" : "913");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Servers0, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5900;
+ break;
+
+ case kAction101632192:
+ setup_function22();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Servers0, function22)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+
+ getEntities()->clearSequences(kEntityServers0);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Servers0, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityServers0);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes1;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Servers0, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getEntities()->isInKitchen(kEntityServers0) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ break;
+
+ HANDLE_TABLE(1, 3, 1, setup_function25);
+ HANDLE_TABLE(1, 4, 2, setup_function26);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ HANDLE_TABLE(1, 4, 2, setup_function26);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Servers0, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("957");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityServers0, kEntityAugust, kAction123712592);
+ getEntities()->drawSequenceLeft(kEntityServers0, "BLANK");
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_5900;
+ getEntities()->clearSequences(kEntityServers0);
+ ENTITY_PARAM(1, 3) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+
+ case kAction219522616:
+ setCallback(2);
+ setup_draw("959");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Servers0, function26)
+ serveTable(savepoint, "957", kEntityTables0, "016E", "016D", "959", &ENTITY_PARAM(1, 4));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Servers0, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityServers0);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes1;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ ENTITY_PARAM(1, 6) = 0;
+ ENTITY_PARAM(2, 3) = 0;
+ ENTITY_PARAM(2, 4) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Servers0, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ break;
+
+ if (ENTITY_PARAM(1, 5)) {
+ setCallback(1);
+ setup_augustAnnaDateOrder();
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(1, 6)) {
+ setCallback(2);
+ setup_function9();
+ break;
+ }
+
+label_callback_2:
+ if (ENTITY_PARAM(2, 4)) {
+ setCallback(3);
+ setup_function30();
+ break;
+ }
+
+label_callback_3:
+ if (ENTITY_PARAM(2, 3)) {
+ setCallback(4);
+ setup_function10();
+ break;
+ }
+
+label_callback_4:
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(5);
+ setup_function7();
+ break;
+ }
+
+label_callback_5:
+ if (ENTITY_PARAM(1, 2)) {
+ setCallback(6);
+ setup_function8();
+ break;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("911");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityServers0, kEntityAnna, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityServers0, "026D");
+
+ setCallback(2);
+ setup_playSound("Ann3138");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityServers0, kEntityAnna, kAction122288808);
+
+ setCallback(3);
+ setup_draw("913");
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_5900;
+ getEntities()->clearSequences(kEntityServers0);
+ ENTITY_PARAM(1, 5) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Servers0, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("916");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityServers0, "029D");
+
+ setCallback(2);
+ setup_playSound("Abb3016a");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122288808);
+
+ setCallback(3);
+ setup_draw("918");
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_5900;
+ getEntities()->clearSequences(kEntityServers0);
+ ENTITY_PARAM(2, 4) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Servers0, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityServers0);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+ ENTITY_PARAM(1, 8) = 0;
+ ENTITY_PARAM(2, 1) = 0;
+ ENTITY_PARAM(2, 2) = 0;
+ ENTITY_PARAM(2, 3) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Servers0, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM_PROC(params->param2, getState()->time, 3600)
+ ENTITY_PARAM(1, 8) = 1;
+ params->param1 = 0;
+ UPDATE_PARAM_PROC_END
+
+ if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ break;
+
+ if (ENTITY_PARAM(1, 7)) {
+ setCallback(1);
+ setup_augustOrderSteak();
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(1, 8)) {
+ setCallback(2);
+ setup_augustServeDuck();
+ break;
+ }
+
+label_callback_2:
+ if (ENTITY_PARAM(2, 1)) {
+ setCallback(3);
+ setup_function35();
+ break;
+ }
+
+label_callback_3:
+ if (ENTITY_PARAM(2, 2)) {
+ setCallback(4);
+ setup_function9();
+ break;
+ }
+
+label_callback_4:
+ if (ENTITY_PARAM(2, 3)) {
+ setCallback(5);
+ setup_function10();
+ break;
+ }
+
+label_callback_5:
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(6);
+ setup_function7();
+ break;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ params->param1 = 1;
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+ }
+ break;
+
+ case kAction201431954:
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(1, 7) = 0;
+ ENTITY_PARAM(1, 8) = 0;
+ ENTITY_PARAM(2, 1) = 0;
+ ENTITY_PARAM(2, 3) = 0;
+ params->param1 = 0;
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_draw("911");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityServers0, "010F3");
+ getEntities()->drawSequenceLeft(kEntityAugust, "010D3");
+
+ setCallback(2);
+ setup_playSound("AUG4002");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityServers0, kEntityAugust, kAction122288808);
+
+ setCallback(3);
+ setup_draw("913");
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_5900;
+ getEntities()->clearSequences(kEntityServers0);
+ ENTITY_PARAM(1, 7) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_draw("912");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityServers0, kEntityAugust, kAction122358304);
+ getSound()->playSound(kEntityServers0, "AUG1053");
+
+ setCallback(2);
+ setup_draw("010G3");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityServers0, kEntityAugust, kAction201964801);
+
+ setCallback(3);
+ setup_draw("914");
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_5900;
+ getEntities()->clearSequences(kEntityServers0);
+ ENTITY_PARAM(1, 8) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Servers0, function35)
+ serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "914", &ENTITY_PARAM(2, 1), false, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Servers0, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityServers0);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Servers0, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_nullfunction();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(38, Servers0)
+
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions
+//////////////////////////////////////////////////////////////////////////
+void Servers0::handleServer(const SavePoint &savepoint, const char *name, EntityIndex entity, ActionIndex action, uint *parameter, const char *name2) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw(name);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ // Prepare or draw sequences depending of value of string
+ if (strcmp(name2, ""))
+ getEntities()->clearSequences(kEntityServers0);
+ else
+ getEntities()->drawSequenceLeft(kEntityServers0, name2);
+
+ getSavePoints()->push(kEntityServers0, entity, action);
+ *parameter = 0;
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, bool shouldUpdatePosition, bool pushSavepoint, Position position) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (shouldUpdatePosition) {
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+ }
+
+ setCallback(1);
+ setup_draw(seq1);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (position)
+ getEntities()->updatePositionEnter(kEntityServers0, kCarRestaurant, position);
+
+ getSavePoints()->push(kEntityServers0, entity, kAction136455232);
+
+ setCallback(2);
+ setup_callSavepoint(seq2, entity, kActionDrawTablesWithChairs, seq3);
+ break;
+
+ case 2:
+ if (position)
+ getEntities()->updatePositionExit(kEntityServers0, kCarRestaurant, position);
+
+ setCallback(3);
+ setup_draw(seq4);
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_5900;
+
+ // Special case for functions 19 & 35
+ if (pushSavepoint)
+ getSavePoints()->push(kEntityServers0, kEntityRebecca, kAction224253538);
+
+ getEntities()->clearSequences(kEntityServers0);
+ *parameter = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/servers0.h b/engines/lastexpress/entities/servers0.h
new file mode 100644
index 0000000000..3e1bd21e0d
--- /dev/null
+++ b/engines/lastexpress/entities/servers0.h
@@ -0,0 +1,172 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SERVERS0_H
+#define LASTEXPRESS_SERVERS0_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Servers0 : public Entity {
+public:
+ Servers0(LastExpressEngine *engine);
+ ~Servers0() {}
+
+ /**
+ * Call a savepoint (or draw sequence in default case)
+ *
+ * @param sequence1 The sequence to draw in the default case
+ * @param entity The entity
+ * @param action The action
+ * @param sequence2 The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_4(callSavepoint, const char *sequence1, EntityIndex entity, ActionIndex action, const char *sequence2)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param savepoint The savepoint
+ * - Time to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTime)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence1, CarIndex car, Position position)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION_NOSETUP(callbackActionOnDirection)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ DECLARE_FUNCTION(function7)
+ DECLARE_FUNCTION(function8)
+ DECLARE_FUNCTION(function9)
+ DECLARE_FUNCTION(function10)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+ DECLARE_FUNCTION(function12)
+ DECLARE_FUNCTION(function13)
+ DECLARE_FUNCTION(function14)
+ DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION(function16)
+ DECLARE_FUNCTION(function17)
+ DECLARE_FUNCTION(function18)
+ DECLARE_FUNCTION(function19)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION(function26)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(augustAnnaDateOrder)
+ DECLARE_FUNCTION(function30)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(augustOrderSteak)
+ DECLARE_FUNCTION(augustServeDuck)
+ DECLARE_FUNCTION(function35)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_NULL_FUNCTION()
+
+private:
+ void handleServer(const SavePoint &savepoint, const char *name, EntityIndex entity, ActionIndex action, uint *parameter, const char *name2 = "");
+ void serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, bool shouldUpdatePosition = true, bool pushSavepoint = false, Position position = 0);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SERVERS0_H
diff --git a/engines/lastexpress/entities/servers1.cpp b/engines/lastexpress/entities/servers1.cpp
new file mode 100644
index 0000000000..1afeeab894
--- /dev/null
+++ b/engines/lastexpress/entities/servers1.cpp
@@ -0,0 +1,787 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/servers1.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Servers1::Servers1(LastExpressEngine *engine) : Entity(engine, kEntityServers1) {
+ ADD_CALLBACK_FUNCTION(Servers1, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Servers1, draw);
+ ADD_CALLBACK_FUNCTION(Servers1, updatePosition);
+ ADD_CALLBACK_FUNCTION(Servers1, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Servers1, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Servers1, playSound);
+ ADD_CALLBACK_FUNCTION(Servers1, function7);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter1);
+ ADD_CALLBACK_FUNCTION(Servers1, function9);
+ ADD_CALLBACK_FUNCTION(Servers1, function10);
+ ADD_CALLBACK_FUNCTION(Servers1, function11);
+ ADD_CALLBACK_FUNCTION(Servers1, function12);
+ ADD_CALLBACK_FUNCTION(Servers1, function13);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Servers1, function15);
+ ADD_CALLBACK_FUNCTION(Servers1, function16);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter2);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Servers1, function19);
+ ADD_CALLBACK_FUNCTION(Servers1, function20);
+ ADD_CALLBACK_FUNCTION(Servers1, function21);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter3);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Servers1, function24);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter4);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Servers1, function27);
+ ADD_CALLBACK_FUNCTION(Servers1, function28);
+ ADD_CALLBACK_FUNCTION(Servers1, function29);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter5);
+ ADD_CALLBACK_FUNCTION(Servers1, chapter5Handler);
+ ADD_NULL_FUNCTION()
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(1, Servers1, updateFromTime)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Servers1, draw)
+ Entity::draw(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SII(3, Servers1, updatePosition, CarIndex, Position)
+ Entity::updatePosition(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Servers1, callbackActionOnDirection)
+ if (savepoint.action == kActionExcuseMeCath) {
+ if (!params->param1) {
+ getSound()->excuseMe(kEntityServers1);
+ params->param1 = 1;
+ }
+ }
+
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIIS(5, Servers1, callSavepoint, EntityIndex, ActionIndex)
+ Entity::callSavepoint(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(6, Servers1, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Servers1, function7)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("924");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction122358304);
+ setCallback(2);
+ setup_draw("008C");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction122288808);
+ setCallback(2);
+ setup_draw("926");
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityServers1);
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(1, 2) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Servers1, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter1Handler();
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityServers1, kAction223002560, 0);
+ getSavePoints()->addData(kEntityServers1, kAction302996448, 2);
+ getSavePoints()->addData(kEntityServers1, kAction269485588, 3);
+ getSavePoints()->addData(kEntityServers1, kAction326144276, 4);
+ getSavePoints()->addData(kEntityServers1, kAction302203328, 5);
+ getSavePoints()->addData(kEntityServers1, kAction189688608, 6);
+ getSavePoints()->addData(kEntityServers1, kAction236237423, 7);
+ getSavePoints()->addData(kEntityServers1, kAction219377792, 8);
+ getSavePoints()->addData(kEntityServers1, kAction256200848, 9);
+ getSavePoints()->addData(kEntityServers1, kAction291721418, 10);
+ getSavePoints()->addData(kEntityServers1, kAction258136010, 11);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Servers1, function9)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("924");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityMilos, "BLANK");
+ getEntities()->drawSequenceLeft(kEntityServers1, "009B");
+
+ setCallback(2);
+ setup_playSound("WAT1001");
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityMilos, "009A");
+
+ setCallback(3);
+ setup_draw("926");
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityServers1);
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(0, 1) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Servers1, function10)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("924");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityBoutarel, "BLANK");
+ getEntities()->drawSequenceLeft(kEntityServers1, "008C");
+
+ setCallback(2);
+ setup_playSound("MRB1077");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction168717392);
+
+ setCallback(3);
+ setup_draw("926");
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityServers1);
+ getData()->entityPosition = kPosition_5900;
+ ENTITY_PARAM(0, 2) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Servers1, function11)
+ serveTable(savepoint, "919", kEntityTables1, "005H", "005J", "921", &ENTITY_PARAM(0, 3), 63);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Servers1, function12)
+ serveTable(savepoint, "923", kEntityTables2, "009F", "009G", "926", &ENTITY_PARAM(0, 4));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Servers1, function13)
+ serveTable(savepoint, "923", kEntityTables2, "009F", "009G", "926", &ENTITY_PARAM(0, 5));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Servers1, chapter1Handler)
+switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ break;
+
+ if (ENTITY_PARAM(0, 1)) {
+ setCallback(1);
+ setup_function9();
+ break;
+ }
+
+ if (ENTITY_PARAM(1, 2)) {
+ setCallback(2);
+ setup_function10();
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(3);
+ setup_function11();
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 4)) {
+ setCallback(4);
+ setup_function12();
+ break;
+ }
+
+ if (ENTITY_PARAM(0, 5)) {
+ setCallback(5);
+ setup_function13();
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 5) {
+ getSavePoints()->push(kEntityServers1, kEntityPascale, kAction352768896);
+ setup_function15();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Servers1, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5900;
+ break;
+
+ case kAction101632192:
+ setup_function16();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Servers1, function16)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+
+ getEntities()->clearSequences(kEntityServers1);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Servers1, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityServers1);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes1;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 6) = 0;
+ ENTITY_PARAM(0, 7) = 0;
+ ENTITY_PARAM(0, 8) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Servers1, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ break;
+
+ if (ENTITY_PARAM(0, 6)) {
+ setCallback(1);
+ setup_function19();
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(0, 7)) {
+ setCallback(2);
+ setup_function20();
+ break;
+ }
+
+label_callback_2:
+ if (ENTITY_PARAM(0, 8) || ENTITY_PARAM(0, 5)) {
+ setCallback(3);
+ setup_function21();
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 4:
+ getEntities()->clearSequences(kEntityServers1);
+ getData()->entityPosition = kPosition_5900;
+ break;
+ }
+ break;
+
+ case kAction101106391:
+ setCallback(4);
+ setup_draw("975");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Servers1, function19)
+ serveTable(savepoint, "969", kEntityTables1, "005H2", "018A", "971", &ENTITY_PARAM(0, 6), 63);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Servers1, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("973");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getSavePoints()->push(kEntityServers1, kEntityIvo, kAction123712592);
+ getEntities()->drawSequenceLeft(kEntityServers1, "BLANK");
+ ENTITY_PARAM(0, 7) = 0;
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Servers1, function21)
+ serveTable(savepoint, "974", kEntityTables2, "009F2", "009G", "976", &ENTITY_PARAM(0, 8), 0, true, &ENTITY_PARAM(0, 5));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Servers1, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityServers1);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes1;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(1, 1) = 0;
+ ENTITY_PARAM(1, 2) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Servers1, chapter3Handler)
+ if (savepoint.action != kActionNone)
+ return;
+
+ if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ return;
+
+ if (ENTITY_PARAM(1, 1)) {
+ setCallback(1);
+ setup_function24();
+ return;
+ }
+
+ if (ENTITY_PARAM(1, 2)) {
+ setCallback(2);
+ setup_function7();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Servers1, function24)
+ serveSalon(savepoint, "927", "Ann3143A", kEntityAnna, "Ann31444", "112C", kAction122288808, "928", &ENTITY_PARAM(1, 1));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Servers1, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityServers1);
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ getEntities()->clearSequences(kEntityServers1);
+
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param2) {
+ UPDATE_PARAM_PROC(params->param2, getState()->time, 900)
+ ENTITY_PARAM(1, 5) = 1;
+ params->param1 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+ if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ break;
+
+ if (ENTITY_PARAM(1, 5)) {
+ setCallback(2);
+ setup_function28();
+ break;
+ }
+
+ if (ENTITY_PARAM(1, 4)) {
+ setCallback(3);
+ setup_function29();
+ break;
+ }
+
+ if (ENTITY_PARAM(1, 2)) {
+ setCallback(4);
+ setup_function7();
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ params->param1 = 1;
+ break;
+
+ case kAction201431954:
+ ENTITY_PARAM(1, 2) = 0;
+ ENTITY_PARAM(1, 3) = 0;
+ ENTITY_PARAM(1, 4) = 0;
+ ENTITY_PARAM(1, 5) = 0;
+
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationOutsideCompartment;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Servers1, function27)
+ serveSalon(savepoint, "929", "", kEntityAugust, "Aug4003", "122D", kAction134486752, "930", &ENTITY_PARAM(1, 3));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Servers1, function28)
+ serveSalon(savepoint, "931", "", kEntityAugust, "Aug4004", "122E", kAction125826561, "930", &ENTITY_PARAM(1, 5));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Servers1, function29)
+ serveSalon(savepoint, "932", "", kEntityAnna, "Ann4151", "127D", kAction122288808, "930", &ENTITY_PARAM(1, 4));
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Servers1, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityServers1);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Servers1, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_nullfunction();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(32, Servers1)
+
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions
+//////////////////////////////////////////////////////////////////////////
+void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, Position position, bool shouldUpdatePosition, uint *parameter2) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ if (shouldUpdatePosition) {
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+ }
+
+ setCallback(1);
+ setup_draw(seq1);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (position)
+ getEntities()->updatePositionEnter(kEntityServers1, kCarRestaurant, position);
+
+ getSavePoints()->push(kEntityServers1, entity, kAction136455232);
+
+ setCallback(2);
+ setup_callSavepoint(seq2, entity, kActionDrawTablesWithChairs, seq3);
+ break;
+
+ case 2:
+ if (position)
+ getEntities()->updatePositionExit(kEntityServers1, kCarRestaurant, position);
+
+ setCallback(3);
+ setup_draw(seq4);
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_5900;
+ getEntities()->clearSequences(kEntityServers1);
+ *parameter = 0;
+
+ if (parameter2 != NULL)
+ *parameter2 = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+void Servers1::serveSalon(const SavePoint &savepoint, const char *seq1, const char *snd1, EntityIndex entity, const char *snd2, const char *seq2, ActionIndex action, const char *seq3, uint *parameter) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_draw("816DD");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceRight(kEntityServers1, seq1);
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityServers1);
+
+ if (!strcmp(snd1, ""))
+ getSound()->playSound(kEntityServers1, snd1);
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityServers1, entity, kAction122358304);
+
+ getSound()->playSound(kEntityServers1, snd2);
+
+ setCallback(3);
+ setup_updatePosition(seq2, kCarRestaurant, 57);
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityServers1, entity, action);
+
+ setCallback(4);
+ setup_draw(seq3);
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityServers1, "816UD");
+
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityServers1);
+
+ setCallback(5);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 5:
+ getEntities()->clearSequences(kEntityServers1);
+ getData()->entityPosition = kPosition_5900;
+ *parameter = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/servers1.h b/engines/lastexpress/entities/servers1.h
new file mode 100644
index 0000000000..14a6bf09a6
--- /dev/null
+++ b/engines/lastexpress/entities/servers1.h
@@ -0,0 +1,167 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SERVERS1_H
+#define LASTEXPRESS_SERVERS1_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Servers1 : public Entity {
+public:
+ Servers1(LastExpressEngine *engine);
+ ~Servers1() {}
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param savepoint The savepoint
+ * - Time to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTime)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence, CarIndex car, Position position)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Call a savepoint (or draw sequence in default case)
+ *
+ * @param sequence1 The sequence to draw in the default case
+ * @param entity The entity
+ * @param action The action
+ * @param sequence2 The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_4(callSavepoint, const char *sequence1, EntityIndex entity, ActionIndex action, const char *sequence2)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ DECLARE_FUNCTION(function7)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION(function9)
+ DECLARE_FUNCTION(function10)
+ DECLARE_FUNCTION(function11)
+ DECLARE_FUNCTION(function12)
+ DECLARE_FUNCTION(function13)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION(function16)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function19)
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function24)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(function28)
+ DECLARE_FUNCTION(function29)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_NULL_FUNCTION()
+
+private:
+ void serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, Position position = 0, bool updatePosition = true, uint *parameter2 = NULL);
+ void serveSalon(const SavePoint &savepoint, const char *seq1, const char *snd1, EntityIndex entity, const char *snd2, const char *seq2, ActionIndex action, const char *seq3, uint *parameter);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SERVERS1_H
diff --git a/engines/lastexpress/entities/sophie.cpp b/engines/lastexpress/entities/sophie.cpp
new file mode 100644
index 0000000000..1b2d7b92ee
--- /dev/null
+++ b/engines/lastexpress/entities/sophie.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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/sophie.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+#define CHAPTER_IMPLEMENTATION() \
+ switch (savepoint.action) { \
+ default: \
+ break; \
+ case kActionNone: \
+ setup_chaptersHandler(); \
+ break; \
+ case kActionDefault: \
+ getEntities()->clearSequences(kEntitySophie); \
+ getData()->entityPosition = kPosition_4840; \
+ getData()->location = kLocationInsideCompartment; \
+ getData()->car = kCarRedSleeping; \
+ getData()->clothes = kClothesDefault; \
+ getData()->inventoryItem = kItemNone; \
+ break; \
+ }
+
+#define DEFAULT_ACTION_IMPLEMENTATION() \
+ if (savepoint.action == kActionDefault) { \
+ getData()->entityPosition = kPosition_4840; \
+ getData()->location = kLocationInsideCompartment; \
+ getData()->car = kCarRedSleeping; \
+ getEntities()->clearSequences(kEntitySophie); \
+ }
+
+Sophie::Sophie(LastExpressEngine *engine) : Entity(engine, kEntitySophie) {
+ ADD_CALLBACK_FUNCTION(Sophie, reset);
+ ADD_CALLBACK_FUNCTION(Sophie, updateEntity);
+ ADD_CALLBACK_FUNCTION(Sophie, chaptersHandler);
+ ADD_CALLBACK_FUNCTION(Sophie, chapter1);
+ ADD_CALLBACK_FUNCTION(Sophie, function5);
+ ADD_CALLBACK_FUNCTION(Sophie, chapter2);
+ ADD_CALLBACK_FUNCTION(Sophie, chapter3);
+ ADD_CALLBACK_FUNCTION(Sophie, chapter4);
+ ADD_CALLBACK_FUNCTION(Sophie, function9);
+ ADD_CALLBACK_FUNCTION(Sophie, chapter5);
+ ADD_CALLBACK_FUNCTION(Sophie, chapter5Handler);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Sophie, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(2, Sophie, updateEntity, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone: {
+ params->param3 = 0;
+
+ // Sophie
+ byte direction = getData()->direction;
+ EntityPosition position = getData()->entityPosition;
+ CarIndex car = getData()->car;
+
+ // Rebecca
+ EntityPosition rebecca_position = getEntityData(kEntityRebecca)->entityPosition;
+ CarIndex rebeccaCar = getEntityData(kEntityRebecca)->car;
+
+ if (getEntities()->isDistanceBetweenEntities(kEntitySophie, kEntityRebecca, 500)
+ || (direction == kDirectionUp && car >= rebeccaCar && position > rebecca_position)
+ || (direction == kDirectionDown && car <= rebeccaCar && position < rebecca_position)) {
+ getData()->field_49B = 0;
+ params->param3 = 1;
+ }
+
+ if (!params->param3)
+ getEntities()->updateEntity(kEntitySophie, (CarIndex)params->param1, (EntityPosition)params->param2);
+
+ break;
+ }
+
+ case kActionExcuseMeCath:
+ getSound()->excuseMeCath();
+ break;
+
+ case kActionExcuseMe:
+ getSound()->excuseMe(kEntitySophie);
+ break;
+
+ case kActionDefault:
+ getEntities()->updateEntity(kEntitySophie, (CarIndex)params->param1, (EntityPosition)params->param2);
+ break;
+
+ case kAction123668192:
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(3, Sophie, chaptersHandler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ getData()->entityPosition = getEntityData(kEntityRebecca)->entityPosition;
+ getData()->car = getEntityData(kEntityRebecca)->car;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntitySophie);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntitySophie, "BLANK");
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntitySophie);
+ break;
+
+ case 4:
+ getEntities()->drawSequenceLeft(kEntitySophie, "BLANK");
+ break;
+ }
+ break;
+
+ case kAction125242096:
+ getData()->entityPosition = (EntityPosition)(getEntityData(kEntityRebecca)->entityPosition - 100);
+ getData()->location = getEntityData(kEntityRebecca)->location;
+ getData()->car = getEntityData(kEntityRebecca)->car;
+
+ setCallback(1);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case kAction136654208:
+ getData()->entityPosition = (EntityPosition)(getEntityData(kEntityRebecca)->entityPosition + 100);
+ getData()->location = getEntityData(kEntityRebecca)->location;
+ getData()->car = getEntityData(kEntityRebecca)->car;
+
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_4840);
+ break;
+
+ case kAction259921280:
+ getData()->entityPosition = (EntityPosition)(getEntityData(kEntityRebecca)->entityPosition + 100);
+ getData()->location = getEntityData(kEntityRebecca)->location;
+ getData()->car = getEntityData(kEntityRebecca)->car;
+
+ setCallback(3);
+ setup_updateEntity(kCarKronos, kPosition_9460);
+ break;
+
+ case kAction292775040:
+ getData()->entityPosition = kPosition_9270;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarKronos;
+
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_4840);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Sophie, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chaptersHandler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Sophie, function5)
+ DEFAULT_ACTION_IMPLEMENTATION()
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Sophie, chapter2)
+ CHAPTER_IMPLEMENTATION()
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Sophie, chapter3)
+ CHAPTER_IMPLEMENTATION()
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Sophie, chapter4)
+ CHAPTER_IMPLEMENTATION()
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Sophie, function9)
+ DEFAULT_ACTION_IMPLEMENTATION()
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Sophie, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntitySophie);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Sophie, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_nullfunction();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(12, Sophie)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/sophie.h b/engines/lastexpress/entities/sophie.h
new file mode 100644
index 0000000000..24a70188da
--- /dev/null
+++ b/engines/lastexpress/entities/sophie.h
@@ -0,0 +1,98 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SOPHIE_H
+#define LASTEXPRESS_SOPHIE_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Sophie : public Entity {
+public:
+ Sophie(LastExpressEngine *engine);
+ ~Sophie() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Handle chapters events
+ */
+ DECLARE_FUNCTION(chaptersHandler)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION(function5)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ DECLARE_FUNCTION(function9)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SOPHIE_H
diff --git a/engines/lastexpress/entities/tables.cpp b/engines/lastexpress/entities/tables.cpp
new file mode 100644
index 0000000000..eca60a536b
--- /dev/null
+++ b/engines/lastexpress/entities/tables.cpp
@@ -0,0 +1,221 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/tables.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Tables::Tables(LastExpressEngine *engine, EntityIndex id) : Entity(engine, id) {
+ _id = id;
+
+ ADD_CALLBACK_FUNCTION(Tables, chapter1);
+ ADD_CALLBACK_FUNCTION(Tables, chapter2);
+ ADD_CALLBACK_FUNCTION(Tables, chapter3);
+ ADD_CALLBACK_FUNCTION(Tables, chapter4);
+ ADD_CALLBACK_FUNCTION(Tables, chapter5);
+ ADD_CALLBACK_FUNCTION(Tables, draw);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Tables, chapter1)
+ if (savepoint.action == kActionDefault) {
+ if (_id == kEntityTables2)
+ getSound()->playSoundWithSubtitles("LOOP8A.SND", SoundManager::kFlagLoop, kEntityTables2);
+
+ setup_draw();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(2, Tables, chapter2)
+ if (savepoint.action == kActionDefault) {
+ if (_id == kEntityTables2)
+ getSound()->playSoundWithSubtitles("LOOP8A.SND", SoundManager::kFlagLoop, kEntityTables2);
+
+ setup_draw();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(3, Tables, chapter3)
+ if (savepoint.action == kActionDefault) {
+ if (_id == kEntityTables2)
+ getSound()->playSoundWithSubtitles("LOOP8A.SND", SoundManager::kFlagLoop, kEntityTables2);
+
+ setup_draw();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Tables, chapter4)
+ if (savepoint.action == kActionDefault) {
+ if (_id == kEntityTables2)
+ getSound()->playSoundWithSubtitles("LOOP8A.SND", SoundManager::kFlagLoop, kEntityTables2);
+
+ setup_draw();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Tables, chapter5)
+ if (savepoint.action == kActionDefault) {
+ if (_id == kEntityTables2 && getSound()->isBuffered(kEntityTables2))
+ getSound()->processEntry(kEntityTables2);
+
+ setup_draw();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Tables, draw)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ // Only applicable to Tables2 entity
+ if (_id != kEntityTables2)
+ break;
+
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ if (getState()->time > kTime1165500 && !params->param1) {
+ params->param1 = 1;
+ getSound()->processEntry(kEntityTables2);
+ }
+ break;
+
+ case kChapter3:
+ if (getState()->time > kTime2052000 && !params->param2) {
+ params->param2 = 1;
+ getSound()->processEntry(kEntityTables2);
+ }
+ break;
+
+ case kChapter4:
+ if (getState()->time > kTime2488500 && !params->param3) {
+ params->param3 = 1;
+ getSound()->processEntry(kEntityTables2);
+ }
+ break;
+
+ }
+ break;
+
+ case kActionDefault:
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ switch(_id) {
+ default:
+ break;
+
+ case kEntityTables0:
+ getData()->entityPosition = kPosition_3970;
+ getEntities()->drawSequenceLeft(_id, "001P");
+ break;
+
+ case kEntityTables1:
+ getData()->entityPosition = kPosition_3970;
+ getEntities()->drawSequenceLeft(_id, "005J");
+ break;
+
+ case kEntityTables2:
+ getData()->entityPosition = kPosition_4690;
+ getEntities()->drawSequenceLeft(_id, "009G");
+ break;
+
+ case kEntityTables3:
+ getData()->entityPosition = kPosition_4690;
+ getEntities()->drawSequenceLeft(_id, "010M");
+ break;
+
+ case kEntityTables4:
+ getData()->entityPosition = kPosition_5420;
+ getEntities()->drawSequenceLeft(_id, "014F");
+ break;
+
+ case kEntityTables5:
+ getData()->entityPosition = kPosition_5420;
+ getEntities()->drawSequenceLeft(_id, "024D");
+ break;
+ }
+
+ break;
+
+ case kActionDrawTablesWithChairs:
+ if (!strcmp(savepoint.param.charValue, "")) {
+ getEntities()->drawSequenceLeft(_id, savepoint.param.charValue);
+ } else {
+ switch(_id) {
+ default:
+ break;
+
+ case kEntityTables0:
+ getEntities()->drawSequenceLeft(_id, "001P");
+ break;
+
+ case kEntityTables1:
+ getEntities()->drawSequenceLeft(_id, "005J");
+ break;
+
+ case kEntityTables2:
+ getEntities()->drawSequenceLeft(_id, "009G");
+ break;
+
+ case kEntityTables3:
+ getEntities()->drawSequenceLeft(_id, "010M");
+ break;
+
+ case kEntityTables4:
+ getEntities()->drawSequenceLeft(_id, "014F");
+ break;
+
+ case kEntityTables5:
+ getEntities()->drawSequenceLeft(_id, "024D");
+ break;
+ }
+ }
+ break;
+
+ case kAction136455232:
+ getEntities()->drawSequenceLeft(_id, "BLANK");
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/backends/events/symbiansdl/symbiansdl-events.h b/engines/lastexpress/entities/tables.h
index fa1c066cae..e5fe28128b 100644
--- a/backends/events/symbiansdl/symbiansdl-events.h
+++ b/engines/lastexpress/entities/tables.h
@@ -23,37 +23,55 @@
*
*/
-#if !defined(BACKEND_EVENTS_SYMBIAN_SDL_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
-#define BACKEND_EVENTS_SYMBIAN_SDL_H
+#ifndef LASTEXPRESS_TABLES_H
+#define LASTEXPRESS_TABLES_H
-#include "backends/events/sdl/sdl-events.h"
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
-#define TOTAL_ZONES 3
+namespace LastExpress {
-/**
- * SDL events manager for Symbian
- */
-class SymbianSdlEventManager : public SdlEventManager {
+class LastExpressEngine;
+
+class Tables : public Entity {
public:
- SymbianSdlEventManager(Common::EventSource *boss);
+ Tables(LastExpressEngine *engine, EntityIndex id);
+ ~Tables() {}
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
-protected:
- // Used to handle joystick navi zones
- int _mouseXZone[TOTAL_ZONES];
- int _mouseYZone[TOTAL_ZONES];
- int _currentZone;
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
- struct zoneDesc {
- int x;
- int y;
- int width;
- int height;
- };
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
- static zoneDesc _zones[TOTAL_ZONES];
+ /**
+ * Draws tables
+ */
+ DECLARE_FUNCTION(draw)
- virtual bool remapKey(SDL_Event &ev, Common::Event &event);
+private:
+ EntityIndex _id; ///< Table entity id
};
-#endif
+} // End of namespace LastExpress
+#endif // LASTEXPRESS_TABLES_H
diff --git a/engines/lastexpress/entities/tatiana.cpp b/engines/lastexpress/entities/tatiana.cpp
new file mode 100644
index 0000000000..8e6be41ad4
--- /dev/null
+++ b/engines/lastexpress/entities/tatiana.cpp
@@ -0,0 +1,2272 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/tatiana.h"
+
+#include "lastexpress/entities/alexei.h"
+#include "lastexpress/entities/coudert.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Tatiana::Tatiana(LastExpressEngine *engine) : Entity(engine, kEntityTatiana) {
+ ADD_CALLBACK_FUNCTION(Tatiana, reset);
+ ADD_CALLBACK_FUNCTION(Tatiana, playSound);
+ ADD_CALLBACK_FUNCTION(Tatiana, draw);
+ ADD_CALLBACK_FUNCTION(Tatiana, updatePosition);
+ ADD_CALLBACK_FUNCTION(Tatiana, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Tatiana, enterExitCompartment2);
+ ADD_CALLBACK_FUNCTION(Tatiana, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Tatiana, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Tatiana, updateFromTicks);
+ ADD_CALLBACK_FUNCTION(Tatiana, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Tatiana, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Tatiana, savegame);
+ ADD_CALLBACK_FUNCTION(Tatiana, updateEntity);
+ ADD_CALLBACK_FUNCTION(Tatiana, function14);
+ ADD_CALLBACK_FUNCTION(Tatiana, function15);
+ ADD_CALLBACK_FUNCTION(Tatiana, function16);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter1);
+ ADD_CALLBACK_FUNCTION(Tatiana, function18);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Tatiana, function20);
+ ADD_CALLBACK_FUNCTION(Tatiana, function21);
+ ADD_CALLBACK_FUNCTION(Tatiana, function22);
+ ADD_CALLBACK_FUNCTION(Tatiana, function23);
+ ADD_CALLBACK_FUNCTION(Tatiana, function24);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter2);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Tatiana, function27);
+ ADD_CALLBACK_FUNCTION(Tatiana, function28);
+ ADD_CALLBACK_FUNCTION(Tatiana, function29);
+ ADD_CALLBACK_FUNCTION(Tatiana, function30);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter3);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Tatiana, function33);
+ ADD_CALLBACK_FUNCTION(Tatiana, function34);
+ ADD_CALLBACK_FUNCTION(Tatiana, function35);
+ ADD_CALLBACK_FUNCTION(Tatiana, function36);
+ ADD_CALLBACK_FUNCTION(Tatiana, function37);
+ ADD_CALLBACK_FUNCTION(Tatiana, function38);
+ ADD_CALLBACK_FUNCTION(Tatiana, function39);
+ ADD_CALLBACK_FUNCTION(Tatiana, function40);
+ ADD_CALLBACK_FUNCTION(Tatiana, function41);
+ ADD_CALLBACK_FUNCTION(Tatiana, function42);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter4);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Tatiana, function45);
+ ADD_CALLBACK_FUNCTION(Tatiana, function46);
+ ADD_CALLBACK_FUNCTION(Tatiana, function47);
+ ADD_CALLBACK_FUNCTION(Tatiana, function48);
+ ADD_CALLBACK_FUNCTION(Tatiana, function49);
+ ADD_CALLBACK_FUNCTION(Tatiana, function50);
+ ADD_CALLBACK_FUNCTION(Tatiana, function51);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter5);
+ ADD_CALLBACK_FUNCTION(Tatiana, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Tatiana, function54);
+ ADD_CALLBACK_FUNCTION(Tatiana, function55);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Tatiana, reset)
+ Entity::reset(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Tatiana, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Tatiana, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SII(4, Tatiana, updatePosition, CarIndex, Position)
+ Entity::updatePosition(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(5, Tatiana, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(6, Tatiana, enterExitCompartment2, ObjectIndex)
+ Entity::enterExitCompartment(savepoint, kPosition_7500, kPosition_7850, kCarRedSleeping, kObjectCompartmentB);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SIIS(7, Tatiana, callSavepoint, EntityIndex, ActionIndex)
+ Entity::callSavepoint(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Tatiana, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(9, Tatiana, updateFromTicks)
+ Entity::updateFromTicks(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(10, Tatiana, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Tatiana, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(12, Tatiana, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(13, Tatiana, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ if (getEvent(kEventTatianaAskMatchSpeakRussian) || getEvent(kEventTatianaAskMatch) || getEvent(kEventVassiliSeizure)) {
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1010" : "CAT1010A");
+ } else {
+ getSound()->excuseMeCath();
+ }
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Tatiana, function14)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityTatiana, kEntityCoudert, kAction326348944);
+ getEntities()->drawSequenceLeft(kEntityTatiana, getProgress().chapter == kChapter1 ? "603Fb" : "673Fb");
+ getEntities()->enterCompartment(kEntityTatiana, kObjectCompartmentB, true);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1 || getCallback() == 2) {
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentB, true);
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityTatiana);
+
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kAction69239528:
+ setCallback(getProgress().chapter == kChapter1 ? 1 : 2);
+ setup_enterExitCompartment2(getProgress().chapter == kChapter1 ? "603Db" : "673Db", kObjectCompartmentB);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Tatiana, function15)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(getProgress().chapter == kChapter1 ? 1 : 2);
+ setup_enterExitCompartment2(getProgress().chapter == kChapter1 ? "603Bb" : "673Bb", kObjectCompartmentB);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1 || getCallback() == 2) {
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityTatiana, kEntityCoudert, kAction292048641);
+
+ getEntities()->drawSequenceLeft(kEntityTatiana, getProgress().chapter == kChapter1 ? "603Fb" : "673Fb");
+ getEntities()->enterCompartment(kEntityTatiana, kObjectCompartmentB, true);
+ }
+ break;
+
+ case kAction69239528:
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentB, true);
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(16, Tatiana, function16, uint32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 < getState()->time && !params->param4) {
+ params->param4 = 1;
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param2) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+
+ params->param2 = 0;
+ params->param3 = 1;
+
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ params->param5 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (params->param2) {
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (savepoint.param.intValue == 49) {
+ setCallback(4);
+ setup_playSound(getSound()->justAMinuteCath());
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(5);
+ setup_playSound(rnd(2) ? "CAT1512" : getSound()->wrongDoorCath());
+ break;
+ }
+
+ setCallback(6);
+ setup_playSound(getSound()->wrongDoorCath());
+ } else {
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (params->param2 || params->param3) {
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ params->param2 = 0;
+ params->param3 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound(rnd(2) ? "TAT1133A" : "TAT1133B");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param2 = 1;
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ params->param2 = 0;
+ params->param3 = 1;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Tatiana, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityTatiana, kAction191198209, 0);
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject41, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getData()->entityPosition = kPosition_5419;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Tatiana, function18)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+
+ if (getState()->time > kTime1143000 && !params->param2) {
+ params->param2 = 1;
+ getEntities()->drawSequenceRight(kEntityTatiana, "806DS");
+ params->param1 = 1;
+ }
+
+ if (!params->param1) {
+ UPDATE_PARAM_PROC(params->param3, getState()->time, 4500)
+ getEntities()->drawSequenceRight(kEntityTatiana, "806DS");
+ params->param1 = 1;
+ UPDATE_PARAM_PROC_END
+ }
+ }
+
+ if (getData()->entityPosition <= kPosition_2330) {
+ getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction157159392);
+ getEntities()->clearSequences(kEntityTatiana);
+
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionExitCompartment:
+ getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction188784532);
+
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ if (getEntities()->isInSalon(kEntityPlayer)) {
+ getEntities()->drawSequenceRight(kEntityTatiana, "806DS");
+ params->param1 = 1;
+ } else {
+ getEntities()->clearSequences(kEntityTatiana);
+ }
+ break;
+
+ case kActionDrawScene:
+ if (!params->param1 && getEntities()->isInSalon(kEntityPlayer)) {
+ getEntities()->drawSequenceRight(kEntityTatiana, "806DS");
+ getEntities()->updateFrame(kEntityTatiana);
+ params->param1 = 1;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Tatiana, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getSound()->isBuffered(kEntityTatiana) || !params->param4 || params->param3 == 2 || getSound()->isBuffered("TAT1066"))
+ goto label_tatiana_chapter1_2;
+
+ UPDATE_PARAM_PROC(params->param5, getState()->timeTicks, 450)
+ getSound()->playSound(kEntityTatiana, params->param3 ? "TAT1069B" : "TAT1069A");
+ getProgress().field_64 = 1;
+ params->param3++;
+ params->param5 = 0;
+ UPDATE_PARAM_PROC_END
+
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 71)) {
+ UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, 75)
+ getSound()->playSound(kEntityTatiana, params->param3 ? "TAT1069B" : "TAT1069A");
+ getProgress().field_64 = 1;
+ params->param3++;
+ params->param6 = 0;
+ UPDATE_PARAM_PROC_END
+ }
+
+label_tatiana_chapter1_2:
+ TIME_CHECK_SAVEPOINT(kTime1084500, params->param7, kEntityTatiana, kEntityPascale, kAction257489762);
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param8, getState()->timeTicks, 90);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
+ } else {
+ params->param8 = 0;
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityTatiana, kEntityTables4, kAction136455232);
+ getEntities()->drawSequenceLeft(kEntityTatiana, "014A");
+ break;
+
+ case kActionDrawScene:
+ params->param1 = getEntities()->isPlayerPosition(kCarRestaurant, 67) ? 1 : 0;
+ params->param4 = getEntities()->isPlayerPosition(kCarRestaurant, 69)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 70)
+ || getEntities()->isPlayerPosition(kCarRestaurant, 71);
+ break;
+
+ case kAction122288808:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "014A");
+ break;
+
+ case kAction122358304:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "BLANK");
+ break;
+
+ case kAction124973510:
+ setup_function20();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Tatiana, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getSavePoints()->push(kEntityTatiana, kEntityAugust, kAction223183000);
+ getEntities()->updatePositionEnter(kEntityTatiana, kCarRestaurant, 67);
+ getSound()->playSound(kEntityTatiana, "TAT1070");
+
+ setCallback(2);
+ setup_callSavepoint("014C", kEntityTables4, kActionDrawTablesWithChairs, "014D");
+ break;
+
+ case 2:
+ getEntities()->updatePositionExit(kEntityTatiana, kCarRestaurant, 67);
+ getSavePoints()->push(kEntityTatiana, kEntityServers0, kAction188893625);
+
+ setCallback(3);
+ setup_function18();
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityTatiana, kEntityAugust, kAction268620864);
+ setup_function21();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Tatiana, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->clothes = kClothes1;
+
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_8513);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->clothes = kClothesDefault;
+
+ getSound()->playSound(kEntityTatiana, "TAT1071");
+ getEntities()->drawSequenceRight(kEntityTatiana, "604Aa");
+ getEntities()->enterCompartment(kEntityTatiana, kObjectCompartmentA);
+
+ getData()->location = kLocationInsideCompartment;
+
+ if (getEntities()->checkFields19(kEntityPlayer, kCarRedSleeping, kPosition_7850)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(kObjectCompartmentA, true);
+ }
+
+ setCallback(2);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 2:
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentA);
+
+ getData()->location = kLocationInsideCompartment;
+
+ getEntities()->clearSequences(kEntityTatiana);
+ getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction135854208);
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ // Fallback to next case
+
+ case 3:
+ if (getSound()->isBuffered(kEntityTatiana)) {
+ setCallback(3);
+ setup_updateFromTime(75);
+ } else {
+ setCallback(4);
+ setup_playSound("TAT1071A");
+ }
+ break;
+
+ case 4:
+ getData()->entityPosition = kPosition_7500;
+
+ getSavePoints()->push(kEntityTatiana, kEntityVassili, kAction168459827);
+
+ setCallback(5);
+ setup_function16(kTime1156500);
+ break;
+
+ case 5:
+ case 6:
+ if (getProgress().field_14 == 29) {
+ setCallback(6);
+ setup_function16((uint)getState()->time + 900);
+ } else {
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ setup_function22();
+ }
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Tatiana, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 == kTimeInvalid || getState()->time <= kTime1179000)
+ goto label_update;
+
+ UPDATE_PARAM_PROC_TIME(kTime1233000, ((!getEvent(kEventTatianaAskMatchSpeakRussian) && !getEvent(kEventTatianaAskMatch)) || getEntities()->isInGreenCarEntrance(kEntityPlayer)), params->param1, 0)
+label_update:
+ if (!getEvent(kEventTatianaAskMatchSpeakRussian)
+ && !getEvent(kEventTatianaAskMatch)
+ && getInventory()->hasItem(kItemMatchBox)
+ && getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getObjects()->update(kObject25, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorForward);
+ getObjects()->update(kObjectTrainTimeTable, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorForward);
+ }
+ UPDATE_PARAM_PROC_END
+
+ params->param1 = kTimeInvalid;
+
+ getObjects()->update(kObject25, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectTrainTimeTable, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getEntities()->updatePositionExit(kEntityTatiana, kCarGreenSleeping, 70);
+ getEntities()->updatePositionExit(kEntityTatiana, kCarGreenSleeping, 71);
+
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityTatiana);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 72);
+ }
+
+ getData()->inventoryItem = kItemNone;
+
+ setup_function23();
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(4);
+ setup_savegame(kSavegameTypeEvent, kEventTatianaGivePoem);
+ break;
+
+ case kActionOpenDoor:
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventTatianaAskMatchSpeakRussian);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityTatiana, kEntityVassili, kAction122732000);
+
+ setCallback(1);
+ setup_function15();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+ break;
+
+ case 2:
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityTatiana);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 72);
+ }
+
+ getEntities()->drawSequenceLeft(kEntityTatiana, "306B");
+ getEntities()->updatePositionEnter(kEntityTatiana, kCarGreenSleeping, 70);
+ getEntities()->updatePositionEnter(kEntityTatiana, kCarGreenSleeping, 71);
+ break;
+
+ case 3:
+ getAction()->playAnimation(getEvent(kEventAlexeiSalonVassili) ? kEventTatianaAskMatchSpeakRussian : kEventTatianaAskMatch);
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 62);
+ getData()->inventoryItem = kItemParchemin;
+
+ getObjects()->update(kObject25, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectTrainTimeTable, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ break;
+
+ case 4:
+ getAction()->playAnimation(kEventTatianaGivePoem);
+ getInventory()->removeItem(kItemParchemin);
+ getScenes()->processScene();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Tatiana, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function14();
+ break;
+
+ case 2:
+ setup_function24();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Tatiana, function24)
+ if (savepoint.action == kActionDefault) {
+
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObject25, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getObjects()->update(kObjectTrainTimeTable, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getEntities()->updatePositionExit(kEntityTatiana, kCarGreenSleeping, 70);
+ getEntities()->updatePositionExit(kEntityTatiana, kCarGreenSleeping, 71);
+ getEntities()->clearSequences(kEntityTatiana);
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject41, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Tatiana, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityTatiana);
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject41, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+
+ getData()->entityPosition = kPosition_5420;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes2;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Tatiana, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime1800000 && params->param1 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->inventoryItem = kItemNone;
+ setup_function28();
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+ setup_function28();
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "024A");
+ getSavePoints()->push(kEntityTatiana, kEntityTables5, kAction136455232);
+ getData()->inventoryItem = kItemInvalid;
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 64) || getEntities()->isPlayerPosition(kCarRestaurant, 65)) {
+ getData()->inventoryItem = kItemNone;
+ setup_function27();
+ }
+ break;
+
+ case kAction290869168:
+ params->param1 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Tatiana, function27)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(getEvent(kEventTatianaGivePoem) ? 1 : 2);
+ setup_savegame(kSavegameTypeEvent, getEvent(kEventTatianaGivePoem) ? kEventTatianaBreakfastAlexei : kEventTatianaBreakfast);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_function30);
+ getAction()->playAnimation(kEventTatianaBreakfastAlexei);
+ getInventory()->addItem(kItemParchemin);
+ getInventory()->setLocationAndProcess(kItem11, kObjectLocation1);
+ setup_function28();
+ break;
+
+ case 2:
+ RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_function30);
+ getAction()->playAnimation(kEventTatianaBreakfast);
+ if (getInventory()->hasItem(kItemParchemin)) {
+ getAction()->playAnimation(kEventTatianaBreakfastGivePoem);
+ getInventory()->removeItem(kItemParchemin);
+ } else {
+ getAction()->playAnimation(kEventTatianaAlexei);
+ }
+ setup_function28();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Tatiana, function28)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->inventoryItem = kItemNone;
+ getData()->location = kLocationOutsideCompartment;
+
+ getSavePoints()->push(kEntityTatiana, kEntityTables5, kActionDrawTablesWithChairs, "024D");
+ getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction236053296, (getEvent(kEventTatianaBreakfastAlexei) || getEvent(kEventTatianaBreakfast)) ? 69 : 0);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function29();
+ break;
+
+ case kAction123857088:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "018G");
+
+ setCallback(1);
+ setup_updateFromTime(1800);
+ break;
+
+ case kAction156444784:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->drawSequenceLeft(kEntityTatiana, "BLANK");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Tatiana, function29)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getEntities()->updatePositionEnter(kEntityTatiana, kCarRestaurant, 63);
+
+ setCallback(2);
+ setup_callSavepoint("018H", kEntityTables1, kActionDrawTablesWithChairs, "018A");
+ break;
+
+ case 2:
+ getEntities()->updatePositionExit(kEntityTatiana, kCarRestaurant, 63);
+ getSavePoints()->push(kEntityTatiana, kEntityServers1, kAction302203328);
+ getEntities()->drawSequenceRight(kEntityTatiana, "805DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityTatiana);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ setup_function30();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Tatiana, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_function14();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function16(kTimeEnd);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Tatiana, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityTatiana);
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_1750;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothes2;
+ getData()->inventoryItem = kItemNone;
+
+ // Update inventory
+ getInventory()->get(kItemFirebird)->location = kObjectLocation2;
+
+ if (getEvent(kEventTatianaBreakfastGivePoem) || (getEvent(kEventTatianaGivePoem) && !getEvent(kEventTatianaBreakfastAlexei)))
+ getInventory()->get(kItemParchemin)->location = kObjectLocation2;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Tatiana, chapter3Handler)
+ EntityData::EntityParametersI5S *parameters = (EntityData::EntityParametersI5S*)_data->getCurrentParameters();
+ EntityData::EntityParametersSIII *parameters1 = (EntityData::EntityParametersSIII*)_data->getCurrentParameters(1);
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!parameters->param2 && !parameters->param5) {
+ parameters->param1 -= getState()->timeDelta;
+
+ if (getState()->timeDelta > parameters->param1) {
+
+ getEntities()->drawSequenceLeft(kEntityTatiana, (char *)&parameters1->seq);
+ getSound()->playSound(kEntityTatiana, (char *)&parameters->seq);
+
+ if (parameters->param3 == 4 && getEntities()->isInSalon(kEntityPlayer))
+ getProgress().field_90 = 1;
+
+ parameters->param2 = 1;
+ }
+ }
+
+ if (parameters->param4 && parameters->param5) {
+ UPDATE_PARAM_CHECK(parameters->param4, getState()->time, 6300)
+ if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_updatePosition("110E", kCarRestaurant, 52);
+ }
+ }
+ }
+ break;
+
+ case kActionEndSound:
+ parameters->param2 = 0;
+ ++parameters->param3;
+
+ switch (parameters->param3) {
+ default:
+ parameters->param5 = 1;
+ break;
+
+ case 1:
+ parameters->param1 = 900;
+ getEntities()->drawSequenceLeft(kEntityTatiana, "110A");
+ strcpy((char *)&parameters->seq, "Tat3160B");
+ strcpy((char *)&parameters1->seq, "110A");
+ break;
+
+ case 2:
+ parameters->param1 = 9000;
+ strcpy((char *)&parameters->seq, "Tat3160C");
+ strcpy((char *)&parameters1->seq, "110C");
+ break;
+
+ case 3:
+ parameters->param1 = 13500;
+ getEntities()->drawSequenceLeft(kEntityTatiana, "110B");
+ strcpy((char *)&parameters->seq, "Tat3160D");
+ strcpy((char *)&parameters1->seq, "110D");
+ break;
+
+ case 4:
+ parameters->param1 = 9000;
+ getEntities()->drawSequenceLeft(kEntityTatiana, "110B");
+ strcpy((char *)&parameters->seq, "Tat3160E");
+ strcpy((char *)&parameters1->seq, "110D");
+ break;
+
+ case 5:
+ parameters->param1 = 4500;
+ getEntities()->drawSequenceLeft(kEntityTatiana, "110B");
+ strcpy((char *)&parameters->seq, "Tat3160G");
+ strcpy((char *)&parameters1->seq, "110D");
+ break;
+
+ case 6:
+ parameters->param1 = 4500;
+ getEntities()->drawSequenceLeft(kEntityTatiana, "110B");
+ strcpy((char *)&parameters->seq, "Tat3160B");
+ break;
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction122358304);
+ getSavePoints()->push(kEntityTatiana, kEntityKronos, kAction157159392);
+ getEntities()->drawSequenceLeft(kEntityTatiana, "110C");
+ getSound()->playSound(kEntityTatiana, "Tat3160A");
+
+ parameters->param2 = 1;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction122288808);
+ setup_function33();
+ }
+ break;
+
+ case kAction101169422:
+ parameters->param4 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Tatiana, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityTatiana);
+ setCallback(1);
+ setup_updateFromTime(75);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function14();
+ break;
+
+ case 3:
+ setup_function34();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Tatiana, function34)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16(kTime2097000);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getInventory()->get(kItemFirebird)->location = kObjectLocation1;
+ if (getEntities()->checkFields19(kEntityPlayer, kCarRedSleeping, kPosition_7850))
+ getScenes()->loadSceneFromObject(kObjectCompartmentB);
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ setup_function15();
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_updateEntity(kCarKronos, kPosition_9270);
+ break;
+
+ case 3:
+ setup_function35();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Tatiana, function35)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1
+ && getInventory()->hasItem(kItemFirebird)
+ && getEntities()->checkFields19(kEntityPlayer, kCarRedSleeping, kPosition_7850)
+ && (getState()->time < kTime2133000 || getProgress().field_40)) {
+ setCallback(1);
+ setup_function41();
+ break;
+ }
+
+label_callback_1:
+ if (getState()->time > kTime2133000) {
+ if (getData()->car >= kCarRedSleeping || (getData()->car == kCarGreenSleeping && getData()->entityPosition > kPosition_5790))
+ setup_function36();
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getEntities()->clearSequences(kEntityTatiana);
+
+ getData()->car = kCarKronos;
+ getData()->entityPosition = kPosition_6000;
+ getData()->location = kLocationInsideCompartment;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ params->param1 = 1;
+ goto label_callback_1;
+ }
+ break;
+
+ case kAction191668032:
+ setup_function36();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Tatiana, function36)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_850;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_7500);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ if (!getEntities()->checkFields19(kEntityPlayer, kCarGreenSleeping, kPosition_7850) || getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
+ setCallback(2);
+ setup_function14();
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemFirebird)) {
+ getAction()->playAnimation(kEventTatianaCompartmentStealEgg);
+ getInventory()->removeItem(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation2;
+ } else {
+ getAction()->playAnimation(kEventTatianaCompartment);
+ }
+
+ getScenes()->loadSceneFromObject(kObjectCompartmentB);
+ break;
+
+ case 2:
+ setup_function37();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Tatiana, function37)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getInventory()->get(kItemFirebird)->location != kObjectLocation1 && getInventory()->get(kItemFirebird)->location != kObjectLocation2) {
+ if(!params->param3)
+ params->param3 = (uint)getState()->time + 900;
+
+ if (params->param4 != kTimeInvalid && params->param3 < getState()->time) {
+ UPDATE_PARAM_PROC_TIME(kTime2227500, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param4, 450)
+ getProgress().field_5C = 1;
+ if (getEntities()->isInsideCompartment(kEntityAnna, kCarRedSleeping, kPosition_4070)) {
+ setup_function38();
+ break;
+ }
+ UPDATE_PARAM_PROC_END
+ }
+ }
+
+ if (params->param1) {
+ UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ params->param1 = 0;
+ params->param2 = 1;
+ }
+
+ params->param5 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (params->param1) {
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ if (savepoint.param.intValue == 49) {
+ setCallback(4);
+ setup_playSound(getSound()->justAMinuteCath());
+ break;
+ }
+
+ if (getInventory()->hasItem(kItemPassengerList)) {
+ setCallback(5);
+ setup_playSound(rnd(2) ? "CAT1512" : getSound()->wrongDoorCath());
+ break;
+ }
+
+ setCallback(6);
+ setup_playSound(getSound()->wrongDoorCath());
+ break;
+ }
+
+ if (savepoint.param.intValue == 49) {
+
+ if (getInventory()->hasItem(kItemFirebird)) {
+ getAction()->playAnimation(kEventTatianaCompartmentStealEgg);
+ getInventory()->removeItem(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation2;
+ } else {
+ getAction()->playAnimation(kEventTatianaCompartment);
+ }
+
+ getScenes()->loadSceneFromObject(kObjectCompartmentB);
+ break;
+ }
+
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorHand);
+
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityTatiana);
+ break;
+
+ case kActionDrawScene:
+ if (params->param1 || params->param2) {
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorHand);
+
+ params->param1 = 0;
+ params->param2 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound(rnd(2) ? "TAT1133A" : "TAT1133B");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorTalk, kCursorNormal);
+ getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorTalk, kCursorNormal);
+ params->param1 = 1;
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ params->param1 = 0;
+ params->param2 = 1;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Tatiana, function38)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->time, 450);
+
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentF, true);
+
+ setCallback(4);
+ setup_function42(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case kActionDefault:
+ getData()->clothes = kClothes3;
+
+ setCallback(1);
+ setup_enterExitCompartment("673Jb", kObjectCompartmentB);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(2);
+ setup_function42(kCarRedSleeping, kPosition_4070);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "673Gf");
+ getEntities()->enterCompartment(kEntityTatiana, kObjectCompartmentF, true);
+
+ setCallback(3);
+ setup_playSound("Tat3164");
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityTatiana, kEntityAnna, kAction236241630);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment2("673Db", kObjectCompartmentB);
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityTatiana);
+
+ setup_function39();
+ break;
+
+ case 6:
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentF, true);
+ getEntities()->clearSequences(kEntityTatiana);
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(7);
+ setup_playSound("ANN3011");
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_updateFromTime(900);
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_enterExitCompartment("673Jf", kObjectCompartmentF);
+ break;
+
+ case 9:
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(10);
+ setup_function42(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case 10:
+ getSavePoints()->push(kEntityTatiana, kEntityAnna, kAction236517970);
+
+ setCallback(11);
+ setup_enterExitCompartment2("673Db", kObjectCompartmentB);
+ break;
+
+ case 11:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityTatiana);
+
+ setup_function39();
+ break;
+ }
+ break;
+
+ case kAction100906246:
+ setCallback(6);
+ setup_enterExitCompartment("673Df", kObjectCompartmentF);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(39, Tatiana, function39)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1 && getEntities()->isDistanceBetweenEntities(kEntityTatiana, kEntityPlayer, 1000)) {
+ params->param1 = 1;
+ getSound()->playSound(kEntityTatiana, "Tat3164"); // Tatiana weeping
+ }
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(40, Tatiana, function40)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)
+ || getData()->car != getEntityData(kEntityPlayer)->car
+ || getEntities()->updateEntity(kEntityTatiana, kCarKronos, kPosition_9270))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMe:
+ if (getEvent(kEventTatianaAskMatchSpeakRussian) || getEvent(kEventTatianaAskMatch) || getEvent(kEventVassiliSeizure))
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT1001A" : "CAT1010");
+ else
+ getSound()->excuseMeCath();
+ break;
+
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityTatiana, kCarKronos, kPosition_9270))
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(41, Tatiana, function41)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1)
+ break;
+
+ if (getEntities()->checkFields19(kEntityPlayer, kCarRedSleeping, kPosition_7850)
+ && !getEvent(kEventVassiliCompartmentStealEgg)
+ && (getState()->time <= kTime2133000 || getProgress().field_40)) {
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_7500)) {
+
+ getSavePoints()->push(kEntityTatiana, kEntityCoudert, kAction235061888);
+ getEntities()->clearSequences(kEntityTatiana);
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentB, true);
+ getData()->location = kLocationInsideCompartment;
+
+ if (getInventory()->hasItem(kItemFirebird)) {
+ getAction()->playAnimation(kEventTatianaCompartmentStealEgg);
+ getInventory()->removeItem(kItemFirebird);
+ getInventory()->get(kItemFirebird)->location = kObjectLocation2;
+ } else {
+ getAction()->playAnimation(kEventTatianaCompartment);
+ }
+
+ getScenes()->loadSceneFromObject(kObjectCompartmentB);
+
+ setCallback(4);
+ setup_updateFromTime(150);
+ }
+ } else {
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentB, true);
+
+ if (getState()->time < kTime2133000 || getProgress().field_40) {
+ setCallback(3);
+ setup_function40();
+ break;
+ }
+
+ getEntities()->clearSequences(kEntityTatiana);
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationOutsideCompartment;
+
+ RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_function51);
+
+ getEntities()->drawSequenceLeft(kEntityTatiana, "673Fb");
+ getEntities()->enterCompartment(kEntityTatiana, kObjectCompartmentB, true);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_playSound("Tat3161B");
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityTatiana, kEntityCoudert, kAction168316032);
+ params->param1 = 1;
+ break;
+
+ case 3:
+ case 6:
+ getEntities()->clearSequences(kEntityTatiana);
+
+ CALLBACK_ACTION();
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function15();
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function40();
+ break;
+ }
+ break;
+
+ case kAction154071333:
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(42, Tatiana, function42, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath || savepoint.action == kActionExcuseMe) {
+ getSound()->playSound(kEntityPlayer, "Tat3124", getSound()->getSoundFlag(kEntityTatiana));
+ return;
+ }
+
+ Entity::updateEntity(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(43, Tatiana, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityTatiana);
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothes2;
+ getData()->inventoryItem = kItemNone;
+
+ ENTITY_PARAM(0, 1) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(44, Tatiana, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function16(kTime2362500);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function45();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(45, Tatiana, function45)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("673Bb", kObjectCompartmentB);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+ break;
+
+ case 2:
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityTatiana);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 72);
+ }
+
+ getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction123712592);
+ setup_function46();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(46, Tatiana, function46)
+ // Expose parameters as IIIIIS and ignore the default exposed parameters
+ EntityData::EntityParametersI5S *parameters = (EntityData::EntityParametersI5S*)_data->getCurrentParameters();
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!parameters->param2 && !parameters->param3) {
+ parameters->param1 -= getState()->timeDelta;
+
+ if (parameters->param1 < getState()->timeDelta) {
+ getSound()->playSound(kEntityTatiana, (char *)&parameters->seq);
+
+ if (getEntities()->isDistanceBetweenEntities(kEntityTatiana, kEntityPlayer, 2000)) {
+ if (parameters->param4 == 4)
+ getProgress().field_8C = 1;
+ else if (parameters->param4 == 7)
+ getProgress().field_88 = 1;
+ }
+
+ parameters->param2 = 1;
+ }
+ }
+
+ if (CURRENT_PARAM(1, 1) == kTimeInvalid || getState()->time <= kTime2394000)
+ break;
+
+ if (getState()->time >= kTime2398500) {
+ CURRENT_PARAM(1, 1) = kTimeInvalid;
+ } else {
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer) || !CURRENT_PARAM(1, 1))
+ CURRENT_PARAM(1, 1) = (uint)getState()->time;
+
+ if (CURRENT_PARAM(1, 1) >= getState()->time)
+ break;
+
+ CURRENT_PARAM(1, 1) = kTimeInvalid;
+ }
+
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->excuseMe(kEntityTatiana);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62))
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 72);
+ }
+
+ getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction123536024);
+
+ setup_function47();
+ break;
+
+ case kActionEndSound:
+ parameters->param2 = 0;
+ ++parameters->param4;
+
+ switch(parameters->param4) {
+ default:
+ parameters->param1 = 162000;
+ break;
+
+ case 1:
+ parameters->param1 = 900;
+ strcpy((char *)&parameters->seq, "Tat4165F");
+ break;
+
+ case 2:
+ parameters->param1 = 900;
+ strcpy((char *)&parameters->seq, "Tat4165B");
+ break;
+
+ case 3:
+ parameters->param1 = 1800;
+ strcpy((char *)&parameters->seq, "Tat4165G");
+ break;
+
+ case 4:
+ parameters->param1 = 900;
+ strcpy((char *)&parameters->seq, "Tat4165H");
+ break;
+
+ case 5:
+ parameters->param1 = 2700;
+ strcpy((char *)&parameters->seq, "Tat4165C");
+ break;
+
+ case 6:
+ parameters->param1 = 900;
+ strcpy((char *)&parameters->seq, "Tat4165D");
+ break;
+
+ case 7:
+ parameters->param1 = 900;
+ strcpy((char *)&parameters->seq, "Tat4165E");
+ break;
+ }
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "306E");
+ parameters->param1 = 450;
+ strcpy((char *)&parameters->seq, "Tat4165A");
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer)) {
+ parameters->param3 = 1;
+
+ if (parameters->param2) {
+ getSound()->removeFromQueue(kEntityTatiana);
+ getSavePoints()->call(kEntityTatiana, kEntityTatiana, kActionEndSound);
+ }
+ } else {
+ parameters->param3 = 0;
+ parameters->param5 = 0;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 62) && !parameters->param5) {
+ setCallback(1);
+ setup_draw("306D");
+ }
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->drawSequenceLeft(kEntityTatiana, "306E");
+ parameters->param5 = 1;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(47, Tatiana, function47)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRedSleeping, kPosition_7500);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment2("673Db", kObjectCompartmentB);
+ break;
+
+ case 2:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityTatiana);
+
+ setCallback(3);
+ setup_function16(kTime2407500);
+ break;
+
+ case 3:
+ case 4:
+ if (ENTITY_PARAM(0, 1) && getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) {
+ setup_function48();
+ } else {
+ setCallback(4);
+ setup_function16(900);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(48, Tatiana, function48)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ if (!getEvent(kEventTatianaTylerCompartment) && getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_8200)) {
+ params->param1 = 1;
+ getProgress().field_E4 = 1;
+ getObjects()->update(kObjectCompartment1, kEntityTatiana, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorHand);
+ }
+
+ if (!params->param1)
+ goto label_end;
+ }
+
+ if (!getEntities()->checkFields19(kEntityPlayer, kCarGreenSleeping, kPosition_7850)) {
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+ params->param1 = 0;
+ }
+
+ if (!params->param1 || getSound()->isBuffered(kEntityTatiana))
+ goto label_end;
+
+ UPDATE_PARAM_GOTO(params->param2, getState()->timeTicks, 5 * (3 * rnd(5) + 30), label_end);
+
+ getSound()->playSound(kEntityTatiana, "LIB012", SoundManager::kFlagDefault);
+ params->param2 = 0;
+
+label_end:
+ if (getEvent(kEventTatianaTylerCompartment) || getState()->time > kTime2475000) {
+ if (params->param1)
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+
+ getProgress().field_E4 = 0;
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartment2, true);
+
+ setCallback(3);
+ setup_updateEntity(kCarRedSleeping, kPosition_7500);
+ }
+ break;
+
+ case kActionOpenDoor:
+ params->param1 = 0;
+
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventTatianaTylerCompartment);
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("673Bb", kObjectCompartmentB);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_7500);
+ break;
+
+ case 2:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "673Fb");
+ getEntities()->enterCompartment(kEntityTatiana, kObjectCompartment2, true);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_enterExitCompartment2("673Db", kObjectCompartmentB);
+ break;
+
+ case 4:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityTatiana);
+
+ setup_function49();
+ break;
+
+ case 5:
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ getAction()->playAnimation(kEventTatianaTylerCompartment);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getScenes()->loadScene(kScene41);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_updateEntity(kCarGreenSleeping, kPosition_7500);
+ break;
+
+ case 7:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "673Fb");
+ getEntities()->enterCompartment(kEntityTatiana, kObjectCompartment2, true);
+ break;
+ }
+ break;
+
+ case kAction238790488:
+ params->param1 = 0;
+
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
+ getEntities()->exitCompartment(kEntityTatiana, kObjectCompartment2, true);
+ getEntities()->clearSequences(kEntityTatiana);
+
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_9460;
+
+ setCallback(6);
+ setup_updateFromTime(1800);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(49, Tatiana, function49)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_7500;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kAction169360385:
+ setup_function50();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(50, Tatiana, function50)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2520000 && !params->param1) {
+ params->param1 = 1;
+ setup_function51();
+ }
+ break;
+
+ case kActionEndSound:
+ getSound()->playSound(kEntityTatiana, "Tat4166");
+ break;
+
+ case kActionKnock:
+ if (!getSound()->isBuffered("LIB012", true))
+ getSound()->playSound(kEntityPlayer, "LIB012");
+ break;
+
+ case kActionOpenDoor:
+ getSound()->playSound(kEntityPlayer, "LIB014");
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventVassiliDeadAlexei);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject48, kEntityTatiana, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartmentA, kEntityTatiana, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ if (!getSound()->isBuffered(kEntityTatiana))
+ getSound()->playSound(kEntityTatiana, "Tat4166");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (getSound()->isBuffered("MUS013"))
+ getSound()->processEntry("MUS013");
+
+ getAction()->playAnimation(kEventVassiliDeadAlexei);
+ getSavePoints()->push(kEntityTatiana, kEntityAbbot, kAction104060776);
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 38);
+
+ setup_function51();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(51, Tatiana, function51)
+ if (savepoint.action == kActionDefault) {
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ getObjects()->update(kObject48, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(52, Tatiana, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityTatiana);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(53, Tatiana, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function54();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(54, Tatiana, function54)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param2) {
+ switch (params->param1) {
+ default:
+ break;
+
+ case 0:
+ getSound()->playSound(kEntityTatiana, "Tat5167A");
+ params->param2 = 1;
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityTatiana, "Tat5167B");
+ params->param2 = 1;
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityTatiana, "Tat5167C");
+ params->param2 = 1;
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityTatiana, "Tat5167D");
+ params->param2 = 1;
+ break;
+ }
+ }
+
+ if (params->param1 > 3) {
+ UPDATE_PARAM(params->param3, getState()->timeTicks, 225);
+
+ params->param1 = 0;
+ params->param3 = 0;
+ }
+ break;
+
+ case kAction1:
+ getData()->inventoryItem = kItemNone;
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventTatianaVassiliTalk);
+ break;
+
+ case kActionEndSound:
+ ++params->param1;
+ params->param2 = 0;
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "033A");
+ getData()->inventoryItem = kItemInvalid;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (getSound()->isBuffered("MUS050"))
+ getSound()->processEntry("MUS050");
+
+ if (getSound()->isBuffered(kEntityTatiana))
+ getSound()->processEntry(kEntityTatiana);
+
+ getAction()->playAnimation(isNight() ? kEventTatianaVassiliTalkNight : kEventTatianaVassiliTalk);
+ getScenes()->processScene();
+
+ params->param1 = 4;
+ params->param2 = 0;
+ params->param3 = 0;
+ }
+ break;
+
+ case kAction203078272:
+ getEntities()->drawSequenceLeft(kEntityTatiana, "033E");
+ break;
+
+ case kAction236060709:
+ getData()->inventoryItem = kItemNone;
+ setup_function55();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(55, Tatiana, function55)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityTatiana);
+ // fall back to next action
+
+ case kActionDrawScene:
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 72))
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 86);
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/tatiana.h b/engines/lastexpress/entities/tatiana.h
new file mode 100644
index 0000000000..171f7d62d3
--- /dev/null
+++ b/engines/lastexpress/entities/tatiana.h
@@ -0,0 +1,235 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_TATIANA_H
+#define LASTEXPRESS_TATIANA_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Tatiana : public Entity {
+public:
+ Tatiana(LastExpressEngine *engine);
+ ~Tatiana() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates the position
+ *
+ * @param sequence1 The sequence to draw
+ * @param car The car
+ * @param position The position
+ */
+ DECLARE_FUNCTION_3(updatePosition, const char *sequence1, CarIndex car, Position position)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Handles entering/exiting a compartment and updates position/play animation
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment2, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Call a savepoint (or draw sequence in default case)
+ *
+ * @param sequence1 The sequence to draw in the default case
+ * @param entity The entity
+ * @param action The action
+ * @param sequence2 The sequence name for the savepoint
+ */
+ DECLARE_FUNCTION_4(callSavepoint, const char *sequence1, EntityIndex entity, ActionIndex action, const char *sequence2)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Updates parameter 2 using ticks value
+ *
+ * @param savepoint The savepoint
+ * - ticks to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTicks)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION(function14)
+ DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION_1(function16, uint32)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION(function18)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(function24)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(function28)
+ DECLARE_FUNCTION(function29)
+ DECLARE_FUNCTION(function30)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(function34)
+ DECLARE_FUNCTION(function35)
+ DECLARE_FUNCTION(function36)
+ DECLARE_FUNCTION(function37)
+ DECLARE_FUNCTION(function38)
+ DECLARE_FUNCTION(function39)
+ DECLARE_FUNCTION(function40)
+ DECLARE_FUNCTION(function41)
+
+ /**
+ * ???
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(function42, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function45)
+ DECLARE_FUNCTION(function46)
+ DECLARE_FUNCTION(function47)
+ DECLARE_FUNCTION(function48)
+ DECLARE_FUNCTION(function49)
+ DECLARE_FUNCTION(function50)
+ DECLARE_FUNCTION(function51)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function54)
+ DECLARE_FUNCTION(function55)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_TATIANA_H
diff --git a/engines/lastexpress/entities/train.cpp b/engines/lastexpress/entities/train.cpp
new file mode 100644
index 0000000000..b3aa6e9a66
--- /dev/null
+++ b/engines/lastexpress/entities/train.cpp
@@ -0,0 +1,575 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/train.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savegame.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/state.h"
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Train::Train(LastExpressEngine *engine) : Entity(engine, kEntityTrain) {
+ ADD_CALLBACK_FUNCTION(Train, savegame);
+ ADD_CALLBACK_FUNCTION(Train, chapter1);
+ ADD_CALLBACK_FUNCTION(Train, chapter2);
+ ADD_CALLBACK_FUNCTION(Train, chapter3);
+ ADD_CALLBACK_FUNCTION(Train, chapter4);
+ ADD_CALLBACK_FUNCTION(Train, chapter5);
+ ADD_CALLBACK_FUNCTION(Train, harem);
+ ADD_CALLBACK_FUNCTION(Train, process);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(1, Train, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(2, Train, chapter1)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(3, Train, chapter2)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Train, chapter3)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Train, chapter4)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Train, chapter5)
+ if (savepoint.action == kActionDefault)
+ setup_process();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(7, Train, harem, ObjectIndex, uint32)
+ if (savepoint.action != kActionDefault)
+ return;
+
+ switch (params->param1) {
+ default:
+ error("Train::harem: Invalid value for parameter 1: %d", params->param1);
+ break;
+
+ case kObjectCompartment5:
+ params->param3 = kPosition_4840;
+ break;
+
+ case kObjectCompartment6:
+ params->param3 = kPosition_4070;
+ break;
+
+ case kObjectCompartment7:
+ params->param3 = kPosition_3050;
+ break;
+
+ case kObjectCompartment8:
+ params->param3 = kPosition_2740;
+ break;
+ }
+
+ params->param4 = getEntities()->isInsideCompartment(kEntityAlouan, kCarGreenSleeping, (EntityPosition)params->param3);
+ params->param5 = (ENTITY_PARAM(0, 7) - params->param3) < 1 ? true : false;
+ params->param6 = getEntities()->isInsideCompartment(kEntityYasmin, kCarGreenSleeping, (EntityPosition)params->param3);
+ params->param7 = getEntities()->isInsideCompartment(kEntityHadija, kCarGreenSleeping, (EntityPosition)params->param3);
+
+ getObjects()->update((ObjectIndex)params->param1, kEntityTrain, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ // Knock / closed door sound
+ getSound()->playSound(kEntityTables5, (params->param2 == 8) ? "LIB012" : "LIB013", SoundManager::kFlagDefault);
+
+ if (params->param4 && params->param5) {
+
+ ENTITY_PARAM(0, 5)++;
+
+ switch (ENTITY_PARAM(0, 5)) {
+ default:
+ params->param8 = 1;
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityTables5, "Har1014", SoundManager::kFlagDefault, 15);
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityTables5, "Har1013", SoundManager::kFlagDefault, 15);
+ getSound()->playSound(kEntityTables5, "Har1016", SoundManager::kFlagDefault, 150);
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityTables5, "Har1015A", SoundManager::kFlagDefault, 15);
+ getSound()->playSound(kEntityTables5, "Har1015", SoundManager::kFlagDefault, 150);
+ break;
+ }
+
+ // Update progress
+ getProgress().field_DC = 1;
+ getProgress().field_E0 = 1;
+
+ handleCompartmentAction();
+
+ // Done with it!
+ return;
+ }
+
+ if (params->param6 && params->param7) {
+
+ ENTITY_PARAM(0, 6)++;
+
+ switch(ENTITY_PARAM(0, 6)) {
+ default:
+ params->param8 = 1;
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityTables5, "Har1014", SoundManager::kFlagDefault, 15);
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityTables5, "Har1013", SoundManager::kFlagDefault, 15);
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityTables5, "Har1013A", SoundManager::kFlagDefault, 15);
+ break;
+ }
+
+ handleCompartmentAction();
+ return;
+ }
+
+ if (!params->param5) {
+
+ if (params->param6) {
+ ENTITY_PARAM(0, 3)++;
+
+ switch(ENTITY_PARAM(0, 3)) {
+ default:
+ params->param8 = 1;
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityTables5, "Har1012", SoundManager::kFlagDefault, 15);
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityTables5, "Har1012A", SoundManager::kFlagDefault, 15);
+ break;
+ }
+
+ handleCompartmentAction();
+ return;
+ } else {
+
+ if (params->param4) {
+ ENTITY_PARAM(0, 1)++;
+
+ if (ENTITY_PARAM(0, 1) <= 1)
+ getSound()->playSound(kEntityTables5, "Har1014", SoundManager::kFlagDefault, 15);
+ else
+ params->param8 = 1;
+
+ getProgress().field_DC = 1;
+
+ handleCompartmentAction();
+ return;
+ }
+
+ if (params->param7) {
+ ENTITY_PARAM(0, 4)++;
+
+ if (ENTITY_PARAM(0, 4) <= 1) {
+ getSound()->playSound(kEntityTables5, "Har1011", SoundManager::kFlagDefault, 15);
+ handleCompartmentAction();
+ return;
+ }
+ }
+ }
+
+ params->param8 = 1;
+ handleCompartmentAction();
+ return;
+ }
+
+ ENTITY_PARAM(0, 2) += 1;
+
+ switch (ENTITY_PARAM(0, 2)) {
+ default:
+ params->param8 = 1;
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityTables5, "Har1013", SoundManager::kFlagDefault, 15);
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityTables5, "Har1013A", SoundManager::kFlagDefault, 15);
+ break;
+ }
+
+ getProgress().field_E0 = 1;
+
+ handleCompartmentAction();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Train, process)
+ EntityData::EntityParametersIIIS *params1 = (EntityData::EntityParametersIIIS*)_data->getCurrentParameters(1);
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ // Play smoke animation
+ if ((getEntities()->isPlayerInCar(kCarGreenSleeping) || getEntities()->isPlayerInCar(kCarRedSleeping))
+ && params->param4 && !params->param5) {
+
+ params->param4 -= 1;
+
+ if (!params->param4 && getProgress().jacket == kJacketGreen) {
+
+ getAction()->playAnimation(isNight() ? kEventCathSmokeNight : kEventCathSmokeDay);
+ params->param5 = 1;
+ getScenes()->processScene();
+ }
+ }
+
+ if (params->param6) {
+ UPDATE_PARAM_GOTO(params1->param7, getState()->time, 900, label_process);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 58);
+ }
+
+ params1->param7 = 0;
+
+label_process:
+ if (params->param7) {
+ if (!params1->param8) {
+ params1->param8 = (uint)(getState()->time + 4500);
+
+ if (!params1->param8)
+ params->param7 = 0;
+ }
+
+ if (params1->param8 && params1->param8 < getState()->time) {
+ params->param7 = 0;
+ params1->param8 = 0;
+ }
+ }
+
+ // Update object
+ if (ENTITY_PARAM(0, 8) && !getSound()->isBuffered(kEntityTables5)) {
+ getObjects()->update((ObjectIndex)ENTITY_PARAM(0, 8), getObjects()->get((ObjectIndex)ENTITY_PARAM(0, 8)).entity, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ ENTITY_PARAM(0, 8) = 0;
+ }
+
+ // Play clock sound
+ if (params->param6 && !getSound()->isBuffered("ZFX1001", true))
+ getSound()->playSound(kEntityPlayer, "ZFX1001");
+
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor: {
+ // Handle opening harem compartments
+ ObjectIndex compartment = (ObjectIndex)savepoint.param.intValue;
+ if (compartment == kObjectCompartment5 || compartment == kObjectCompartment6 || compartment == kObjectCompartment7 || compartment == kObjectCompartment8) {
+ setCallback(savepoint.action == kActionKnock ? 3 : 4);
+ setup_harem(compartment, savepoint.action);
+ }
+ break;
+ }
+
+ case kActionDefault:
+ params->param3 = 1;
+ if (getProgress().chapter < kChapter5) {
+ getObjects()->update(kObjectCompartment5, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment6, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment7, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment8, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ }
+ getData()->entityPosition = kPosition_30000;
+ break;
+
+ case kActionDrawScene:
+ getData()->car = getEntityData(kEntityPlayer)->car;
+
+ // Play clock sound
+ if (getEntities()->isPlayerPosition(kCarRestaurant, 81)) {
+ params->param6 = 1;
+ if (!getSound()->isBuffered("ZFX1001"))
+ getSound()->playSound(kEntityPlayer, "ZFX1001");
+ } else {
+ params->param6 = 0;
+ if (getSound()->isBuffered("ZFX1001", true))
+ getSound()->removeFromQueue("ZFX1001");
+ }
+
+ // Draw moving background behind windows
+ if (params->param3) {
+ if (getEntityData(kEntityPlayer)->car != (CarIndex)params->param1 || isNight() != (bool)(params->param2)) {
+ switch (getEntityData(kEntityPlayer)->car) {
+ default:
+ getEntities()->clearSequences(kEntityTrain);
+ break;
+
+ case kCarBaggageRear:
+ case kCarBaggage:
+ if (getProgress().isNightTime)
+ getEntities()->drawSequenceLeft(kEntityTrain, "B1WNM");
+ else
+ getEntities()->drawSequenceLeft(kEntityTrain, isNight() ? "B1WNN" : "B1WND");
+ break;
+
+ case kCarGreenSleeping:
+ case kCarRedSleeping:
+ if (getProgress().isNightTime)
+ getEntities()->drawSequenceLeft(kEntityTrain, "S1WNM");
+ else
+ getEntities()->drawSequenceLeft(kEntityTrain, isNight() ? "S1WNN" : "S1WND");
+ break;
+
+ case kCarRestaurant:
+ getEntities()->drawSequenceLeft(kEntityTrain, isNight() ? "RCWNN" : "RCWND");
+ break;
+ }
+
+ // Set parameters so we do not get called twice
+ params->param1 = getEntityData(kEntityPlayer)->car;
+ params->param2 = isNight();
+ }
+ }
+
+ if (!params->param5) {
+ params->param4 = 2700; // this is the sound file name
+ params->param5 = 0;
+ }
+
+ if (getProgress().jacket == kJacketBlood) {
+ if (getEntities()->isPlayerPosition(kCarRedSleeping, 18)) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
+ break;
+ }
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 22)) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket);
+ break;
+ }
+ }
+
+ resetParam8();
+ break;
+
+
+ case kActionCallback: {
+ int action = getCallback();
+ switch(action) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ getAction()->playAnimation(action == 1 ? kEventCoudertBloodJacket : kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
+ resetParam8();
+ break;
+
+ case 5:
+ getAction()->playAnimation(kEventLocomotiveConductorsDiscovered);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice2, true);
+ break;
+
+ case 6:
+ getAction()->playAnimation(kEventCathBreakCeiling);
+ getObjects()->update(kObjectCeiling, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ getScenes()->processScene();
+ break;
+
+ case 7:
+ getAction()->playAnimation(kEventCathJumpDownCeiling);
+ getScenes()->loadSceneFromPosition(kCarKronos, 89);
+ break;
+
+ case 8:
+ getAction()->playAnimation(kEventCloseMatchbox);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 51);
+ break;
+ }
+ break;
+ }
+
+ case kAction191070912:
+ ENTITY_PARAM(0, 7) = savepoint.param.intValue;
+ break;
+
+ case kActionTrainStopRunning:
+ params->param3 = 0;
+ getEntities()->clearSequences(kEntityTrain);
+ break;
+
+ case kActionCatchBeetle:
+ setCallback(8);
+ setup_savegame(kSavegameTypeEvent, kEventCloseMatchbox);
+ break;
+
+ case kAction203339360:
+ if (params->param7) {
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventLocomotiveConductorsDiscovered);
+ } else {
+ params->param7 = 1;
+ getAction()->playAnimation(kEventLocomotiveConductorsLook);
+ getScenes()->loadSceneFromPosition(kCarCoalTender, 2);
+ }
+ break;
+
+ case kActionTrainStartRunning:
+ if (!params->param3) {
+ params->param1 = 0;
+ params->param3 = 1;
+ getSavePoints()->push(kEntityTrain, kEntityTrain, kActionDrawScene);
+ }
+ break;
+
+ case kAction203863200:
+ if (!strcmp(savepoint.param.charValue, "")) {
+ params->param8 = 1;
+ strcpy((char *)&params1->seq, savepoint.param.charValue); // this is the sound file name
+ }
+ break;
+
+ case kAction222746496:
+ switch(savepoint.param.intValue) {
+ default:
+ break;
+
+ case kObjectCompartment1:
+ case kObjectCompartment2:
+ case kObjectCompartmentA:
+ case kObjectCompartmentB:
+ params1->param1 = (savepoint.param.intValue == kObjectCompartment1 || savepoint.param.intValue == kObjectCompartment2) ? kCarGreenSleeping : kCarRedSleeping;
+ params1->param2 = (savepoint.param.intValue == kObjectCompartment1 || savepoint.param.intValue == kObjectCompartmentA) ? kPosition_8200 : kPosition_7500;
+ params1->param3 = kPosition_7850;
+ break;
+
+ case kObjectCompartment3:
+ case kObjectCompartment4:
+ case kObjectCompartmentC:
+ case kObjectCompartmentD:
+ params1->param1 = (savepoint.param.intValue == kObjectCompartment1 || savepoint.param.intValue == kObjectCompartment2) ? kCarGreenSleeping : kCarRedSleeping;
+ params1->param2 = (savepoint.param.intValue == kObjectCompartment3 || savepoint.param.intValue == kObjectCompartmentC) ? kPosition_6470 : kPosition_5790;
+ params1->param3 = kPosition_6130;
+ break;
+
+ case kObjectCompartment5:
+ case kObjectCompartment6:
+ case kObjectCompartmentE:
+ case kObjectCompartmentF:
+ params1->param1 = (savepoint.param.intValue == kObjectCompartment1 || savepoint.param.intValue == kObjectCompartment2) ? kCarGreenSleeping : kCarRedSleeping;
+ params1->param2 = (savepoint.param.intValue == kObjectCompartment5 || savepoint.param.intValue == kObjectCompartmentE) ? kPosition_4840 : kPosition_4070;
+ params1->param3 = kPosition_4455;
+ break;
+
+ case kObjectCompartment7:
+ case kObjectCompartment8:
+ case kObjectCompartmentG:
+ case kObjectCompartmentH:
+ params1->param1 = (savepoint.param.intValue == kObjectCompartment1 || savepoint.param.intValue == kObjectCompartment2) ? kCarGreenSleeping : kCarRedSleeping;
+ params1->param2 = (savepoint.param.intValue == kObjectCompartment7 || savepoint.param.intValue == kObjectCompartmentG) ? kPosition_3050 : kPosition_2740;
+ params1->param3 = kPositionNone;
+ break;
+ }
+ break;
+
+ case kActionBreakCeiling:
+ setCallback(6);
+ setup_savegame(kSavegameTypeEvent, kEventCathBreakCeiling);
+ break;
+
+ case kActionJumpDownCeiling:
+ setCallback(7);
+ setup_savegame(kSavegameTypeEvent, kEventCathJumpDownCeiling);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions
+//////////////////////////////////////////////////////////////////////////
+void Train::handleCompartmentAction() {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII)
+
+ if (params->param8)
+ getSavePoints()->push(kEntityTrain, kEntityMahmud, kAction290410610, params->param1);
+
+ getAction()->handleOtherCompartment((ObjectIndex)params->param1, false, !params->param8);
+
+ ENTITY_PARAM(0, 8) = params->param1;
+
+ CALLBACK_ACTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+void Train::resetParam8() {
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII)
+ EntityData::EntityParametersIIIS *params1 = (EntityData::EntityParametersIIIS*)_data->getCurrentParameters(1);
+
+ if (params->param8
+ && !getEntities()->isInsideCompartment(kEntityPlayer, (CarIndex)params1->param1, (EntityPosition)params1->param2)
+ && !getEntities()->isInsideCompartment(kEntityPlayer, (CarIndex)params1->param1, (EntityPosition)params1->param3)) {
+
+ if (getSound()->isBuffered((const char *)&params1->seq))
+ getSound()->processEntry((const char *)&params1->seq);
+
+ params->param8 = 0;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/train.h b/engines/lastexpress/entities/train.h
new file mode 100644
index 0000000000..95cb0f28bd
--- /dev/null
+++ b/engines/lastexpress/entities/train.h
@@ -0,0 +1,95 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_TRAIN_H
+#define LASTEXPRESS_TRAIN_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Train : public Entity {
+public:
+ Train(LastExpressEngine *engine);
+ ~Train() {}
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Harem events
+ *
+ * @param compartment The compartment to handle
+ * @param counter ??? (checked to decide which sound to make when knocking)
+ */
+ DECLARE_FUNCTION_2(harem, ObjectIndex compartment, uint32 counter)
+
+ /**
+ * Handles Train events
+ */
+ DECLARE_FUNCTION(process)
+
+private:
+ // Helper methods
+ void resetParam8();
+ void handleCompartmentAction();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_TRAIN_H
diff --git a/engines/lastexpress/entities/vassili.cpp b/engines/lastexpress/entities/vassili.cpp
new file mode 100644
index 0000000000..64327c2534
--- /dev/null
+++ b/engines/lastexpress/entities/vassili.cpp
@@ -0,0 +1,589 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/vassili.h"
+
+#include "lastexpress/entities/anna.h"
+#include "lastexpress/entities/coudert.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Vassili::Vassili(LastExpressEngine *engine) : Entity(engine, kEntityVassili) {
+ ADD_CALLBACK_FUNCTION(Vassili, reset);
+ ADD_CALLBACK_FUNCTION(Vassili, draw);
+ ADD_CALLBACK_FUNCTION(Vassili, savegame);
+ ADD_CALLBACK_FUNCTION(Vassili, chapter1);
+ ADD_CALLBACK_FUNCTION(Vassili, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Vassili, function6);
+ ADD_CALLBACK_FUNCTION(Vassili, function7);
+ ADD_CALLBACK_FUNCTION(Vassili, function8);
+ ADD_CALLBACK_FUNCTION(Vassili, function9);
+ ADD_CALLBACK_FUNCTION(Vassili, seizure);
+ ADD_CALLBACK_FUNCTION(Vassili, drawInBed);
+ ADD_CALLBACK_FUNCTION(Vassili, chapter2);
+ ADD_CALLBACK_FUNCTION(Vassili, sleeping);
+ ADD_CALLBACK_FUNCTION(Vassili, chapter3);
+ ADD_CALLBACK_FUNCTION(Vassili, stealEgg);
+ ADD_CALLBACK_FUNCTION(Vassili, chapter4);
+ ADD_CALLBACK_FUNCTION(Vassili, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Vassili, chapter5);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Vassili, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Vassili, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(3, Vassili, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(4, Vassili, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObject40, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(5, Vassili, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1) {
+ getData()->entityPosition = getEntityData(kEntityTatiana)->entityPosition;
+ getData()->location = getEntityData(kEntityTatiana)->location;
+ } else {
+ if (params->param3 && params->param3 >= getState()->time) {
+ break;
+ }else {
+ params->param3 = (uint)getState()->time + 450;
+ if (params->param3 == 0)
+ break;
+ }
+
+ if (!params->param2 && getObjects()->get(kObjectCompartmentA).location == kObjectLocation1) {
+ params->param2 = 1;
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ }
+ break;
+ }
+ break;
+
+ case kActionDefault:
+ params->param1 = 1;
+ break;
+
+ case kAction122732000:
+ setup_function6();
+ break;
+
+ case kAction168459827:
+ params->param1 = 0;
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Vassili, function6)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
+ UPDATE_PARAM_GOTO(params->param3, getState()->timeTicks, params->param1, label_function7);
+
+ setCallback(1);
+ setup_draw("303B");
+ break;
+ }
+
+ params->param3 = 0;
+
+ if (params->param2)
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+
+label_function7:
+ if (params->param4 != kTimeInvalid && getState()->time > kTime1489500) {
+
+ if (getState()->time <= kTime1503000) {
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200) || !params->param4) {
+
+ params->param4 = (uint)getState()->time;
+ if (!params->param4) {
+ setup_function7();
+ break;
+ }
+ }
+
+ if (params->param4 >= getState()->time)
+ break;
+ }
+
+ params->param4 = kTimeInvalid;
+ setup_function7();
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ params->param1 = 5 * (3 * rnd(25) + 15);
+
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->drawSequenceLeft(kEntityVassili, "303C");
+ params->param1 = 5 * (3 * rnd(25) + 15);
+ params->param2 = 1;
+
+ // Shared part with kActionNone
+ goto label_function7;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Vassili, function7)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param1 != kTimeInvalid && getState()->time > kTime1503000) {
+
+ if (getState()->time <= kTime1512000) {
+ if (getEntities()->isPlayerInCar(kCarRedSleeping) || !params->param1) {
+ params->param1 = (uint)getState()->time + 150;
+ if (params->param1) {
+ setup_function8();
+ break;
+ }
+ }
+
+ if (params->param1 >= getState()->time)
+ break;
+ }
+
+ params->param1 = kTimeInvalid;
+ setup_function8();
+ }
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->clearSequences(kEntityVassili);
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200))
+ getScenes()->loadSceneFromObject(kObjectCompartmentA);
+
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kAction339669520:
+ setup_function9();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Vassili, function8)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ setup_function9();
+ break;
+
+ case kActionDefault:
+ if (!getEntities()->isInsideTrainCar(kEntityPlayer, kCarRedSleeping)) {
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, (getEntityData(kEntityPlayer)->car <= kCarRedSleeping) ? 1 : 40);
+ }
+
+ getSavePoints()->push(kEntityVassili, kEntityAnna, kAction226031488);
+ getSavePoints()->push(kEntityVassili, kEntityVerges, kAction226031488);
+ getSavePoints()->push(kEntityVassili, kEntityCoudert, kAction226031488);
+ getSound()->playSound(kEntityVassili, "VAS1027", SoundManager::kFlagDefault);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Vassili, function9)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionEndSound:
+ if (!getEntities()->isDistanceBetweenEntities(kEntityVassili, kEntityPlayer, 2500))
+ getSound()->playSound(kEntityPlayer, "BUMP");
+
+ setup_seizure();
+ break;
+
+ case kActionDefault:
+ case kActionDrawScene:
+ if ((getObjects()->get(kObjectCompartmentA).location == kObjectLocation2 && getEntities()->isPlayerPosition(kCarRedSleeping, 17))
+ || getEntities()->isPlayerPosition(kCarRedSleeping, 18)
+ || getEntities()->isPlayerPosition(kCarRedSleeping, 37)
+ || getEntities()->isPlayerPosition(kCarRedSleeping, 38)
+ || getEntities()->isPlayerPosition(kCarRedSleeping, 41)) {
+
+ if (savepoint.action == kActionDrawScene)
+ getSound()->processEntry(kEntityVassili);
+
+ setup_seizure();
+ } else {
+ if (savepoint.action == kActionDefault)
+ getSound()->playSound(kEntityVassili, "VAS1028", SoundManager::kFlagDefault);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Vassili, seizure)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ // Check that we have removed the body from the train and changed jacket
+ if (!getProgress().eventCorpseMovedFromFloor) {
+ getAction()->playAnimation(kEventMertensCorpseFloor);
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, false);
+ break;
+ }
+
+ if (!getProgress().eventCorpseThrown) {
+ getAction()->playAnimation(kEventMertensCorpseBed);
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, false);
+ break;
+ }
+
+ if (getProgress().jacket == kJacketBlood) {
+ getAction()->playAnimation(kEventMertensBloodJacket);
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, false);
+ break;
+ }
+
+ // Setup Anna & Coudert
+ RESET_ENTITY_STATE(kEntityAnna, Anna, setup_function37);
+ RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_function38);
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventVassiliSeizure);
+ break;
+
+ case kActionCallback:
+ if (getCallback() != 1)
+ break;
+
+ getData()->location = kLocationInsideCompartment;
+ getAction()->playAnimation(kEventVassiliSeizure);
+
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getProgress().field_18 = 2;
+
+ getSavePoints()->push(kEntityVassili, kEntityAnna, kAction191477936);
+ getSavePoints()->push(kEntityVassili, kEntityVerges, kAction191477936);
+ getSavePoints()->push(kEntityVassili, kEntityCoudert, kAction191477936);
+ getScenes()->loadSceneFromObject(kObjectCompartmentA);
+
+ setup_drawInBed();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Vassili, drawInBed)
+ if (savepoint.action == kActionDefault)
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Vassili, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_sleeping();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVassili);
+
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->updateLocation2(kObjectCompartmentA, kObjectLocation1);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Vassili, sleeping)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
+ UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1);
+
+ setCallback(1);
+ setup_draw("303B");
+ } else {
+ params->param3 = 0;
+ if (params->param2)
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+ }
+ break;
+
+ case kActionDefault:
+ params->param5 = 5 * (3 * rnd(25) + 15);
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+ break;
+
+ case kActionCallback:
+ if (getCallback() != 1)
+ break;
+
+ getEntities()->drawSequenceLeft(kEntityVassili, "303C");
+ params->param1 = 5 * (3 * rnd(25) + 15);
+ params->param2 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Vassili, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_stealEgg();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVassili);
+
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Vassili, stealEgg)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
+ UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1);
+
+ setCallback(1);
+ setup_draw("303B");
+ } else {
+ params->param3 = 0;
+ if (params->param2)
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+ }
+ break;
+
+ case kActionOpenDoor:
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventVassiliCompartmentStealEgg);
+ break;
+
+ case kActionDefault:
+ params->param5 = 5 * (3 * rnd(25) + 15);
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_7850)
+ && getInventory()->hasItem(kItemFirebird)
+ && !getEvent(kEventVassiliCompartmentStealEgg))
+ getObjects()->update(kObject48, kEntityVassili, kObjectLocationNone, kCursorNormal, kCursorHand);
+ else
+ getObjects()->update(kObject48, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityVassili, "303C");
+ params->param1 = 5 * (3 * rnd(25) + 15);
+ params->param2 = 1;
+ break;
+
+ case 2:
+ getAction()->playAnimation(kEventVassiliCompartmentStealEgg);
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 67);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Vassili, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVassili);
+
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getObjects()->updateLocation2(kObjectCompartmentA, kObjectLocation1);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Looks identical to sleeping (#13)
+IMPLEMENT_FUNCTION(17, Vassili, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
+ UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1);
+
+ setCallback(1);
+ setup_draw("303B");
+ } else {
+ params->param3 = 0;
+ if (params->param2)
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+ }
+ break;
+
+ case kActionDefault:
+ params->param5 = 5 * (3 * rnd(25) + 15);
+ getEntities()->drawSequenceLeft(kEntityVassili, "303A");
+ break;
+
+ case kActionCallback:
+ if (getCallback() != 1)
+ break;
+
+ getEntities()->drawSequenceLeft(kEntityVassili, "303C");
+ params->param1 = 5 * (3 * rnd(25) + 15);
+ params->param2 = 1;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Vassili, chapter5)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityVassili);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/vassili.h b/engines/lastexpress/entities/vassili.h
new file mode 100644
index 0000000000..1862069e25
--- /dev/null
+++ b/engines/lastexpress/entities/vassili.h
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_VASSILI_H
+#define LASTEXPRESS_VASSILI_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Vassili : public Entity {
+public:
+ Vassili(LastExpressEngine *engine);
+ ~Vassili() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function6)
+ DECLARE_FUNCTION(function7)
+ DECLARE_FUNCTION(function8)
+ DECLARE_FUNCTION(function9)
+ DECLARE_FUNCTION(seizure)
+ DECLARE_FUNCTION(drawInBed)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ DECLARE_FUNCTION(sleeping)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ DECLARE_FUNCTION(stealEgg)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_VASSILI_H
diff --git a/engines/lastexpress/entities/verges.cpp b/engines/lastexpress/entities/verges.cpp
new file mode 100644
index 0000000000..76bf646113
--- /dev/null
+++ b/engines/lastexpress/entities/verges.cpp
@@ -0,0 +1,1898 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/verges.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Verges::Verges(LastExpressEngine *engine) : Entity(engine, kEntityVerges) {
+ ADD_CALLBACK_FUNCTION(Verges, reset);
+ ADD_CALLBACK_FUNCTION(Verges, draw);
+ ADD_CALLBACK_FUNCTION(Verges, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Verges, playSound);
+ ADD_CALLBACK_FUNCTION(Verges, playSound16);
+ ADD_CALLBACK_FUNCTION(Verges, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Verges, savegame);
+ ADD_CALLBACK_FUNCTION(Verges, updateEntity);
+ ADD_CALLBACK_FUNCTION(Verges, function9);
+ ADD_CALLBACK_FUNCTION(Verges, function10);
+ ADD_CALLBACK_FUNCTION(Verges, function11);
+ ADD_CALLBACK_FUNCTION(Verges, function12);
+ ADD_CALLBACK_FUNCTION(Verges, function13);
+ ADD_CALLBACK_FUNCTION(Verges, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Verges, function15);
+ ADD_CALLBACK_FUNCTION(Verges, function16);
+ ADD_CALLBACK_FUNCTION(Verges, function17);
+ ADD_CALLBACK_FUNCTION(Verges, chapter1);
+ ADD_CALLBACK_FUNCTION(Verges, talkHarem);
+ ADD_CALLBACK_FUNCTION(Verges, talkPassengerList);
+ ADD_CALLBACK_FUNCTION(Verges, talkGendarmes);
+ ADD_CALLBACK_FUNCTION(Verges, function22);
+ ADD_CALLBACK_FUNCTION(Verges, function23);
+ ADD_CALLBACK_FUNCTION(Verges, policeGettingOffTrain);
+ ADD_CALLBACK_FUNCTION(Verges, function25);
+ ADD_CALLBACK_FUNCTION(Verges, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Verges, chapter2);
+ ADD_CALLBACK_FUNCTION(Verges, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Verges, chapter3);
+ ADD_CALLBACK_FUNCTION(Verges, function30);
+ ADD_CALLBACK_FUNCTION(Verges, function31);
+ ADD_CALLBACK_FUNCTION(Verges, function32);
+ ADD_CALLBACK_FUNCTION(Verges, function33);
+ ADD_CALLBACK_FUNCTION(Verges, function34);
+ ADD_CALLBACK_FUNCTION(Verges, function35);
+ ADD_CALLBACK_FUNCTION(Verges, chapter4);
+ ADD_CALLBACK_FUNCTION(Verges, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Verges, function38);
+ ADD_CALLBACK_FUNCTION(Verges, chapter5);
+ ADD_CALLBACK_FUNCTION(Verges, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Verges, function41);
+ ADD_CALLBACK_FUNCTION(Verges, function42);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Verges, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Verges, draw)
+ Entity::draw(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(3, Verges, callbackActionOnDirection)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getData()->direction != kDirectionRight)
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExitCompartment:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMeCath:
+ if (!params->param1) {
+ getSound()->excuseMe(kEntityVerges);
+ params->param1 = 1;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(4, Verges, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(5, Verges, playSound16)
+ Entity::playSound(savepoint, false, SoundManager::kFlagDefault);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Verges, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(7, Verges, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(8, Verges, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ if (!getSound()->isBuffered(kEntityVerges))
+ getSound()->playSound(kEntityPlayer, "TRA1113", getSound()->getSoundFlag(kEntityVerges));
+
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(9, Verges, function9)
+switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObject104, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ if (getEntities()->isInBaggageCar(kEntityPlayer) || getEntities()->isInKitchen(kEntityPlayer)) {
+ getAction()->playAnimation(getEntities()->isInBaggageCar(kEntityPlayer) ? kEventVergesBaggageCarOffLimits : kEventVergesCanIHelpYou);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
+ }
+
+ getScenes()->loadSceneFromItemPosition(kItem9);
+ getData()->car = kCarRestaurant;
+ getData()->entityPosition = kPosition_5900;
+
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+ getSound()->playSound(kEntityVerges, (char *)&params->seq1);
+
+ setCallback(2);
+ setup_draw("813DD");
+ break;
+
+ case 2:
+ if (!getSound()->isBuffered(kEntityVerges))
+ getSound()->playSound(kEntityVerges, (char *)&params->seq1);
+
+ getEntities()->drawSequenceRight(kEntityVerges, "813DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVerges);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function10(kCarGreenSleeping, kPosition_540, (char *)&params->seq1);
+ break;
+
+ case 4:
+ getEntities()->clearSequences(kEntityVerges);
+
+ setCallback(5);
+ setup_updateFromTime(225);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function11();
+ break;
+
+ case 6:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IIS(10, Verges, function10, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param7) {
+ if (!getSound()->isBuffered(kEntityVerges)) {
+ getSound()->playSound(kEntityVerges, (char *)&params->seq);
+ params->param7 = 1;
+ }
+ }
+
+ if (getEntities()->updateEntity(kEntityVerges, (CarIndex)params->param1, (EntityPosition)params->param2)) {
+ CALLBACK_ACTION();
+ break;
+ }
+
+ if (params->param6) {
+ UPDATE_PARAM(params->param8, getState()->timeTicks, 75);
+
+ getSound()->playSound(kEntityVerges, (char *)&params->seq);
+
+ params->param6 = 0;
+ params->param8 = 0;
+ }
+ break;
+
+ case kActionEndSound:
+ params->param6 = 1;
+ break;
+
+ case kActionDefault:
+ if (!getSound()->isBuffered(kEntityVerges)) {
+ getSound()->playSound(kEntityVerges, (char *)&params->seq);
+ params->param7 = 1;
+ }
+
+ if (getEntities()->updateEntity(kEntityVerges, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Verges, function11)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_updateEntity(kCarRestaurant, kPosition_540);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 2:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(3);
+ setup_draw("813US");
+ break;
+
+ case 3:
+ getEntities()->drawSequenceRight(kEntityVerges, "813UD");
+
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVerges);
+
+ setCallback(4);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 4: {
+ getEntities()->clearSequences(kEntityVerges);
+
+ bool loadscene = true;
+
+ if (getEntities()->isInBaggageCarEntrance(kEntityPlayer))
+ getAction()->playAnimation(kEventVergesEscortToDiningCar);
+ else if (getEntities()->isInBaggageCar(kEntityPlayer))
+ getAction()->playAnimation(kEventVergesBaggageCarOffLimits);
+ else if (getEntities()->isInKitchen(kEntityPlayer))
+ getAction()->playAnimation(kEventVergesCanIHelpYou);
+ else
+ loadscene = false;
+
+ if (loadscene) {
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
+ }
+
+ getInventory()->setLocationAndProcess(kItem9, kObjectLocation1);
+
+ getData()->car = kCarBaggage;
+ getData()->entityPosition = kPosition_5000;
+
+ getObjects()->update(kObject104, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Verges, function12)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObject104, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ if (getEntities()->isInBaggageCar(kEntityPlayer) || getEntities()->isInKitchen(kEntityPlayer)) {
+ getAction()->playAnimation(getEntities()->isInBaggageCar(kEntityPlayer) ? kEventVergesBaggageCarOffLimits : kEventVergesCanIHelpYou);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
+ }
+
+ getScenes()->loadSceneFromItemPosition(kItem9);
+
+ getData()->car = kCarRestaurant;
+ getData()->entityPosition = kPosition_5900;
+
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_draw("813DD");
+ break;
+
+ case 2:
+ getEntities()->drawSequenceRight(kEntityVerges, "813DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVerges);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_850;
+ getEntities()->clearSequences(kEntityVerges);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(13, Verges, function13, bool)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventVergesSuitcase);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ if (getEvent(kEventVergesSuitcase) || getEvent(kEventVergesSuitcaseNight) || getEvent(kEventVergesSuitcaseOtherEntry) || getEvent(kEventVergesSuitcaseNightOtherEntry))
+ params->param2 = 1;
+
+ if (isNight() && getProgress().chapter != kChapter1)
+ params->param2 = 1;
+
+ if (params->param1) {
+ if (isNight())
+ getAction()->playAnimation(params->param2 ? kEventVergesSuitcaseNightOtherEntryStart : kEventVergesSuitcaseNightOtherEntry);
+ else
+ getAction()->playAnimation(params->param2 ? kEventVergesSuitcaseOtherEntryStart : kEventVergesSuitcaseOtherEntry);
+ } else {
+ if (isNight())
+ getAction()->playAnimation(params->param2 ? kEventVergesSuitcaseNightStart : kEventVergesSuitcaseNight);
+ else
+ getAction()->playAnimation(params->param2 ? kEventVergesSuitcaseStart : kEventVergesSuitcase);
+ }
+
+ getEntities()->clearSequences(kEntityVerges);
+ getScenes()->loadSceneFromPosition(kCarBaggage, 91);
+
+ CALLBACK_ACTION();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(14, Verges, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_IS(15, Verges, function15, EntityIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (params->param5 && params->param6) {
+ getSavePoints()->push(kEntityVerges, (EntityIndex)params->param1, kAction125499160);
+
+ if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2) && !getEntities()->isPlayerPosition(kCarRedSleeping, 2))
+ getData()->entityPosition = kPosition_2088;
+
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionEndSound:
+ params->param5 = 1;
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityVerges, "620F");
+ getSavePoints()->push(kEntityVerges, (EntityIndex)params->param1, kAction171394341);
+ break;
+
+ case kAction155853632:
+ params->param6 = 1;
+ break;
+
+ case kAction202558662:
+ getEntities()->drawSequenceLeft(kEntityVerges, "620E");
+ getSound()->playSound(kEntityVerges, (char *)&params->seq);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (CURRENT_PARAM(1, 1) && params->param8) {
+ getSavePoints()->push(kEntityVerges, (EntityIndex)params->param1, kAction125499160);
+
+ if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2) && !getEntities()->isPlayerPosition(kCarRedSleeping, 2))
+ getData()->entityPosition = kPosition_2088;
+
+ CALLBACK_ACTION();
+ }
+ break;
+
+ case kActionEndSound:
+ CURRENT_PARAM(1, 1)++;
+
+ if (CURRENT_PARAM(1, 1) == 1)
+ getSound()->playSound(kEntityVerges, (char *)&params->seq2);
+ break;
+
+ case kActionDefault:
+ getEntities()->drawSequenceLeft(kEntityVerges, "620F");
+ getSavePoints()->push(kEntityVerges, (EntityIndex)params->param1, kAction171394341);
+ break;
+
+ case kAction155853632:
+ params->param8 = 1;
+ break;
+
+ case kAction202558662:
+ getEntities()->drawSequenceLeft(kEntityVerges, "620E");
+ getSound()->playSound(kEntityVerges, (char *)&params->seq1);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Verges, function17)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function12();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function15(kEntityMertens, "TRA1291");
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function11();
+ break;
+
+ case 4:
+ ENTITY_PARAM(0, 3) = 0;
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Verges, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityVerges, kActionDeliverMessageToTyler, 0);
+ getSavePoints()->addData(kEntityVerges, kAction226031488, 1);
+ getSavePoints()->addData(kEntityVerges, kAction339669520, 1);
+ getSavePoints()->addData(kEntityVerges, kAction167854368, 4);
+ getSavePoints()->addData(kEntityVerges, kAction158617345, 2);
+ getSavePoints()->addData(kEntityVerges, kAction168255788, 3);
+ getSavePoints()->addData(kEntityVerges, kAction201431954, 5);
+ getSavePoints()->addData(kEntityVerges, kAction168187490, 6);
+
+ getObjects()->update(kObject104, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarBaggage;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(19, Verges, talkHarem)
+ talk(savepoint, "TRA1202", "TRA1201");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Verges, talkPassengerList)
+ talk(savepoint, "TRA1205", "TRA1206");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Verges, talkGendarmes)
+ talk(savepoint, "TRA1250", "TRA1251");
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Verges, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function12();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 2:
+ if (getEvent(kEventMertensAskTylerCompartment) || getEvent(kEventMertensAskTylerCompartmentD) || getEvent(kEventMertensAugustWaiting)) {
+ setCallback(3);
+ setup_function16(kEntityMertens, "TRA1200", "TRA1201");
+ } else {
+ setCallback(4);
+ setup_function16(kEntityMertens, "TRA1200A", "TRA1201");
+ }
+ break;
+
+ case 3:
+ case 4:
+ getSavePoints()->push(kEntityVerges, kEntityMertens, kAction169633856);
+
+ setCallback(5);
+ setup_function11();
+ break;
+
+ case 5:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Verges, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getScenes()->loadSceneFromItemPosition(kItem9);
+
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ break;
+
+ case kAction191477936:
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ setCallback(1);
+ setup_function11();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Verges, policeGettingOffTrain)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isDistanceBetweenEntities(kEntityVerges, kEntityPlayer, 1000) && getEntityData(kEntityPlayer)->location == kLocationOutsideCompartment) {
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventGendarmesArrestation);
+ }
+ break;
+
+ case kActionEndSound:
+ CALLBACK_ACTION();
+ break;
+
+ case kActionDefault:
+ getSound()->playSound(kEntityVerges, "POL1101", SoundManager::kFlagDefault);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getSound()->processEntry(kEntityVerges);
+ getAction()->playAnimation(kEventGendarmesArrestation);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Verges, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getScenes()->loadSceneFromItemPosition(kItem9);
+
+ if (!getEntities()->isInKronosSalon(kEntityPlayer)) {
+
+ if (getEntityData(kEntityPlayer)->car > kCarRedSleeping
+ || (getEntityData(kEntityPlayer)->car == kCarRedSleeping && getEntityData(kEntityPlayer)->entityPosition > kPosition_9270)) {
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 40);
+
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_9270;
+ } else {
+ if (getEntityData(kEntityPlayer)->car > kCarGreenSleeping
+ || (getEntityData(kEntityPlayer)->car == kCarGreenSleeping && getEntityData(kEntityPlayer)->entityPosition < kPosition_4840)) {
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(kObjectCompartment5, true);
+ }
+
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_850;
+ }
+
+ getData()->location = kLocationOutsideCompartment;
+
+ getObjects()->update(kObjectRestaurantCar, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorForward);
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ if (getEntities()->isOutsideAnnaWindow())
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_4840)
+ || getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_4455)) {
+ getAction()->playAnimation(isNight() ? kEventCathTurningNight : kEventCathTurningDay);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromObject(kObjectCompartmentE, true);
+ }
+
+ getSavePoints()->push(kEntityVerges, kEntityGendarmes, kAction169499649);
+
+ getProgress().field_3C = 1;
+ getState()->timeDelta = 1;
+
+ if (getData()->car == kCarRedSleeping) {
+ setCallback(6);
+ setup_function10(kCarGreenSleeping, kPosition_540, "TRA1005");
+ } else {
+ setCallback(7);
+ setup_function10(kCarRedSleeping, kPosition_9460, "TRA1006");
+ }
+ break;
+ }
+ // Fallback to next case
+
+ case 2:
+ if (getEvent(kEventKronosConversation)) {
+ getProgress().field_3C = 1;
+ getData()->car = kCarGreenSleeping;
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationOutsideCompartment;
+
+ getState()->timeDelta = 3;
+ getSavePoints()->push(kEntityVerges, kEntityChapters, kAction169629818);
+
+ setCallback(3);
+ setup_policeGettingOffTrain();
+ } else {
+ setCallback(2);
+ setup_updateFromTime(150);
+ }
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction168254872);
+
+ setCallback(4);
+ setup_function10(kCarRedSleeping, kPosition_9460, "TRA1006");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function11();
+ break;
+
+ case 5:
+ case 11:
+ ENTITY_PARAM(0, 7) = 0;
+
+ CALLBACK_ACTION();
+ break;
+
+ case 6:
+ case 7:
+ getEntities()->clearSequences(kEntityVerges);
+ break;
+
+ case 8:
+ getSavePoints()->push(kEntityVerges, kEntityChapters, kAction169629818);
+
+ setCallback(9);
+ setup_policeGettingOffTrain();
+ break;
+
+ case 9:
+ getObjects()->update(kObjectRestaurantCar, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+ getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction168254872);
+
+ setCallback(10);
+ setup_function10(kCarGreenSleeping, kPosition_540, "TRA1006");
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_function11();
+ break;
+ }
+ break;
+
+ case kAction168710784:
+ getData()->car = kCarGreenSleeping;
+
+ if (!(getEntityData(kEntityPlayer)->car == kCarGreenSleeping))
+ getData()->car = kCarRedSleeping;
+
+ getData()->entityPosition = kPosition_8200;
+ getData()->location = kLocationOutsideCompartment;
+
+ getState()->timeDelta = 3;
+
+ setCallback(8);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Verges, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (ENTITY_PARAM(0, 6)) {
+ params->param1 = 1;
+ params->param2 = 1;
+ params->param3 = 1;
+ params->param4 = 1;
+ params->param5 = 1;
+ params->param6 = 1;
+
+ ENTITY_PARAM(0, 6) = 0;
+ }
+
+ if (ENTITY_PARAM(0, 2)) {
+ setCallback(1);
+ setup_function23();
+ break;
+ }
+
+label_callback1:
+ if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) {
+ setCallback(2);
+ setup_function13(false);
+ break;
+ }
+
+label_callback2:
+ if (ENTITY_PARAM(0, 7)) {
+ setCallback(3);
+ setup_function25();
+ break;
+ }
+
+label_callback3:
+ if (params->param6)
+ goto label_callback12;
+
+ TIME_CHECK_CALLBACK_1(kTimeChapter1, params->param7, 4, setup_function9, "TRA1001");
+
+label_callback4:
+ TIME_CHECK_CALLBACK(kTime1089000, params->param8, 5, setup_function12);
+
+ params->param8 = 1;
+
+ if (!params->param5) {
+ setCallback(5);
+ setup_function12();
+ break;
+ }
+
+label_callback8:
+ TIME_CHECK_CALLBACK_1(kTime1107000, CURRENT_PARAM(1, 1), 9, setup_function9, "TRA1001A");
+
+label_callback9:
+ TIME_CHECK_CALLBACK_1(kTime1134000, CURRENT_PARAM(1, 2), 10, setup_function9, "TRA1002");
+
+label_callback10:
+ TIME_CHECK_CALLBACK_1(kTime1165500, CURRENT_PARAM(1, 3), 11, setup_function9, "TRA1003");
+
+label_callback11:
+ TIME_CHECK_CALLBACK_1(kTime1225800, CURRENT_PARAM(1, 4), 12, setup_function9, "TRA1004");
+
+label_callback12:
+ if (ENTITY_PARAM(0, 5) && !params->param2) {
+ setCallback(13);
+ setup_talkGendarmes();
+ break;
+ }
+
+label_callback13:
+ if (getInventory()->hasItem(kItemPassengerList) && !params->param3 && (getState()->time < kTime1134000 || getState()->time > kTime1156500)) {
+ setCallback(14);
+ setup_talkPassengerList();
+ break;
+ }
+
+label_callback14:
+ if (ENTITY_PARAM(0, 3) && !params->param4 && (getState()->time < kTime1134000 || getState()->time > kTime1156500)) {
+ setCallback(15);
+ setup_function17();
+ break;
+ }
+
+label_callback15:
+ if (ENTITY_PARAM(0, 1) && !params->param5) {
+ if (getState()->time < kTime1134000 || getState()->time > kTime1156500) {
+ setCallback(16);
+ setup_function22();
+ }
+ }
+ break;
+
+ case kActionOpenDoor:
+ setCallback(17);
+ setup_function13(savepoint.param.intValue < 106 ? true : false);
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarBaggage;
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+
+ getEntities()->clearSequences(kEntityVerges);
+ getInventory()->setLocationAndProcess(kItem9, kObjectLocation1);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback1;
+
+ case 2:
+ goto label_callback2;
+
+ case 3:
+ goto label_callback3;
+
+ case 4:
+ goto label_callback4;
+
+ case 5:
+ setCallback(6);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_function15(kEntityMertens, "TRA1202");
+ break;
+
+ case 7:
+ setCallback(8);
+ setup_function11();
+ break;
+
+ case 8:
+ goto label_callback8;
+
+ case 9:
+ goto label_callback9;
+
+ case 10:
+ goto label_callback10;
+
+ case 11:
+ goto label_callback11;
+
+ case 12:
+ goto label_callback12;
+
+ case 13:
+ params->param2 = 1;
+ goto label_callback13;
+
+ case 14:
+ params->param3 = 1;
+ goto label_callback14;
+
+ case 15:
+ params->param4 = 1;
+ goto label_callback15;
+
+ case 16:
+ params->param5 = 1;
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Verges, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVerges);
+
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarBaggage;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObject104, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ ENTITY_PARAM(0, 3) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Verges, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) {
+ setCallback(1);
+ setup_function13(false);
+ }
+
+label_callback_1:
+ TIME_CHECK_CALLBACK_1(kTime1818900, params->param1, 2, setup_function9, "Tra2177");
+
+label_callback_2:
+ if (params->param2 == kTimeInvalid || !getState()->time)
+ goto label_callback_6;
+
+ if (getState()->time > kTime1836000) {
+ params->param2 = kTimeInvalid;
+ setCallback(3);
+ setup_function12();
+ break;
+ }
+
+ if (!getEntities()->isPlayerInCar(kCarRedSleeping) || !params->param2) {
+ params->param2 = (uint)getState()->time;
+
+ if (!params->param2) {
+ setCallback(3);
+ setup_function12();
+ break;
+ }
+ }
+
+ if (params->param2 >= getState()->time) {
+label_callback_6:
+
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(7);
+ setup_function17();
+ }
+
+ break;
+ }
+
+ params->param2 = kTimeInvalid;
+ setCallback(3);
+ setup_function12();
+ break;
+
+ case kActionOpenDoor:
+ setCallback(8);
+ setup_function13(savepoint.param.intValue < 106);
+ break;
+
+ case kActionDefault:
+ getInventory()->setLocationAndProcess(kItem9, kObjectLocation1);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function15(kEntityCoudert, "TRA2100");
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function11();
+ break;
+
+ case 6:
+ goto label_callback_6;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Verges, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_function23();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVerges);
+
+ getData()->entityPosition = kPosition_540;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObject104, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(0, 4) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(30, Verges, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function12();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function15(kEntityCoudert, (char *)&params->seq1);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function11();
+ break;
+
+ case 4:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(31, Verges, function31)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function12();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function15(kEntityCoudert, "TRA3015");
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function11();
+ break;
+
+ case 4:
+ getProgress().field_48 = 1;
+ ENTITY_PARAM(0, 4) = 0;
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(32, Verges, function32)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK_3(kTime2263500, params->param1, 5, setup_function10, kCarRedSleeping, kPosition_9460, "TRA3006");
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObject104, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ if (getEntities()->isInBaggageCar(kEntityPlayer) || getEntities()->isInKitchen(kEntityPlayer)) {
+ getAction()->playAnimation(getEntities()->isInBaggageCar(kEntityPlayer) ? kEventVergesBaggageCarOffLimits : kEventVergesCanIHelpYou);
+ getSound()->playSound(kEntityPlayer, "BUMP");
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
+ }
+
+ getScenes()->loadSceneFromItemPosition(kItem9);
+ getData()->car = kCarRestaurant;
+ getData()->entityPosition = kPosition_5900;
+
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_8500;
+ getData()->location = kLocationOutsideCompartment;
+ getSound()->playSound(kEntityVerges, "TRA3004");
+
+ setCallback(2);
+ setup_draw("813DD");
+ break;
+
+ case 2:
+ if (!getSound()->isBuffered(kEntityVerges))
+ getSound()->playSound(kEntityVerges, "TRA3004");
+
+ getEntities()->drawSequenceRight(kEntityVerges, "813DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVerges);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_function10(kCarGreenSleeping, kPosition_540, "TRA3004");
+ break;
+
+ case 4:
+ getEntities()->clearSequences(kEntityVerges);
+ break;
+
+ case 5:
+ setCallback(6);
+ setup_function11();
+ break;
+
+ case 6:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(33, Verges, function33)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_draw("813US");
+ break;
+
+ case 2:
+ getEntities()->drawSequenceRight(kEntityVerges, "813UD");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVerges);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ getEntities()->clearSequences(kEntityVerges);
+ getData()->location = kLocationInsideCompartment;
+ getData()->entityPosition = kPosition_5799;
+
+ setCallback(getProgress().field_3C ? 4 : 5);
+ setup_playSound(getProgress().field_3C ? "ABB3035A" : "ABB3035");
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_playSound("ABB3035");
+ break;
+
+ case 5:
+ getSavePoints()->push(kEntityVerges, kEntityAbbot, kAction192054567);
+
+ setCallback(6);
+ setup_function9("Tra3010");
+ break;
+
+ case 6:
+ setup_function34();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(34, Verges, function34)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) {
+ setCallback(1);
+ setup_function13(false);
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(0, 4)) {
+ setCallback(2);
+ setup_function31();
+ break;
+ }
+
+label_callback_2:
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(3);
+ setup_function17();
+ break;
+ }
+
+label_callback_3:
+ TIME_CHECK_CALLBACK_1(kTime1971000, params->param1, 4, setup_function9, "Tra3001");
+
+label_callback_4:
+ TIME_CHECK_CALLBACK_1(kTime1998000, params->param2, 5, setup_function9, "Tra3010a");
+
+label_callback_5:
+ TIME_CHECK_CALLBACK(kTime2016000, params->param3, 6, setup_function35);
+
+label_callback_6:
+ TIME_CHECK_CALLBACK_1(kTime2070000, params->param4, 7, setup_function9, "Tra3002");
+
+label_callback_7:
+ TIME_CHECK_CALLBACK_1(kTime2142000, params->param5, 8, setup_function9, "Tra3003");
+
+label_callback_8:
+ TIME_CHECK_CALLBACK_1(kTime2173500, params->param6, 9, setup_function30, "Tra3012");
+
+label_callback_9:
+ TIME_CHECK_CALLBACK(kTime2218500, params->param7, 10, setup_function32);
+ break;
+
+ case kActionOpenDoor:
+ setCallback(11);
+ setup_function13(savepoint.param.intValue < 106);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+
+ case 8:
+ goto label_callback_8;
+
+ case 9:
+ goto label_callback_9;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(35, Verges, function35)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function12();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function15(kEntityMertens, "Tra3011A");
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction188570113);
+
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function15(kEntityMertens, "Tra3011");
+ break;
+
+ case 5:
+ getSavePoints()->push(kEntityVerges, kEntityMertens, kAction188635520);
+
+ setCallback(6);
+ setup_function11();
+ break;
+
+ case 6:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(36, Verges, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVerges);
+
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarBaggage;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObject104, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
+
+ ENTITY_PARAM(0, 3) = 0;
+ ENTITY_PARAM(0, 6) = 0;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(37, Verges, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) {
+ setCallback(1);
+ setup_function13(false);
+ break;
+ }
+
+label_callback_1:
+ if (ENTITY_PARAM(0, 6)) {
+ if (ENTITY_PARAM(0, 3)) {
+ setCallback(2);
+ setup_function17();
+ break;
+ }
+
+label_callback_2:
+ TIME_CHECK_CALLBACK_1(kTime2349000, params->param1, 3, setup_function9, "Tra1001");
+
+label_callback_3:
+ TIME_CHECK_CALLBACK_1(kTime2378700, params->param2, 4, setup_function9, "Tra4001");
+
+label_callback_4:
+ TIME_CHECK_CALLBACK_1(kTime2403000, params->param3, 5, setup_function9, "Tra1001A");
+
+label_callback_5:
+ TIME_CHECK_CALLBACK_1(kTime2414700, params->param4, 6, setup_function9, "Tra4002");
+
+label_callback_6:
+ TIME_CHECK_CALLBACK_1(kTime2484000, params->param5, 7, setup_function9, "Tra4003");
+
+label_callback_7:
+ TIME_CHECK_CALLBACK_1(kTime2511000, params->param6, 8, setup_function9, "Tra4004");
+ }
+
+label_callback_8:
+ TIME_CHECK_CALLBACK_1(kTime2538000, params->param7, 9, setup_function9, "Tra4005");
+
+ break;
+
+ case kActionOpenDoor:
+ setCallback(10);
+ setup_function13(savepoint.param.intValue < 106);
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarBaggage;
+ getData()->entityPosition = kPosition_5000;
+ getData()->location = kLocationOutsideCompartment;
+
+ getInventory()->setLocationAndProcess(kItem9, kObjectLocation1);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ goto label_callback_1;
+
+ case 2:
+ goto label_callback_2;
+
+ case 3:
+ goto label_callback_3;
+
+ case 4:
+ goto label_callback_4;
+
+ case 5:
+ goto label_callback_5;
+
+ case 6:
+ goto label_callback_6;
+
+ case 7:
+ goto label_callback_7;
+
+ case 8:
+ goto label_callback_8;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(38, Verges, function38)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObject104, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getScenes()->loadSceneFromItemPosition(kItem9);
+ getEntities()->clearSequences(kEntityVerges);
+
+ getData()->entityPosition = kPosition_6469;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->clearSequences(kEntityVerges);
+ setCallback(2);
+ setup_updateFromTime(1800);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function11();
+ break;
+
+ case 3:
+ setup_chapter4Handler();
+ break;
+ }
+ break;
+
+ case kAction125233040:
+ getData()->entityPosition = kPosition_5790;
+
+ setCallback(1);
+ setup_updateEntity(kCarGreenSleeping, kPosition_540);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(39, Verges, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVerges);
+
+ getData()->entityPosition = kPosition_3650;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObject104, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ getObjects()->update(kObject105, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(40, Verges, chapter5Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getEntities()->isInSalon(kEntityPlayer) && !getSound()->isBuffered(kEntityVerges))
+ getSound()->playSound(kEntityVerges, "WAT5000");
+ break;
+
+ case kActionOpenDoor:
+ if (getSound()->isBuffered(kEntityVerges))
+ getSound()->processEntry(kEntityVerges);
+
+ if (getSound()->isBuffered("MUS050"))
+ getSound()->processEntry("MUS050");
+
+ getObjects()->update(kObject65, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventCathFreePassengers);
+ break;
+
+ case kActionDefault:
+ getScenes()->loadSceneFromItemPosition(kItem9);
+ getObjects()->update(kObject65, kEntityVerges, kObjectLocation1, kCursorNormal, kCursorForward);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCathFreePassengers);
+ getSavePoints()->pushAll(kEntityVerges, kActionProceedChapter5);
+ getScenes()->loadSceneFromPosition(kCarRedSleeping, 40);
+ setup_function41();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(41, Verges, function41)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getObjects()->updateLocation2(kObjectRestaurantCar, kObjectLocation3);
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_9460;
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(1);
+ setup_function10(kCarRedSleeping, kPosition_2000, "Tra5001");
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getEntities()->drawSequenceLeft(kEntityVerges, "620E");
+ // Fallback to next case
+
+ case 2:
+ if (getSound()->isBuffered(kEntityVerges)) {
+ setCallback(2);
+ setup_updateFromTime(225);
+ } else {
+ setCallback(3);
+ setup_playSound("Con5001");
+ }
+ break;
+
+ case 3:
+ getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction155991520);
+
+ setCallback(4);
+ setup_updateEntity(kCarBaggageRear, kPosition_9460);
+ break;
+
+ case 4:
+ setup_function42();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(42, Verges, function42)
+ if (savepoint.action == kActionDefault)
+ getEntities()->clearSequences(kEntityVerges);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions
+//////////////////////////////////////////////////////////////////////////
+void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *sound2) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_function12();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarRedSleeping, kPosition_2000);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_function15(kEntityCoudert, sound1);
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarGreenSleeping, kPosition_2000);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_function15(kEntityMertens, sound2);
+ break;
+
+ case 5:
+ setup_function11();
+ break;
+
+ case 6:
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/verges.h b/engines/lastexpress/entities/verges.h
new file mode 100644
index 0000000000..40a43eac9d
--- /dev/null
+++ b/engines/lastexpress/entities/verges.h
@@ -0,0 +1,182 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_VERGES_H
+#define LASTEXPRESS_VERGES_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Verges : public Entity {
+public:
+ Verges(LastExpressEngine *engine);
+ ~Verges() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Plays sound
+ *
+ * @param savepoint The savepoint
+ * - the sound filename
+ */
+ DECLARE_FUNCTION_NOSETUP(playSound16)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION_1(function9, const char *soundName)
+ DECLARE_FUNCTION_3(function10, CarIndex car, EntityPosition entityPosition, const char *soundName)
+ DECLARE_FUNCTION(function11)
+ DECLARE_FUNCTION(function12)
+ DECLARE_FUNCTION_1(function13, bool)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ DECLARE_FUNCTION_2(function15, EntityIndex entity, const char *soundName)
+ DECLARE_FUNCTION_3(function16, EntityIndex entityIndex, const char *soundName1, const char *soundName2)
+ DECLARE_FUNCTION(function17)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ DECLARE_FUNCTION_NOSETUP(talkHarem)
+ DECLARE_FUNCTION(talkPassengerList)
+ DECLARE_FUNCTION(talkGendarmes)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(policeGettingOffTrain)
+ DECLARE_FUNCTION(function25)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ DECLARE_FUNCTION_1(function30, const char *soundName)
+ DECLARE_FUNCTION(function31)
+ DECLARE_FUNCTION(function32)
+ DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(function34)
+ DECLARE_FUNCTION(function35)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function38)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function41)
+ DECLARE_FUNCTION(function42)
+
+private:
+ void talk(const SavePoint &savepoint, const char *sound1, const char *sound2);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_VERGES_H
diff --git a/engines/lastexpress/entities/vesna.cpp b/engines/lastexpress/entities/vesna.cpp
new file mode 100644
index 0000000000..0e8d3bda12
--- /dev/null
+++ b/engines/lastexpress/entities/vesna.cpp
@@ -0,0 +1,1161 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/vesna.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/fight.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Vesna::Vesna(LastExpressEngine *engine) : Entity(engine, kEntityVesna) {
+ ADD_CALLBACK_FUNCTION(Vesna, reset);
+ ADD_CALLBACK_FUNCTION(Vesna, playSound);
+ ADD_CALLBACK_FUNCTION(Vesna, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Vesna, draw);
+ ADD_CALLBACK_FUNCTION(Vesna, updateEntity);
+ ADD_CALLBACK_FUNCTION(Vesna, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Vesna, updateEntity2);
+ ADD_CALLBACK_FUNCTION(Vesna, callbackActionRestaurantOrSalon);
+ ADD_CALLBACK_FUNCTION(Vesna, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Vesna, savegame);
+ ADD_CALLBACK_FUNCTION(Vesna, function11);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter1);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Vesna, function14);
+ ADD_CALLBACK_FUNCTION(Vesna, function15);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter2);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Vesna, function18);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter3);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Vesna, function21);
+ ADD_CALLBACK_FUNCTION(Vesna, function22);
+ ADD_CALLBACK_FUNCTION(Vesna, function23);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter4);
+ ADD_CALLBACK_FUNCTION(Vesna, function25);
+ ADD_CALLBACK_FUNCTION(Vesna, function26);
+ ADD_CALLBACK_FUNCTION(Vesna, function27);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter5);
+ ADD_CALLBACK_FUNCTION(Vesna, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Vesna, function30);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Vesna, reset)
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(2, Vesna, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(3, Vesna, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(4, Vesna, draw)
+ Entity::draw(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(5, Vesna, updateEntity, CarIndex, EntityPosition)
+ if (savepoint.action == kActionExcuseMeCath) {
+ getSound()->playSound(kEntityPlayer, rnd(2) ? "CAT10150" : "CAT1015A");
+
+ return;
+ }
+
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_I(6, Vesna, updateFromTime, uint32)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(7, Vesna, updateEntity2, CarIndex, EntityPosition)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ params->param3 = 0;
+
+ if (getEntities()->isDistanceBetweenEntities(kEntityVesna, kEntityMilos, 500)
+ || (((getData()->direction == kDirectionUp && (getData()->car > getEntityData(kEntityMilos)->car)) || (getData()->car == getEntityData(kEntityMilos)->car && getData()->entityPosition > getEntityData(kEntityMilos)->entityPosition)))
+ || (((getData()->direction == kDirectionDown && (getData()->car < getEntityData(kEntityMilos)->car)) || (getData()->car == getEntityData(kEntityMilos)->car && getData()->entityPosition < getEntityData(kEntityMilos)->entityPosition)))) {
+ getData()->field_49B = 0;
+ params->param3 = 1;
+ }
+
+ if (!params->param3)
+ getEntities()->updateEntity(kEntityVesna, (CarIndex)params->param1, (EntityPosition)params->param2);
+ break;
+
+ case kActionDefault:
+ getEntities()->updateEntity(kEntityVesna, (CarIndex)params->param1, (EntityPosition)params->param2);
+ break;
+
+ case kAction123668192:
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Vesna, callbackActionRestaurantOrSalon)
+ Entity::callbackActionRestaurantOrSalon(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Vesna, callbackActionOnDirection)
+ Entity::callbackActionOnDirection(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(10, Vesna, savegame, SavegameType, uint32)
+ Entity::savegame(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Vesna, function11)
+ // Expose parameters as IIIS and ignore the default exposed parameters
+ EntityData::EntityParametersIIIS *parameters = (EntityData::EntityParametersIIIS*)_data->getCurrentParameters();
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (parameters->param3) {
+ UPDATE_PARAM(parameters->param7, getState()->timeTicks, 75);
+
+ parameters->param2 = 1;
+ parameters->param3 = 0;
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ parameters->param7 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (parameters->param3) {
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ setCallback(4);
+ setup_playSound(getSound()->wrongDoorCath());
+ break;
+ }
+
+ parameters->param1++;
+ switch (parameters->param1) {
+ default:
+ strcpy((char *)&parameters->seq, "VES1015C");
+ parameters->param1 = 0;
+ break;
+
+ case 1:
+ strcpy((char *)&parameters->seq, "VES1015A");
+ break;
+
+ case 2:
+ strcpy((char *)&parameters->seq, "VES1015B");
+ break;
+ }
+
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 2 : 1);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionDrawScene:
+ if (parameters->param2 || parameters->param3) {
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+
+ parameters->param2 = 0;
+ parameters->param3 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound((char *)&parameters->seq);
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorTalk, kCursorNormal);
+ parameters->param3 = 1;
+ break;
+
+ case 4:
+ parameters->param2 = 1;
+ parameters->param3 = 0;
+ break;
+ }
+ break;
+
+ case kAction55996766:
+ case kAction101687594:
+ CALLBACK_ACTION();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Vesna, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getSavePoints()->addData(kEntityVesna, kAction124190740, 0);
+
+ getData()->entityPosition = kPosition_4689;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Vesna, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ getData()->entityPosition = getEntityData(kEntityMilos)->entityPosition;
+ getData()->location = getEntityData(kEntityMilos)->location;
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getEntities()->clearSequences(kEntityVesna);
+ setup_function14();
+ }
+ break;
+
+ case kAction204832737:
+ setCallback(1);
+ setup_updateEntity2(kCarRedSleeping, kPosition_3050);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Vesna, function14)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ break;
+
+ case kAction190412928:
+ setCallback(1);
+ setup_function11();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Vesna, function15)
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+
+ getEntities()->clearSequences(kEntityVesna);
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Vesna, chapter2)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter2Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVesna);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Vesna, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kAction135024800:
+ setCallback(2);
+ setup_function18();
+ break;
+
+ case kAction137165825:
+ setCallback(1);
+ setup_function11();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Vesna, function18)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("610Bg", kObjectCompartmentG);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ if (getData()->entityPosition < kPosition_2087)
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("808US");
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityVesna, "808UD");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVesna);
+
+ setCallback(5);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 5:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityVesna);
+
+ setCallback(6);
+ setup_updateFromTime(4500);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 7:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(8);
+ setup_draw("808DD");
+ break;
+
+ case 8:
+ getEntities()->drawSequenceRight(kEntityVesna, "808DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVesna);
+
+ setCallback(9);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_updateEntity(kCarRedSleeping, kPosition_3050);
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_enterExitCompartment("610Ag", kObjectCompartmentG);
+ break;
+
+ case 11:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityVesna);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Vesna, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVesna);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Vesna, chapter3Handler)
+ EntityData::EntityParametersIIIS *parameters = (EntityData::EntityParametersIIIS*)_data->getCurrentParameters();
+
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getProgress().field_54 && parameters->param7 != kTimeInvalid) {
+ if (getState()->time > kTime2250000) {
+ parameters->param7 = kTimeInvalid;
+ setup_function22();
+ break;
+ }
+
+ if (!getEntities()->isPlayerInCar(kCarRedSleeping) || !parameters->param7)
+ parameters->param7 = (uint)getState()->time;
+
+ if (parameters->param7 < getState()->time) {
+ parameters->param7 = kTimeInvalid;
+ setup_function22();
+ break;
+ }
+ }
+
+ if (parameters->param2) {
+ UPDATE_PARAM(parameters->param8, getState()->timeTicks, 75);
+
+ parameters->param1 = 1;
+ parameters->param2 = 0;
+
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation1, kCursorNormal, kCursorNormal);
+ }
+
+ parameters->param8 = 0;
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ if (parameters->param2) {
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ setCallback(4);
+ setup_playSound(getSound()->wrongDoorCath());
+ break;
+ }
+
+ ++parameters->param3;
+
+ switch (parameters->param3) {
+ default:
+ break;
+
+ case 1:
+ strcpy((char *)&parameters->seq, "VES1015A");
+ break;
+
+ case 2:
+ strcpy((char *)&parameters->seq, "VES1015B");
+ break;
+
+ case 3:
+ strcpy((char *)&parameters->seq, "VES1015C");
+ parameters->param3 = 0;
+ break;
+ }
+
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorNormal, kCursorNormal);
+
+ setCallback(savepoint.action == kActionKnock ? 2 : 1);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ getEntities()->clearSequences(kEntityVesna);
+ break;
+
+ case kActionDrawScene:
+ if (parameters->param1 || parameters->param2) {
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ parameters->param1 = 0;
+ parameters->param2 = 0;
+ }
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound((char *)&parameters->seq);
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorTalk, kCursorNormal);
+ parameters->param2 = 1;
+ break;
+
+ case 4:
+ parameters->param1 = 1;
+ parameters->param2 = 0;
+ break;
+ }
+ break;
+
+ case kAction137165825:
+ setCallback(5);
+ setup_function11();
+ break;
+
+ case kAction155913424:
+ setCallback(6);
+ setup_function21();
+ break;
+
+ case kAction203663744:
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Vesna, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_enterExitCompartment("610Bg", kObjectCompartmentG);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ if (getData()->entityPosition < kPosition_2087)
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("808US");
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityVesna, "808UD");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVesna);
+
+ setCallback(5);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 5:
+ getEntities()->clearSequences(kEntityVesna);
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationInsideCompartment;
+
+ setCallback(6);
+ setup_updateFromTime(4500);
+ break;
+
+ case 6:
+ setCallback(7);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 7:
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(8);
+ setup_draw("808DD");
+ break;
+
+ case 8:
+ getEntities()->drawSequenceRight(kEntityVesna, "808DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVesna);
+
+ setCallback(9);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_updateEntity(kCarRedSleeping, kPosition_3050);
+ break;
+
+ case 10:
+ setCallback(11);
+ setup_enterExitCompartment("610Ag", kObjectCompartmentG); /* BUG the original engine passes 3050 here */
+ break;
+
+ case 11:
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityVesna);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(22, Vesna, function22)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityVesna, kEntityMilos, kAction259125998);
+
+ setCallback(1);
+ setup_enterExitCompartment("610Bg", kObjectCompartmentG);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ if (getData()->entityPosition < kPosition_2087)
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("808US");
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityVesna, "808UD");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVesna);
+
+ setCallback(5);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 5:
+ getEntities()->clearSequences(kEntityVesna);
+ getData()->car = kCarBaggage;
+ getSavePoints()->push(kEntityVesna, kEntityAnna, kAction235856512);
+ break;
+
+ case 6:
+ getData()->car = kCarRestaurant;
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(7);
+ setup_draw("808DD");
+ break;
+
+ case 7:
+ getEntities()->drawSequenceRight(kEntityVesna, "808DS");
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVesna);
+
+ setCallback(8);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 8:
+ setCallback(9);
+ setup_updateEntity(kCarRedSleeping, kPosition_3050);
+ break;
+
+ case 9:
+ setCallback(10);
+ setup_enterExitCompartment("610Ag", kObjectCompartmentG); /* BUG the original engine passes 3050 here */
+ break;
+
+ case 10:
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityVesna);
+
+ setup_function23();
+ break;
+ }
+ break;
+
+ case kAction189299008:
+ setCallback(6);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(23, Vesna, function23)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionKnock:
+ case kActionOpenDoor:
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorNormal, kCursorNormal);
+ setCallback(savepoint.action == kActionKnock ? 1 : 2);
+ setup_playSound(savepoint.action == kActionKnock ? "LIB012" : "LIB013");
+ break;
+
+ case kActionDefault:
+ getData()->car = kCarRedSleeping;
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ setCallback(3);
+ setup_playSound("VES1015A");
+ break;
+
+ case 3:
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+ }
+ break;
+
+ case kAction203663744:
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(24, Vesna, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setCallback(1);
+ setup_function11();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVesna);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->inventoryItem = kItemNone;
+
+ getObjects()->update(kObjectCompartmentG, kEntityVesna, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1)
+ setup_function25();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(25, Vesna, function25)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (getState()->time > kTime2428200 && !params->param1) {
+ params->param1 = 1;
+ setup_function26();
+ }
+ break;
+
+ case kActionDefault:
+ getSavePoints()->push(kEntityVesna, kEntityMilos, kAction135600432);
+
+ setCallback(1);
+ setup_enterExitCompartment("610BG", kObjectCompartmentG);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->location = kLocationOutsideCompartment;
+ if (getData()->entityPosition < kPosition_2087)
+ getData()->entityPosition = kPosition_2088;
+
+ setCallback(2);
+ setup_updateEntity(kCarRestaurant, kPosition_850);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case 3:
+ getData()->entityPosition = kPosition_1540;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(4);
+ setup_draw("808US");
+ break;
+
+ case 4:
+ getEntities()->drawSequenceRight(kEntityVesna, "808UD");
+ if (getEntities()->isInSalon(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVesna);
+
+ setCallback(5);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 5:
+ getEntities()->clearSequences(kEntityVesna);
+ getData()->entityPosition = kPosition_5900;
+ getData()->location = kLocationInsideCompartment;
+
+ // Original game calls clearSequences a second time
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(26, Vesna, function26)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ setCallback(1);
+ setup_callbackActionRestaurantOrSalon();
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->car = kCarRestaurant;
+ getData()->entityPosition = kPosition_5800;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(2);
+ setup_draw("808DD");
+ break;
+
+ case 2:
+ getEntities()->drawSequenceRight(kEntityVesna, "808DS");
+
+ if (getEntities()->isInRestaurant(kEntityPlayer))
+ getEntities()->updateFrame(kEntityVesna);
+
+ setCallback(3);
+ setup_callbackActionOnDirection();
+ break;
+
+ case 3:
+ setCallback(4);
+ setup_updateEntity(kCarRedSleeping, kPosition_3050);
+ break;
+
+ case 4:
+ setCallback(5);
+ setup_enterExitCompartment("610AG", kObjectCompartmentG);
+ break;
+
+ case 5:
+ setup_function27();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(27, Vesna, function27)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityVesna);
+ getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getData()->inventoryItem = kItemNone;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(28, Vesna, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityVesna);
+
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(29, Vesna, chapter5Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionOpenDoor:
+ setCallback(1);
+
+ getData()->currentCall++;
+ setup_savegame(kSavegameTypeEvent, kEventCathVesnaRestaurantKilled);
+ break;
+
+ case kActionDefault:
+ getObjects()->update(kObject64, kEntityVesna, kObjectLocationNone, kCursorNormal, kCursorForward);
+ break;
+
+ case kActionCallback:
+ if (getCallback() == 1) {
+ getAction()->playAnimation(kEventCathVesnaRestaurantKilled);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ }
+ break;
+
+ case kAction134427424:
+ getObjects()->update(kObject64, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
+ setup_function30();
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(30, Vesna, function30)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ if (!params->param1) {
+ UPDATE_PARAM_PROC(params->param3, getState()->timeTicks, 120)
+ getSound()->playSound(kEntityVesna, "Ves50001", SoundManager::kFlagDefault);
+ params->param1 = 1;
+ UPDATE_PARAM_PROC_END
+ }
+
+ UPDATE_PARAM(params->param4, getState()->timeTicks, 180);
+
+ setCallback(1);
+ setup_savegame(kSavegameTypeEvent, kEventCathVesnaTrainTopKilled);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ getAction()->playAnimation(kEventCathVesnaTrainTopKilled);
+ getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
+ break;
+
+ case 3:
+ getAction()->playAnimation(kEventCathVesnaTrainTopFight);
+
+ setCallback(4);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+ break;
+
+ case 4:
+ params->param2 = getFight()->setup(kFightVesna);
+
+ if (params->param2) {
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, params->param2 != Fight::kFightEndExit);
+ } else {
+ getSound()->playSound(kEntityPlayer, "TUNNEL");
+
+ getState()->time = (TimeValue)(getState()->time + 1800);
+
+ setCallback(5);
+ setup_savegame(kSavegameTypeEvent, kEventCathVesnaTrainTopWin);
+ }
+ break;
+
+ case 5:
+ getAction()->playAnimation(kEventCathVesnaTrainTopWin);
+ getScenes()->loadSceneFromPosition(kCarRestaurant, 11);
+
+ setup_nullfunction();
+ break;
+ }
+ break;
+
+ case kAction167992577:
+ setCallback(3);
+ setup_savegame(kSavegameTypeEvent, kEventCathVesnaTrainTopFight);
+ break;
+
+ case kAction202884544:
+ if (params->param1) {
+ setCallback(2);
+ setup_savegame(kSavegameTypeEvent, kEventCathVesnaTrainTopKilled);
+ } else {
+ getSound()->playSound(kEntityVesna, "Ves5001", SoundManager::kFlagDefault);
+ params->param1 = 1;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_NULL_FUNCTION(31, Vesna)
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/vesna.h b/engines/lastexpress/entities/vesna.h
new file mode 100644
index 0000000000..55a9a989c5
--- /dev/null
+++ b/engines/lastexpress/entities/vesna.h
@@ -0,0 +1,176 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_VESNA_H
+#define LASTEXPRESS_VESNA_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Vesna : public Entity {
+public:
+ Vesna(LastExpressEngine *engine);
+ ~Vesna() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+
+ /**
+ * Draws the entity
+ *
+ * @param sequence The sequence to draw
+ */
+ DECLARE_FUNCTION_1(draw, const char *sequence)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param time The time to add
+ */
+ DECLARE_FUNCTION_1(updateFromTime, uint32 time)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity2, CarIndex car, EntityPosition entityPosition)
+
+ /**
+ * Process callback action when somebody is standing in the restaurant or salon.
+ */
+ DECLARE_FUNCTION(callbackActionRestaurantOrSalon)
+
+ /**
+ * Process callback action when the entity direction is not kDirectionRight
+ */
+ DECLARE_FUNCTION(callbackActionOnDirection)
+
+ /**
+ * Saves the game
+ *
+ * @param savegameType The type of the savegame
+ * @param param The param for the savegame (EventIndex or TimeValue)
+ */
+ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
+
+ DECLARE_FUNCTION(function11)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function14)
+ DECLARE_FUNCTION(function15)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ DECLARE_FUNCTION(function18)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(function22)
+ DECLARE_FUNCTION(function23)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ DECLARE_FUNCTION(function25)
+ DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(function27)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function30)
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_VESNA_H
diff --git a/engines/lastexpress/entities/yasmin.cpp b/engines/lastexpress/entities/yasmin.cpp
new file mode 100644
index 0000000000..7dc46f9690
--- /dev/null
+++ b/engines/lastexpress/entities/yasmin.cpp
@@ -0,0 +1,490 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/entities/yasmin.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+namespace LastExpress {
+
+Yasmin::Yasmin(LastExpressEngine *engine) : Entity(engine, kEntityYasmin) {
+ ADD_CALLBACK_FUNCTION(Yasmin, reset);
+ ADD_CALLBACK_FUNCTION(Yasmin, enterExitCompartment);
+ ADD_CALLBACK_FUNCTION(Yasmin, playSound);
+ ADD_CALLBACK_FUNCTION(Yasmin, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Yasmin, updateEntity);
+ ADD_CALLBACK_FUNCTION(Yasmin, function6);
+ ADD_CALLBACK_FUNCTION(Yasmin, function7);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter1);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Yasmin, function10);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter2);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter3);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter4);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Yasmin, function17);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter5);
+ ADD_CALLBACK_FUNCTION(Yasmin, chapter5Handler);
+ ADD_CALLBACK_FUNCTION(Yasmin, function20);
+ ADD_CALLBACK_FUNCTION(Yasmin, function21);
+ ADD_NULL_FUNCTION();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(1, Yasmin, reset)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionExcuseMeCath:
+ getSound()->excuseMeCath();
+ break;
+
+ case kActionExcuseMe:
+ getSound()->excuseMe(kEntityYasmin);
+ break;
+ }
+
+ // Process default actions
+ Entity::reset(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_SI(2, Yasmin, enterExitCompartment, ObjectIndex)
+ Entity::enterExitCompartment(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_S(3, Yasmin, playSound)
+ Entity::playSound(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_NOSETUP(4, Yasmin, updateFromTime)
+ Entity::updateFromTime(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION_II(5, Yasmin, updateEntity, CarIndex, EntityPosition)
+ Entity::updateEntity(savepoint, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(6, Yasmin, function6)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_enterExitCompartment("615Be", kObjectCompartment5);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_3050);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment("615Ag", kObjectCompartment7);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityYasmin);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(7, Yasmin, function7)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationOutsideCompartment;
+
+ setCallback(1);
+ setup_enterExitCompartment("615Bg", kObjectCompartment7);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, kPosition_4840);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment("615Ae", kObjectCompartment5);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(kEntityYasmin);
+
+ CALLBACK_ACTION();
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(8, Yasmin, chapter1)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(9, Yasmin, chapter1Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTime1093500, params->param1, 1, setup_function6);
+ TIME_CHECK_CALLBACK(kTime1161000, params->param2, 3, setup_function7);
+ TIME_CHECK_PLAYSOUND_UPDATEPOSITION(kTime1162800, params->param3, 4, "Har1102", kPosition_4070);
+ TIME_CHECK_CALLBACK_1(kTime1165500, params->param4, 5, setup_playSound, "Har1104");
+ TIME_CHECK_CALLBACK_1(kTime1174500, params->param5, 6, setup_playSound, "Har1106");
+ TIME_CHECK_CALLBACK(kTime1183500, params->param6, 7, setup_function6);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_2740;
+ setCallback(2);
+ setup_playSound("Har1102");
+ break;
+
+ case 2:
+ TIME_CHECK_CALLBACK(kTime1161000, params->param2, 3, setup_function7);
+ // Fallback to case 3
+
+ case 3:
+ TIME_CHECK_PLAYSOUND_UPDATEPOSITION(kTime1162800, params->param3, 4, "Har1102", kPosition_4070);
+ // Fallback to case 4
+
+ case 4:
+ TIME_CHECK_CALLBACK_1(kTime1165500, params->param4, 5, setup_playSound, "Har1104");
+ // Fallback to case 5
+
+ case 5:
+ TIME_CHECK_CALLBACK_1(kTime1174500, params->param5, 6, setup_playSound, "Har1106");
+ // Fallback to case 6
+
+ case 6:
+ TIME_CHECK_CALLBACK(kTime1183500, params->param6, 7, setup_function6);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(10, Yasmin, function10)
+ if (savepoint.action == kActionDefault) {
+ getObjects()->update(kObjectCompartment7, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+
+ getEntities()->clearSequences(kEntityYasmin);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(11, Yasmin, chapter2)
+ if (savepoint.action == kActionDefault) {
+ getEntities()->clearSequences(kEntityYasmin);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+
+ setup_chapter2Handler();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(12, Yasmin, chapter2Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTime1759500, params->param1, 1, setup_function7);
+
+ if (getState()->time > kTime1800000 && !params->param2) {
+ params->param2 = 1;
+ getData()->entityPosition = kPosition_4070;
+
+ getSavePoints()->push(kEntityYasmin, kEntityTrain, kAction191070912, kPosition_4070);
+ }
+ break;
+
+ case kActionCallback:
+
+ if (getCallback() != 1)
+ break;
+
+ if (getState()->time > kTime1800000 && !params->param2) {
+ params->param2 = 1;
+ getData()->entityPosition = kPosition_4070;
+
+ getSavePoints()->push(kEntityYasmin, kEntityTrain, kAction191070912, kPosition_4070);
+ }
+
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(13, Yasmin, chapter3)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter3Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityYasmin);
+
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(14, Yasmin, chapter3Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTime2062800, params->param1, 1, setup_function6);
+ TIME_CHECK_CALLBACK(kTime2106000, params->param2, 2, setup_function7);
+ TIME_CHECK_CALLBACK(kTime2160000, params->param3, 3, setup_function6);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ TIME_CHECK_CALLBACK(kTime2106000, params->param2, 2, setup_function7);
+ // Fallback to case 2
+
+ case 2:
+ TIME_CHECK_CALLBACK(kTime2160000, params->param3, 3, setup_function6);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(15, Yasmin, chapter4)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter4Handler();
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_3050;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(16, Yasmin, chapter4Handler)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ TIME_CHECK_CALLBACK(kTime2457000, params->param1, 1, setup_function7);
+ TIME_CHECK_CALLBACK(kTime2479500, params->param2, 3, setup_function6);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ getData()->entityPosition = kPosition_4070;
+ setCallback(2);
+ setup_playSound("Har1110");
+ break;
+
+ case 2:
+ TIME_CHECK_CALLBACK(kTime2479500, params->param2, 3, setup_function6);
+ break;
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(17, Yasmin, function17)
+ // Same as existing function 10 ?
+ function10(savepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(18, Yasmin, chapter5)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ setup_chapter5Handler();
+ break;
+
+ case kActionDefault:
+ getEntities()->clearSequences(kEntityYasmin);
+
+ getData()->entityPosition = kPosition_3969;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRestaurant;
+ getData()->clothes = kClothesDefault;
+ getData()->inventoryItem = kItemNone;
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(19, Yasmin, chapter5Handler)
+ if (savepoint.action == kActionProceedChapter5)
+ setup_function20();
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(20, Yasmin, function20)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ UPDATE_PARAM(params->param1, getState()->time, 2700);
+ setup_function21();
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = kPosition_2500;
+ getData()->location = kLocationOutsideCompartment;
+ getData()->car = kCarGreenSleeping;
+ break;
+
+ case kActionDrawScene:
+ if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
+ setup_function21();
+ }
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+IMPLEMENT_FUNCTION(21, Yasmin, function21)
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionNone:
+ case kActionDefault:
+ if (getEntities()->updateEntity(kEntityYasmin, (CarIndex)params->param1, (EntityPosition)params->param2))
+ CALLBACK_ACTION();
+ break;
+
+ case kActionExcuseMeCath:
+ getSound()->excuseMeCath();
+ break;
+
+ case kActionExcuseMe:
+ getSound()->excuseMe(kEntityYasmin);
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/yasmin.h b/engines/lastexpress/entities/yasmin.h
new file mode 100644
index 0000000000..b35c713f8b
--- /dev/null
+++ b/engines/lastexpress/entities/yasmin.h
@@ -0,0 +1,142 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_YASMIN_H
+#define LASTEXPRESS_YASMIN_H
+
+#include "lastexpress/entities/entity.h"
+#include "lastexpress/entities/entity_intern.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Yasmin : public Entity {
+public:
+ Yasmin(LastExpressEngine *engine);
+ ~Yasmin() {}
+
+ /**
+ * Resets the entity
+ */
+ DECLARE_FUNCTION(reset)
+
+ /**
+ * Handles entering/exiting a compartment.
+ *
+ * @param sequence The sequence to draw
+ * @param compartment The compartment
+ */
+ DECLARE_FUNCTION_2(enterExitCompartment, const char *sequence, ObjectIndex compartment)
+
+ /**
+ * Plays sound
+ *
+ * @param filename The sound filename
+ */
+ DECLARE_FUNCTION_1(playSound, const char *filename)
+
+ /**
+ * Updates parameter 2 using time value
+ *
+ * @param savepoint The savepoint
+ * - Time to add
+ */
+ DECLARE_FUNCTION_NOSETUP(updateFromTime)
+
+ /**
+ * Updates the entity
+ *
+ * @param car The car
+ * @param entityPosition The entity position
+ */
+ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
+
+ DECLARE_FUNCTION(function6)
+ DECLARE_FUNCTION(function7)
+
+ /**
+ * Setup Chapter 1
+ */
+ DECLARE_FUNCTION(chapter1)
+
+ /**
+ * Handle Chapter 1 events
+ */
+ DECLARE_FUNCTION(chapter1Handler)
+
+ DECLARE_FUNCTION(function10)
+
+ /**
+ * Setup Chapter 2
+ */
+ DECLARE_FUNCTION(chapter2)
+
+ /**
+ * Handle Chapter 2 events
+ */
+ DECLARE_FUNCTION(chapter2Handler)
+
+ /**
+ * Setup Chapter 3
+ */
+ DECLARE_FUNCTION(chapter3)
+
+ /**
+ * Handle Chapter 3 events
+ */
+ DECLARE_FUNCTION(chapter3Handler)
+
+ /**
+ * Setup Chapter 4
+ */
+ DECLARE_FUNCTION(chapter4)
+
+ /**
+ * Handle Chapter 4 events
+ */
+ DECLARE_FUNCTION(chapter4Handler)
+
+ DECLARE_FUNCTION(function17)
+
+ /**
+ * Setup Chapter 5
+ */
+ DECLARE_FUNCTION(chapter5)
+
+ /**
+ * Handle Chapter 5 events
+ */
+ DECLARE_FUNCTION(chapter5Handler)
+
+ DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(function21)
+
+ DECLARE_NULL_FUNCTION()
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_YASMIN_H
diff --git a/backends/graphics/gp2xwizsdl/gp2xwizsdl-graphics.h b/engines/lastexpress/eventhandler.h
index 5f0c739379..106878fbbd 100644
--- a/backends/graphics/gp2xwizsdl/gp2xwizsdl-graphics.h
+++ b/engines/lastexpress/eventhandler.h
@@ -23,36 +23,31 @@
*
*/
-#ifndef BACKENDS_GRAPHICS_SDL_GP2XWIZ_H
-#define BACKENDS_GRAPHICS_SDL_GP2XWIZ_H
+#ifndef LASTEXPRESS_EVENTHANDLER_H
+#define LASTEXPRESS_EVENTHANDLER_H
-#include "backends/graphics/sdl/sdl-graphics.h"
+#include "common/EventRecorder.h"
+#include "common/func.h"
-// FIXME: For now keep hacks in this header to save polluting the SDL backend.
-enum {
- GFX_HALF = 12
-};
-
-class GP2XWIZSdlGraphicsManager : public SdlGraphicsManager {
-public:
- virtual void setGraphicsModeIntern();
- virtual bool setGraphicsMode(int mode);
- virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
+namespace LastExpress {
- virtual void initSize(uint w, uint h);
+#define SET_EVENT_HANDLERS(class, inst) \
+ _engine->setEventHandlers(new EVENT_HANDLER(class, eventMouse, inst), new EVENT_HANDLER(class, eventTick, inst));
- virtual void internUpdateScreen();
+#define EVENT_HANDLER(class, name, inst) \
+ Common::Functor1Mem<const Common::Event&, void, class>(inst, &class::name)
- virtual bool loadGFXMode();
-
- virtual void drawMouse();
- virtual void undrawMouse();
+class EventHandler {
+public:
+ virtual ~EventHandler() {}
- virtual void showOverlay();
- virtual void hideOverlay();
+ // Function pointer for event handler
+ typedef Common::Functor1<const Common::Event&, void> EventFunction;
- virtual void warpMouse(int x, int y);
+ virtual void eventMouse(const Common::Event &ev) {} // Event type 1
+ virtual void eventTick(const Common::Event &ev) {} // Event type 3
};
-#endif
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_EVENTHANDLER_H
diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp
new file mode 100644
index 0000000000..8058d22f05
--- /dev/null
+++ b/engines/lastexpress/game/action.cpp
@@ -0,0 +1,1966 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/action.h"
+
+#include "lastexpress/data/animation.h"
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/snd.h"
+#include "lastexpress/data/scene.h"
+
+#include "lastexpress/entities/abbot.h"
+#include "lastexpress/entities/anna.h"
+#include "lastexpress/entities/entity.h"
+
+#include "lastexpress/game/beetle.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savegame.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+static const int _animationListSize = 273;
+
+// List of animations
+static const struct {
+ const char *filename;
+ uint16 time;
+} _animationList[_animationListSize] = {
+ {"", 0},
+ {"1002", 255},
+ {"1002D", 255},
+ {"1003", 0},
+ {"1005", 195},
+ {"1006", 750}, // 5
+ {"1006A", 750},
+ {"1008", 765},
+ {"1008N", 765},
+ {"1008A", 750},
+ {"1008AN", 750}, // 10
+ {"1009", 0},
+ {"1011", 1005},
+ {"1011A", 780},
+ {"1012", 300},
+ {"1013", 285},
+ {"1017", 870}, // 15
+ {"1017A", 0}, // Not in the data files?
+ {"1019", 120},
+ {"1019D", 120},
+ {"1020", 120}, // 20
+ {"1022", 525},
+ {"1022A", 180},
+ {"1022AD", 210},
+ {"1022B", 210},
+ {"1022C", 210}, // 25
+ {"1023", 135},
+ {"1025", 945},
+ {"1028", 300},
+ {"1030", 390},
+ {"1031", 375}, // 30
+ {"1032", 1050},
+ {"1033", 945},
+ {"1034", 495},
+ {"1035", 1230},
+ {"1037", 1425}, // 35
+ {"1038", 195},
+ {"1038A", 405},
+ {"1039", 600},
+ {"1040", 945},
+ {"1041", 510}, // 40
+ {"1042", 540},
+ {"1043", 855},
+ {"1044", 645},
+ {"1046", 0},
+ {"1047", 0}, // 45
+ {"1047A", 0},
+ {"1059", 1005},
+ {"1060", 255},
+ {"1063", 0},
+ {"1101", 255}, // 50
+ {"1102", 1320},
+ {"1103", 210},
+ {"1104", 120},
+ {"1105", 1350},
+ {"1106", 315}, // 55
+ {"1106A", 315},
+ {"1106D", 315},
+ {"1107", 1},
+ {"1107A", 660},
+ {"1108", 300}, // 60
+ {"1109", 1305},
+ {"1110", 300},
+ {"1112", 0},
+ {"1115", 0},
+ {"1115A", 0}, // 65
+ {"1115B", 0},
+ {"1115C", 0},
+ {"1115D", 0},
+ {"1115E", 0},
+ {"1115F", 0}, // 70
+ {"1115G", 0},
+ {"1115H", 0},
+ {"1116", 0},
+ {"1117", 0},
+ {"1118", 105}, // 75
+ {"1202", 510},
+ {"1202A", 510},
+ {"1203", 720},
+ {"1204", 120},
+ {"1205", 465}, // 80
+ {"1206", 690},
+ {"1206A", 450},
+ {"1208", 465},
+ {"1210", 1020},
+ {"1211", 600}, // 85
+ {"1212", 435},
+ {"1213", 525},
+ {"1213A", 150},
+ {"1215", 390},
+ {"1216", 0}, // 90
+ {"1219", 240},
+ {"1222", 1095},
+ {"1223", 0},
+ {"1224", 720},
+ {"1225", 1005}, // 95
+ {"1227", 840},
+ {"1227A", 840},
+ {"1303", 450},
+ {"1303N", 450},
+ {"1304", 450}, // 100
+ {"1304N", 450},
+ {"1305", 630},
+ {"1309", 0},
+ {"1311", 1710},
+ {"1312", 240}, // 105
+ {"1312D", 240},
+ {"1313", 930},
+ {"1315", 1035},
+ {"1315A", 1035},
+ {"1401", 540}, // 110
+ {"1402", 150},
+ {"1402B", 150},
+ {"1403", 90},
+ {"1404", 885},
+ {"1404A", 0}, // 115
+ {"1405", 135},
+ {"1406", 1665},
+ {"1501", 285},
+ {"1501A", 285},
+ {"1502", 165}, // 120
+ {"1502A", 165},
+ {"1502D", 165},
+ {"1503", 0},
+ {"1504", 0},
+ {"1505", 0}, // 125
+ {"1505A", 0},
+ {"1506", 300},
+ {"1506A", 180},
+ {"1508", 0},
+ {"1509", 450}, // 130
+ {"1509S", 450},
+ {"1509A", 450},
+ {"1509AS", 450},
+ {"1509N", 450},
+ {"1509SN", 450}, // 135
+ {"1509AN", 450},
+ {"1509BN", 450},
+ {"1511", 150},
+ {"1511A", 150},
+ {"1511B", 90}, // 140
+ {"1511BA", 90},
+ {"1511C", 135},
+ {"1511D", 105},
+ {"1930", 0},
+ {"1511E", 150}, // 145
+ {"1512", 165},
+ {"1513", 180},
+ {"1517", 0},
+ {"1517A", 165},
+ {"1518", 165}, // 150
+ {"1518A", 165},
+ {"1518B", 165},
+ {"1591", 450},
+ {"1592", 450},
+ {"1593", 450}, // 155
+ {"1594", 450},
+ {"1595", 450},
+ {"1596", 450},
+ {"1601", 0},
+ {"1603", 0}, // 160
+ {"1606B", 315},
+ {"1607A", 0},
+ {"1610", 0},
+ {"1611", 0},
+ {"1612", 0}, // 165
+ {"1615", 0},
+ {"1619", 0},
+ {"1620", 120},
+ {"1621", 105},
+ {"1622", 105}, // 170
+ {"1629", 450},
+ {"1630", 450},
+ {"1631", 525},
+ {"1632", 0},
+ {"1633", 615}, // 175
+ {"1634", 180},
+ {"1702", 180},
+ {"1702DD", 180},
+ {"1702NU", 180},
+ {"1702ND", 180}, // 180
+ {"1704", 300},
+ {"1704D", 300},
+ {"1705", 195},
+ {"1705D", 195},
+ {"1706", 195}, // 185
+ {"1706DD", 195},
+ {"1706ND", 195},
+ {"1706NU", 195},
+ {"1901", 135},
+ {"1902", 1410}, // 190
+ {"1903", 0},
+ {"1904", 1920},
+ {"1908", 600},
+ {"1908A", 195},
+ {"1908B", 105}, // 195
+ {"1908C", 165},
+ {"1908CD", 0},
+ {"1909A", 150},
+ {"1909B", 150},
+ {"1909C", 150}, // 200
+ {"1910A", 180},
+ {"1910B", 180},
+ {"1910C", 180},
+ {"1911A", 90},
+ {"1911B", 90}, // 205
+ {"1911C", 90},
+ {"1912", 0},
+ {"1913", 0},
+ {"1917", 0},
+ {"1918", 390}, // 210
+ {"1919", 360},
+ {"1919A", 105},
+ {"1920", 75},
+ {"1922", 75},
+ {"1923", 150}, // 215
+ {"8001", 120},
+ {"8001A", 120},
+ {"8002", 120},
+ {"8002A", 120},
+ {"8002B", 120}, // 220
+ {"8003", 105},
+ {"8003A", 105},
+ {"8004", 105},
+ {"8004A", 105},
+ {"8005", 270}, // 225
+ {"8005B", 270},
+ {"8010", 270},
+ {"8013", 120},
+ {"8013A", 120},
+ {"8014", 165}, // 230
+ {"8014A", 165},
+ {"8014R", 165},
+ {"8014AR", 165},
+ {"8015", 150},
+ {"8015A", 150}, // 235
+ {"8015R", 150},
+ {"8015AR", 150},
+ {"8017", 120},
+ {"8017A", 120},
+ {"8017R", 120}, // 240
+ {"8017AR", 120},
+ {"8017N", 90},
+ {"8023", 135},
+ {"8023A", 135},
+ {"8023M", 135}, // 245
+ {"8024", 150},
+ {"8024A", 180},
+ {"8024M", 180},
+ {"8025", 150},
+ {"8025A", 150}, // 250
+ {"8025M", 150},
+ {"8027", 75},
+ {"8028", 75},
+ {"8029", 120},
+ {"8029A", 120}, // 255
+ {"8031", 375},
+ {"8032", 0},
+ {"8032A", 0},
+ {"8033", 105},
+ {"8035", 195}, // 260
+ {"8035A", 120},
+ {"8035B", 180},
+ {"8035C", 135},
+ {"8036", 105},
+ {"8037", 195}, // 265
+ {"8037A", 195},
+ {"8040", 240},
+ {"8040A", 240},
+ {"8041", 195},
+ {"8041A", 195}, // 270
+ {"8042", 600},
+ {"8042A", 600}
+};
+
+Action::Action(LastExpressEngine *engine) : _engine(engine) {
+ ADD_ACTION(dummy);
+ ADD_ACTION(inventory);
+ ADD_ACTION(savePoint);
+ ADD_ACTION(playSound);
+ ADD_ACTION(playMusic);
+ ADD_ACTION(knock);
+ ADD_ACTION(compartment);
+ ADD_ACTION(playSounds);
+ ADD_ACTION(playAnimation);
+ ADD_ACTION(openCloseObject);
+ ADD_ACTION(updateObjetLocation2);
+ ADD_ACTION(setItemLocation);
+ ADD_ACTION(knockNoSound);
+ ADD_ACTION(pickItem);
+ ADD_ACTION(dropItem);
+ ADD_ACTION(dummy);
+ ADD_ACTION(enterCompartment);
+ ADD_ACTION(dummy);
+ ADD_ACTION(getOutsideTrain);
+ ADD_ACTION(slip);
+ ADD_ACTION(getInsideTrain);
+ ADD_ACTION(climbUpTrain);
+ ADD_ACTION(climbDownTrain);
+ ADD_ACTION(jumpUpDownTrain);
+ ADD_ACTION(unbound);
+ ADD_ACTION(25);
+ ADD_ACTION(26);
+ ADD_ACTION(27);
+ ADD_ACTION(concertSitCough);
+ ADD_ACTION(29);
+ ADD_ACTION(catchBeetle);
+ ADD_ACTION(exitCompartment);
+ ADD_ACTION(32);
+ ADD_ACTION(useWhistle);
+ ADD_ACTION(openMatchBox);
+ ADD_ACTION(openBed);
+ ADD_ACTION(dummy);
+ ADD_ACTION(dialog);
+ ADD_ACTION(eggBox);
+ ADD_ACTION(39);
+ ADD_ACTION(bed);
+ ADD_ACTION(playMusicChapter);
+ ADD_ACTION(playMusicChapterSetupTrain);
+ ADD_ACTION(switchChapter);
+ ADD_ACTION(44);
+}
+
+Action::~Action() {
+ for (int i = 0; i < (int)_actions.size(); i++)
+ delete _actions[i];
+
+ // Zero-out passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Processing hotspot
+//////////////////////////////////////////////////////////////////////////
+SceneIndex Action::processHotspot(const SceneHotspot &hotspot) {
+ if (!hotspot.action || hotspot.action >= (int)_actions.size())
+ return kSceneInvalid;
+
+ return (*_actions[hotspot.action])(hotspot);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Actions
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+// Action 0
+IMPLEMENT_ACTION(dummy)
+ warning("Action::action_dummy: Dummy action function called (hotspot action: %d)!", hotspot.action);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 1
+IMPLEMENT_ACTION(inventory)
+ if (!getState()->sceneUseBackup)
+ return kSceneInvalid;
+
+ SceneIndex index = kSceneNone;
+ if (getState()->sceneBackup2) {
+ index = getState()->sceneBackup2;
+ getState()->sceneBackup2 = kSceneNone;
+ } else {
+ getState()->sceneUseBackup = false;
+ index = getState()->sceneBackup;
+
+ Scene *backup = getScenes()->get(getState()->sceneBackup);
+ if (getEntities()->getPosition(backup->car, backup->position))
+ index = getScenes()->processIndex(getState()->sceneBackup);
+ }
+
+ getScenes()->loadScene(index);
+
+ if (!getInventory()->getSelectedItem())
+ return kSceneInvalid;
+
+ if (!getInventory()->getSelectedEntry()->isSelectable || (!getState()->sceneBackup2 && getInventory()->getFirstExaminableItem()))
+ getInventory()->selectItem(getInventory()->getFirstExaminableItem());
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 2
+IMPLEMENT_ACTION(savePoint)
+ getSavePoints()->push(kEntityPlayer, (EntityIndex)hotspot.param1, (ActionIndex)hotspot.param2);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 3
+IMPLEMENT_ACTION(playSound)
+
+ // Check that the file is not already buffered
+ if (hotspot.param2 || !getSound()->isBuffered(Common::String::format("LIB%03d", hotspot.param1), true))
+ getSound()->playSoundEvent(kEntityPlayer, hotspot.param1, hotspot.param2);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 4
+IMPLEMENT_ACTION(playMusic)
+ // Check that the file is not already buffered
+ Common::String filename = Common::String::format("MUS%03d", hotspot.param1);
+
+ if (!getSound()->isBuffered(filename) && (hotspot.param1 != 50 || getProgress().chapter == kChapter5))
+ getSound()->playSound(kEntityPlayer, filename, SoundManager::kFlagDefault, hotspot.param2);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 5
+IMPLEMENT_ACTION(knock)
+ ObjectIndex object = (ObjectIndex)hotspot.param1;
+ if (object >= kObjectMax)
+ return kSceneInvalid;
+
+ if (getObjects()->get(object).entity) {
+ getSavePoints()->push(kEntityPlayer, getObjects()->get(object).entity, kActionKnock, object);
+ } else {
+ if (!getSound()->isBuffered("LIB012", true))
+ getSound()->playSoundEvent(kEntityPlayer, 12);
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 6
+IMPLEMENT_ACTION(compartment)
+ ObjectIndex compartment = (ObjectIndex)hotspot.param1;
+
+ if (compartment >= kObjectMax)
+ return kSceneInvalid;
+
+ if (getObjects()->get(compartment).entity) {
+ getSavePoints()->push(kEntityPlayer, getObjects()->get(compartment).entity, kActionOpenDoor, compartment);
+
+ // Stop processing further
+ return kSceneNone;
+ }
+
+ if (handleOtherCompartment(compartment, true, true)) {
+ // Stop processing further
+ return kSceneNone;
+ }
+
+ ObjectLocation location = getObjects()->get(compartment).location;
+ if (location == kObjectLocation1 || location == kObjectLocation3 || getEntities()->checkFields2(compartment)) {
+
+ if (location != kObjectLocation1 || getEntities()->checkFields2(compartment)
+ || (getInventory()->getSelectedItem() != kItemKey
+ && (compartment != kObjectCompartment1
+ || !getInventory()->hasItem(kItemKey)
+ || (getInventory()->getSelectedItem() != kItemFirebird && getInventory()->getSelectedItem() != kItemBriefcase)))) {
+ if (!getSound()->isBuffered("LIB13"))
+ getSound()->playSoundEvent(kEntityPlayer, 13);
+
+ // Stop processing further
+ return kSceneNone;
+ }
+
+ getSound()->playSoundEvent(kEntityPlayer, 32);
+
+ if ((compartment >= kObjectCompartment1 && compartment <= kObjectCompartment3) || (compartment >= kObjectCompartmentA && compartment <= kObjectCompartmentF))
+ getObjects()->update(compartment, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
+
+ getSound()->playSoundEvent(kEntityPlayer, 15, 22);
+ getInventory()->unselectItem();
+
+ return kSceneInvalid;
+ }
+
+ if (hotspot.action != SceneHotspot::kActionEnterCompartment || getInventory()->getSelectedItem() != kItemKey) {
+ if (compartment == kObjectCageMax) {
+ getSound()->playSoundEvent(kEntityPlayer, 26);
+ } else {
+ getSound()->playSoundEvent(kEntityPlayer, 14);
+ getSound()->playSoundEvent(kEntityPlayer, 15, 22);
+ }
+ return kSceneInvalid;
+ }
+
+ getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
+ getSound()->playSoundEvent(kEntityPlayer, 16);
+ getInventory()->unselectItem();
+
+ // Stop processing further
+ return kSceneNone;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 7
+IMPLEMENT_ACTION(playSounds)
+ getSound()->playSoundEvent(kEntityPlayer, hotspot.param1);
+ getSound()->playSoundEvent(kEntityPlayer, hotspot.param3, hotspot.param2);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 8
+IMPLEMENT_ACTION(playAnimation)
+ if (getEvent(hotspot.param1))
+ return kSceneInvalid;
+
+ playAnimation((EventIndex)hotspot.param1);
+
+ if (!hotspot.scene)
+ getScenes()->processScene();
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 9
+IMPLEMENT_ACTION(openCloseObject)
+ ObjectIndex object = (ObjectIndex)hotspot.param1;
+ ObjectLocation location = (ObjectLocation)hotspot.param2;
+
+ if (object >= kObjectMax)
+ return kSceneInvalid;
+
+ getObjects()->update(object, getObjects()->get(object).entity, location, kCursorKeepValue, kCursorKeepValue);
+
+ bool isNotWindow = ((object <= kObjectCompartment8 || object >= kObjectHandleBathroom) && (object <= kObjectCompartmentH || object >= kObject48));
+
+ switch (location) {
+ default:
+ break;
+
+ case kObjectLocation1:
+ if (isNotWindow)
+ getSound()->playSoundEvent(kEntityPlayer, 24);
+ else
+ getSound()->playSoundEvent(kEntityPlayer, 21);
+ break;
+
+ case kObjectLocation2:
+ if (isNotWindow)
+ getSound()->playSoundEvent(kEntityPlayer, 36);
+ else
+ getSound()->playSoundEvent(kEntityPlayer, 20);
+ break;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 10
+IMPLEMENT_ACTION(updateObjetLocation2)
+ ObjectIndex object = (ObjectIndex)hotspot.param1;
+ ObjectLocation location = (ObjectLocation)hotspot.param2;
+
+ if (object >= kObjectMax)
+ return kSceneInvalid;
+
+ getObjects()->updateLocation2(object, location);
+
+ if (object != kObject112 || getSound()->isBuffered("LIB096")) {
+ if (object == 1)
+ getSound()->playSoundEvent(kEntityPlayer, 73);
+ } else {
+ getSound()->playSoundEvent(kEntityPlayer, 96);
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 11
+IMPLEMENT_ACTION(setItemLocation)
+ InventoryItem item = (InventoryItem)hotspot.param1;
+ if (item >= kPortraitOriginal)
+ return kSceneInvalid;
+
+ Inventory::InventoryEntry *entry = getInventory()->get(item);
+ if (entry->isPresent)
+ return kSceneInvalid;
+
+ entry->location = (ObjectLocation)hotspot.param2;
+
+ if (item == kItemCorpse) {
+ ObjectLocation corpseLocation = getInventory()->get(kItemCorpse)->location;
+ getProgress().eventCorpseMovedFromFloor = (corpseLocation == kObjectLocation3 || corpseLocation == kObjectLocation4);
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 12
+IMPLEMENT_ACTION(knockNoSound)
+ ObjectIndex object = (ObjectIndex)hotspot.param1;
+ if (object >= kObjectMax)
+ return kSceneInvalid;
+
+ if (getObjects()->get(object).entity)
+ getSavePoints()->push(kEntityPlayer, getObjects()->get(object).entity, kActionKnock, object);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 13
+IMPLEMENT_ACTION(pickItem)
+ InventoryItem item = (InventoryItem)hotspot.param1;
+ ObjectLocation location = (ObjectLocation)hotspot.param2;
+ bool process = (hotspot.scene == 0);
+ SceneIndex sceneIndex = kSceneInvalid;
+
+ if (item >= kPortraitOriginal)
+ return kSceneInvalid;
+
+ Inventory::InventoryEntry *entry = getInventory()->get(item);
+ if (!entry->location)
+ return kSceneInvalid;
+
+ // Special case for corpse
+ if (item == kItemCorpse) {
+ pickCorpse(location, process);
+ return kSceneInvalid;
+ }
+
+ // Add and process items
+ getInventory()->addItem(item);
+
+ switch (item) {
+ default:
+ break;
+
+ case kItemGreenJacket:
+ pickGreenJacket(process);
+ break;
+
+ case kItemScarf:
+ pickScarf(process);
+
+ // stop processing
+ return kSceneInvalid;
+
+ case kItemParchemin:
+ if (location != kObjectLocation2)
+ break;
+
+ getInventory()->addItem(kItemParchemin);
+ getInventory()->get(kItem11)->location = kObjectLocation1;
+ getSound()->playSoundEvent(kEntityPlayer, 9);
+ break;
+
+ case kItemBomb:
+ RESET_ENTITY_STATE(kEntityAbbot, Abbot, setup_pickBomb);
+ break;
+
+ case kItemBriefcase:
+ getSound()->playSoundEvent(kEntityPlayer, 83);
+ break;
+ }
+
+ // Load item scene
+ if (getInventory()->get(item)->scene) {
+ if (!getState()->sceneUseBackup) {
+ getState()->sceneUseBackup = true;
+ getState()->sceneBackup = (hotspot.scene ? hotspot.scene : getState()->scene);
+ }
+
+ getScenes()->loadScene(getInventory()->get(item)->scene);
+
+ // do not process further
+ sceneIndex = kSceneNone;
+ }
+
+ // Select item
+ if (getInventory()->get(item)->isSelectable) {
+ getInventory()->selectItem(item);
+ _engine->getCursor()->setStyle(getInventory()->get(item)->cursor);
+ }
+
+ return sceneIndex;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 14
+IMPLEMENT_ACTION(dropItem)
+ InventoryItem item = (InventoryItem)hotspot.param1;
+ ObjectLocation location = (ObjectLocation)hotspot.param2;
+ bool process = (hotspot.scene == kSceneNone);
+
+ if (item >= kPortraitOriginal)
+ return kSceneInvalid;
+
+ if (!getInventory()->hasItem(item))
+ return kSceneInvalid;
+
+ if (location < kObjectLocation1)
+ return kSceneInvalid;
+
+ // Handle actions
+ if (item == kItemBriefcase) {
+ getSound()->playSoundEvent(kEntityPlayer, 82);
+
+ if (location == kObjectLocation2) {
+ if (!getProgress().field_58) {
+ getSaveLoad()->saveGame(kSavegameTypeTime, kEntityPlayer, kTimeNone);
+ getProgress().field_58 = 1;
+ }
+
+ if (getInventory()->get(kItemParchemin)->location == kObjectLocation2) {
+ getInventory()->addItem(kItemParchemin);
+ getInventory()->get(kItem11)->location = kObjectLocation1;
+ getSound()->playSoundEvent(kEntityPlayer, 9);
+ }
+ }
+ }
+
+ // Update item location
+ getInventory()->removeItem(item, location);
+
+ if (item == kItemCorpse)
+ dropCorpse(process);
+
+ // Unselect item
+ getInventory()->unselectItem();
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 15: Dummy action
+
+//////////////////////////////////////////////////////////////////////////
+// Action 16
+IMPLEMENT_ACTION(enterCompartment)
+ if (getObjects()->get(kObjectCompartment1).location == kObjectLocation1 || getObjects()->get(kObjectCompartment1).location == kObjectLocation3 || getInventory()->getSelectedItem() == kItemKey)
+ return action_compartment(hotspot);
+
+ if (getProgress().eventCorpseFound) {
+ if (hotspot.action != SceneHotspot::kActionEnterCompartment || getInventory()->get(kItemBriefcase)->location != kObjectLocation2)
+ return action_compartment(hotspot);
+
+ getSound()->playSoundEvent(kEntityPlayer, 14);
+ getSound()->playSoundEvent(kEntityPlayer, 15, 22);
+
+ if (getProgress().field_78 && !getSound()->isBuffered("MUS003")) {
+ getSound()->playSound(kEntityPlayer, "MUS003", SoundManager::kFlagDefault);
+ getProgress().field_78 = 0;
+ }
+
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 77);
+
+ return kSceneNone;
+ }
+
+ getSaveLoad()->saveGame(kSavegameTypeTime, kEntityPlayer, kTimeNone);
+ getSound()->playSound(kEntityPlayer, "LIB014");
+ playAnimation(kEventCathFindCorpse);
+ getSound()->playSound(kEntityPlayer, "LIB015");
+ getProgress().eventCorpseFound = true;
+
+ return kSceneCompartmentCorpse;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 17: Dummy action
+
+//////////////////////////////////////////////////////////////////////////
+// Action 18
+IMPLEMENT_ACTION(getOutsideTrain)
+ ObjectIndex object = (ObjectIndex)hotspot.param1;
+
+ if ((getEvent(kEventCathLookOutsideWindowDay) || getEvent(kEventCathLookOutsideWindowNight) || getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1)
+ && getProgress().isTrainRunning
+ && (object != kObjectOutsideAnnaCompartment || (!getEntities()->isInsideCompartment(kEntityRebecca, kCarRedSleeping, kPosition_4840) && getObjects()->get(kObjectOutsideBetweenCompartments).location == kObjectLocation2))
+ && getInventory()->getSelectedItem() != kItemFirebird
+ && getInventory()->getSelectedItem() != kItemBriefcase) {
+
+ switch (object) {
+ default:
+ return kSceneInvalid;
+
+ case kObjectOutsideTylerCompartment:
+ getEvent(kEventCathLookOutsideWindowDay) = 1;
+ playAnimation(isNight() ? kEventCathGoOutsideTylerCompartmentNight : kEventCathGoOutsideTylerCompartmentDay);
+ getProgress().field_C8 = 1;
+ break;
+
+ case kObjectOutsideBetweenCompartments:
+ getEvent(kEventCathLookOutsideWindowDay) = 1;
+ playAnimation(isNight() ? kEventCathGoOutsideNight : kEventCathGoOutsideDay);
+ getProgress().field_C8 = 1;
+ break;
+
+ case kObjectOutsideAnnaCompartment:
+ getEvent(kEventCathLookOutsideWindowDay) = 1;
+ playAnimation(isNight() ? kEventCathGetInsideNight : kEventCathGetInsideDay);
+ if (!hotspot.scene)
+ getScenes()->processScene();
+ break;
+ }
+ } else {
+ if (object == kObjectOutsideTylerCompartment || object == kObjectOutsideBetweenCompartments || object == kObjectOutsideAnnaCompartment) {
+ playAnimation(isNight() ? kEventCathLookOutsideWindowNight : kEventCathLookOutsideWindowDay);
+ getScenes()->processScene();
+ return kSceneNone;
+ }
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 19
+IMPLEMENT_ACTION(slip)
+ switch((ObjectIndex)hotspot.param1) {
+ default:
+ return kSceneInvalid;
+
+ case kObjectOutsideTylerCompartment:
+ playAnimation(isNight() ? kEventCathSlipTylerCompartmentNight : kEventCathSlipTylerCompartmentDay);
+ break;
+
+ case kObjectOutsideBetweenCompartments:
+ playAnimation(isNight() ? kEventCathSlipNight : kEventCathSlipDay);
+ break;
+ }
+
+ getProgress().field_C8 = 0;
+
+ if (!hotspot.scene)
+ getScenes()->processScene();
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 20
+IMPLEMENT_ACTION(getInsideTrain)
+ switch ((ObjectIndex)hotspot.param1) {
+ default:
+ return kSceneInvalid;
+
+ case kObjectOutsideTylerCompartment:
+ playAnimation(isNight() ? kEventCathGetInsideTylerCompartmentNight : kEventCathGetInsideTylerCompartmentDay);
+ break;
+
+ case kObjectOutsideBetweenCompartments:
+ playAnimation(isNight() ? kEventCathGetInsideNight : kEventCathGetInsideDay);
+ break;
+
+ case kObjectOutsideAnnaCompartment:
+ playAnimation(kEventCathGettingInsideAnnaCompartment);
+ break;
+ }
+
+ if (!hotspot.scene)
+ getScenes()->processScene();
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 21
+IMPLEMENT_ACTION(climbUpTrain)
+ byte action = hotspot.param1;
+
+ if (action != 1 && action != 2)
+ return kSceneInvalid;
+
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter2:
+ case kChapter3:
+ if (action == 2)
+ playAnimation(kEventCathClimbUpTrainGreenJacket);
+
+ playAnimation(kEventCathTopTrainGreenJacket);
+ break;
+
+ case kChapter5:
+ if (action == 2)
+ playAnimation(getProgress().isNightTime ? kEventCathClimbUpTrainNoJacketNight : kEventCathClimbUpTrainNoJacketDay);
+
+ playAnimation(getProgress().isNightTime ? kEventCathTopTrainNoJacketNight : kEventCathTopTrainNoJacketDay);
+ break;
+ }
+
+ if (!hotspot.scene)
+ getScenes()->processScene();
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 22
+IMPLEMENT_ACTION(climbDownTrain)
+ EventIndex evt = kEventNone;
+ switch (getProgress().chapter) {
+ default:
+ return kSceneInvalid;
+
+ case kChapter2:
+ case kChapter3:
+ evt = kEventCathClimbDownTrainGreenJacket;
+ break;
+
+ case kChapter5:
+ evt = (getProgress().isNightTime ? kEventCathClimbDownTrainNoJacketNight : kEventCathClimbDownTrainNoJacketDay);
+ break;
+ }
+
+ playAnimation(evt);
+ if (evt == kEventCathClimbDownTrainNoJacketDay)
+ getSound()->playSoundEvent(kEntityPlayer, 37);
+
+ if (!hotspot.scene)
+ getScenes()->processScene();
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 23
+IMPLEMENT_ACTION(jumpUpDownTrain)
+ switch (hotspot.param1) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kActionBreakCeiling);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kActionJumpDownCeiling);
+ break;
+
+ case 3:
+ if (getInventory()->getSelectedItem() == kItemBriefcase) {
+ getInventory()->removeItem(kItemBriefcase, kObjectLocation3);
+ getSound()->playSoundEvent(kEntityPlayer, 82);
+ getInventory()->unselectItem();
+ }
+
+ // Show animation with or without briefcase
+ playAnimation((getInventory()->get(kItemBriefcase)->location - 3) ? kEventCathJumpUpCeilingBriefcase : kEventCathJumpUpCeiling);
+
+ if (!hotspot.scene)
+ getScenes()->processScene();
+
+ break;
+
+ case 4:
+ if (getProgress().chapter == kChapter1)
+ getSavePoints()->push(kEntityPlayer, kEntityKronos, kAction202621266);
+ break;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 24
+IMPLEMENT_ACTION(unbound)
+ byte action = hotspot.param1;
+
+ switch (action) {
+ default:
+ break;
+
+ case 1:
+ playAnimation(kEventCathStruggleWithBonds);
+ if (hotspot.scene)
+ getScenes()->processScene();
+ break;
+
+ case 2:
+ playAnimation(kEventCathBurnRope);
+ if (hotspot.scene)
+ getScenes()->processScene();
+ break;
+
+ case 3:
+ if (getEvent(kEventCathBurnRope)) {
+ playAnimation(kEventCathRemoveBonds);
+ getProgress().field_84 = 0;
+ getScenes()->loadSceneFromPosition(kCarBaggageRear, 89);
+ return kSceneNone;
+ }
+ break;
+
+ case 4:
+ if (!getEvent(kEventCathStruggleWithBonds2)) {
+ playAnimation(kEventCathStruggleWithBonds2);
+ getSound()->playSoundEvent(kEntityPlayer, 101);
+ getInventory()->setLocationAndProcess(kItemMatch, kObjectLocation2);
+ if (!hotspot.scene)
+ getScenes()->processScene();
+ }
+ break;
+
+ case 5:
+ getSavePoints()->push(kEntityPlayer, kEntityIvo, kAction192637492);
+ break;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 25
+IMPLEMENT_ACTION(25)
+ switch(hotspot.param1) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityPlayer, kEntityAnna, kAction272177921);
+ break;
+
+ case 2:
+ if (!getSound()->isBuffered("MUS021"))
+ getSound()->playSound(kEntityPlayer, "MUS021", SoundManager::kFlagDefault);
+ break;
+
+ case 3:
+ getSound()->playSoundEvent(kEntityPlayer, 43);
+ if (!getInventory()->hasItem(kItemKey) && !getEvent(kEventAnnaBaggageArgument)) {
+ RESET_ENTITY_STATE(kEntityAnna, Anna, setup_baggage);
+ return kSceneNone;
+ }
+ break;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 26
+IMPLEMENT_ACTION(26)
+ switch(hotspot.param1) {
+ default:
+ return kSceneInvalid;
+
+ case 1:
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kAction158610240);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kAction225367984);
+ getInventory()->unselectItem();
+ return kSceneNone;
+
+ case 3:
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kAction191001984);
+ return kSceneNone;
+
+ case 4:
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kAction201959744);
+ return kSceneNone;
+
+ case 5:
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kAction169300225);
+ break;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 27
+IMPLEMENT_ACTION(27)
+ if (!getSound()->isBuffered("LIB031", true))
+ getSound()->playSoundEvent(kEntityPlayer, 31);
+
+ switch (getEntityData(kEntityPlayer)->car) {
+ default:
+ break;
+
+ case kCarGreenSleeping:
+ getSavePoints()->push(kEntityPlayer, kEntityMertens, kAction225358684, hotspot.param1);
+ break;
+
+ case kCarRedSleeping:
+ getSavePoints()->push(kEntityPlayer, kEntityCoudert, kAction225358684, hotspot.param1);
+ break;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 28
+IMPLEMENT_ACTION(concertSitCough)
+ switch(hotspot.param1) {
+ default:
+ return kSceneInvalid;
+
+ case 1:
+ playAnimation(kEventConcertSit);
+ break;
+
+ case 2:
+ playAnimation(kEventConcertCough);
+ break;
+ }
+
+ if (!hotspot.scene)
+ getScenes()->processScene();
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 29
+IMPLEMENT_ACTION(29)
+ getProgress().field_C = 1;
+ getSound()->playSoundEvent(kEntityPlayer, hotspot.param1, hotspot.param2);
+
+ Common::String filename = Common::String::format("MUS%03d", hotspot.param3);
+ if (!getSound()->isBuffered(filename))
+ getSound()->playSound(kEntityPlayer, filename, SoundManager::kFlagDefault);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 30
+IMPLEMENT_ACTION(catchBeetle)
+ if (!getBeetle()->isLoaded())
+ return kSceneInvalid;
+
+ if (getBeetle()->catchBeetle()) {
+ getBeetle()->unload();
+ getInventory()->get(kItemBeetle)->location = kObjectLocation1;
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kActionCatchBeetle);
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 31
+IMPLEMENT_ACTION(exitCompartment)
+ if (!getProgress().field_30 && getProgress().jacket != kJacketOriginal) {
+ getSaveLoad()->saveGame(kSavegameTypeTime, kEntityPlayer, kTimeNone);
+ getProgress().field_30 = 1;
+ }
+
+ getObjects()->updateLocation2(kObjectCompartment1, (ObjectLocation)hotspot.param2);
+
+ // fall to case enterCompartment action
+ return action_enterCompartment(hotspot);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 32
+IMPLEMENT_ACTION(32)
+ switch(hotspot.param1) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityPlayer, kEntitySalko, kAction167992577);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityPlayer, kEntityVesna, kAction202884544);
+ break;
+
+ case 3:
+ if (getProgress().chapter == kChapter5) {
+ getSavePoints()->push(kEntityPlayer, kEntityAbbot, kAction168646401);
+ getSavePoints()->push(kEntityPlayer, kEntityMilos, kAction168646401);
+ } else {
+ getSavePoints()->push(kEntityPlayer, kEntityTrain, kAction203339360);
+ }
+ // Stop processing further scenes
+ return kSceneNone;
+
+ case 4:
+ getSavePoints()->push(kEntityPlayer, kEntityMilos, kAction169773228);
+ break;
+
+ case 5:
+ getSavePoints()->push(kEntityPlayer, kEntityVesna, kAction167992577);
+ break;
+
+ case 6:
+ getSavePoints()->push(kEntityPlayer, kEntityAugust, kAction203078272);
+ break;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 33
+IMPLEMENT_ACTION(useWhistle)
+ EventIndex evt = kEventNone;
+ SceneIndex sceneIndex = kSceneInvalid;
+
+ switch (hotspot.param1) {
+ default:
+ break;
+
+ case 1:
+ if (getEvent(kEventKronosBringFirebird)) {
+ getSavePoints()->push(kEntityPlayer, kEntityAnna, kAction205294778);
+ break;
+ }
+
+ if (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_8200)) {
+ evt = kEventCathOpenEgg;
+
+ Scene *scene = getScenes()->get(hotspot.scene);
+ if (scene->getHotspot())
+ sceneIndex = scene->getHotspot()->scene;
+
+ } else {
+ evt = kEventCathOpenEggNoBackground;
+ }
+ getProgress().isEggOpen = true;
+ break;
+
+ case 2:
+ if (getEvent(kEventKronosBringFirebird)) {
+ getSavePoints()->push(kEntityPlayer, kEntityAnna, kAction224309120);
+ break;
+ }
+
+ evt = (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_8200)) ? kEventCathCloseEgg : kEventCathCloseEggNoBackground;
+ getProgress().isEggOpen = false;
+ break;
+
+ case 3:
+ if (getEvent(kEventKronosBringFirebird)) {
+ getSavePoints()->push(kEntityPlayer, kEntityAnna, kActionUseWhistle);
+ break;
+ }
+
+ evt = (getEntities()->isInsideCompartment(kEntityPlayer, kCarGreenSleeping, kPosition_8200)) ? kEventCathUseWhistleOpenEgg : kEventCathUseWhistleOpenEggNoBackground;
+ break;
+
+ }
+
+ if (evt != kEventNone) {
+ playAnimation(evt);
+ if (sceneIndex == kSceneNone || !hotspot.scene)
+ getScenes()->processScene();
+ }
+
+ return sceneIndex;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 34
+IMPLEMENT_ACTION(openMatchBox)
+ // If the match is already in the inventory, do nothing
+ if (!getInventory()->get(kItemMatch)->location
+ || getInventory()->get(kItemMatch)->isPresent)
+ return kSceneInvalid;
+
+ getInventory()->addItem(kItemMatch);
+ getSound()->playSoundEvent(kEntityPlayer, 102);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 35
+IMPLEMENT_ACTION(openBed)
+ getSound()->playSoundEvent(kEntityPlayer, 59);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 36: Dummy action
+
+//////////////////////////////////////////////////////////////////////////
+// Action 37
+IMPLEMENT_ACTION(dialog)
+ getSound()->playDialog(kEntityTables4, (EntityIndex)hotspot.param1, SoundManager::kFlagDefault, 0);
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 38
+IMPLEMENT_ACTION(eggBox)
+ getSound()->playSoundEvent(kEntityPlayer, 43);
+ if (getProgress().field_7C && !getSound()->isBuffered("MUS003")) {
+ getSound()->playSound(kEntityPlayer, "MUS003", SoundManager::kFlagDefault);
+ getProgress().field_7C = 0;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 39
+IMPLEMENT_ACTION(39)
+ getSound()->playSoundEvent(kEntityPlayer, 24);
+ if (getProgress().field_80 && !getSound()->isBuffered("MUS003")) {
+ getSound()->playSound(kEntityPlayer, "MUS003", SoundManager::kFlagDefault);
+ getProgress().field_80 = 0;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 40
+IMPLEMENT_ACTION(bed)
+ getSound()->playSoundEvent(kEntityPlayer, 85);
+ // falls to case knockNoSound
+ return action_knockNoSound(hotspot);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 41
+IMPLEMENT_ACTION(playMusicChapter)
+ byte id = 0;
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ id = hotspot.param1;
+ break;
+
+ case kChapter2:
+ case kChapter3:
+ id = hotspot.param2;
+ break;
+
+ case kChapter4:
+ case kChapter5:
+ id = hotspot.param3;
+ break;
+ }
+
+ if (id) {
+ Common::String filename = Common::String::format("MUS%03d", id);
+
+ if (!getSound()->isBuffered(filename))
+ getSound()->playSound(kEntityPlayer, filename, SoundManager::kFlagDefault);
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 42
+IMPLEMENT_ACTION(playMusicChapterSetupTrain)
+ int id = 0;
+ switch (getProgress().chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ id = 1;
+ break;
+
+ case kChapter2:
+ case kChapter3:
+ id = 2;
+ break;
+
+ case kChapter4:
+ case kChapter5:
+ id = 4;
+ break;
+ }
+
+ Common::String filename = Common::String::format("MUS%03d", hotspot.param1);
+
+ if (!getSound()->isBuffered(filename) && hotspot.param3 & id) {
+ getSound()->playSound(kEntityPlayer, filename, SoundManager::kFlagDefault);
+
+ getSavePoints()->call(kEntityPlayer, kEntityTrain, kAction203863200, filename.c_str());
+ getSavePoints()->push(kEntityPlayer, kEntityTrain, kAction222746496, hotspot.param2);
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// // Action 43
+IMPLEMENT_ACTION(switchChapter)
+ // Nothing to do here as an hotspot action
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Action 44
+IMPLEMENT_ACTION(44)
+ switch (hotspot.param1) {
+ default:
+ break;
+
+ case 1:
+ getSavePoints()->push(kEntityPlayer, kEntityRebecca, kAction205034665);
+ break;
+
+ case 2:
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kAction225358684);
+ break;
+ }
+
+ return kSceneInvalid;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Helper functions
+//////////////////////////////////////////////////////////////////////////
+void Action::pickGreenJacket(bool process) const {
+ getProgress().jacket = kJacketGreen;
+ getInventory()->addItem(kItemMatchBox);
+
+ getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
+ playAnimation(kEventPickGreenJacket);
+
+ getInventory()->setPortrait(kPortraitGreen);
+
+ if (process)
+ getScenes()->processScene();
+}
+
+void Action::pickScarf(bool process) const {
+ playAnimation(getProgress().jacket == kJacketGreen ? kEventPickScarfGreen : kEventPickScarfOriginal);
+
+ if (process)
+ getScenes()->processScene();
+}
+
+void Action::pickCorpse(ObjectLocation bedPosition, bool process) const {
+
+ if (getProgress().jacket == kJacketOriginal)
+ getProgress().jacket = kJacketBlood;
+
+ switch(getInventory()->get(kItemCorpse)->location) {
+ // No way to pick the corpse
+ default:
+ break;
+
+ // Floor
+ case kObjectLocation1:
+ // Bed is fully opened, move corpse directly there
+ if (bedPosition == 4) {
+ playAnimation(kEventCorpsePickFloorOpenedBedOriginal);
+
+ getInventory()->get(kItemCorpse)->location = kObjectLocation5;
+ break;
+ }
+
+ playAnimation(getProgress().jacket == kJacketGreen ? kEventCorpsePickFloorGreen : kEventCorpsePickFloorOriginal);
+ break;
+
+ // Bed
+ case kObjectLocation2:
+ playAnimation(getProgress().jacket == kJacketGreen ? kEventCorpsePickBedGreen : kEventCorpsePickBedOriginal);
+ break;
+ }
+
+ if (process)
+ getScenes()->processScene();
+
+ // Add corpse to inventory
+ if (bedPosition != 4) { // bed is not fully opened
+ getInventory()->addItem(kItemCorpse);
+ getInventory()->selectItem(kItemCorpse);
+ _engine->getCursor()->setStyle(kCursorCorpse);
+ }
+}
+
+void Action::dropCorpse(bool process) const {
+ switch(getInventory()->get(kItemCorpse)->location) {
+ default:
+ break;
+
+ case kObjectLocation1: // Floor
+ playAnimation(getProgress().jacket == kJacketGreen ? kEventCorpseDropFloorGreen : kEventCorpseDropFloorOriginal);
+ break;
+
+ case kObjectLocation2: // Bed
+ playAnimation(getProgress().jacket == kJacketGreen ? kEventCorpseDropBedGreen : kEventCorpseDropBedOriginal);
+ break;
+
+ case kObjectLocation4: // Window
+ // Say goodbye to an old friend
+ getInventory()->get(kItemCorpse)->location = kObjectLocationNone;
+ getProgress().eventCorpseThrown = true;
+
+ if (getState()->time <= kTime1138500) {
+ playAnimation(getProgress().jacket == kJacketGreen ? kEventCorpseDropWindowGreen : kEventCorpseDropWindowOriginal);
+
+ getProgress().field_24 = true;
+ } else {
+ playAnimation(kEventCorpseDropBridge);
+ }
+
+ getProgress().eventCorpseMovedFromFloor = true;
+ break;
+ }
+
+ if (process)
+ getScenes()->processScene();
+}
+
+bool Action::handleOtherCompartment(ObjectIndex object, bool doPlaySound, bool doLoadScene) const {
+#define ENTITY_PARAMS(entity, index, id) \
+ ((EntityData::EntityParametersIIII*)getEntities()->get(entity)->getParamData()->getParameters(8, index))->param##id
+
+ // Only handle compartments
+ if (getEntityData(kEntityPlayer)->location != kLocationOutsideCompartment
+ || ((object < kObjectCompartment2 || object > kObjectCompartment8) && (object < kObjectCompartmentA || object > kObjectCompartmentH)))
+ return false;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Gendarmes
+ if (getEntityData(kEntityPlayer)->car == getEntityData(kEntityGendarmes)->car
+ && getEntityData(kEntityGendarmes)->location == kLocationOutsideCompartment
+ && !getEntities()->compare(kEntityPlayer, kEntityGendarmes)) {
+ if (doPlaySound)
+ playCompartmentSoundEvents(object);
+
+ if (doLoadScene)
+ getScenes()->loadSceneFromObject(object);
+
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Mertens
+ if (getEntityData(kEntityPlayer)->car == kCarGreenSleeping
+ && getEntityData(kEntityMertens)->car == kCarGreenSleeping
+ && !getEntityData(kEntityMertens)->location
+ && !ENTITY_PARAMS(kEntityMertens, 0, 1)) {
+
+ if (!getEntities()->compare(kEntityPlayer, kEntityMertens)) {
+
+ if (getEntityData(kEntityMertens)->entityPosition < kPosition_2740
+ && getEntityData(kEntityMertens)->entityPosition > kPosition_850
+ && (getEntityData(kEntityCoudert)->car != kCarGreenSleeping || getEntityData(kEntityCoudert)->entityPosition > kPosition_2740)
+ && (getEntityData(kEntityVerges)->car != kCarGreenSleeping || getEntityData(kEntityVerges)->entityPosition > kPosition_2740)) {
+ if (doPlaySound)
+ playCompartmentSoundEvents(object);
+
+ if (!getSound()->isBuffered(kEntityMertens))
+ getSound()->playWarningCompartment(kEntityMertens, object);
+
+ getSavePoints()->push(kEntityPlayer, kEntityMertens, kAction305159806);
+
+ if (doLoadScene)
+ getScenes()->loadSceneFromObject(object);
+
+ return true;
+ }
+
+ if (getEntityData(kEntityMertens)->direction == kDirectionUp
+ && getEntityData(kEntityMertens)->entityPosition < getEntityData(kEntityPlayer)->entityPosition) {
+ if (doPlaySound)
+ playCompartmentSoundEvents(object);
+
+ if (!getSound()->isBuffered(kEntityMertens))
+ getSound()->playSound(kEntityMertens, (rnd(2)) ? "JAC1000" : "JAC1000A");
+
+ if (doLoadScene)
+ getScenes()->loadSceneFromObject(object);
+ }
+
+ if (getEntityData(kEntityMertens)->direction == kDirectionDown
+ && getEntityData(kEntityMertens)->entityPosition > getEntityData(kEntityPlayer)->entityPosition) {
+ if (doPlaySound)
+ playCompartmentSoundEvents(object);
+
+ if (!getSound()->isBuffered(kEntityMertens))
+ getSound()->playSound(kEntityMertens, (rnd(2)) ? "JAC1000" : "JAC1000A");
+
+ if (doLoadScene)
+ getScenes()->loadSceneFromObject(object, true);
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Coudert
+ if (getEntityData(kEntityPlayer)->car != kCarRedSleeping
+ || !getEntityData(kEntityCoudert)->car
+ || getEntityData(kEntityCoudert)->location != kLocationOutsideCompartment
+ || ENTITY_PARAMS(kEntityCoudert, 0, 1))
+ return false;
+
+ if (!getEntities()->compare(kEntityPlayer, kEntityCoudert)) {
+
+ if (getEntityData(kEntityCoudert)->entityPosition < kPosition_2740
+ && getEntityData(kEntityCoudert)->entityPosition > kPosition_850
+ && (getEntityData(kEntityMertens)->car != kCarRedSleeping || getEntityData(kEntityMertens)->entityPosition > kPosition_2740)
+ && (getEntityData(kEntityVerges)->car != kCarRedSleeping || getEntityData(kEntityVerges)->entityPosition > kPosition_2740)
+ && (getEntityData(kEntityMmeBoutarel)->car != kCarRedSleeping || getEntityData(kEntityMmeBoutarel)->entityPosition > kPosition_2740)) {
+ if (doPlaySound)
+ playCompartmentSoundEvents(object);
+
+ if (!getSound()->isBuffered(kEntityCoudert))
+ getSound()->playWarningCompartment(kEntityCoudert, object);
+
+ getSavePoints()->push(kEntityPlayer, kEntityCoudert, kAction305159806);
+
+ if (doLoadScene)
+ getScenes()->loadSceneFromObject(object);
+
+ return true;
+ }
+
+ // Direction = Up
+ if (getEntityData(kEntityCoudert)->direction == kDirectionUp
+ && getEntityData(kEntityCoudert)->entityPosition < getEntityData(kEntityPlayer)->entityPosition) {
+ if (doPlaySound)
+ playCompartmentSoundEvents(object);
+
+ if (!getSound()->isBuffered(kEntityCoudert))
+ getSound()->playSound(kEntityCoudert, (rnd(2)) ? "JAC1000" : "JAC1000A");
+
+ if (doLoadScene)
+ getScenes()->loadSceneFromObject(object);
+
+ return true;
+ }
+
+ // Direction = down
+ if (getEntityData(kEntityCoudert)->direction == kDirectionDown
+ && getEntityData(kEntityCoudert)->entityPosition > getEntityData(kEntityPlayer)->entityPosition) {
+ if (doPlaySound)
+ playCompartmentSoundEvents(object);
+
+ if (!getSound()->isBuffered(kEntityCoudert))
+ getSound()->playSound(kEntityCoudert, (rnd(2)) ? "JAC1000" : "JAC1000A");
+
+ if (doLoadScene)
+ getScenes()->loadSceneFromObject(object, true);
+ }
+ }
+
+ return false;
+}
+
+void Action::playCompartmentSoundEvents(ObjectIndex object) const {
+ if (getObjects()->get(object).location == kObjectLocation1 || getObjects()->get(object).location == kObjectLocation3 || getEntities()->checkFields2(object)) {
+ getSound()->playSoundEvent(kEntityPlayer, 13);
+ } else {
+ getSound()->playSoundEvent(kEntityPlayer, 14);
+ getSound()->playSoundEvent(kEntityPlayer, 15, 3);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Cursors
+//////////////////////////////////////////////////////////////////////////
+CursorStyle Action::getCursor(const SceneHotspot &hotspot) const {
+ // Simple cursor style
+ if (hotspot.cursor != kCursorProcess)
+ return (CursorStyle)hotspot.cursor;
+
+ ObjectIndex object = (ObjectIndex)hotspot.param1;
+
+ switch (hotspot.action) {
+ default:
+ return kCursorNormal;
+
+ case SceneHotspot::kActionInventory:
+ if (!getState()->sceneBackup2 && (getEvent(kEventKronosBringFirebird) || getProgress().isEggOpen))
+ return kCursorNormal;
+ else
+ return kCursorBackward;
+
+ case SceneHotspot::kActionKnockOnDoor:
+ warning("================================= DOOR %03d =================================", object);
+ if (object >= kObjectMax)
+ return kCursorNormal;
+ else
+ return (CursorStyle)getObjects()->get(object).cursor;
+
+ case SceneHotspot::kAction12:
+ warning("================================= OBJECT %03d =================================", object);
+ if (object >= kObjectMax)
+ return kCursorNormal;
+
+ if (getObjects()->get(object).entity)
+ return (CursorStyle)getObjects()->get(object).cursor;
+ else
+ return kCursorNormal;
+
+ case SceneHotspot::kActionPickItem:
+ warning("================================= ITEM %03d =================================", object);
+ if (object >= kObjectCompartmentA)
+ return kCursorNormal;
+
+ if ((!getInventory()->getSelectedItem() || getInventory()->getSelectedEntry()->manualSelect)
+ && (object != kObject21 || getProgress().eventCorpseMovedFromFloor))
+ return kCursorHand;
+ else
+ return kCursorNormal;
+
+ case SceneHotspot::kActionDropItem:
+ warning("================================= ITEM %03d =================================", object);
+ if (object >= kObjectCompartmentA)
+ return kCursorNormal;
+
+ if (getInventory()->getSelectedItem() != (InventoryItem)object)
+ return kCursorNormal;
+
+ if (object == kObject20 && hotspot.param2 == 4 && !getProgress().isTrainRunning)
+ return kCursorNormal;
+
+ if (object == kObjectHandleInsideBathroom && hotspot.param2 == 1 && getProgress().field_5C)
+ return kCursorNormal;
+
+ return (CursorStyle)getInventory()->getSelectedEntry()->cursor;
+
+ case SceneHotspot::kAction15:
+ if (object >= kObjectMax)
+ return kCursorNormal;
+
+ if (getProgress().isEqual(object, hotspot.param2))
+ return (CursorStyle)hotspot.param3;
+
+ return kCursorNormal;
+
+ case SceneHotspot::kActionEnterCompartment:
+ if ((getInventory()->getSelectedItem() != kItemKey || getObjects()->get(kObjectCompartment1).location)
+ && (getObjects()->get(kObjectCompartment1).location != 1 || !getInventory()->hasItem(kItemKey)
+ || (getInventory()->getSelectedItem() != kItemFirebird && getInventory()->getSelectedItem() != kItemBriefcase)))
+ goto LABEL_KEY;
+
+ return (CursorStyle)getInventory()->get(kItemKey)->cursor; // TODO is that always the same as kCursorKey ?
+
+ case SceneHotspot::kActionGetOutsideTrain:
+ if (getProgress().jacket != kJacketGreen)
+ return kCursorNormal;
+
+ if ((getEvent(kEventCathLookOutsideWindowDay) || getEvent(kEventCathLookOutsideWindowDay) || getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1)
+ && getProgress().isTrainRunning
+ && (object != kObjectOutsideAnnaCompartment || (getEntities()->isInsideCompartment(kEntityRebecca, kCarRedSleeping, kPosition_4840) && getObjects()->get(kObjectOutsideBetweenCompartments).location == 2))
+ && getInventory()->getSelectedItem() != kItemBriefcase && getInventory()->getSelectedItem() != kItemFirebird)
+ return kCursorForward;
+
+ return (getObjects()->get(kObjectCompartment1).location2 < kObjectLocation2) ? kCursorNormal : kCursorMagnifier;
+
+ case SceneHotspot::kActionSlip:
+ return (getProgress().field_C8 < 1) ? kCursorNormal : kCursorLeft;
+
+ case SceneHotspot::kActionClimbUpTrain:
+ if (getProgress().isTrainRunning
+ && (getProgress().chapter == kChapter2 || getProgress().chapter == kChapter3 || getProgress().chapter == kChapter5)
+ && getInventory()->getSelectedItem() != kItemFirebird
+ && getInventory()->getSelectedItem() != kItemBriefcase)
+ return kCursorUp;
+
+ return kCursorNormal;
+
+ case SceneHotspot::kActionJumpUpDownTrain:
+ if (object != kObjectCompartment1)
+ return kCursorNormal;
+
+ return (getObjects()->get(kObjectCeiling).location < kObjectLocation1) ? kCursorHand : kCursorNormal;
+
+ case SceneHotspot::kActionUnbound:
+ if (hotspot.param2 != 2)
+ return kCursorNormal;
+
+ if (getEvent(kEventCathBurnRope) || !getEvent(kEventCathStruggleWithBonds2))
+ return kCursorNormal;
+
+ return kCursorHand;
+
+ case SceneHotspot::kActionCatchBeetle:
+ if (!getBeetle()->isLoaded())
+ return kCursorNormal;
+
+ if (!getBeetle()->isCatchable())
+ return kCursorNormal;
+
+ if (getInventory()->getSelectedItem() == kItemMatchBox && getInventory()->hasItem(kItemMatch))
+ return (CursorStyle)getInventory()->get(kItemMatchBox)->cursor;
+
+ return kCursorHandPointer;
+
+ case SceneHotspot::KActionUseWhistle:
+ if (object != kObjectCompartment3)
+ return kCursorNormal;
+
+ if (getInventory()->getSelectedItem() == kItemWhistle)
+ return kCursorWhistle;
+ else
+ return kCursorNormal;
+
+ case SceneHotspot::kActionOpenBed:
+ if (getProgress().chapter < kChapter2)
+ return kCursorHand;
+
+ return kCursorNormal;
+
+ case SceneHotspot::kActionDialog:
+ if (getSound()->getDialogName((EntityIndex)object))
+ return kCursorHandPointer;
+
+ return kCursorNormal;
+
+ case SceneHotspot::kActionBed:
+ if (getProgress().field_18 == 2 && !getProgress().field_E4
+ && (getState()->time > kTimeBedTime
+ || (getProgress().eventMetAugust && getProgress().field_CC
+ && (!getProgress().field_24 || getProgress().field_3C))))
+ return kCursorSleep;
+
+ return kCursorNormal;
+
+LABEL_KEY:
+ // Handle compartment action
+ case SceneHotspot::kActionCompartment:
+ case SceneHotspot::kActionExitCompartment:
+ warning("================================= DOOR %03d =================================", object);
+ if (object >= kObjectMax)
+ return kCursorNormal;
+
+ if (getInventory()->getSelectedItem() != kItemKey
+ || getObjects()->get(object).entity
+ || getObjects()->get(object).location != 1
+ || !getObjects()->get(object).cursor2
+ || getEntities()->isInsideCompartments(kEntityPlayer)
+ || getEntities()->checkFields2(object))
+ return (CursorStyle)getObjects()->get(object).cursor2;
+ else
+ return (CursorStyle)getInventory()->get(kItemKey)->cursor;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Animation
+//////////////////////////////////////////////////////////////////////////
+
+// Play an animation and add delta time to global game time
+void Action::playAnimation(EventIndex index, bool debugMode) const {
+ if (index >= _animationListSize)
+ error("Action::playAnimation: invalid event index (value=%i, max=%i)", index, _animationListSize);
+
+ // In debug mode, just show the animation
+ if (debugMode) {
+ Animation animation;
+ if (animation.load(getArchive(Common::String(_animationList[index].filename) + ".nis")))
+ animation.play();
+ return;
+ }
+
+ getFlags()->flag_3 = true;
+
+ // Hide cursor
+ _engine->getCursor()->show(false);
+
+ // Show inventory & hourglass
+ getInventory()->show();
+ getInventory()->showHourGlass();
+
+ if (!getFlags()->mouseRightClick) {
+
+ if (getGlobalTimer()) {
+ if (getSound()->isBuffered("TIMER")) {
+ getSound()->processEntry("TIMER");
+ setGlobalTimer(105);
+ }
+ }
+
+ bool processSound = false;
+ if (index >= kEventCorpseDropFloorOriginal
+ || index == kEventCathWakingUp
+ || index == kEventConcertCough
+ || index == kEventConcertSit
+ || index == kEventConcertLeaveWithBriefcase)
+ processSound = true;
+
+ Animation animation;
+ if (animation.load(getArchive(Common::String(_animationList[index].filename) + ".nis") , processSound ? Animation::kFlagDefault : Animation::kFlagProcess))
+ animation.play();
+
+ if (getSound()->isBuffered("TIMER"))
+ getSound()->removeFromQueue("TIMER");
+ }
+
+ // Show cursor
+ _engine->getCursor()->show(true);
+
+ getEvent(index) = 1;
+
+ // Adjust game time
+ getState()->timeTicks += _animationList[index].time;
+ getState()->time = (TimeValue)(getState()->time + (TimeValue)(_animationList[index].time * getState()->timeDelta));
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/action.h b/engines/lastexpress/game/action.h
new file mode 100644
index 0000000000..6a2e3eb597
--- /dev/null
+++ b/engines/lastexpress/game/action.h
@@ -0,0 +1,135 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ACTION_H
+#define LASTEXPRESS_ACTION_H
+
+#include "lastexpress/shared.h"
+
+#include "common/array.h"
+#include "common/func.h"
+#include "common/system.h"
+
+namespace LastExpress {
+
+#define DECLARE_ACTION(name) \
+ SceneIndex action_##name(const SceneHotspot &hotspot) const
+
+#define ADD_ACTION(name) \
+ _actions.push_back(new Functor1MemConst<const SceneHotspot &, SceneIndex, Action>(this, &Action::action_##name));
+
+#define IMPLEMENT_ACTION(name) \
+ SceneIndex Action::action_##name(const SceneHotspot &hotspot) const { \
+ debugC(6, kLastExpressDebugLogic, "Hotspot action: " #name "%s", hotspot.toString().c_str());
+
+class LastExpressEngine;
+class SceneHotspot;
+
+class Action {
+public:
+ Action(LastExpressEngine *engine);
+ ~Action();
+
+ // Hotspot action
+ SceneIndex processHotspot(const SceneHotspot &hotspot);
+
+ // Cursor
+ CursorStyle getCursor(const SceneHotspot &hotspot) const;
+
+ // Animation
+ void playAnimation(EventIndex index, bool debugMode = false) const;
+
+ // Compartment action
+ bool handleOtherCompartment(ObjectIndex object, bool doPlaySound, bool doLoadScene) const;
+
+private:
+ typedef Common::Functor1<const SceneHotspot &, SceneIndex> ActionFunctor;
+
+ LastExpressEngine *_engine;
+ Common::Array<ActionFunctor *> _actions;
+
+ // Each action is of the form action_<name>(SceneHotspot *hotspot)
+ // - a pointer to each action is added to the _actions array
+ // - processHotspot simply calls the proper function given by the hotspot->action value
+ //
+ // Note: even though there are 44 actions, only 41 are used in processHotspot
+
+ DECLARE_ACTION(inventory);
+ DECLARE_ACTION(savePoint);
+ DECLARE_ACTION(playSound);
+ DECLARE_ACTION(playMusic);
+ DECLARE_ACTION(knock);
+ DECLARE_ACTION(compartment);
+ DECLARE_ACTION(playSounds);
+ DECLARE_ACTION(playAnimation);
+ DECLARE_ACTION(openCloseObject);
+ DECLARE_ACTION(updateObjetLocation2);
+ DECLARE_ACTION(setItemLocation);
+ DECLARE_ACTION(knockNoSound);
+ DECLARE_ACTION(pickItem);
+ DECLARE_ACTION(dropItem);
+ DECLARE_ACTION(enterCompartment);
+ DECLARE_ACTION(getOutsideTrain);
+ DECLARE_ACTION(slip);
+ DECLARE_ACTION(getInsideTrain);
+ DECLARE_ACTION(climbUpTrain);
+ DECLARE_ACTION(climbDownTrain);
+ DECLARE_ACTION(jumpUpDownTrain);
+ DECLARE_ACTION(unbound);
+ DECLARE_ACTION(25);
+ DECLARE_ACTION(26);
+ DECLARE_ACTION(27);
+ DECLARE_ACTION(concertSitCough);
+ DECLARE_ACTION(29);
+ DECLARE_ACTION(catchBeetle);
+ DECLARE_ACTION(exitCompartment);
+ DECLARE_ACTION(32);
+ DECLARE_ACTION(useWhistle);
+ DECLARE_ACTION(openMatchBox);
+ DECLARE_ACTION(openBed);
+ DECLARE_ACTION(dialog);
+ DECLARE_ACTION(eggBox);
+ DECLARE_ACTION(39);
+ DECLARE_ACTION(bed);
+ DECLARE_ACTION(playMusicChapter);
+ DECLARE_ACTION(playMusicChapterSetupTrain);
+ DECLARE_ACTION(switchChapter);
+ DECLARE_ACTION(44);
+
+ // Special dummy function
+ DECLARE_ACTION(dummy);
+
+ // Helpers
+ void pickGreenJacket(bool process) const;
+ void pickScarf(bool process) const;
+ void pickCorpse(ObjectLocation bedPosition, bool process) const;
+ void dropCorpse(bool process) const;
+
+ void playCompartmentSoundEvents(ObjectIndex object) const;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ACTION_H
diff --git a/engines/lastexpress/game/beetle.cpp b/engines/lastexpress/game/beetle.cpp
new file mode 100644
index 0000000000..665edb79a5
--- /dev/null
+++ b/engines/lastexpress/game/beetle.cpp
@@ -0,0 +1,517 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/beetle.h"
+
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+Beetle::Beetle(LastExpressEngine *engine) : _engine(engine), _data(NULL) {}
+
+Beetle::~Beetle() {
+ SAFE_DELETE(_data);
+
+ // Free passed pointers
+ _engine = NULL;
+}
+
+void Beetle::load() {
+ // Only load in chapter 2 & 3
+ if (getProgress().chapter != kChapter2 && getProgress().chapter != kChapter3)
+ return;
+
+ // Already loaded
+ if (_data)
+ return;
+
+ // Do not load if beetle is in the wrong location
+ if (getInventory()->get(kItemBeetle)->location != kObjectLocation3)
+ return;
+
+ ///////////////////////
+ // Load Beetle data
+ _data = new BeetleData();
+
+ // Load sequences
+ _data->sequences.push_back(loadSequence("BW000.seq")); // 0
+ _data->sequences.push_back(loadSequence("BT000045.seq"));
+ _data->sequences.push_back(loadSequence("BT045000.seq"));
+ _data->sequences.push_back(loadSequence("BW045.seq"));
+ _data->sequences.push_back(loadSequence("BT045090.seq"));
+ _data->sequences.push_back(loadSequence("BT090045.seq")); // 5
+ _data->sequences.push_back(loadSequence("BW090.seq"));
+ _data->sequences.push_back(loadSequence("BT090135.seq"));
+ _data->sequences.push_back(loadSequence("BT135090.seq"));
+ _data->sequences.push_back(loadSequence("BW135.seq"));
+ _data->sequences.push_back(loadSequence("BT135180.seq")); // 10
+ _data->sequences.push_back(loadSequence("BT180135.seq"));
+ _data->sequences.push_back(loadSequence("BW180.seq"));
+ _data->sequences.push_back(loadSequence("BT180225.seq"));
+ _data->sequences.push_back(loadSequence("BT225180.seq"));
+ _data->sequences.push_back(loadSequence("BW225.seq")); // 15
+ _data->sequences.push_back(loadSequence("BT225270.seq"));
+ _data->sequences.push_back(loadSequence("BT270225.seq"));
+ _data->sequences.push_back(loadSequence("BW270.seq"));
+ _data->sequences.push_back(loadSequence("BT270315.seq"));
+ _data->sequences.push_back(loadSequence("BT315270.seq")); // 20
+ _data->sequences.push_back(loadSequence("BW315.seq"));
+ _data->sequences.push_back(loadSequence("BT315000.seq"));
+ _data->sequences.push_back(loadSequence("BT000315.seq"));
+ _data->sequences.push_back(loadSequence("BA135.seq"));
+ _data->sequences.push_back(loadSequence("BL045.seq")); // 25
+ _data->sequences.push_back(loadSequence("BL000.seq"));
+ _data->sequences.push_back(loadSequence("BL315.seq"));
+ _data->sequences.push_back(loadSequence("BL180.seq"));
+
+ // Init fields
+ _data->field_74 = 0;
+
+ // Check that all sequences are loaded properly
+ _data->isLoaded = true;
+ for (int i = 0; i < (int)_data->sequences.size(); i++) {
+ if (!_data->sequences[i]->isLoaded()) {
+ _data->isLoaded = false;
+ break;
+ }
+ }
+
+ _data->field_D9 = 10;
+ _data->coordOffset = 5;
+ _data->coordY = 178;
+ _data->currentSequence = 0;
+ _data->offset = 0;
+ _data->frame = NULL;
+ _data->field_D5 = 0;
+ _data->indexes[0] = 29;
+ _data->field_DD = 0;
+}
+
+void Beetle::unload() {
+ // Remove sequences from display list
+ if (_data)
+ getScenes()->removeFromQueue(_data->frame);
+
+ // Delete all loaded sequences
+ SAFE_DELETE(_data);
+}
+
+bool Beetle::isLoaded() const {
+ if (!_data)
+ return false;
+
+ return _data->isLoaded;
+}
+
+bool Beetle::catchBeetle() {
+ if (!_data)
+ error("Beetle::catchBeetle: sequences have not been loaded!");
+
+ if (getInventory()->getSelectedItem() == kItemMatchBox
+ && getInventory()->hasItem(kItemMatch)
+ && ABS((int16)(getCoords().x - _data->coordX)) < 10
+ && ABS((int16)(getCoords().y - _data->coordY)) < 10) {
+ return true;
+ }
+
+ _data->field_D5 = 0;
+ move();
+
+ return false;
+}
+
+bool Beetle::isCatchable() const {
+ if (!_data)
+ error("Beetle::isCatchable: sequences have not been loaded!");
+
+ return (_data->indexes[_data->offset] >= 30);
+}
+
+void Beetle::update() {
+ if (!_data)
+ error("Beetle::update: sequences have not been loaded!");
+
+ if (!_data->isLoaded)
+ return;
+
+ move();
+
+ if (_data->field_D5)
+ _data->field_D5--;
+
+ if (_data->currentSequence && _data->indexes[_data->offset] != 29) {
+ drawUpdate();
+ return;
+ }
+
+ if (getInventory()->get(kItemBeetle)->location == kObjectLocation3) {
+ if ((!_data->field_DD && rnd(10) < 1)
+ || (_data->field_DD && rnd(30) < 1)
+ || rnd(100) < 1) {
+
+ _data->field_DD++;
+ if (_data->field_DD > 3)
+ _data->field_DD = 0;
+
+ updateData(24);
+
+ _data->coordX = (int16)(rnd(250) + 190);
+ _data->coordOffset = (int16)(rnd(5) + 5);
+
+ if (_data->field_D9 > 1)
+ _data->field_D9--;
+
+ drawUpdate();
+ }
+ }
+}
+
+void Beetle::drawUpdate() {
+ if (!_data)
+ error("Beetle::drawUpdate: sequences have not been loaded!");
+
+ if (_data->frame != NULL) {
+ getScenes()->setCoordinates(_data->frame);
+ getScenes()->removeFromQueue(_data->frame);
+ }
+
+ // Update current frame
+ switch (_data->indexes[_data->offset]) {
+ default:
+ _data->currentFrame += 10;
+ break;
+
+ case 3:
+ case 6:
+ case 9:
+ case 12:
+ case 15:
+ case 18:
+ case 21:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ _data->currentFrame++;
+ break;
+ }
+
+ // Update current sequence
+ if (_data->currentSequence->count() <= _data->currentFrame) {
+ switch (_data->indexes[_data->offset]) {
+ default:
+ _data->offset++;
+ _data->currentSequence = _data->sequences[_data->indexes[_data->offset]];
+ break;
+
+ case 3:
+ case 6:
+ case 9:
+ case 12:
+ case 15:
+ case 18:
+ case 21:
+ break;
+ }
+
+ _data->currentFrame = 0;
+ if (_data->indexes[_data->offset] == 29) {
+ SAFE_DELETE(_data->frame);
+ _data->currentSequence = NULL; // pointer to existing sequence
+ return;
+ }
+ }
+
+ // Update coordinates
+ switch (_data->indexes[_data->offset]) {
+ default:
+ break;
+
+ case 0:
+ _data->coordY -= _data->coordOffset;
+ break;
+
+ case 3:
+ _data->coordX += _data->coordOffset;
+ _data->coordY -= _data->coordOffset;
+ break;
+
+ case 6:
+ _data->coordX += _data->coordOffset;
+ break;
+
+ case 9:
+ _data->coordX += _data->coordOffset;
+ _data->coordY += _data->coordOffset;
+ break;
+
+ case 12:
+ _data->coordY += _data->coordOffset;
+ break;
+
+ case 15:
+ _data->coordX -= _data->coordOffset;
+ _data->coordY += _data->coordOffset;
+ break;
+
+ case 18:
+ _data->coordX -= _data->coordOffset;
+ break;
+
+ case 21:
+ _data->coordX -= _data->coordOffset;
+ _data->coordY -= _data->coordOffset;
+ break;
+ }
+
+ // Update beetle data
+ int rnd = rnd(100);
+ if (_data->coordX < 165 || _data->coordX > 465) {
+ uint index = 0;
+
+ if (rnd >= 30) {
+ if (rnd >= 70)
+ index = (_data->coordX < 165) ? 9 : 15;
+ else
+ index = (_data->coordX < 165) ? 6 : 18;
+ } else {
+ index = (_data->coordX < 165) ? 3 : 21;
+ }
+
+ updateData(index);
+ }
+
+ if (_data->coordY < 178) {
+ switch (_data->indexes[_data->offset]) {
+ default:
+ updateData(26);
+ break;
+
+ case 3:
+ updateData(25);
+ break;
+
+ case 21:
+ updateData(27);
+ break;
+ }
+ }
+
+ if (_data->coordY > 354) {
+ switch (_data->indexes[_data->offset]) {
+ default:
+ break;
+
+ case 9:
+ case 12:
+ case 15:
+ updateData(28);
+ break;
+ }
+ }
+
+#define INVERT_Y() \
+ switch (_data->indexes[_data->offset]) { \
+ default: \
+ break; \
+ case 24: \
+ case 25: \
+ case 26: \
+ case 27: \
+ case 28: \
+ _data->coordY = -_data->coordY; \
+ break; \
+ }
+
+ // Invert direction
+ INVERT_Y();
+
+ SequenceFrame *frame = new SequenceFrame(_data->currentSequence, (uint16)_data->currentFrame);
+ updateFrame(frame);
+
+ INVERT_Y();
+
+ getScenes()->addToQueue(frame);
+
+ SAFE_DELETE(_data->frame);
+ _data->frame = frame;
+}
+
+void Beetle::move() {
+ if (!_data)
+ error("Beetle::move: sequences have not been loaded!");
+
+ if (_data->indexes[_data->offset] >= 24 && _data->indexes[_data->offset] <= 29)
+ return;
+
+ if (_data->field_D5)
+ return;
+
+ if (ABS((int)(getCoords().x - _data->coordX)) > 35)
+ return;
+
+ if (ABS((int)(getCoords().y - _data->coordY)) > 35)
+ return;
+
+ int32 deltaX = getCoords().x - _data->coordX;
+ int32 deltaY = -getCoords().y - _data->coordY;
+ uint32 index = 0;
+
+ // FIXME: check code path
+ if (deltaX >= 0) {
+ if (deltaY > 0) {
+ if (100 * deltaY - 241 * deltaX <= 0) {
+ if (100 * deltaY - 41 * deltaX <= 0)
+ index = 18;
+ else
+ index = 15;
+ } else {
+ index = 12;
+ }
+
+ goto update_data;
+ }
+ }
+
+ if (deltaX < 0) {
+
+ if (deltaY > 0) {
+ if (100 * deltaY + 241 * deltaX <= 0) {
+ if (100 * deltaY + 41 * deltaX <= 0)
+ index = 6;
+ else
+ index = 9;
+ } else {
+ index = 12;
+ }
+
+ goto update_data;
+ }
+
+ if (deltaY <= 0) {
+ if (100 * deltaY - 41 * deltaX <= 0) {
+ if (100 * deltaY - 241 * deltaX <= 0)
+ index = 0;
+ else
+ index = 3;
+ } else {
+ index = 6;
+ }
+
+ goto update_data;
+ }
+ }
+
+update_data:
+ updateData(index);
+
+ if (_data->coordOffset >= 15) {
+ _data->field_D5 = 0;
+ return;
+ }
+
+ _data->coordOffset = _data->coordOffset + (int16)(4 * rnd(100)/100 + _data->field_D9);
+ _data->field_D5 = 0;
+}
+
+// Update the beetle sequence to show the correct frames in the correct place
+void Beetle::updateFrame(SequenceFrame *frame) const {
+ if (!_data)
+ error("Beetle::updateSequence: sequences have not been loaded!");
+
+ if (!frame)
+ return;
+
+ // Update coordinates
+ if (_data->coordX > 0)
+ frame->getInfo()->xPos1 = (uint16)_data->coordX;
+
+ if (_data->coordY > 0)
+ frame->getInfo()->yPos1 = (uint16)_data->coordY;
+}
+
+void Beetle::updateData(uint32 index) {
+ if (!_data)
+ error("Beetle::updateData: sequences have not been loaded!");
+
+ if (!_data->isLoaded)
+ return;
+
+ if (index == 25 || index == 26 || index == 27 || index == 28) {
+ _data->indexes[0] = index;
+ _data->indexes[1] = 29;
+ _data->offset = 0;
+
+ _data->currentSequence = _data->sequences[index];
+ _data->currentFrame = 0;
+ _data->index = index;
+ } else {
+ if (!_data->sequences[index])
+ return;
+
+ if (_data->index == index)
+ return;
+
+ _data->offset = 0;
+
+ // Special case for sequence 24
+ if (index == 24) {
+ _data->indexes[0] = index;
+ _data->coordY = 178;
+ _data->index = _data->indexes[1];
+ _data->indexes[1] = (_data->coordX >= 265) ? 15 : 9;
+ _data->currentFrame = 0;
+ _data->currentSequence = _data->sequences[index];
+ } else {
+ if (index <= _data->index) {
+ for (uint32 i = _data->index - 1; i > index; ++_data->offset) {
+ _data->indexes[_data->offset] = i;
+ i -= 3;
+ }
+ } else {
+ for (uint32 i = _data->index + 1; i < index; ++_data->offset) {
+ _data->indexes[_data->offset] = i;
+ i += 3;
+ }
+ }
+
+ _data->index = index;
+ _data->indexes[_data->offset] = index;
+ _data->currentFrame = 0;
+ _data->offset = 0;
+ _data->currentSequence = _data->sequences[_data->indexes[0]];
+ }
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/beetle.h b/engines/lastexpress/game/beetle.h
new file mode 100644
index 0000000000..3341e92270
--- /dev/null
+++ b/engines/lastexpress/game/beetle.h
@@ -0,0 +1,118 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_BEETLE_H
+#define LASTEXPRESS_BEETLE_H
+
+#include "lastexpress/data/sequence.h"
+
+#include "common/array.h"
+#include "common/system.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Beetle {
+public:
+
+ Beetle(LastExpressEngine *engine);
+ ~Beetle();
+
+ void update();
+
+ void load();
+ void unload();
+
+ bool isLoaded() const;
+
+ bool catchBeetle();
+ bool isCatchable() const;
+
+private:
+ struct BeetleData {
+ Common::Array<Sequence *> sequences;
+
+ uint32 field_74;
+ Sequence *currentSequence;
+ uint32 currentFrame;
+ uint32 index;
+ int16 coordOffset;
+ int16 field_86;
+
+ int16 coordX;
+ int16 coordY;
+
+ uint32 indexes[16];
+
+ uint32 offset;
+ SequenceFrame *frame;
+ bool isLoaded;
+ uint32 field_D5;
+ uint32 field_D9;
+ uint32 field_DD;
+
+ BeetleData() {
+ field_74 = 0;
+ currentSequence = NULL;
+ currentFrame = 0;
+ index = 0;
+ coordOffset = 0;
+
+ field_86 = 0;
+
+ coordX = 0;
+ coordY = 0;
+
+ memset(indexes, 0, sizeof(indexes));
+ offset = 0;
+
+ frame = NULL;
+ isLoaded = false;
+ field_D5 = 0;
+ field_D9 = 0;
+ field_DD = 0;
+ }
+
+ ~BeetleData() {
+ for (int i = 0; i < (int)sequences.size(); i++)
+ if (sequences[i])
+ delete sequences[i];
+ }
+ };
+
+ LastExpressEngine *_engine;
+
+ BeetleData *_data;
+
+ void move();
+ void updateFrame(SequenceFrame *frame) const;
+ void updateData(uint32 index);
+ void drawUpdate();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_BEETLE_H
diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp
new file mode 100644
index 0000000000..adba0f1b4c
--- /dev/null
+++ b/engines/lastexpress/game/entities.cpp
@@ -0,0 +1,2744 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/entities.h"
+
+// Data
+#include "lastexpress/data/scene.h"
+#include "lastexpress/data/sequence.h"
+
+// Entities
+#include "lastexpress/entities/entity.h"
+
+#include "lastexpress/entities/abbot.h"
+#include "lastexpress/entities/alexei.h"
+#include "lastexpress/entities/alouan.h"
+#include "lastexpress/entities/anna.h"
+#include "lastexpress/entities/august.h"
+#include "lastexpress/entities/boutarel.h"
+#include "lastexpress/entities/chapters.h"
+#include "lastexpress/entities/cooks.h"
+#include "lastexpress/entities/coudert.h"
+#include "lastexpress/entities/entity39.h"
+#include "lastexpress/entities/francois.h"
+#include "lastexpress/entities/gendarmes.h"
+#include "lastexpress/entities/hadija.h"
+#include "lastexpress/entities/ivo.h"
+#include "lastexpress/entities/kahina.h"
+#include "lastexpress/entities/kronos.h"
+#include "lastexpress/entities/mahmud.h"
+#include "lastexpress/entities/max.h"
+#include "lastexpress/entities/mertens.h"
+#include "lastexpress/entities/milos.h"
+#include "lastexpress/entities/mmeboutarel.h"
+#include "lastexpress/entities/pascale.h"
+#include "lastexpress/entities/rebecca.h"
+#include "lastexpress/entities/salko.h"
+#include "lastexpress/entities/servers0.h"
+#include "lastexpress/entities/servers1.h"
+#include "lastexpress/entities/sophie.h"
+#include "lastexpress/entities/tables.h"
+#include "lastexpress/entities/tatiana.h"
+#include "lastexpress/entities/train.h"
+#include "lastexpress/entities/vassili.h"
+#include "lastexpress/entities/verges.h"
+#include "lastexpress/entities/vesna.h"
+#include "lastexpress/entities/yasmin.h"
+
+// Game
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+#define STORE_VALUE(data) ((uint)1 << (uint)data)
+
+static const EntityPosition objectsPosition[8] = {kPosition_8200, kPosition_7500,
+ kPosition_6470, kPosition_5790,
+ kPosition_4840, kPosition_4070,
+ kPosition_3050, kPosition_2740};
+
+static const EntityPosition entityPositions[41] = {
+ kPositionNone, kPosition_851, kPosition_1430, kPosition_2110, kPositionNone,
+ kPosition_2410, kPosition_2980, kPosition_3450, kPosition_3760, kPosition_4100,
+ kPosition_4680, kPosition_5140, kPosition_5440, kPosition_5810, kPosition_6410,
+ kPosition_6850, kPosition_7160, kPosition_7510, kPosition_8514, kPositionNone,
+ kPositionNone, kPositionNone, kPosition_2086, kPosition_2690, kPositionNone,
+ kPosition_3110, kPosition_3390, kPosition_3890, kPosition_4460, kPosition_4770,
+ kPosition_5090, kPosition_5610, kPosition_6160, kPosition_6460, kPosition_6800,
+ kPosition_7320, kPosition_7870, kPosition_8160, kPosition_8500, kPosition_9020,
+ kPosition_9269};
+
+#define ADD_ENTITY(class) \
+ _entities.push_back(new class(engine));
+
+#define COMPUTE_SEQUENCE_NAME(sequenceTo, sequenceFrom) { \
+ sequenceTo = sequenceFrom; \
+ for (int seqIdx = 0; seqIdx < 7; seqIdx++) \
+ sequenceTo.deleteLastChar(); \
+ if (isInsideTrainCar(entityIndex, kCarGreenSleeping) || isInsideTrainCar(entityIndex, kCarGreenSleeping)) { \
+ if (data->car < getData(kEntityPlayer)->car || (data->car == getData(kEntityPlayer)->car && data->entityPosition < getData(kEntityPlayer)->entityPosition)) \
+ sequenceTo += "R.SEQ"; \
+ else \
+ sequenceTo += "F.SEQ"; \
+ } else { \
+ sequenceTo += ".SEQ"; \
+ } \
+}
+
+#define TRY_LOAD_SEQUENCE(sequence, name, name1, name2) { \
+ if (data->car == getData(kEntityPlayer)->car) \
+ sequence = loadSequence1(name1, field30); \
+ if (sequence) { \
+ name = name1; \
+ } else { \
+ if (name2 != "") \
+ sequence = loadSequence1(name2, field30); \
+ name = (sequence ? name2 : ""); \
+ } \
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Entities
+//////////////////////////////////////////////////////////////////////////
+Entities::Entities(LastExpressEngine *engine) : _engine(engine) {
+ _header = new EntityData();
+
+ _entities.push_back(NULL); // Header
+ ADD_ENTITY(Anna);
+ ADD_ENTITY(August);
+ ADD_ENTITY(Mertens);
+ ADD_ENTITY(Coudert);
+ ADD_ENTITY(Pascale);
+ ADD_ENTITY(Servers0);
+ ADD_ENTITY(Servers1);
+ ADD_ENTITY(Cooks);
+ ADD_ENTITY(Verges);
+ ADD_ENTITY(Tatiana);
+ ADD_ENTITY(Vassili);
+ ADD_ENTITY(Alexei);
+ ADD_ENTITY(Abbot);
+ ADD_ENTITY(Milos);
+ ADD_ENTITY(Vesna);
+ ADD_ENTITY(Ivo);
+ ADD_ENTITY(Salko);
+ ADD_ENTITY(Kronos);
+ ADD_ENTITY(Kahina);
+ ADD_ENTITY(Francois);
+ ADD_ENTITY(MmeBoutarel);
+ ADD_ENTITY(Boutarel);
+ ADD_ENTITY(Rebecca);
+ ADD_ENTITY(Sophie);
+ ADD_ENTITY(Mahmud);
+ ADD_ENTITY(Yasmin);
+ ADD_ENTITY(Hadija);
+ ADD_ENTITY(Alouan);
+ ADD_ENTITY(Gendarmes);
+ ADD_ENTITY(Max);
+ ADD_ENTITY(Chapters);
+ ADD_ENTITY(Train);
+
+ // Special case for tables
+ _entities.push_back(new Tables(engine, kEntityTables0));
+ _entities.push_back(new Tables(engine, kEntityTables1));
+ _entities.push_back(new Tables(engine, kEntityTables2));
+ _entities.push_back(new Tables(engine, kEntityTables3));
+ _entities.push_back(new Tables(engine, kEntityTables4));
+ _entities.push_back(new Tables(engine, kEntityTables5));
+
+ ADD_ENTITY(Entity39);
+
+ // Init compartments & positions
+ memset(&_compartments, 0, sizeof(_compartments));
+ memset(&_compartments1, 0, sizeof(_compartments1));
+ memset(&_positions, 0, sizeof(_positions));
+}
+
+Entities::~Entities() {
+ delete _header;
+
+ for (int i = 0; i < (int)_entities.size(); i++)
+ delete _entities[i];
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Accessors
+//////////////////////////////////////////////////////////////////////////
+Entity *Entities::get(EntityIndex entity) {
+ assert((uint)entity < _entities.size());
+
+ if (entity == kEntityPlayer)
+ error("Cannot get entity for index == 0!");
+
+ return _entities[entity];
+}
+
+EntityData::EntityCallData *Entities::getData(EntityIndex entity) const {
+ assert((uint)entity < _entities.size());
+
+ if (entity == kEntityPlayer)
+ return _header->getCallData();
+
+ return _entities[entity]->getData();
+}
+
+int Entities::getPosition(CarIndex car, Position position) const {
+ int index = 100 * car + position;
+
+ if (car > 10)
+ error("Entities::getPosition: trying to access an invalid car (was: %d, valid:0-9)", car);
+
+ if (position > 100)
+ error("Entities::getPosition: trying to access an invalid position (was: %d, valid:0-100)", position);
+
+ return _positions[index];
+}
+
+int Entities::getCompartments(int index) const {
+ if (index >= _compartmentsCount)
+ error("Entities::getCompartments: trying to access an invalid compartment (was: %d, valid:0-15)", index);
+
+ return _compartments[index];
+}
+
+int Entities::getCompartments1(int index) const {
+ if (index >= _compartmentsCount)
+ error("Entities::getCompartments: trying to access an invalid compartment (was: %d, valid:0-15)", index);
+
+ return _compartments1[index];
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Savegame
+//////////////////////////////////////////////////////////////////////////
+void Entities::saveLoadWithSerializer(Common::Serializer &s) {
+ _header->saveLoadWithSerializer(s);
+ for (uint i = 1; i < _entities.size(); i++)
+ _entities[i]->saveLoadWithSerializer(s);
+}
+
+void Entities::savePositions(Common::Serializer &s) {
+ for (uint i = 0; i < (uint)_positionsCount; i++)
+ s.syncAsUint32LE(_positions[i]);
+}
+
+void Entities::saveCompartments(Common::Serializer &s) {
+ for (uint i = 0; i < (uint)_compartmentsCount; i++)
+ s.syncAsUint32LE(_compartments[i]);
+
+ for (uint i = 0; i < (uint)_compartmentsCount; i++)
+ s.syncAsUint32LE(_compartments1[i]);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Setup
+//////////////////////////////////////////////////////////////////////////
+void Entities::setup(bool isFirstChapter, EntityIndex entityIndex) {
+ setupChapter(isFirstChapter ? kChapter1 : kChapterAll);
+
+ bool flag_4 = false;
+
+ if (!isFirstChapter) {
+ getFlags()->flag_4 = false;
+
+ if (entityIndex) {
+ getSavePoints()->call(kEntityPlayer, entityIndex, kActionNone);
+ flag_4 = getFlags()->flag_4;
+ }
+ }
+
+ getFlags()->flag_4 = flag_4;
+ if (!getFlags()->flag_4)
+ getScenes()->loadScene(getState()->scene);
+}
+
+void Entities::setupChapter(ChapterIndex chapter) {
+ if (chapter) {
+ // Reset current call, inventory item & draw sequences
+ for (uint i = 1; i < _entities.size(); i++) {
+ getData((EntityIndex)i)->currentCall = 0;
+ getData((EntityIndex)i)->inventoryItem = kItemNone;
+
+ clearSequences((EntityIndex)i);
+ }
+
+ // Init compartments & positions
+ memset(&_compartments, 0, sizeof(_compartments));
+ memset(&_compartments1, 0, sizeof(_compartments1));
+ memset(&_positions, 0, sizeof(_positions));
+
+ getSound()->resetQueue(SoundManager::kSoundType13);
+ }
+
+ // we skip the header when doing entity setup
+ for (uint i = 1; i < _entities.size(); i++) {
+ // Special case of chapters (prevents infinite loop as we will be called from Chapters functions when changing chapters)
+ if (i == kEntityChapters && chapter >= 2)
+ continue;
+
+ _entities[i]->setup(chapter);
+ }
+}
+
+void Entities::reset() {
+ // Reset header
+ delete _header;
+ _header = new EntityData();
+
+ for (uint i = 1; i < _entities.size(); i++)
+ resetSequences((EntityIndex)i);
+
+ getScenes()->resetDoorsAndClock();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// State & Sequences
+//////////////////////////////////////////////////////////////////////////
+
+EntityIndex Entities::canInteractWith(const Common::Point &point) const {
+ if (!getFlags()->isGameRunning)
+ return kEntityPlayer;
+
+ EntityIndex index = kEntityPlayer;
+ int location = 10000;
+
+ // Check if there is an entity we can interact with
+ for (uint i = 0; i < _entities.size(); i++) {
+
+ // Skip entities with no current frame
+ if (!getData((EntityIndex)i)->frame)
+ continue;
+
+ FrameInfo *info = getData((EntityIndex)i)->frame->getInfo();
+
+ // Check the hotspot
+ if (info->hotspot.contains(point)) {
+
+ // If closer to us, update with its values
+ if (location > info->location) {
+ location = info->location;
+ index = (EntityIndex)i;
+ }
+ }
+ }
+
+ // Check if we found an entity
+ if (!index)
+ return kEntityPlayer;
+
+ // Check that there is an item to interact with
+ if (!getData(index)->inventoryItem)
+ return kEntityPlayer;
+
+ return index;
+}
+
+void Entities::resetState(EntityIndex entityIndex) {
+ getData(entityIndex)->currentCall = 0;
+ getData(entityIndex)->inventoryItem = kItemNone;
+
+ if (getSound()->isBuffered(entityIndex))
+ getSound()->removeFromQueue(entityIndex);
+
+ clearSequences(entityIndex);
+
+ if (entityIndex == kEntity39)
+ entityIndex = kEntityPlayer;
+
+ if (entityIndex > kEntityChapters)
+ return;
+
+ // reset compartments and positions for this entity
+ for (int i = 0; i < _positionsCount; i++)
+ _positions[i] &= ~STORE_VALUE(entityIndex);
+
+ for (int i = 0; i < _compartmentsCount; i++) {
+ _compartments[i] &= ~STORE_VALUE(entityIndex);
+ _compartments1[i] &= ~STORE_VALUE(entityIndex);
+ }
+
+ getLogic()->updateCursor();
+}
+
+
+void Entities::updateFields() const {
+ if (!getFlags()->isGameRunning)
+ return;
+
+ for (int i = 0; i < (int)_entities.size(); i++) {
+
+ if (!getSavePoints()->getCallback((EntityIndex)i))
+ continue;
+
+ EntityData::EntityCallData *data = getData((EntityIndex)i);
+ int positionDelta = data->field_4A3 * 10;
+ switch (data->direction) {
+ default:
+ break;
+
+ case kDirectionUp:
+ if (data->entityPosition >= 10000 - positionDelta)
+ data->entityPosition = (EntityPosition)(data->entityPosition + positionDelta);
+ break;
+
+ case kDirectionDown:
+ if (data->entityPosition > positionDelta)
+ data->entityPosition = (EntityPosition)(data->entityPosition - positionDelta);
+ break;
+
+ case kDirectionLeft:
+ data->currentFrame++;
+ break;
+
+ case kDirectionRight:
+ data->field_4A1 += 9;
+ break;
+
+ case kDirectionSwitch:
+ if (data->directionSwitch == kDirectionRight)
+ data->field_4A1 += 9;
+ break;
+
+ }
+ }
+}
+
+void Entities::updateFrame(EntityIndex entityIndex) const {
+ Sequence *sequence = NULL;
+ int16 *currentFrame = NULL;
+ bool found = false;
+
+ if (getData(entityIndex)->direction == kDirectionSwitch) {
+ sequence = getData(entityIndex)->sequence2;
+ currentFrame = &getData(entityIndex)->currentFrame2;
+ } else {
+ sequence = getData(entityIndex)->sequence;
+ currentFrame = &getData(entityIndex)->currentFrame;
+ }
+
+ if (!sequence)
+ return;
+
+ // Save current values
+ int16 oldFrame = *currentFrame;
+ int16 field_4A1 = getData(entityIndex)->field_4A1;
+
+ do {
+ // Check we do not get past the end
+ if (*currentFrame >= (int)sequence->count() - 1)
+ break;
+
+ // Get the proper frame
+ FrameInfo *info = sequence->getFrameInfo((uint16)*currentFrame);
+
+ if (info->field_33 & 8) {
+ found = true;
+ } else {
+ if (info->soundAction == 35)
+ found = true;
+
+ getData(entityIndex)->field_4A1 += info->field_30;
+
+ // Progress to the next frame
+ ++*currentFrame;
+ }
+ } while (!found);
+
+ // Restore old values
+ if (!found) {
+ *currentFrame = oldFrame;
+ getData(entityIndex)->field_4A1 = field_4A1;
+ }
+}
+
+void Entities::updateSequences() const {
+ if (!getFlags()->isGameRunning)
+ return;
+
+ // Update the train clock & doors
+ getScenes()->updateDoorsAndClock();
+
+ //////////////////////////////////////////////////////////////////////////
+ // First pass: Drawing
+ //////////////////////////////////////////////////////////////////////////
+ for (uint i = 1; i < _entities.size(); i++) {
+ EntityIndex entityIndex = (EntityIndex)i;
+
+ if (!getSavePoints()->getCallback(entityIndex))
+ continue;
+
+ EntityData::EntityCallData *data = getData(entityIndex);
+
+ if (data->frame) {
+ getScenes()->removeFromQueue(data->frame);
+ SAFE_DELETE(data->frame);
+ }
+
+ if (data->frame1) {
+ getScenes()->removeFromQueue(data->frame1);
+ SAFE_DELETE(data->frame1);
+ }
+
+ if (data->direction == kDirectionSwitch) {
+
+ // Clear sequence 2
+ if (data->sequence)
+ SAFE_DELETE(data->sequence);
+
+ // Replace by sequence 3 if available
+ if (data->sequence2) {
+ data->sequence = data->sequence2;
+ data->sequenceName = data->sequenceName2;
+
+ data->sequence2 = NULL;
+ data->sequenceName2 = "";
+ }
+
+ data->direction = data->directionSwitch;
+ data->currentFrame = -1;
+ data->field_49B = 0;
+ }
+
+ // Draw sequences
+ drawSequences(entityIndex, data->direction, false);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Second pass: Load sequences for next pass
+ //////////////////////////////////////////////////////////////////////////
+ for (uint i = 1; i < _entities.size(); i++) {
+ EntityIndex entityIndex = (EntityIndex)i;
+
+ if (!getSavePoints()->getCallback(entityIndex))
+ continue;
+
+ EntityData::EntityCallData *data = getData(entityIndex);
+ byte field30 = (data->direction == kDirectionLeft ? entityIndex + 35 : 15);
+
+ if (data->sequenceName != "" && !data->sequence) {
+ data->sequence = loadSequence1(data->sequenceName, field30);
+
+ // If sequence 2 was loaded correctly, remove the copied name
+ // otherwise, compute new name
+ if (data->sequence) {
+ data->sequenceNameCopy = "";
+ } else {
+ Common::String sequenceName;
+
+ // Left and down directions
+ if (data->direction == kDirectionLeft || data->direction == kDirectionRight) {
+ COMPUTE_SEQUENCE_NAME(sequenceName, data->sequenceName);
+
+ // Try loading the sequence
+ data->sequence = loadSequence1(sequenceName, field30);
+ }
+
+ // Update sequence names
+ data->sequenceNameCopy = (data->sequence ? "" : data->sequenceName);
+ data->sequenceName = (data->sequence ? sequenceName : "");
+ }
+ }
+
+ // Update sequence 3
+ if (data->sequenceName2 != "" && !data->sequence2) {
+
+ if (data->car == getData(kEntityPlayer)->car)
+ data->sequence2 = loadSequence1(data->sequenceName2, field30);
+
+ if (!data->sequence2) {
+ Common::String sequenceName;
+
+ // Left and down directions
+ if (data->directionSwitch == kDirectionLeft || data->directionSwitch == kDirectionRight) {
+ COMPUTE_SEQUENCE_NAME(sequenceName, data->sequenceName2);
+
+ // Try loading the sequence
+ data->sequence2 = loadSequence1(sequenceName, field30);
+ }
+
+ // Update sequence names
+ data->sequenceName2 = (data->sequence2 ? sequenceName : "");
+ }
+ }
+ }
+}
+
+void Entities::resetSequences(EntityIndex entityIndex) const {
+
+ // Reset direction
+ if (getData(entityIndex)->direction == kDirectionSwitch) {
+ getData(entityIndex)->direction = getData(entityIndex)->directionSwitch;
+ getData(entityIndex)->field_49B = 0;
+ getData(entityIndex)->currentFrame = -1;
+ }
+
+ // FIXME: in the original engine, the sequence pointers might just be copies,
+ // make sure we free the associated memory at some point
+ getData(entityIndex)->frame = NULL;
+ getData(entityIndex)->frame1 = NULL;
+
+ SAFE_DELETE(getData(entityIndex)->sequence);
+ SAFE_DELETE(getData(entityIndex)->sequence2);
+ SAFE_DELETE(getData(entityIndex)->sequence3);
+
+ getData(entityIndex)->field_4A9 = false;
+ getData(entityIndex)->field_4AA = false;
+
+ strcpy((char*)&getData(entityIndex)->sequenceNameCopy, "");
+ strcpy((char*)&getData(entityIndex)->sequenceName, "");
+ strcpy((char*)&getData(entityIndex)->sequenceName2, "");
+
+ // Original engine resets flag to decompress data on the fly (we don't need to do that)
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Callbacks
+//////////////////////////////////////////////////////////////////////////
+void Entities::updateCallbacks() {
+ if (!getFlags()->isGameRunning)
+ return;
+
+ getFlags()->flag_entities_0 = false;
+
+ if (getFlags()->flag_entities_1) {
+ executeCallbacks();
+ getFlags()->flag_entities_0 = true;
+ } else {
+ getFlags()->flag_entities_1 = true;
+ executeCallbacks();
+ getFlags()->flag_entities_1 = false;
+ }
+}
+
+void Entities::executeCallbacks() {
+ for (uint i = 1; i < _entities.size(); i++) {
+ if (getFlags()->flag_entities_0)
+ break;
+
+ if (getSavePoints()->getCallback((EntityIndex)i))
+ processEntity((EntityIndex)i);
+ }
+
+ if (getFlags()->flag_entities_0)
+ return;
+
+ bool processed = true;
+ do {
+ processed = true;
+ for (int i = 1; i < (int)_entities.size(); i++) {
+ if (getFlags()->flag_entities_0)
+ break;
+
+ if (getSavePoints()->getCallback((EntityIndex)i)) {
+ if (getData((EntityIndex)i)->doProcessEntity) {
+ processed = false;
+ processEntity((EntityIndex)i);
+ }
+ }
+ }
+ } while (!processed);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Processing
+//////////////////////////////////////////////////////////////////////////
+#define INCREMENT_DIRECTION_COUNTER() { \
+ data->doProcessEntity = false; \
+ if (data->direction == kDirectionRight || (data->direction == kDirectionSwitch && data->directionSwitch == kDirectionRight)) \
+ ++data->field_4A1; \
+ }
+
+void Entities::processEntity(EntityIndex entityIndex) {
+ EntityData::EntityCallData *data = getData(entityIndex);
+ bool keepPreviousFrame = false;
+
+ data->doProcessEntity = false;
+
+ if (getData(kEntityPlayer)->car != data->car && data->direction != kDirectionRight && data->direction != kDirectionSwitch) {
+
+ if (data->position) {
+ updatePositionExit(entityIndex, data->car2, data->position);
+ data->car2 = kCarNone;
+ data->position = 0;
+ }
+
+ getScenes()->removeAndRedraw(&data->frame, false);
+ getScenes()->removeAndRedraw(&data->frame1, false);
+
+ INCREMENT_DIRECTION_COUNTER();
+ return;
+ }
+
+ if (data->frame1) {
+ getScenes()->removeAndRedraw(&data->frame1, false);
+
+ if (data->frame && data->frame->getInfo()->subType != kFrameType3) {
+ data->frame->getInfo()->subType = kFrameTypeNone;
+ getScenes()->setFlagDrawSequences();
+ }
+ }
+
+ SAFE_DELETE(data->sequence3);
+
+ if (!data->frame || !data->direction) {
+ if (!data->sequence)
+label_nosequence:
+ drawSequences(entityIndex, data->direction, true);
+
+ data->doProcessEntity = false;
+ computeCurrentFrame(entityIndex);
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+
+ if (data->sequence && data->currentFrame != -1 && data->currentFrame <= (int16)(data->sequence->count() - 1)) {
+ processFrame(entityIndex, false, true);
+
+ if (!getFlags()->flag_entities_0 && !data->doProcessEntity) {
+ INCREMENT_DIRECTION_COUNTER();
+ return;
+ }
+ } else {
+ if (data->direction == kDirectionRight && data->field_4A1 > 100) {
+ getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
+ getSavePoints()->process();
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+ }
+
+ if (data->position) {
+ updatePositionExit(entityIndex, data->car2, data->position);
+ data->car2 = kCarNone;
+ data->position = 0;
+ }
+
+ INCREMENT_DIRECTION_COUNTER();
+ }
+ return;
+ }
+
+ if (!data->sequence)
+ goto label_nosequence;
+
+ if (data->frame->getInfo()->field_30 > data->field_49B + 1 || (data->direction == kDirectionLeft && data->sequence->count() == 1)) {
+ ++data->field_49B;
+ INCREMENT_DIRECTION_COUNTER();
+ return;
+ }
+
+ if (data->frame->getInfo()->field_30 > data->field_49B && !data->frame->getInfo()->keepPreviousFrame) {
+ ++data->field_49B;
+ INCREMENT_DIRECTION_COUNTER();
+ return;
+ }
+
+ if (data->frame->getInfo()->keepPreviousFrame == 1)
+ keepPreviousFrame = true;
+
+ // Increment current frame
+ ++data->currentFrame;
+
+ if (data->currentFrame > (int16)(data->sequence->count() - 1) || (data->field_4A9 && checkSequenceFromPosition(entityIndex))) {
+
+ if (data->direction == kDirectionLeft) {
+ data->currentFrame = 0;
+ } else {
+ keepPreviousFrame = true;
+ drawNextSequence(entityIndex);
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+
+ if (!data->sequence2) {
+ updateEntityPosition(entityIndex);
+ data->doProcessEntity = false;
+ return;
+ }
+
+ copySequenceData(entityIndex);
+ }
+
+ }
+
+ processFrame(entityIndex, keepPreviousFrame, false);
+
+ if (!getFlags()->flag_entities_0 && !data->doProcessEntity)
+ INCREMENT_DIRECTION_COUNTER();
+}
+
+void Entities::computeCurrentFrame(EntityIndex entityIndex) const {
+ EntityData::EntityCallData *data = getData(entityIndex);
+ int16 originalCurrentFrame = data->currentFrame;
+
+ if (!data->sequence) {
+ data->currentFrame = -1;
+ return;
+ }
+
+ switch (data->direction) {
+ default:
+ break;
+
+ case kDirectionNone:
+ case kDirectionSwitch:
+ data->currentFrame = -1;
+ break;
+
+ case kDirectionUp:
+ case kDirectionDown: {
+ Scene *scene = getScenes()->get(getState()->scene);
+
+ if (scene->position > 40)
+ break;
+
+ switch (scene->position) {
+ default:
+ case 4:
+ case 19:
+ case 20:
+ case 21:
+ case 24:
+ break;
+
+ case 1:
+ case 18:
+ case 22:
+ case 40:
+ data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
+ break;
+
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ if (data->field_4A9) {
+ if (getData(kEntityPlayer)->entityPosition >= data->entityPosition) {
+ data->currentFrame = -1;
+ } else {
+ data->currentFrame = getCurrentFrame(entityIndex, data->sequence, getEntityPositionFromCurrentPosition(), true);
+
+ if (data->currentFrame != -1 && originalCurrentFrame == data->currentFrame)
+ if (data->currentFrame < (int)(data->sequence->count() - 2))
+ data->currentFrame += 2;
+ }
+ } else {
+ data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
+ }
+ break;
+
+ case 23:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ if (data->field_4A9) {
+ if (getData(kEntityPlayer)->entityPosition <= data->entityPosition) {
+ data->currentFrame = -1;
+ } else {
+ data->currentFrame = getCurrentFrame(entityIndex, data->sequence, getEntityPositionFromCurrentPosition(), true);
+
+ if (data->currentFrame != -1 && originalCurrentFrame == data->currentFrame)
+ if (data->currentFrame < (int)(data->sequence->count() - 2))
+ data->currentFrame += 2;
+ }
+ } else {
+ data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
+ }
+ break;
+ }
+
+ }
+ break;
+
+
+ case kDirectionLeft:
+ if (data->currentFrame == -1 || data->currentFrame >= (int32)data->sequence->count()) {
+ data->currentFrame = 0;
+ data->field_49B = 0;
+ }
+ break;
+
+ case kDirectionRight:
+ bool found = false;
+ bool flag = false;
+ uint16 frameIndex = 0;
+ byte field30 = 0;
+
+ int16 currentFrameCopy = (!data->currentFrame && !data->field_4A1) ? -1 : data->currentFrame;
+
+ // Process frames
+ do {
+ if (frameIndex >= data->sequence->count())
+ break;
+
+ FrameInfo *info = data->sequence->getFrameInfo(frameIndex);
+
+ if (field30 + info->field_30 >= data->field_4A1) {
+ found = true;
+ break;
+ }
+
+ if (field30 > data->field_4A1 - 10) {
+ if (info->soundAction)
+ getSound()->playSoundEvent(entityIndex, info->soundAction, (field30 <= data->field_4A1 - info->field_31) ? 0 : (byte)(field30 + info->field_31 - data->field_4A1));
+ }
+
+ field30 += info->field_30;
+
+ if (info->field_33 & 4)
+ flag = true;
+
+ if (info->field_33 & 2) {
+ flag = false;
+
+ getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
+ getSavePoints()->process();
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+ }
+
+ if (info->field_33 & 16) {
+ getSavePoints()->push(kEntityPlayer, entityIndex, kAction4);
+ getSavePoints()->process();
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+ }
+
+ frameIndex++;
+
+ } while (!found);
+
+ if (found) {
+
+ if (flag) {
+ bool found2 = false;
+
+ do {
+ if (frameIndex >= data->sequence->count())
+ break;
+
+ FrameInfo *info = data->sequence->getFrameInfo(frameIndex);
+ if (info->field_33 & 2) {
+ found2 = true;
+
+ getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
+ getSavePoints()->process();
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+
+ } else {
+ data->field_4A1 += info->field_30;
+
+ byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
+ if (soundAction)
+ getSound()->playSoundEvent(entityIndex, soundAction);
+
+ ++frameIndex;
+ }
+
+ } while (!found2);
+
+ if (found2) {
+ data->currentFrame = frameIndex;
+ data->field_49B = 0;
+
+ byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
+ byte field31 = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_31;
+ if (soundAction && data->currentFrame != currentFrameCopy)
+ getSound()->playSoundEvent(entityIndex, soundAction, field31);
+
+ } else {
+ data->currentFrame = (int16)(data->sequence->count() - 1);
+ data->field_49B = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_30;
+ }
+
+ } else {
+
+ data->currentFrame = frameIndex;
+ data->field_49B = data->field_4A1 - field30;
+
+ byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
+ byte field31 = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_31;
+ if (soundAction && data->currentFrame != currentFrameCopy)
+ getSound()->playSoundEvent(entityIndex, soundAction, field31 <= data->field_49B ? 0 : (byte)(field31 - data->field_49B));
+ }
+ } else {
+ data->currentFrame = (int16)(data->sequence->count() - 1);
+ data->field_49B = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_30;
+
+ getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
+ getSavePoints()->process();
+ }
+ break;
+ }
+}
+
+int16 Entities::getCurrentFrame(EntityIndex entity, Sequence *sequence, EntityPosition position, bool doProcessing) const {
+ EntityData::EntityCallData *data = getData(entity);
+
+ EntityPosition firstFramePosition = sequence->getFrameInfo(0)->entityPosition;
+ EntityPosition lastFramePosition = sequence->getFrameInfo(sequence->count() - 1)->entityPosition;
+
+ bool isGoingForward = (firstFramePosition < lastFramePosition);
+
+ if (!doProcessing) {
+ if (!isGoingForward) {
+ if (data->field_4A3 + firstFramePosition < data->entityPosition || lastFramePosition - data->field_4A3 > data->entityPosition)
+ return -1;
+ } else {
+ if (firstFramePosition - data->field_4A3 > data->entityPosition || lastFramePosition + data->field_4A3 < data->entityPosition)
+ return -1;
+ }
+ }
+
+ if (sequence->count() == 0)
+ return 0;
+
+ // Search for the correct frame
+ // TODO: looks slightly like some sort of binary search
+ uint16 frame = 0;
+ uint16 numFrames = sequence->count() - 1;
+
+ for (;;) {
+ uint16 currentFrame = (frame + numFrames) / 2;
+
+ if (position + sequence->getFrameInfo(currentFrame)->entityPosition <= data->entityPosition) {
+ if (!isGoingForward)
+ numFrames = (frame + numFrames) / 2;
+ else
+ frame = (frame + numFrames) / 2;
+ } else {
+ if (isGoingForward)
+ numFrames = (frame + numFrames) / 2;
+ else
+ frame = (frame + numFrames) / 2;
+ }
+
+ if (numFrames - frame == 1) {
+ uint16 lastFramePos = ABS(position - (sequence->getFrameInfo(numFrames)->entityPosition + data->entityPosition));
+ uint16 framePosition = ABS(position - (sequence->getFrameInfo(frame)->entityPosition + data->entityPosition));
+
+ return (framePosition > lastFramePos) ? numFrames : frame;
+ }
+
+ if (numFrames <= frame)
+ return currentFrame;
+ }
+}
+
+void Entities::processFrame(EntityIndex entityIndex, bool keepPreviousFrame, bool dontPlaySound) {
+ EntityData::EntityCallData *data = getData(entityIndex);
+
+ // Set frame to be drawn again
+ if (data->frame && keepPreviousFrame) {
+ if (data->frame->getInfo()->subType != kFrameType3)
+ data->frame->getInfo()->subType = kFrameType2;
+
+ getScenes()->setFlagDrawSequences();
+ }
+
+ // Remove old frame from queue
+ if (data->frame && !keepPreviousFrame)
+ getScenes()->removeFromQueue(data->frame);
+
+ // Stop if nothing else to draw
+ if (data->currentFrame < 0)
+ return;
+
+ if (data->currentFrame > (int)data->sequence->count())
+ return;
+
+ // Get new frame info
+ FrameInfo *info = data->sequence->getFrameInfo((uint16)data->currentFrame);
+
+ if (data->frame && data->frame->getInfo()->subType != kFrameType3)
+ if (!info->field_2E || keepPreviousFrame)
+ getScenes()->setCoordinates(data->frame);
+
+ // Update position
+ if (info->entityPosition) {
+ data->entityPosition = info->entityPosition;
+ if (data->field_4A9)
+ data->entityPosition = (EntityPosition)(data->entityPosition + getEntityPositionFromCurrentPosition());
+ }
+
+ info->location = entityIndex + ABS(getData(entityIndex)->entityPosition - getData(kEntityPlayer)->entityPosition);
+
+ if (info->subType != kFrameType3) {
+ info->subType = kFrameType1;
+
+ if (!keepPreviousFrame)
+ info->subType = kFrameTypeNone;
+ }
+
+ if (info->field_33 & 1)
+ getSavePoints()->push(kEntityPlayer, entityIndex, kActionExcuseMeCath);
+
+ if (info->field_33 & 2) {
+ getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
+ getSavePoints()->process();
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+ }
+
+ if (info->field_33 & 16) {
+ getSavePoints()->push(kEntityPlayer, entityIndex, kAction4);
+ getSavePoints()->process();
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+ }
+
+ if (data->position) {
+ updatePositionExit(entityIndex, data->car2, data->position);
+ data->car2 = kCarNone;
+ data->position = 0;
+ }
+
+ if (info->position) {
+ data->car2 = data->car;
+ data->position = info->position;
+ updatePositionEnter(entityIndex, data->car2, data->position);
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+ }
+
+ if (info->soundAction && !dontPlaySound)
+ getSound()->playSoundEvent(entityIndex, info->soundAction, info->field_31);
+
+ // Add the new frame to the queue
+ SequenceFrame *frame = new SequenceFrame(data->sequence, (uint16)data->currentFrame);
+ getScenes()->addToQueue(frame);
+
+ // Keep previous frame if needed and store the new frame
+ if (keepPreviousFrame)
+ data->frame1 = data->frame;
+
+ data->frame = frame;
+
+ if (!dontPlaySound)
+ data->field_49B = keepPreviousFrame ? 0 : 1;
+}
+
+void Entities::drawNextSequence(EntityIndex entityIndex) const {
+ EntityData::EntityCallData *data = getData(entityIndex);
+
+ if (data->direction == kDirectionRight) {
+ getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
+ getSavePoints()->process();
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+ }
+
+ if (!isDirectionUpOrDown(entityIndex))
+ return;
+
+ if (data->sequence2)
+ return;
+
+ if (!getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingAtDoors))
+ return;
+
+ if (getData(kEntityPlayer)->car != data->car)
+ return;
+
+ if (!data->field_4A9 || isWalkingOppositeToPlayer(entityIndex)) {
+ if (!data->field_4A9 && isWalkingOppositeToPlayer(entityIndex)) {
+ data->entityPosition = kPosition_2088;
+
+ if (data->direction != kDirectionUp)
+ data->entityPosition = kPosition_8512;
+
+ drawSequences(entityIndex, data->direction, true);
+ }
+ } else {
+ data->entityPosition = kPosition_8514;
+
+ if (data->direction != kDirectionUp)
+ data->entityPosition = kPosition_2086;
+
+ drawSequences(entityIndex, data->direction, true);
+ }
+}
+
+void Entities::updateEntityPosition(EntityIndex entityIndex) const {
+ EntityData::EntityCallData *data = getData(entityIndex);
+
+ getScenes()->removeAndRedraw(&data->frame, false);
+
+ SAFE_DELETE(data->frame1);
+ data->field_49B = 0;
+
+ if (isDirectionUpOrDown(entityIndex)
+ && (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) || getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
+ && data->car == getData(kEntityPlayer)->car) {
+
+ if (isWalkingOppositeToPlayer(entityIndex)) {
+ data->entityPosition = getData(kEntityPlayer)->entityPosition;
+ } else if (data->field_4A9) {
+ data->entityPosition = (data->direction == kDirectionUp) ? kPosition_8514 : kPosition_2086;
+ } else {
+ if (isPlayerPosition(kCarGreenSleeping, 1) || isPlayerPosition(kCarGreenSleeping, 40)
+ || isPlayerPosition(kCarRedSleeping, 1) || isPlayerPosition(kCarRedSleeping, 40)) {
+ data->entityPosition = (data->direction == kDirectionUp) ? kPosition_2588 : kPosition_8012;
+ } else {
+ data->entityPosition = (data->direction == kDirectionUp) ? kPosition_9271 : kPosition_849;
+ }
+ }
+ }
+
+ SAFE_DELETE(data->sequence);
+ data->sequenceName = "";
+ data->field_4A9 = false;
+
+ if (data->directionSwitch)
+ data->direction = data->directionSwitch;
+}
+
+void Entities::copySequenceData(EntityIndex entityIndex) const {
+ EntityData::EntityCallData *data = getData(entityIndex);
+
+ if (data->sequence)
+ data->sequence3 = data->sequence;
+
+ data->sequence = data->sequence2;
+ data->sequenceName = data->sequenceName2;
+ data->field_4A9 = data->field_4AA;
+
+ if (data->directionSwitch)
+ data->direction = data->directionSwitch;
+
+ // Clear sequence 3
+ data->sequence2 = NULL;
+ data->sequenceName2 = "";
+ data->field_4AA = false;
+ data->directionSwitch = kDirectionNone;
+
+ if (data->field_4A9) {
+ computeCurrentFrame(entityIndex);
+
+ if (data->currentFrame == -1)
+ data->currentFrame = 0;
+ } else {
+ data->currentFrame = data->currentFrame2;
+ data->currentFrame2 = 0;
+
+ if (data->currentFrame == -1)
+ data->currentFrame = 0;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Drawing
+//////////////////////////////////////////////////////////////////////////
+void Entities::drawSequenceLeft(EntityIndex index, const char *sequence) const {
+ drawSequence(index, sequence, kDirectionLeft);
+}
+
+void Entities::drawSequenceRight(EntityIndex index, const char *sequence) const {
+ drawSequence(index, sequence, kDirectionRight);
+}
+
+void Entities::clearSequences(EntityIndex entityIndex) const {
+ debugC(8, kLastExpressDebugLogic, "Clear sequences for entity %s", ENTITY_NAME(entityIndex));
+
+ EntityData::EntityCallData *data = getData(entityIndex);
+
+ getScenes()->removeAndRedraw(&data->frame, false);
+ getScenes()->removeAndRedraw(&data->frame1, false);
+
+ if (data->sequence2) {
+ SAFE_DELETE(data->sequence2);
+ data->sequenceName2 = "";
+ data->field_4AA = false;
+ data->directionSwitch = kDirectionNone;
+ }
+
+ if (data->sequence) {
+ SAFE_DELETE(data->sequence);
+ data->sequenceName = "";
+ data->field_4A9 = false;
+ data->currentFrame = -1;
+ }
+
+ data->sequenceNamePrefix = "";
+ data->direction = kDirectionNone;
+ data->doProcessEntity = true;
+}
+
+void Entities::drawSequence(EntityIndex index, const char *sequence, EntityDirection direction) const {
+ debugC(8, kLastExpressDebugLogic, "Drawing sequence %s for entity %s with direction %s", sequence, ENTITY_NAME(index), DIRECTION_NAME(direction));
+
+ // Copy sequence name
+ getData(index)->sequenceNamePrefix = sequence;
+ getData(index)->sequenceNamePrefix.toUppercase();
+ getData(index)->sequenceNamePrefix += "-";
+
+ // Reset fields
+ getData(index)->field_49B = 0;
+ getData(index)->currentFrame = 0;
+ getData(index)->field_4A1 = 0;
+
+ drawSequences(index, direction, true);
+}
+
+void Entities::drawSequences(EntityIndex entityIndex, EntityDirection direction, bool loadSequence) const {
+ EntityData::EntityCallData *data = getData(entityIndex);
+
+ // Compute value for loading sequence depending on direction
+ byte field30 = (direction == kDirectionLeft ? entityIndex + 35 : 15);
+
+ data->doProcessEntity = true;
+ bool field4A9 = data->field_4A9;
+
+ // First case: different car and not going right: cleanup and return
+ if (data->car != getData(kEntityPlayer)->car && direction != kDirectionRight) {
+ clearEntitySequenceData(data, direction);
+ return;
+ }
+
+ data->directionSwitch = kDirectionNone;
+
+ // Process sequence names
+ Common::String sequenceName;
+ Common::String sequenceName1;
+ Common::String sequenceName2;
+ Common::String sequenceName3;
+
+ getSequenceName(entityIndex, direction, sequenceName1, sequenceName2);
+
+ // No sequence 1: cleanup and return
+ if (sequenceName1 == "") {
+ clearEntitySequenceData(data, direction);
+ return;
+ }
+
+ if (sequenceName1 == data->sequenceNameCopy) {
+ data->direction = direction;
+ return;
+ }
+
+ if (direction == kDirectionLeft || direction == kDirectionRight) {
+ COMPUTE_SEQUENCE_NAME(sequenceName, sequenceName1);
+
+ if (sequenceName3 != "")
+ COMPUTE_SEQUENCE_NAME(sequenceName3, sequenceName2);
+ }
+
+ if (!data->frame) {
+ data->direction = direction;
+
+ if (sequenceName1 == data->sequenceName) {
+ if (sequenceName2 == "")
+ return;
+
+ loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
+ return;
+ }
+
+ SAFE_DELETE(data->sequence);
+
+ if (sequenceName1 != data->sequenceName2) {
+
+ if (loadSequence) {
+
+ if (data->car == getData(kEntityPlayer)->car)
+ data->sequence = loadSequence1(sequenceName1, field30);
+
+ if (data->sequence) {
+ data->sequenceName = sequenceName1;
+ data->sequenceNameCopy = "";
+ } else {
+ if (sequenceName != "")
+ data->sequence = loadSequence1(sequenceName, field30);
+
+ data->sequenceName = (data->sequence ? sequenceName : "");
+ data->sequenceNameCopy = (data->sequence ? "" : sequenceName1);
+ }
+ } else {
+ data->sequenceName = sequenceName1;
+ }
+
+ if (sequenceName2 != "") {
+ loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
+ return;
+ }
+
+ if (!data->sequence2) {
+ if (sequenceName2 == "")
+ return;
+
+ loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
+ return;
+ }
+
+ SAFE_DELETE(data->sequence2);
+ } else {
+ data->sequence = data->sequence2;
+ data->sequenceName = data->sequenceName2;
+ data->sequence2 = NULL;
+ }
+
+ data->sequenceName2 = "";
+
+ if (sequenceName2 == "")
+ return;
+
+ loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
+ return;
+ }
+
+ if (data->sequenceName != sequenceName1) {
+
+ if (data->sequenceName2 != sequenceName1) {
+ SAFE_DELETE(data->sequence2);
+ TRY_LOAD_SEQUENCE(data->sequence2, data->sequenceName2, sequenceName1, sequenceName);
+ }
+
+ data->field_4AA = data->field_4A9;
+ if ((direction != kDirectionUp && direction != kDirectionDown) || data->field_4AA || !data->sequence2) {
+ data->currentFrame2 = 0;
+ } else {
+ data->currentFrame2 = getCurrentFrame(entityIndex, data->sequence2, kPositionNone, false);
+
+ if (data->currentFrame2 == -1) {
+ clearSequences(entityIndex);
+ return;
+ }
+ }
+
+ data->field_4A9 = field4A9;
+ data->field_49B = data->frame->getInfo()->field_30;
+ data->currentFrame = (int16)(data->sequence->count() - 1);
+ data->direction = kDirectionSwitch;
+ data->directionSwitch = direction;
+ } else {
+ SAFE_DELETE(data->sequence2);
+
+ data->sequence2 = loadSequence1(data->sequence->getName(), data->sequence->getField30());
+
+ data->sequenceName2 = data->sequenceName;
+ data->field_4AA = data->field_4A9;
+ data->field_49B = data->frame->getInfo()->field_30;
+ data->currentFrame = (int16)(data->sequence->count() - 1);
+ data->direction = kDirectionSwitch;
+ data->directionSwitch = direction;
+
+ if ((direction != kDirectionUp && direction != kDirectionDown) || data->field_4AA || !data->sequence2) {
+ data->currentFrame2 = 0;
+ } else {
+ data->currentFrame2 = getCurrentFrame(entityIndex, data->sequence2, kPositionNone, false);
+
+ if (data->currentFrame2 == -1)
+ clearSequences(entityIndex);
+ }
+ }
+}
+
+void Entities::loadSequence2(EntityIndex entityIndex, Common::String sequenceName, Common::String sequenceName2, byte field30, bool reloadSequence) const {
+ EntityData::EntityCallData *data = getData(entityIndex);
+
+ if (data->sequenceName2 == sequenceName)
+ return;
+
+ if (data->sequence2)
+ SAFE_DELETE(data->sequence2);
+
+ if (reloadSequence) {
+ TRY_LOAD_SEQUENCE(data->sequence2, data->sequenceName2, sequenceName, sequenceName2);
+ } else {
+ data->sequenceName2 = sequenceName;
+ }
+}
+
+void Entities::getSequenceName(EntityIndex index, EntityDirection direction, Common::String &sequence1, Common::String &sequence2) const {
+ EntityData::EntityCallData *data = getData(index);
+ Position position = getScenes()->get(getState()->scene)->position;
+
+ // reset fields
+ data->field_4A9 = false;
+ data->field_4AA = false;
+
+ switch (direction) {
+ default:
+ break;
+
+ case kDirectionUp:
+ switch (position) {
+ default:
+ break;
+
+ case 1:
+ if (data->entityPosition < kPosition_2587)
+ sequence1 = Common::String::format("%02d%01d-01u.seq", index, data->clothes);
+ break;
+
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ if (data->entityPosition >= kPosition_9270)
+ break;
+
+ if (data->entityPosition >= kPosition_8513) {
+ sequence1 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
+ } else {
+ sequence1 = Common::String::format("%02d%01d-03u.seq", index, data->clothes);
+ sequence2 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
+ data->field_4A9 = true;
+ }
+ break;
+
+ case 18:
+ if (data->entityPosition < kPosition_9270)
+ sequence1 = Common::String::format("%02d%01d-18u.seq", index, data->clothes);
+ break;
+
+ case 22:
+ if (getData(kEntityPlayer)->entityPosition > data->entityPosition)
+ sequence1 = Common::String::format("%02d%01d-22u.seq", index, data->clothes);
+ break;
+
+ case 23:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ if (getData(kEntityPlayer)->entityPosition <= data->entityPosition)
+ break;
+
+ if (data->entityPosition >= kPosition_2087) {
+ sequence1 = Common::String::format("%02d%01d-38u.seq", index, data->clothes);
+ data->field_4A9 = true;
+ } else {
+ sequence1 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
+ sequence2 = Common::String::format("%02d%01d-38u.seq", index, data->clothes);
+ data->field_4AA = true;
+ }
+ break;
+
+ case 40:
+ if (getData(kEntityPlayer)->entityPosition > data->entityPosition)
+ sequence1 = Common::String::format("%02d%01d-40u.seq", index, data->clothes);
+ break;
+ }
+ break;
+
+ case kDirectionDown:
+ switch (position) {
+ default:
+ break;
+
+ case 1:
+ if (getData(kEntityPlayer)->entityPosition < data->entityPosition)
+ sequence1 = Common::String::format("%02d%01d-01d.seq", index, data->clothes);
+ break;
+
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ if (getData(kEntityPlayer)->entityPosition >= data->entityPosition)
+ break;
+
+ if (data->entityPosition <= kPosition_8513) {
+ sequence1 = Common::String::format("%02d%01d-03d.seq", index, data->clothes);
+ data->field_4A9 = true;
+ } else {
+ sequence1 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
+ sequence2 = Common::String::format("%02d%01d-03d.seq", index, data->clothes);
+ data->field_4AA = true;
+ }
+ break;
+
+ case 18:
+ if (getData(kEntityPlayer)->entityPosition < data->entityPosition)
+ sequence1 = Common::String::format("%02d%01d-18d.seq", index, data->clothes);
+ break;
+
+ case 22:
+ if (data->entityPosition > kPosition_850)
+ sequence1 = Common::String::format("%02d%01d-22d.seq", index, data->clothes);
+ break;
+
+ case 23:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ if (data->entityPosition <= kPosition_850)
+ break;
+
+ if (data->entityPosition <= kPosition_2087) {
+ sequence1 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
+ } else {
+ sequence1 = Common::String::format("%02d%01d-38d.seq", index, data->clothes);
+ sequence2 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
+ data->field_4A9 = true;
+ }
+ break;
+
+ case 40:
+ if (getData(kEntityPlayer)->entityPosition > kPosition_8013)
+ sequence1 = Common::String::format("%02d%01d-40d.seq", index, data->clothes);
+ break;
+ }
+ break;
+
+ // First part of sequence is already set
+ case kDirectionLeft:
+ case kDirectionRight:
+ sequence1 = Common::String::format("%s%02d.seq", data->sequenceNamePrefix.c_str(), position);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// Compartments
+//////////////////////////////////////////////////////////////////////////
+void Entities::enterCompartment(EntityIndex entity, ObjectIndex compartment, bool useCompartment1) {
+ if (entity > kEntityChapters)
+ return;
+
+ switch (compartment) {
+ default:
+ // Return here so we do not update the compartments
+ return;
+
+ case kObjectCompartment1:
+ updatePositionsEnter(entity, kCarGreenSleeping, 41, 51, 17, 38);
+ break;
+
+ case kObjectCompartment2:
+ updatePositionsEnter(entity, kCarGreenSleeping, 42, 52, 15, 36);
+ break;
+
+ case kObjectCompartment3:
+ updatePositionsEnter(entity, kCarGreenSleeping, 43, 53, 13, 34);
+ break;
+
+ case kObjectCompartment4:
+ updatePositionsEnter(entity, kCarGreenSleeping, 44, 54, 11, 32);
+ break;
+
+ case kObjectCompartment5:
+ updatePositionsEnter(entity, kCarGreenSleeping, 45, 55, 9, 30);
+ break;
+
+ case kObjectCompartment6:
+ updatePositionsEnter(entity, kCarGreenSleeping, 46, 56, 7, 28);
+ break;
+
+ case kObjectCompartment7:
+ updatePositionsEnter(entity, kCarGreenSleeping, 47, 57, 5, 26);
+ break;
+
+ case kObjectCompartment8:
+ updatePositionsEnter(entity, kCarGreenSleeping, 48, 58, 3, 25);
+ break;
+
+ case kObjectCompartmentA:
+ updatePositionsEnter(entity, kCarRedSleeping, 41, 51, 17, 38);
+ break;
+
+ case kObjectCompartmentB:
+ updatePositionsEnter(entity, kCarRedSleeping, 42, 52, 15, 36);
+ break;
+
+ case kObjectCompartmentC:
+ updatePositionsEnter(entity, kCarRedSleeping, 43, 53, 13, 34);
+ break;
+
+ case kObjectCompartmentD:
+ updatePositionsEnter(entity, kCarRedSleeping, 44, 54, 11, 32);
+ break;
+
+ case kObjectCompartmentE:
+ updatePositionsEnter(entity, kCarRedSleeping, 45, 55, 9, 30);
+ break;
+
+ case kObjectCompartmentF:
+ updatePositionsEnter(entity, kCarRedSleeping, 46, 56, 7, 28);
+ break;
+
+ case kObjectCompartmentG:
+ updatePositionsEnter(entity, kCarRedSleeping, 47, 57, 5, 26);
+ break;
+
+ case kObjectCompartmentH:
+ updatePositionsEnter(entity, kCarRedSleeping, 48, 58, 3, 25);
+ break;
+ }
+
+ // Update compartments
+ int index = (compartment < 32 ? compartment - 1 : compartment - 24);
+ if (index >= 16)
+ error("Entities::exitCompartment: invalid compartment index!");
+
+ if (useCompartment1)
+ _compartments1[index] |= STORE_VALUE(entity);
+ else
+ _compartments[index] |= STORE_VALUE(entity);
+}
+
+void Entities::exitCompartment(EntityIndex entity, ObjectIndex compartment, bool useCompartment1) {
+ if (entity > kEntityChapters)
+ return;
+
+ // TODO factorize in one line
+ switch (compartment) {
+ default:
+ // Return here so we do not update the compartments
+ return;
+
+ case kObjectCompartment1:
+ updatePositionsExit(entity, kCarGreenSleeping, 41, 51);
+ break;
+
+ case kObjectCompartment2:
+ updatePositionsExit(entity, kCarGreenSleeping, 42, 52);
+ break;
+
+ case kObjectCompartment3:
+ updatePositionsExit(entity, kCarGreenSleeping, 43, 53);
+ break;
+
+ case kObjectCompartment4:
+ updatePositionsExit(entity, kCarGreenSleeping, 44, 54);
+ break;
+
+ case kObjectCompartment5:
+ updatePositionsExit(entity, kCarGreenSleeping, 45, 55);
+ break;
+
+ case kObjectCompartment6:
+ updatePositionsExit(entity, kCarGreenSleeping, 46, 56);
+ break;
+
+ case kObjectCompartment7:
+ updatePositionsExit(entity, kCarGreenSleeping, 47, 57);
+ break;
+
+ case kObjectCompartment8:
+ updatePositionsExit(entity, kCarGreenSleeping, 48, 58);
+ break;
+
+ case kObjectCompartmentA:
+ updatePositionsExit(entity, kCarRedSleeping, 41, 51);
+ break;
+
+ case kObjectCompartmentB:
+ updatePositionsExit(entity, kCarRedSleeping, 42, 52);
+ break;
+
+ case kObjectCompartmentC:
+ updatePositionsExit(entity, kCarRedSleeping, 43, 53);
+ break;
+
+ case kObjectCompartmentD:
+ updatePositionsExit(entity, kCarRedSleeping, 44, 54);
+ break;
+
+ case kObjectCompartmentE:
+ updatePositionsExit(entity, kCarRedSleeping, 45, 55);
+ break;
+
+ case kObjectCompartmentF:
+ updatePositionsExit(entity, kCarRedSleeping, 46, 56);
+ break;
+
+ case kObjectCompartmentG:
+ updatePositionsExit(entity, kCarRedSleeping, 47, 57);
+ break;
+
+ case kObjectCompartmentH:
+ updatePositionsExit(entity, kCarRedSleeping, 48, 58);
+ break;
+ }
+
+ // Update compartments
+ int index = (compartment < 32 ? compartment - 1 : compartment - 24);
+ if (index >= 16)
+ error("Entities::exitCompartment: invalid compartment index!");
+
+ if (useCompartment1)
+ _compartments1[index] &= ~STORE_VALUE(entity);
+ else
+ _compartments[index] &= ~STORE_VALUE(entity);
+}
+
+void Entities::updatePositionEnter(EntityIndex entity, CarIndex car, Position position) {
+ if (entity == kEntity39)
+ entity = kEntityPlayer;
+
+ if (entity > kEntityChapters)
+ return;
+
+ _positions[100 * car + position] |= STORE_VALUE(entity);
+
+ if (isPlayerPosition(car, position) || (car == kCarRestaurant && position == 57 && isPlayerPosition(kCarRestaurant, 50))) {
+ getSound()->excuseMe(entity);
+ getScenes()->loadScene(getScenes()->processIndex(getState()->scene));
+ getSound()->playSound(kEntityPlayer, "CAT1127A");
+ } else {
+ getLogic()->updateCursor();
+ }
+}
+
+void Entities::updatePositionExit(EntityIndex entity, CarIndex car, Position position) {
+ if (entity == kEntity39)
+ entity = kEntityPlayer;
+
+ if (entity > kEntityChapters)
+ return;
+
+ _positions[100 * car + position] &= ~STORE_VALUE(entity);
+
+ getLogic()->updateCursor();
+}
+
+void Entities::updatePositionsEnter(EntityIndex entity, CarIndex car, Position position1, Position position2, Position position3, Position position4) {
+ if (entity == kEntity39)
+ entity = kEntityPlayer;
+
+ if (entity > kEntityChapters)
+ return;
+
+ _positions[100 * car + position1] |= STORE_VALUE(entity);
+ _positions[100 * car + position2] |= STORE_VALUE(entity);
+
+ // FIXME: also checking two DWORD values that do not seem to updated anywhere...
+ if (isPlayerPosition(car, position1) || isPlayerPosition(car, position2) || isPlayerPosition(car, position3) || isPlayerPosition(car, position4)) {
+ getSound()->excuseMe(entity);
+ getScenes()->loadScene(getScenes()->processIndex(getState()->scene));
+ getSound()->playSound(kEntityPlayer, "CAT1127A");
+ } else {
+ getLogic()->updateCursor();
+ }
+}
+
+void Entities::updatePositionsExit(EntityIndex entity, CarIndex car, Position position1, Position position2) {
+ if (entity == kEntity39)
+ entity = kEntityPlayer;
+
+ if (entity > kEntityChapters)
+ return;
+
+ _positions[100 * car + position1] &= ~STORE_VALUE(entity);
+ _positions[100 * car + position2] &= ~STORE_VALUE(entity);
+
+ getLogic()->updateCursor();
+}
+
+void Entities::loadSceneFromEntityPosition(CarIndex car, EntityPosition entityPosition, bool alternate) const {
+
+ // Determine position
+ Position position = (alternate ? 1 : 40);
+ do {
+ if (entityPosition > entityPositions[position]) {
+ if (alternate)
+ break;
+
+ // For default value, we ignore position 24
+ if (position != 24)
+ break;
+ }
+
+ alternate ? ++position : --position;
+
+ } while (alternate ? position <= 18 : position >= 22);
+
+ // For position outside bounds, use minimal value
+ if ((alternate && position > 18) || (alternate && position < 22)) {
+ getScenes()->loadSceneFromPosition(car, alternate ? 18 : 22);
+ return;
+ }
+
+ // Load scene from position
+ switch (position) {
+ default:
+ getScenes()->loadSceneFromPosition(car, (Position)(position + (alternate ? - 1 : 1)));
+ break;
+
+ // Alternate
+ case 1:
+ if (alternate) getScenes()->loadSceneFromPosition(car, 1);
+ break;
+
+ case 5:
+ if (alternate) getScenes()->loadSceneFromPosition(car, 3);
+ break;
+
+ // Default
+ case 23:
+ if (!alternate) getScenes()->loadSceneFromPosition(car, 25);
+ break;
+
+ case 40:
+ if (!alternate) getScenes()->loadSceneFromPosition(car, 40);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Checks
+//////////////////////////////////////////////////////////////////////////
+bool Entities::hasValidFrame(EntityIndex entity) const {
+ return (getData(entity)->frame && (getData(entity)->frame->getInfo()->subType != kFrameType3));
+}
+
+bool Entities::compare(EntityIndex entity1, EntityIndex entity2) const {
+ EntityData::EntityCallData *data1 = getData(entity1);
+ EntityData::EntityCallData *data2 = getData(entity2);
+
+ if (data2->car != data1->car
+ || data1->car < kCarGreenSleeping
+ || data1->car > kCarRedSleeping)
+ return false;
+
+ EntityPosition position1 = (data1->entityPosition >= data2->entityPosition) ? data1->entityPosition : data2->entityPosition;
+ EntityPosition position2 = (data1->entityPosition >= data2->entityPosition) ? data2->entityPosition : data1->entityPosition;
+
+ // Compute position
+ int index1 = 7;
+ do {
+ if (objectsPosition[index1] >= position2)
+ break;
+
+ --index1;
+ } while (index1 > -1);
+
+ int index2 = 0;
+ do {
+ if (objectsPosition[index2] <= position2)
+ break;
+
+ ++index2;
+ } while (index2 < 8);
+
+ if (index1 > -1 && index2 < 8 && index2 <= index1) {
+ while (index2 <= index1) {
+ if (getCompartments(index2 + (data1->car == kCarGreenSleeping ? 0 : 8)))
+ return true;
+
+ if (getCompartments1(index2 + (data1->car == kCarGreenSleeping ? 0 : 8)))
+ return true;
+
+ ++index2;
+ }
+ }
+
+ for (EntityIndex entity = kEntityAnna; entity <= kEntity39; entity = (EntityIndex)(entity + 1)) {
+
+ if (entity1 == entity || entity2 == entity)
+ continue;
+
+ if (!isDirectionUpOrDown(entity))
+ continue;
+
+ if (data1->car == getEntityData(entity)->car
+ && getEntityData(entity)->entityPosition > position2
+ && getEntityData(entity)->entityPosition < position1)
+ return true;
+ }
+
+ return false;
+}
+
+bool Entities::updateEntity(EntityIndex entity, CarIndex car, EntityPosition position) const {
+ EntityData::EntityCallData *data = getData(entity);
+ EntityDirection direction = kDirectionNone;
+ int delta = 0;
+ bool flag1 = false;
+ bool flag2 = false;
+ bool flag3 = false;
+
+ if (position == kPosition_2000
+ && getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)
+ && !isPlayerPosition(kCarGreenSleeping, 1)
+ && !isPlayerPosition(kCarRedSleeping, 2))
+ position = kPosition_1500;
+
+ if (data->direction != kDirectionUp && data->direction != kDirectionDown)
+ data->field_497 = 0;
+
+ if (data->field_497) {
+ data->field_497--;
+
+ if (data->field_497 == 128)
+ data->field_497 = 0;
+
+ if ((data->field_497 & 127) != 8) {
+ data->field_49B = 0;
+ return false;
+ }
+
+ flag1 = true;
+
+ if (data->field_497 & 128)
+ flag2 = true;
+ }
+
+ if (data->car != car)
+ goto label_process_entity;
+
+ // Calculate delta
+ delta = ABS(data->entityPosition - position);
+ if (delta < 100 || (position > kPosition_850 && position < kPosition_9270 && delta < 300))
+ flag3 = true;
+
+ if (!flag3) {
+ if ((getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) && data->direction == kDirectionUp)
+ || (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) && data->direction == kDirectionDown)) {
+ if (!checkPosition(position) && isDistanceBetweenEntities(entity, kEntityPlayer, 250))
+ flag3 = true;
+ }
+
+ if (!flag3)
+ goto label_process_entity;
+ }
+
+ if (getEntities()->hasValidFrame(entity)
+ && getEntities()->isWalkingOppositeToPlayer(entity)
+ && !getEntities()->checkPosition(position)) {
+ flag3 = false;
+ position = (EntityPosition)(getData(kEntityPlayer)->entityPosition + 250 * (data->direction == kDirectionUp ? 1 : -1));
+ }
+
+ if (!flag3) {
+label_process_entity:
+
+ // Calculate direction
+ if (data->car < car)
+ direction = kDirectionUp;
+ else if (data->car > car)
+ direction = kDirectionDown;
+ else // same car
+ direction = (data->entityPosition < position) ? kDirectionUp : kDirectionDown;
+
+ if (data->direction == direction) {
+ if (!flag1) {
+
+ if (checkDistanceFromPosition(entity, kPosition_1500, 750) && entity != kEntityFrancois) {
+
+ if (data->entity != kEntityPlayer) {
+ if (data->direction != kDirectionUp || (position <= kPosition_2000 && data->car == car)) {
+ if (data->direction == kDirectionDown && (position < kPosition_1500 || data->car != car)) {
+ if (data->entityPosition > kPosition_1500 && (data->car == kCarGreenSleeping || data->car == kCarRedSleeping)) {
+ data->entity = (data->car == kCarGreenSleeping) ? kEntityMertens : kEntityCoudert;
+ getSavePoints()->push(entity, data->entity, kAction11);
+ }
+ }
+ } else {
+ if (data->entityPosition < kPosition_1500 && (data->car == kCarGreenSleeping || data->car == kCarRedSleeping)) {
+ data->entity = (data->car == kCarGreenSleeping) ? kEntityMertens : kEntityCoudert;
+ getSavePoints()->push(entity, data->entity, kAction11, 1);
+ }
+ }
+ }
+
+ } else if (data->entity) {
+ getSavePoints()->push(entity, data->entity, kAction16);
+ data->entity = kEntityPlayer;
+ }
+
+ if (hasValidFrame(entity)) {
+
+ if (!data->field_4A9)
+ return false;
+
+ int compartmentIndex = 0;
+ if (data->car == kCarGreenSleeping)
+ compartmentIndex = 0;
+ else if (data->car == kCarRedSleeping)
+ compartmentIndex = 8;
+
+ for (int i = 0; i < 8; i++) {
+ if (getCompartments(compartmentIndex) || getCompartments1(compartmentIndex)) {
+ if (checkDistanceFromPosition(entity, objectsPosition[i], 750)) {
+ if (checkPosition(objectsPosition[i])) {
+
+ if ((data->direction == kDirectionUp && data->entityPosition < objectsPosition[i] && (data->car != car || position > objectsPosition[i]))
+ || (data->direction == kDirectionDown && data->entityPosition > objectsPosition[i] && (data->car != car || position < objectsPosition[i]))) {
+
+ getSound()->excuseMe(entity, (EntityIndex)(State::getPowerOfTwo((uint32)(getCompartments(compartmentIndex) ? getCompartments(compartmentIndex) : getCompartments1(compartmentIndex)))));
+
+ data->field_497 = 144;
+
+ break;
+ }
+ }
+ }
+ }
+
+ compartmentIndex++;
+ }
+
+ for (EntityIndex entityIndex = kEntityAnna; entityIndex <= kEntity39; entityIndex = (EntityIndex)(entityIndex + 1)) {
+ if (getSavePoints()->getCallback(entityIndex)
+ && hasValidFrame(entityIndex)
+ && entityIndex != entity
+ && isDistanceBetweenEntities(entity, entityIndex, 750)
+ && isDirectionUpOrDown(entityIndex)
+ && (entity != kEntityRebecca || entityIndex != kEntitySophie)
+ && (entity != kEntitySophie || entityIndex != kEntityRebecca)
+ && (entity != kEntityIvo || entityIndex != kEntitySalko)
+ && (entity != kEntitySalko || entityIndex != kEntityIvo)
+ && (entity != kEntityMilos || entityIndex != kEntityVesna)
+ && (entity != kEntityVesna || entityIndex != kEntityMilos)) {
+
+ EntityData::EntityCallData *data2 = getData(entityIndex);
+
+ if (data->direction != data2->direction) {
+
+ if ((data->direction != kDirectionUp || data2->entityPosition <= data->entityPosition)
+ && (data->direction != kDirectionDown || data2->entityPosition >= data->entityPosition))
+ continue;
+
+ data->field_49B = 0;
+ data2->field_49B = 0;
+
+ data->field_497 = 16;
+ data2->field_497 = 16;
+
+ getSound()->excuseMe(entity, entityIndex);
+ getSound()->excuseMe(entityIndex, entity);
+
+ if (entityIndex > entity)
+ ++data2->field_497;
+
+ break;
+ }
+
+ if (ABS(data2->entityPosition - getData(kEntityPlayer)->entityPosition) < ABS(data->entityPosition - getData(kEntityPlayer)->entityPosition)) {
+
+ if (!isWalkingOppositeToPlayer(entity)) {
+
+ if (direction == kDirectionUp) {
+ if (data->entityPosition < kPosition_9500)
+ data->entityPosition = (EntityPosition)(data->entityPosition + 500);
+ } else {
+ if (data->entityPosition > kPosition_500)
+ data->entityPosition = (EntityPosition)(data->entityPosition - 500);
+ }
+
+ drawSequences(entity, direction, true);
+
+ return false;
+ }
+ data->field_49B = 0;
+
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ if (data->direction == kDirectionUp) {
+ if (data->entityPosition + data->field_4A3 < 10000)
+ data->entityPosition = (EntityPosition)(data->entityPosition + data->field_4A3);
+ } else {
+ if (data->entityPosition > data->field_4A3)
+ data->entityPosition = (EntityPosition)(data->entityPosition - data->field_4A3);
+ }
+
+ if (data->entityPosition <= kPosition_9270 || data->direction != kDirectionUp) {
+ if (data->entityPosition < kPosition_850 && data->direction == kDirectionDown) {
+ if (changeCar(data, entity, car, position, false, kPosition_9269, kCarKronos))
+ return true;
+ }
+ } else {
+ if (changeCar(data, entity, car, position, true, kPosition_851, kCarGreenSleeping))
+ return true;
+ }
+
+ if (getData(kEntityPlayer)->car == data->car && data->location == kLocationOutsideCompartment) {
+ if (data->direction == kDirectionUp) {
+
+ if (getData(kEntityPlayer)->entityPosition > data->entityPosition
+ && getData(kEntityPlayer)->entityPosition - data->entityPosition >= 500
+ && data->field_4A3 + 500 > getData(kEntityPlayer)->entityPosition - data->entityPosition) {
+
+ if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) || getScenes()->checkCurrentPosition(false)) {
+ getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMe);
+
+ if (getScenes()->checkCurrentPosition(false))
+ getScenes()->loadSceneFromObject((ObjectIndex)getScenes()->get(getState()->scene)->param1, true);
+
+ } else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown)) {
+ getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMeCath);
+ }
+ }
+ } else {
+ if (getData(kEntityPlayer)->entityPosition < data->entityPosition
+ && data->entityPosition - getData(kEntityPlayer)->entityPosition >= 500
+ && data->field_4A3 + 500 > data->entityPosition - getData(kEntityPlayer)->entityPosition) {
+
+ if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)) {
+ getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMeCath);
+ } else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) || getScenes()->checkCurrentPosition(false)){
+ getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMe);
+
+ if (getScenes()->checkCurrentPosition(false))
+ getScenes()->loadSceneFromObject((ObjectIndex)getScenes()->get(getState()->scene)->param1);
+ }
+ }
+ }
+ return false;
+ }
+ }
+ } else if (!flag1) {
+ drawSequences(entity, direction, true);
+ return false;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Adjust positions
+
+ // Direction Up
+ if (direction == kDirectionUp) {
+ if (data->entityPosition < (flag2 ? kPosition_8800 : kPosition_9250))
+ data->entityPosition = (EntityPosition)(data->entityPosition + (flag2 ? kPosition_1200 : kPosition_750));
+
+ if (data->car == car && data->entityPosition >= position) {
+ data->entityPosition = position;
+ data->direction = kDirectionNone;
+ data->entity = kEntityPlayer;
+ return true;
+ }
+
+ drawSequences(entity, direction, true);
+ return false;
+ }
+
+ // Direction Down
+ if (data->entityPosition > (flag2 ? kPosition_1200 : kPosition_750))
+ data->entityPosition = (EntityPosition)(data->entityPosition - (flag2 ? kPosition_1200 : kPosition_750));
+
+ if (data->car == car && data->entityPosition <= position) {
+ data->entityPosition = position;
+ data->direction = kDirectionNone;
+ data->entity = kEntityPlayer;
+ return true;
+ }
+
+ drawSequences(entity, direction, true);
+ return false;
+ }
+
+ data->entityPosition = position;
+ if (data->direction == kDirectionUp || data->direction == kDirectionDown)
+ data->direction = kDirectionNone;
+ data->entity = kEntityPlayer;
+
+ return true;
+}
+
+bool Entities::changeCar(EntityData::EntityCallData *data, EntityIndex entity, CarIndex car, EntityPosition position, bool increment, EntityPosition newPosition, CarIndex newCar) const {
+ if (getData(kEntityPlayer)->car == data->car) {
+ getSound()->playSoundEvent(entity, 36);
+ getSound()->playSoundEvent(entity, 37, 30);
+ }
+
+ data->car = (CarIndex)(increment ? data->car + 1 : data->car - 1);
+ data->entityPosition = newPosition;
+
+ if (data->car == newCar) {
+ if (isInGreenCarEntrance(kEntityPlayer)) {
+ getSound()->playSoundEvent(kEntityPlayer, 14);
+ getSound()->excuseMe(entity, kEntityPlayer, SoundManager::kFlagDefault);
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 1);
+ getSound()->playSound(kEntityPlayer, "CAT1127A");
+ getSound()->playSoundEvent(kEntityPlayer, 15);
+ }
+ }
+
+ if ((increment ? data->car > car : data->car < car) || (data->car == car && (increment ? data->entityPosition >= position : data->entityPosition <= position))) {
+ data->car = car;
+ data->entityPosition = position;
+ data->direction = kDirectionNone;
+ data->entity = kEntityPlayer;
+
+ return true;
+ }
+
+ if (data->car == newCar) {
+ if (isInKronosCarEntrance(kEntityPlayer)) {
+ getSound()->playSoundEvent(kEntityPlayer, 14);
+ getSound()->excuseMe(entity, kEntityPlayer, SoundManager::kFlagDefault);
+ getScenes()->loadSceneFromPosition(kCarGreenSleeping, 62);
+ getSound()->playSound(kEntityPlayer, "CAT1127A");
+ getSound()->playSoundEvent(kEntityPlayer, 15);
+ }
+ }
+
+ if (data->car == getData(kEntityPlayer)->car) {
+ getSound()->playSoundEvent(entity, 36);
+ getSound()->playSoundEvent(entity, 37, 30);
+ }
+
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// CHECKS
+//////////////////////////////////////////////////////////////////////////
+bool Entities::isInsideCompartment(EntityIndex entity, CarIndex car, EntityPosition position) const {
+ return (getData(entity)->entityPosition == position
+ && getData(entity)->location == kLocationInsideCompartment
+ && getData(entity)->car == car);
+}
+
+bool Entities::checkFields2(ObjectIndex object) const {
+
+ EntityPosition position = kPositionNone;
+ CarIndex car = kCarNone;
+
+ switch (object) {
+ default:
+ return false;
+
+ case kObjectCompartment1:
+ case kObjectCompartment2:
+ case kObjectCompartment3:
+ case kObjectCompartment4:
+ case kObjectCompartment5:
+ case kObjectCompartment6:
+ case kObjectCompartment7:
+ case kObjectCompartment8:
+ position = objectsPosition[object - 1];
+ car = kCarGreenSleeping;
+ if (isInsideCompartment(kEntityPlayer, car, position))
+ return false;
+ break;
+
+ case kObjectHandleBathroom:
+ case kObjectHandleInsideBathroom:
+ case kObjectKitchen:
+ case kObject20:
+ case kObject21:
+ case kObject22:
+ position = objectsPosition[object-17];
+ car = kCarGreenSleeping;
+ break;
+
+ case kObjectCompartmentA:
+ case kObjectCompartmentB:
+ case kObjectCompartmentC:
+ case kObjectCompartmentD:
+ case kObjectCompartmentE:
+ case kObjectCompartmentF:
+ case kObjectCompartmentG:
+ case kObjectCompartmentH:
+ position = objectsPosition[object-32];
+ car = kCarRedSleeping;
+ if (isInsideCompartment(kEntityPlayer, car, position))
+ return false;
+ break;
+
+ case kObject48:
+ case kObject49:
+ case kObject50:
+ case kObject51:
+ case kObject52:
+ case kObject53:
+ position = objectsPosition[object-48];
+ car = kCarRedSleeping;
+ break;
+
+ }
+
+ uint index = 1;
+ while (!isInsideCompartment((EntityIndex)index, car, position) || index == kEntityVassili) {
+ index++;
+ if (index >= 40)
+ return false;
+ }
+
+ return true;
+}
+
+bool Entities::isInsideCompartments(EntityIndex entity) const {
+ return (getData(entity)->car == kCarGreenSleeping
+ || getData(entity)->car == kCarRedSleeping)
+ && getData(entity)->location == kLocationInsideCompartment;
+}
+
+bool Entities::isPlayerPosition(CarIndex car, Position position) const {
+ return getData(kEntityPlayer)->car == car && getScenes()->get(getState()->scene)->position == position;
+}
+
+bool Entities::isInsideTrainCar(EntityIndex entity, CarIndex car) const {
+ return getData(entity)->car == car && getData(entity)->location <= kLocationInsideCompartment;
+}
+
+bool Entities::isInGreenCarEntrance(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarGreenSleeping) && getData(entity)->entityPosition < kPosition_850;
+}
+
+bool Entities::isPlayerInCar(CarIndex car) const {
+ return isInsideTrainCar(kEntityPlayer, car) && getData(kEntityPlayer)->location && !isInGreenCarEntrance(kEntityPlayer);
+}
+
+bool Entities::isDirectionUpOrDown(EntityIndex entity) const {
+ return getData(entity)->direction == kDirectionUp || getData(entity)->direction == kDirectionDown;
+}
+
+bool Entities::isDistanceBetweenEntities(EntityIndex entity1, EntityIndex entity2, uint distance) const {
+ return getData(entity1)->car == getData(entity2)->car
+ && (uint)ABS(getData(entity1)->entityPosition - getData(entity2)->entityPosition) <= distance
+ && (getData(entity1)->location != kLocationOutsideTrain || getData(entity2)->location != kLocationOutsideTrain);
+}
+
+bool Entities::checkFields10(EntityIndex entity) const {
+ return getData(entity)->location <= kLocationOutsideTrain;
+}
+
+bool Entities::isSomebodyInsideRestaurantOrSalon() const {
+ for (uint i = 1; i < _entities.size(); i++) {
+ EntityIndex index = (EntityIndex)i;
+
+ if (getData(index)->location == kLocationOutsideCompartment && (isInSalon(index) || isInRestaurant(index)))
+ return false;
+ }
+
+ return true;
+}
+
+bool Entities::isInSalon(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarRestaurant)
+ && getData(entity)->entityPosition >= kPosition_1540
+ && getData(entity)->entityPosition <= kPosition_3650;
+}
+
+bool Entities::isInRestaurant(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarRestaurant)
+ && getData(entity)->entityPosition >= kPosition_3650
+ && getData(entity)->entityPosition <= kPosition_5800;
+}
+
+bool Entities::isInKronosSalon(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarKronos)
+ && getData(entity)->entityPosition >= kPosition_5500
+ && getData(entity)->entityPosition <= kPosition_7500;
+}
+
+bool Entities::isOutsideAlexeiWindow() const {
+ return (getData(kEntityPlayer)->entityPosition == kPosition_7500 || getData(kEntityPlayer)->entityPosition == kPosition_8200)
+ && getData(kEntityPlayer)->location == kLocationOutsideTrain
+ && getData(kEntityPlayer)->car == kCarGreenSleeping;
+}
+
+bool Entities::isOutsideAnnaWindow() const {
+ return (getData(kEntityPlayer)->entityPosition == kPosition_4070 || getData(kEntityPlayer)->entityPosition == kPosition_4840)
+ && getData(kEntityPlayer)->location == kLocationOutsideTrain
+ && getData(kEntityPlayer)->car == kCarRedSleeping;
+}
+
+bool Entities::isInKitchen(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarRestaurant) && getData(entity)->entityPosition > kPosition_5800;
+}
+
+bool Entities::isNobodyInCompartment(CarIndex car, EntityPosition position) const {
+ for (uint i = 1; i < _entities.size(); i++) {
+ if (isInsideCompartment((EntityIndex)i, car, position))
+ return false;
+ }
+ return true;
+}
+
+bool Entities::checkFields19(EntityIndex entity, CarIndex car, EntityPosition position) const {
+
+ if (getData(entity)->car != car || getData(entity)->location != kLocationInsideCompartment)
+ return false;
+
+ EntityPosition entityPosition = getData(entity)->entityPosition;
+
+ // Test values
+ if (position == kPosition_4455) {
+ if (entityPosition == kPosition_4070 || entityPosition == kPosition_4455 || entityPosition == kPosition_4840)
+ return true;
+
+ return false;
+ }
+
+ if (position == kPosition_6130) {
+ if (entityPosition == kPosition_5790 || entityPosition == kPosition_6130 || entityPosition == kPosition_6470)
+ return true;
+
+ return false;
+ }
+
+ if (position != kPosition_7850
+ || (entityPosition != kPosition_7500 && entityPosition != kPosition_7850 && entityPosition != kPosition_8200))
+ return false;
+
+ return true;
+}
+
+bool Entities::isInBaggageCarEntrance(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarBaggage)
+ && getData(entity)->entityPosition >= kPosition_4500
+ && getData(entity)->entityPosition <= kPosition_5500;
+}
+
+bool Entities::isInBaggageCar(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarBaggage) && getData(entity)->entityPosition < kPosition_4500;
+}
+
+bool Entities::isInKronosSanctum(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarKronos)
+ && getData(entity)->entityPosition >= kPosition_3500
+ && getData(entity)->entityPosition <= kPosition_5500;
+}
+
+bool Entities::isInKronosCarEntrance(EntityIndex entity) const {
+ return isInsideTrainCar(entity, kCarKronos) && getData(entity)->entityPosition > kPosition_7900;
+}
+
+bool Entities::checkDistanceFromPosition(EntityIndex entity, EntityPosition position, int distance) const {
+ return distance >= ABS(getData(entity)->entityPosition - position);
+}
+
+bool Entities::isWalkingOppositeToPlayer(EntityIndex entity) const {
+ if (getData(entity)->direction == kDirectionUp && getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
+ return true;
+
+ return (getData(entity)->direction == kDirectionDown && getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp));
+}
+
+bool Entities::isFemale(EntityIndex entity) {
+ return (entity == kEntityAnna
+ || entity == kEntityTatiana
+ || entity == kEntityVesna
+ || entity == kEntityKahina
+ || entity == kEntityMmeBoutarel
+ || entity == kEntityRebecca
+ || entity == kEntitySophie
+ || entity == kEntityYasmin
+ || entity == kEntityHadija
+ || entity == kEntityAlouan);
+}
+
+bool Entities::isMarried(EntityIndex entity) {
+ return (entity != kEntityTatiana
+ && entity != kEntityRebecca
+ && entity != kEntitySophie);
+}
+
+bool Entities::checkPosition(EntityPosition position) const {
+ Position position1 = 0;
+ Position position2 = 0;
+
+ switch (position) {
+ default:
+ return true;
+
+ case kPosition_1500:
+ position1 = 1;
+ position2 = 23;
+ break;
+
+ case kPosition_2740:
+ position1 = 3;
+ position2 = 25;
+ break;
+
+ case kPosition_3050:
+ position1 = 5;
+ position2 = 26;
+ break;
+
+ case kPosition_4070:
+ position1 = 7;
+ position2 = 28;
+ break;
+
+ case kPosition_4840:
+ position1 = 9;
+ position2 = 30;
+ break;
+
+ case kPosition_5790:
+ position1 = 11;
+ position2 = 32;
+ break;
+
+ case kPosition_6470:
+ position1 = 13;
+ position2 = 34;
+ break;
+
+ case kPosition_7500:
+ position1 = 15;
+ position2 = 36;
+ break;
+
+ case kPosition_8200:
+ position1 = 17;
+ position2 = 38;
+ break;
+ }
+
+ if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) && entityPositions[position1] >= getEntityData(kEntityPlayer)->entityPosition)
+ return true;
+ else
+ return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) && entityPositions[position2] <= getEntityData(kEntityPlayer)->entityPosition);
+}
+
+bool Entities::checkSequenceFromPosition(EntityIndex entity) const {
+ FrameInfo *info = getEntityData(entity)->sequence->getFrameInfo((uint16)getEntityData(entity)->currentFrame);
+
+ if (getEntityData(entity)->direction == kDirectionUp)
+ return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)
+ && info->entityPosition + getEntityPositionFromCurrentPosition() > kPosition_8513);
+
+ if (getEntityData(entity)->direction == kDirectionDown)
+ return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown)
+ && info->entityPosition + getEntityPositionFromCurrentPosition() < kPosition_2087);
+
+ return false;
+}
+
+EntityPosition Entities::getEntityPositionFromCurrentPosition() const {
+ // Get the scene position first
+ Position position = getScenes()->get(getState()->scene)->position;
+
+ if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp))
+ return (EntityPosition)(entityPositions[position] - kPosition_1430);
+
+ if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
+ return (EntityPosition)(entityPositions[position] - kPosition_9020);
+
+ return kPositionNone;
+}
+
+void Entities::clearEntitySequenceData(EntityData::EntityCallData *data, EntityDirection direction) const {
+ getScenes()->removeAndRedraw(&data->frame, false);
+ getScenes()->removeAndRedraw(&data->frame1, false);
+
+ SAFE_DELETE(data->sequence);
+ SAFE_DELETE(data->sequence2);
+
+ data->sequenceName = "";
+ data->sequenceName2 = "";
+
+ data->field_4A9 = false;
+ data->field_4AA = false;
+ data->directionSwitch = kDirectionNone;
+
+ data->currentFrame = -1;
+ data->currentFrame2 = 0;
+
+ data->direction = direction;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/entities.h b/engines/lastexpress/game/entities.h
new file mode 100644
index 0000000000..8cc2072c42
--- /dev/null
+++ b/engines/lastexpress/game/entities.h
@@ -0,0 +1,380 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_ENTITIES_H
+#define LASTEXPRESS_ENTITIES_H
+
+/*
+ Entities
+ --------
+
+ The entities structure contains 40 Entity_t structures for each entity
+
+*/
+
+#include "lastexpress/entities/entity.h"
+
+#include "lastexpress/shared.h"
+
+#include "common/rect.h"
+#include "common/serializer.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+class Sequence;
+
+class Entities : Common::Serializable {
+public:
+ Entities(LastExpressEngine *engine);
+ ~Entities();
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &ser);
+ void savePositions(Common::Serializer &ser);
+ void saveCompartments(Common::Serializer &ser);
+
+ void setup(bool isFirstChapter, EntityIndex entity);
+ void setupChapter(ChapterIndex chapter);
+ void reset();
+
+ // Update & drawing
+
+ /**
+ * Reset an entity state
+ *
+ * @param entity entity index
+ * @note remember to call the function pointer (we do not pass it our implementation)
+ */
+ void resetState(EntityIndex entity);
+ void updateFields() const;
+ void updateSequences() const;
+ void updateCallbacks();
+
+ EntityIndex canInteractWith(const Common::Point &point) const;
+ bool compare(EntityIndex entity1, EntityIndex entity2) const;
+
+ /**
+ * Update an entity current sequence frame (and related fields)
+ *
+ * @param entity entity index
+ */
+ void updateFrame(EntityIndex entity) const;
+ void updatePositionEnter(EntityIndex entity, CarIndex car, Position position);
+ void updatePositionExit(EntityIndex entity, CarIndex car, Position position);
+ void enterCompartment(EntityIndex entity, ObjectIndex compartment, bool useCompartment1 = false);
+ void exitCompartment(EntityIndex entity, ObjectIndex compartment, bool useCompartment1 = false);
+
+ // Sequences
+ void drawSequenceLeft(EntityIndex index, const char *sequence) const;
+ void drawSequenceRight(EntityIndex index, const char *sequence) const;
+ void clearSequences(EntityIndex index) const;
+
+ bool updateEntity(EntityIndex entity, CarIndex car, EntityPosition position) const;
+ bool hasValidFrame(EntityIndex entity) const;
+
+ // Accessors
+ Entity *get(EntityIndex entity);
+ EntityData::EntityCallData *getData(EntityIndex entity) const;
+ int getPosition(CarIndex car, Position position) const;
+ int getCompartments(int index) const;
+ int getCompartments1(int index) const;
+
+ // Scene
+ void loadSceneFromEntityPosition(CarIndex car, EntityPosition position, bool alternate = false) const;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Checks
+ //////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Query if 'entity' is inside a compartment
+ *
+ * @param entity The entity.
+ * @param car The car.
+ * @param position The position.
+ *
+ * @return true if inside the compartment, false if not.
+ */
+ bool isInsideCompartment(EntityIndex entity, CarIndex car, EntityPosition position) const;
+
+ bool checkFields2(ObjectIndex object) const;
+
+ /**
+ * Query if 'entity' is in compartment cars.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in compartment cars, false if not.
+ */
+ bool isInsideCompartments(EntityIndex entity) const;
+
+ /**
+ * Query if the player is in the specified position
+ *
+ * @param car The car.
+ * @param position The position.
+ * @return true if player is in that position, false if not.
+ */
+ bool isPlayerPosition(CarIndex car, Position position) const;
+
+ /**
+ * Query if 'entity' is inside a train car
+ *
+ * @param entity The entity.
+ * @param car The car.
+ *
+ * @return true if inside a train car, false if not.
+ */
+ bool isInsideTrainCar(EntityIndex entity, CarIndex car) const;
+
+ /**
+ * Query if 'entity' is in green car entrance.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in the green car entrance, false if not.
+ */
+ bool isInGreenCarEntrance(EntityIndex entity) const;
+
+ /**
+ * Query if the player is in a specific car
+ *
+ * @param car The car.
+ *
+ * @return true if player is in the car, false if not.
+ */
+ bool isPlayerInCar(CarIndex car) const;
+
+ /**
+ * Query if 'entity' is going in the up or down direction.
+ *
+ * @param entity The entity.
+ *
+ * @return true if direction is up or down, false if not.
+ */
+ bool isDirectionUpOrDown(EntityIndex entity) const;
+
+ /**
+ * Query if the distance between the two entities is less 'distance'
+ *
+ * @param entity1 The first entity.
+ * @param entity2 The second entity.
+ * @param distance The distance.
+ *
+ * @return true if the distance between entities is less than 'distance', false if not.
+ */
+ bool isDistanceBetweenEntities(EntityIndex entity1, EntityIndex entity2, uint distance) const;
+
+ bool checkFields10(EntityIndex entity) const;
+
+ /**
+ * Query if there is somebody in the restaurant or salon.
+ *
+ * @return true if somebody is in the restaurant or salon, false if not.
+ */
+ bool isSomebodyInsideRestaurantOrSalon() const;
+
+ /**
+ * Query if 'entity' is in the salon.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in the salon, false if not.
+ */
+ bool isInSalon(EntityIndex entity) const;
+
+ /**
+ * Query if 'entity' is in the restaurant.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in the restaurant, false if not.
+ */
+ bool isInRestaurant(EntityIndex entity) const;
+
+ /**
+ * Query if 'entity' is in Kronos salon.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in Kronos salon, false if not.
+ */
+ bool isInKronosSalon(EntityIndex entity) const;
+
+ /**
+ * Query if the player is outside Alexei window.
+ *
+ * @return true if outside alexei window, false if not.
+ */
+ bool isOutsideAlexeiWindow() const;
+
+ /**
+ * Query if the player is outside Anna window.
+ *
+ * @return true if outside anna window, false if not.
+ */
+ bool isOutsideAnnaWindow() const;
+
+ /**
+ * Query if 'entity' is in the kitchen.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in the kitchen, false if not.
+ */
+ bool isInKitchen(EntityIndex entity) const;
+
+ /**
+ * Query if nobody is in a compartment at that position.
+ *
+ * @param car The car.
+ * @param position The position.
+ *
+ * @return true if nobody is in a compartment, false if not.
+ */
+ bool isNobodyInCompartment(CarIndex car, EntityPosition position) const;
+
+ bool checkFields19(EntityIndex entity, CarIndex car, EntityPosition position) const;
+
+ /**
+ * Query if 'entity' is in the baggage car entrance.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in the baggage car entrance, false if not.
+ */
+ bool isInBaggageCarEntrance(EntityIndex entity) const;
+
+ /**
+ * Query if 'entity' is in the baggage car.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in the baggage car, false if not.
+ */
+ bool isInBaggageCar(EntityIndex entity) const;
+
+ /**
+ * Query if 'entity' is in Kronos sanctum.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in Kronos sanctum, false if not.
+ */
+ bool isInKronosSanctum(EntityIndex entity) const;
+
+ /**
+ * Query if 'entity' is in Kronos car entrance.
+ *
+ * @param entity The entity.
+ *
+ * @return true if in Kronos car entrance, false if not.
+ */
+ bool isInKronosCarEntrance(EntityIndex entity) const;
+
+ /**
+ * Check distance from position.
+ *
+ * @param entity The entity.
+ * @param position The position.
+ * @param distance The distance.
+ *
+ * @return true if distance is bigger, false otherwise.
+ */
+ bool checkDistanceFromPosition(EntityIndex entity, EntityPosition position, int distance) const;
+
+ /**
+ * Query if 'entity' is walking opposite to player.
+ *
+ * @param entity The entity.
+ *
+ * @return true if walking opposite to player, false if not.
+ */
+ bool isWalkingOppositeToPlayer(EntityIndex entity) const;
+
+ /**
+ * Query if 'entity' is female.
+ *
+ * @param entity The entity.
+ *
+ * @return true if female, false if not.
+ */
+ static bool isFemale(EntityIndex entity);
+
+ /**
+ * Query if 'entity' is married.
+ *
+ * @param entity The entity.
+ *
+ * @return true if married, false if not.
+ */
+ static bool isMarried(EntityIndex entity);
+
+private:
+ static const int _compartmentsCount = 16;
+ static const int _positionsCount = 100 * 10; // 100 positions per train car
+
+ LastExpressEngine *_engine;
+ EntityData *_header;
+ Common::Array<Entity *> _entities;
+
+ // Compartments & positions
+ uint _compartments[_compartmentsCount];
+ uint _compartments1[_compartmentsCount];
+ uint _positions[_positionsCount];
+
+ void executeCallbacks();
+ void processEntity(EntityIndex entity);
+
+ void drawSequence(EntityIndex entity, const char *sequence, EntityDirection direction) const;
+ void drawSequences(EntityIndex entity, EntityDirection direction, bool loadSequence) const;
+ void loadSequence2(EntityIndex entity, Common::String sequenceName, Common::String sequenceName2, byte field30, bool loadSequence) const;
+
+ void clearEntitySequenceData(EntityData::EntityCallData *data, EntityDirection direction) const;
+ void computeCurrentFrame(EntityIndex entity) const;
+ int16 getCurrentFrame(EntityIndex entity, Sequence *sequence, EntityPosition position, bool doProcessing) const;
+ void processFrame(EntityIndex entity, bool keepPreviousFrame, bool dontPlaySound);
+ void drawNextSequence(EntityIndex entity) const;
+ void updateEntityPosition(EntityIndex entity) const;
+ void copySequenceData(EntityIndex entity) const;
+
+ bool changeCar(EntityData::EntityCallData *data, EntityIndex entity, CarIndex car, EntityPosition position, bool increment, EntityPosition newPosition, CarIndex newCar) const;
+
+ void getSequenceName(EntityIndex entity, EntityDirection direction, Common::String &sequence1, Common::String &sequence2) const;
+
+ void updatePositionsEnter(EntityIndex entity, CarIndex car, Position position1, Position position2, Position position3, Position position4);
+ void updatePositionsExit(EntityIndex entity, CarIndex car, Position position1, Position position2);
+
+ void resetSequences(EntityIndex entity) const;
+
+ bool checkPosition(EntityPosition position) const;
+ bool checkSequenceFromPosition(EntityIndex entity) const;
+ EntityPosition getEntityPositionFromCurrentPosition() const;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_ENTITIES_H
diff --git a/engines/lastexpress/game/fight.cpp b/engines/lastexpress/game/fight.cpp
new file mode 100644
index 0000000000..8fa711df1c
--- /dev/null
+++ b/engines/lastexpress/game/fight.cpp
@@ -0,0 +1,1587 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/fight.h"
+
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/scene.h"
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+#include "common/func.h"
+
+namespace LastExpress {
+
+#define CALL_FUNCTION0(fighter, name) \
+ (*fighter->name)(fighter)
+
+#define CALL_FUNCTION1(fighter, name, a) \
+ (*fighter->name)(fighter, a)
+
+#define REGISTER_PLAYER_FUNCTIONS(name) \
+ if (!_data) \
+ error("Fight::load##namePlayer - invalid data!"); \
+ _data->player->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleAction##name); \
+ _data->player->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::update##name); \
+ _data->player->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract##name);
+
+#define REGISTER_OPPONENT_FUNCTIONS(name) \
+ if (!_data) \
+ error("Fight::load##nameOpponent - invalid data!"); \
+ _data->opponent->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleOpponentAction##name); \
+ _data->opponent->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::updateOpponent##name); \
+ _data->opponent->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract);
+
+#define CHECK_SEQUENCE2(fighter, value) \
+ (fighter->frame->getInfo()->field_33 & value)
+
+Fight::Fight(LastExpressEngine *engine) : _engine(engine), _data(NULL), _endType(kFightEndLost), _state(0), _handleTimer(false) {}
+
+Fight::~Fight() {
+ clearData();
+ _data = NULL;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Events
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::eventMouse(const Common::Event &ev) {
+ if (!_data || _data->index)
+ return;
+
+ // TODO move all the egg handling to inventory functions
+
+ getFlags()->mouseLeftClick = false;
+ getFlags()->shouldRedraw = false;
+ getFlags()->mouseRightClick = false;
+
+ if (ev.mouse.x < 608 || ev.mouse.y < 448 || ev.mouse.x >= 640 || ev.mouse.x >= 480) {
+
+ // Handle right button click
+ if (ev.type == Common::EVENT_RBUTTONUP) {
+ getSound()->removeFromQueue(kEntityTables0);
+ setStopped();
+
+ getGlobalTimer() ? _state = 0 : ++_state;
+
+ getFlags()->mouseRightClick = true;
+ }
+
+ if (_handleTimer) {
+ // Timer expired => show with full brightness
+ if (!getGlobalTimer())
+ getInventory()->drawEgg();
+
+ _handleTimer = false;
+ }
+
+ // Check hotspots
+ Scene *scene = getScenes()->get(getState()->scene);
+ SceneHotspot *hotspot = NULL;
+
+ if (!scene->checkHotSpot(ev.mouse, &hotspot)) {
+ _engine->getCursor()->setStyle(kCursorNormal);
+ } else {
+ _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor);
+
+ // Call player function
+ if (CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) {
+ if (ev.type == Common::EVENT_LBUTTONUP)
+ CALL_FUNCTION1(_data->player, handleAction, (FightAction)hotspot->action);
+ } else {
+ _engine->getCursor()->setStyle(kCursorNormal);
+ }
+ }
+ } else {
+ // Handle clicks on menu icon
+
+ if (!_handleTimer) {
+ // Timer expired => show with full brightness
+ if (!getGlobalTimer())
+ getInventory()->drawEgg();
+
+ _handleTimer = true;
+ }
+
+ // Stop fight if clicked
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ _handleTimer = false;
+ getSound()->removeFromQueue(kEntityTables0);
+ bailout(kFightEndExit);
+ }
+
+ // Reset timer on right click
+ if (ev.type == Common::EVENT_RBUTTONUP) {
+ if (getGlobalTimer()) {
+ if (getSound()->isBuffered("TIMER"))
+ getSound()->removeFromQueue("TIMER");
+
+ setGlobalTimer(900);
+ }
+ }
+ }
+
+ getFlags()->shouldRedraw = true;
+}
+
+void Fight::eventTick(const Common::Event &ev) {
+ handleTick(ev, true);
+}
+
+void Fight::handleTick(const Common::Event &ev, bool isProcessing) {
+ // TODO move all the egg handling to inventory functions
+
+ // Blink egg
+ if (getGlobalTimer()) {
+ warning("Fight::handleMouseMove - egg blinking not implemented!");
+ }
+
+ if (!_data || _data->index)
+ return;
+
+ SceneHotspot *hotspot = NULL;
+ if (!getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot) || !CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) {
+ _engine->getCursor()->setStyle(kCursorNormal);
+ } else {
+ _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor);
+ }
+
+ CALL_FUNCTION0(_data->player, update);
+ CALL_FUNCTION0(_data->opponent, update);
+
+ // Draw sequences
+ if (!_data->isRunning)
+ return;
+
+ if (isProcessing)
+ getScenes()->drawFrames(true);
+
+ if (_data->index) {
+ // Set next sequence name index
+ _data->index--;
+ _data->sequences[_data->index] = loadSequence(_data->names[_data->index]);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Setup
+//////////////////////////////////////////////////////////////////////////
+
+Fight::FightEndType Fight::setup(FightType type) {
+ if (_data)
+ error("Fight::setup - calling fight setup again while a fight is already in progress!");
+
+ //////////////////////////////////////////////////////////////////////////
+ // Prepare UI & state
+ if (_state >= 5 && (type == kFightSalko || type == kFightVesna)) {
+ _state = 0;
+ return kFightEndWin;
+ }
+
+ getInventory()->showHourGlass();
+ // TODO events function
+ getFlags()->flag_0 = false;
+ getFlags()->mouseRightClick = false;
+ getEntities()->reset();
+
+ // Compute scene to use
+ SceneIndex sceneIndex;
+ switch(type) {
+ default:
+ sceneIndex = kSceneFightDefault;
+ break;
+
+ case kFightMilos:
+ sceneIndex = (getObjects()->get(kObjectCompartment1).location2 < kObjectLocation3) ? kSceneFightMilos : kSceneFightMilosBedOpened;
+ break;
+
+ case kFightAnna:
+ sceneIndex = kSceneFightAnna;
+ break;
+
+ case kFightIvo:
+ sceneIndex = kSceneFightIvo;
+ break;
+
+ case kFightSalko:
+ sceneIndex = kSceneFightSalko;
+ break;
+
+ case kFightVesna:
+ sceneIndex = kSceneFightVesna;
+ break;
+ }
+
+ if (getFlags()->shouldRedraw) {
+ getFlags()->shouldRedraw = false;
+ askForRedraw();
+ //redrawScreen();
+ }
+
+ // Load the scene object
+ Scene *scene = getScenes()->get(sceneIndex);
+
+ // Update game entities and state
+ getEntityData(kEntityPlayer)->entityPosition = scene->entityPosition;
+ getEntityData(kEntityPlayer)->location = scene->location;
+
+ getState()->scene = sceneIndex;
+
+ getFlags()->flag_3 = true;
+
+ // Draw the scene
+ _engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC);
+ // FIXME move to start of fight?
+ askForRedraw();
+ redrawScreen();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Setup the fight
+ _data = new FightData;
+ loadData(type);
+
+ // Show opponents & egg button
+ Common::Event emptyEvent;
+ handleTick(emptyEvent, false);
+ getInventory()->drawEgg();
+
+ // Start fight
+ _endType = kFightEndLost;
+ while (_data->isRunning) {
+ if (_engine->handleEvents())
+ continue;
+
+ getSound()->updateQueue();
+ }
+
+ // Cleanup after fight is over
+ clearData();
+
+ return _endType;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Status
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::setStopped() {
+ if (_data)
+ _data->isRunning = false;
+}
+
+void Fight::bailout(FightEndType type) {
+ _state = 0;
+ _endType = type;
+ setStopped();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Cleanup
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::clearData() {
+ if (!_data)
+ return;
+
+ // Clear data
+ clearSequences(_data->player);
+ clearSequences(_data->opponent);
+
+ delete _data->player;
+ delete _data->opponent;
+
+ delete _data;
+ _data = NULL;
+
+ _engine->restoreEventHandlers();
+}
+
+void Fight::clearSequences(Fighter *combatant) const {
+ if (!combatant)
+ return;
+
+ // The original game resets the function pointers to default values, just before deleting the struct
+ getScenes()->removeAndRedraw(&combatant->frame, false);
+
+ // Free sequences
+ for (int i = 0; i < (int)combatant->sequences.size(); i++)
+ delete combatant->sequences[i];
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Drawing
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::setSequenceAndDraw(Fighter *combatant, uint32 sequenceIndex, FightSequenceType type) const {
+ if (combatant->sequences.size() < sequenceIndex)
+ return;
+
+ switch (type) {
+ default:
+ break;
+
+ case kFightSequenceType0:
+ if (combatant->sequenceIndex)
+ return;
+
+ combatant->sequence = combatant->sequences[sequenceIndex];
+ combatant->sequenceIndex = sequenceIndex;
+ draw(combatant);
+ break;
+
+ case kFightSequenceType1:
+ combatant->sequence = combatant->sequences[sequenceIndex];
+ combatant->sequenceIndex = sequenceIndex;
+ combatant->sequenceIndex2 = 0;
+ draw(combatant);
+ break;
+
+ case kFightSequenceType2:
+ combatant->sequenceIndex2 = sequenceIndex;
+ break;
+ }
+}
+
+void Fight::draw(Fighter *combatant) const {
+ getScenes()->removeAndRedraw(&combatant->frame, false);
+
+ combatant->frameIndex = 0;
+ combatant->field_24 = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Loading
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::loadData(FightType type) {
+ if (!_data)
+ error("Fight::loadData - invalid data!");
+
+ switch (type) {
+ default:
+ break;
+
+ case kFightMilos:
+ loadMilosPlayer();
+ loadMilosOpponent();
+ break;
+
+ case kFightAnna:
+ loadAnnaPlayer();
+ loadAnnaOpponent();
+ break;
+
+ case kFightIvo:
+ loadIvoPlayer();
+ loadIvoOpponent();
+ break;
+
+ case kFightSalko:
+ loadSalkoPlayer();
+ loadSalkoOpponent();
+ break;
+
+ case kFightVesna:
+ loadVesnaPlayer();
+ loadVesnaOpponent();
+ break;
+ }
+
+ if (!_data->player || !_data->opponent)
+ error("Fight::loadData - error loading fight data (type=%d)", type);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Start running the fight
+ _data->isRunning = true;
+
+ if (_state < 5) {
+ setSequenceAndDraw(_data->player, 0, kFightSequenceType0);
+ setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0);
+ goto end_load;
+ }
+
+ switch(type) {
+ default:
+ break;
+
+ case kFightMilos:
+ _data->opponent->countdown = 1;
+ setSequenceAndDraw(_data->player, 4, kFightSequenceType0);
+ setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0);
+ break;
+
+ case kFightIvo:
+ _data->opponent->countdown = 1;
+ setSequenceAndDraw(_data->player, 3, kFightSequenceType0);
+ setSequenceAndDraw(_data->opponent, 6, kFightSequenceType0);
+ break;
+
+ case kFightVesna:
+ _data->opponent->countdown = 1;
+ setSequenceAndDraw(_data->player, 0, kFightSequenceType0);
+ setSequenceAndDraw(_data->player, 3, kFightSequenceType2);
+ setSequenceAndDraw(_data->opponent, 5, kFightSequenceType0);
+ break;
+ }
+
+end_load:
+ // Setup event handlers
+ _engine->backupEventHandlers();
+ SET_EVENT_HANDLERS(Fight, this);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Shared
+//////////////////////////////////////////////////////////////////////////
+void Fight::processFighter(Fighter *fighter) {
+ if (!_data)
+ error("Fight::processFighter - invalid data!");
+
+ if (!fighter->sequence) {
+ if (fighter->frame) {
+ getScenes()->removeFromQueue(fighter->frame);
+ getScenes()->setCoordinates(fighter->frame);
+ }
+ SAFE_DELETE(fighter->frame);
+ return;
+ }
+
+ if (fighter->sequence->count() <= fighter->frameIndex) {
+ switch(fighter->action) {
+ default:
+ break;
+
+ case kFightAction101:
+ setSequenceAndDraw(fighter, fighter->sequenceIndex2, kFightSequenceType1);
+ fighter->sequenceIndex2 = 0;
+ break;
+
+ case kFightActionResetFrame:
+ fighter->frameIndex = 0;
+ break;
+
+ case kFightAction103:
+ setSequenceAndDraw(fighter, 0, kFightSequenceType1);
+ CALL_FUNCTION1(fighter, handleAction, kFightAction101);
+ setSequenceAndDraw(fighter->opponent, 0, kFightSequenceType1);
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction101);
+ CALL_FUNCTION0(fighter->opponent, update);
+ break;
+
+ case kFightActionWin:
+ bailout(kFightEndWin);
+ break;
+
+ case kFightActionLost:
+ bailout(kFightEndLost);
+ break;
+ }
+ }
+
+ if (_data->isRunning) {
+
+ // Get the current sequence frame
+ SequenceFrame *frame = new SequenceFrame(fighter->sequence, (uint16)fighter->frameIndex);
+ frame->getInfo()->location = 1;
+
+ if (fighter->frame == frame) {
+ delete frame;
+ return;
+ }
+
+ getSound()->playFightSound(frame->getInfo()->soundAction, frame->getInfo()->field_31);
+
+ // Add current frame to queue and advance
+ getScenes()->addToQueue(frame);
+ fighter->frameIndex++;
+
+ if (fighter->frame) {
+ getScenes()->removeFromQueue(fighter->frame);
+
+ if (!frame->getInfo()->field_2E)
+ getScenes()->setCoordinates(fighter->frame);
+ }
+
+ // Replace by new frame
+ delete fighter->frame;
+ fighter->frame = frame;
+ }
+}
+
+void Fight::handleAction(Fighter *fighter, FightAction action) {
+ switch (action) {
+ default:
+ return;
+
+ case kFightAction101:
+ break;
+
+ case kFightActionResetFrame:
+ fighter->countdown--;
+ break;
+
+ case kFightAction103:
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame);
+ break;
+
+ case kFightActionWin:
+ _endType = kFightEndWin;
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame);
+ break;
+
+ case kFightActionLost:
+ _endType = kFightEndLost;
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame);
+ break;
+ }
+
+ // Update action
+ fighter->action = action;
+}
+
+bool Fight::canInteract(Fighter const *fighter, FightAction /*= (FightAction)0*/ ) {
+ return (fighter->action == kFightAction101 && !fighter->sequenceIndex);
+}
+
+void Fight::update(Fighter *fighter) {
+
+ processFighter(fighter);
+
+ if (fighter->frame)
+ fighter->frame->getInfo()->location = (fighter->action == kFightActionResetFrame ? 2 : 0);
+}
+
+void Fight::updateOpponent(Fighter *fighter) {
+
+ // This is an opponent struct!
+ Opponent *opponent = (Opponent *)fighter;
+
+ processFighter(opponent);
+
+ if (opponent->field_38 && !opponent->sequenceIndex)
+ opponent->field_38--;
+
+ if (fighter->frame)
+ fighter->frame->getInfo()->location = 1;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Milos
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::loadMilosPlayer() {
+ REGISTER_PLAYER_FUNCTIONS(Milos)
+
+ _data->player->sequences.push_back(loadSequence("2001cr.seq"));
+ _data->player->sequences.push_back(loadSequence("2001cdl.seq"));
+ _data->player->sequences.push_back(loadSequence("2001cdr.seq"));
+ _data->player->sequences.push_back(loadSequence("2001cdm.seq"));
+ _data->player->sequences.push_back(loadSequence("2001csgr.seq"));
+ _data->player->sequences.push_back(loadSequence("2001csgl.seq"));
+ _data->player->sequences.push_back(loadSequence("2001dbk.seq"));
+}
+
+void Fight::loadMilosOpponent() {
+ REGISTER_OPPONENT_FUNCTIONS(Milos)
+
+ _data->opponent->sequences.push_back(loadSequence("2001or.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2001oal.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2001oam.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2001okl.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2001okm.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2001dbk.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2001wbk.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS027", SoundManager::kFlagDefault);
+
+ _data->opponent->field_38 = 35;
+}
+
+void Fight::handleActionMilos(Fighter *fighter, FightAction action) {
+ switch (action) {
+ default:
+ handleAction(fighter, action);
+ return;
+
+ case kFightAction1:
+ if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) {
+ setSequenceAndDraw(fighter, 6, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 3, kFightSequenceType1);
+
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ } else {
+ fighter->field_34++;
+ }
+ break;
+
+ case kFightAction2:
+ if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) {
+ setSequenceAndDraw(fighter, 6, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1);
+
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ } else {
+ fighter->field_34++;
+ }
+ break;
+
+ case kFightAction128:
+ if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4) || fighter->opponent->sequenceIndex != 1) {
+ switch (fighter->opponent->sequenceIndex) {
+ default:
+ setSequenceAndDraw(fighter, rnd(3) + 1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(fighter, 1, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(fighter, 3, kFightSequenceType0);
+ break;
+ }
+ } else {
+ setSequenceAndDraw(fighter, 4, kFightSequenceType1);
+ CALL_FUNCTION0(fighter, update);
+ }
+ break;
+ }
+}
+
+void Fight::updateMilos(Fighter *fighter) {
+ if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) {
+
+ // Draw sequences
+ if (fighter->opponent->countdown <= 0) {
+ setSequenceAndDraw(fighter, 5, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1);
+
+ getSound()->removeFromQueue(kEntityTables0);
+ getSound()->playSound(kEntityTrain, "MUS029", SoundManager::kFlagDefault);
+
+ CALL_FUNCTION1(fighter, handleAction, kFightActionWin);
+ }
+
+ if (fighter->sequenceIndex == 4) {
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction4);
+ _endType = kFightEndLost;
+ }
+ }
+
+ update(fighter);
+}
+
+bool Fight::canInteractMilos(Fighter const *fighter, FightAction action) {
+ if (!_data)
+ error("Fight::canInteractMilos - invalid data!");
+
+ if (action != kFightAction128
+ || _data->player->sequenceIndex != 1
+ || !fighter->frame
+ || CHECK_SEQUENCE2(fighter, 4)
+ || fighter->opponent->sequenceIndex != 1) {
+ return canInteract(fighter);
+ }
+
+ _engine->getCursor()->setStyle(kCursorHand);
+
+ return true;
+}
+
+void Fight::handleOpponentActionMilos(Fighter *fighter, FightAction action) {
+ if (action == kFightAction4) {
+ setSequenceAndDraw(fighter, 5, kFightSequenceType1);
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ } else {
+ if (action != kFightAction131)
+ handleAction(fighter, action);
+ }
+}
+
+void Fight::updateOpponentMilos(Fighter *fighter) {
+ // This is an opponent struct!
+ Opponent *opponent = (Opponent *)fighter;
+
+ if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
+
+ if (opponent->opponent->field_34 >= 2) {
+ switch (rnd(5)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType1);
+ break;
+
+ case 3:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 1, kFightSequenceType2);
+ break;
+ }
+ } else {
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ }
+
+ // Update field_38
+ if (opponent->opponent->field_34 < 5)
+ opponent->field_38 = 6 * (5 - opponent->opponent->field_34);
+ else
+ opponent->field_38 = 0;
+ }
+
+ if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
+ if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2)
+ CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
+
+ if (opponent->opponent->countdown <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ CALL_FUNCTION1(opponent, handleAction, kFightActionLost);
+ }
+ }
+
+ updateOpponent(opponent);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Anna
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::loadAnnaPlayer() {
+ if (!_data)
+ error("Fight::loadAnnaPlayer - invalid data!");
+
+ // Special case: we are using some shared functions directly
+ _data->player->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleActionAnna);
+ _data->player->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::update);
+ _data->player->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract);
+
+ _data->player->sequences.push_back(loadSequence("2002cr.seq"));
+ _data->player->sequences.push_back(loadSequence("2002cdl.seq"));
+ _data->player->sequences.push_back(loadSequence("2002cdr.seq"));
+ _data->player->sequences.push_back(loadSequence("2002cdm.seq"));
+ _data->player->sequences.push_back(loadSequence("2002lbk.seq"));
+}
+
+void Fight::loadAnnaOpponent() {
+ if (!_data)
+ error("Fight::loadAnnaOpponent - invalid data!");
+
+ // Special case: we are using some shared functions directly
+ _data->opponent->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleAction);
+ _data->opponent->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::updateOpponentAnna);
+ _data->opponent->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract);
+
+ _data->opponent->sequences.push_back(loadSequence("2002or.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2002oal.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2002oam.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2002oar.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2002okr.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2002okml.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2002okm.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS030", SoundManager::kFlagDefault);
+
+ _data->opponent->field_38 = 30;
+}
+
+void Fight::handleActionAnna(Fighter *fighter, FightAction action) {
+ switch (action) {
+ default:
+ handleAction(fighter, action);
+ return;
+
+ case kFightAction1:
+ if ((fighter->sequenceIndex != 1 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) {
+ setSequenceAndDraw(fighter, 4, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1);
+
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ } else {
+ fighter->field_34++;
+ }
+ break;
+
+ case kFightAction2:
+ if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) {
+ setSequenceAndDraw(fighter, 4, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1);
+
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ } else {
+ fighter->field_34++;
+ }
+ break;
+
+ case kFightAction3:
+ if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 1) || CHECK_SEQUENCE2(fighter, 4)) {
+ setSequenceAndDraw(fighter, 4, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1);
+
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ } else {
+ fighter->field_34++;
+ }
+ break;
+
+ case kFightAction128:
+ switch (fighter->opponent->sequenceIndex) {
+ default:
+ setSequenceAndDraw(fighter, 3, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(fighter, 1, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(fighter, 3, kFightSequenceType0);
+ break;
+
+ case 3:
+ setSequenceAndDraw(fighter, 2, kFightSequenceType0);
+ break;
+ }
+ break;
+ }
+
+ if (fighter->field_34 > 4) {
+ getSound()->removeFromQueue(kEntityTables0);
+ bailout(kFightEndWin);
+ }
+}
+
+void Fight::updateOpponentAnna(Fighter *fighter) {
+ // This is an opponent struct!
+ Opponent *opponent = (Opponent *)fighter;
+
+ if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
+
+ if (opponent->opponent->field_34 >= 2) {
+ switch (rnd(6)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(opponent, 3, kFightSequenceType0);
+ break;
+
+ case 3:
+ setSequenceAndDraw(opponent, 3, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ break;
+
+ case 5:
+ setSequenceAndDraw(opponent, 3, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ break;
+ }
+ }
+
+ // Update field_38
+ opponent->field_38 = (int32)rnd(15);
+ }
+
+ if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
+ if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 3)
+ CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
+
+ if (opponent->opponent->countdown <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ CALL_FUNCTION1(opponent, handleAction, kFightActionLost);
+ }
+ }
+
+ updateOpponent(opponent);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Ivo
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::loadIvoPlayer() {
+ REGISTER_PLAYER_FUNCTIONS(Ivo)
+
+ _data->player->sequences.push_back(loadSequence("2003cr.seq"));
+ _data->player->sequences.push_back(loadSequence("2003car.seq"));
+ _data->player->sequences.push_back(loadSequence("2003cal.seq"));
+ _data->player->sequences.push_back(loadSequence("2003cdr.seq"));
+ _data->player->sequences.push_back(loadSequence("2003cdm.seq"));
+ _data->player->sequences.push_back(loadSequence("2003chr.seq"));
+ _data->player->sequences.push_back(loadSequence("2003chl.seq"));
+ _data->player->sequences.push_back(loadSequence("2003ckr.seq"));
+ _data->player->sequences.push_back(loadSequence("2003lbk.seq"));
+ _data->player->sequences.push_back(loadSequence("2003fbk.seq"));
+
+ _data->player->countdown = 5;
+}
+
+void Fight::loadIvoOpponent() {
+ REGISTER_OPPONENT_FUNCTIONS(Ivo)
+
+ _data->opponent->sequences.push_back(loadSequence("2003or.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2003oal.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2003oar.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2003odm.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2003okl.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2003okj.seq"));
+ _data->opponent->sequences.push_back(loadSequence("blank.seq"));
+ _data->opponent->sequences.push_back(loadSequence("csdr.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2003l.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS032", SoundManager::kFlagDefault);
+
+ _data->opponent->countdown = 5;
+ _data->opponent->field_38 = 15;
+}
+
+void Fight::handleActionIvo(Fighter *fighter, FightAction action) {
+ switch (action) {
+ default:
+ handleAction(fighter, action);
+ return;
+
+ case kFightAction1:
+ if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) {
+ setSequenceAndDraw(fighter, 7, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1);
+
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ }
+ break;
+
+ case kFightAction2:
+ if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) {
+ setSequenceAndDraw(fighter, 7, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1);
+
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ }
+ break;
+
+ case kFightAction128:
+ switch (fighter->opponent->sequenceIndex) {
+ default:
+ case 1:
+ setSequenceAndDraw(fighter, 1, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(fighter, 2, kFightSequenceType0);
+ break;
+ }
+ break;
+
+ case kFightAction129:
+ setSequenceAndDraw(fighter, (fighter->opponent->countdown > 1) ? 4 : 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0);
+ break;
+
+ case kFightAction130:
+ setSequenceAndDraw(fighter, 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0);
+ break;
+ }
+}
+
+void Fight::updateIvo(Fighter *fighter) {
+
+ if ((fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4) && !fighter->frameIndex)
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction131);
+
+ if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) {
+
+ // Draw sequences
+ if (fighter->opponent->countdown <= 0) {
+ setSequenceAndDraw(fighter, 9, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, 8, kFightSequenceType1);
+ getSound()->removeFromQueue(kEntityTables0);
+
+ CALL_FUNCTION1(fighter, handleAction, kFightActionWin);
+ return;
+ }
+
+ if (fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4)
+ CALL_FUNCTION1(fighter->opponent, handleAction, (FightAction)fighter->sequenceIndex);
+ }
+
+ update(fighter);
+}
+
+bool Fight::canInteractIvo(Fighter const *fighter, FightAction action) {
+ if (action == kFightAction129 || action == kFightAction130)
+ return (fighter->sequenceIndex >= 8);
+
+ return canInteract(fighter);
+}
+
+void Fight::handleOpponentActionIvo(Fighter *fighter, FightAction action) {
+ // This is an opponent struct!
+ Opponent *opponent = (Opponent *)fighter;
+
+ switch (action) {
+ default:
+ handleAction(fighter, action);
+ break;
+
+ case kFightAction3:
+ if ((opponent->sequenceIndex != 1 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) {
+ setSequenceAndDraw(opponent, 6, kFightSequenceType1);
+ setSequenceAndDraw(opponent->opponent, 6, kFightSequenceType1);
+ CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103);
+ }
+ break;
+
+ case kFightAction4:
+ if ((opponent->sequenceIndex != 2 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) {
+ setSequenceAndDraw(opponent, 6, kFightSequenceType1);
+ setSequenceAndDraw(opponent->opponent, 5, kFightSequenceType1);
+ CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103);
+ }
+ break;
+
+ case kFightAction131:
+ if (opponent->sequenceIndex)
+ break;
+
+ if (rnd(100) <= (unsigned int)(opponent->countdown > 2 ? 60 : 75)) {
+ setSequenceAndDraw(opponent, 3 , kFightSequenceType1);
+ if (opponent->opponent->sequenceIndex == 4)
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ }
+ break;
+ }
+}
+
+void Fight::updateOpponentIvo(Fighter *fighter) {
+ // This is an opponent struct!
+ Opponent *opponent = (Opponent *)fighter;
+
+ if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
+
+ if (opponent->opponent->field_34 >= 2) {
+ switch (rnd(5)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ break;
+
+ case 3:
+ setSequenceAndDraw(opponent, 0, kFightSequenceType2);
+ setSequenceAndDraw(opponent, 1, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(opponent, 0, kFightSequenceType1);
+ setSequenceAndDraw(opponent, 1, kFightSequenceType2);
+ break;
+ }
+ }
+
+ // Update field_38
+ opponent->field_38 = 3 * opponent->countdown + (int32)rnd(10);
+ }
+
+ if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
+
+ if (opponent->opponent->countdown <= 0) {
+ setSequenceAndDraw(opponent, 7, kFightSequenceType1);
+ setSequenceAndDraw(opponent->opponent, 8, kFightSequenceType1);
+ getSound()->removeFromQueue(kEntityTables0);
+
+ CALL_FUNCTION1(opponent->opponent, handleAction, kFightActionWin);
+
+ return;
+ }
+
+ if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2)
+ CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
+ }
+
+ updateOpponent(opponent);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Salko
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::loadSalkoPlayer() {
+ REGISTER_PLAYER_FUNCTIONS(Salko)
+
+ _data->player->sequences.push_back(loadSequence("2004cr.seq"));
+ _data->player->sequences.push_back(loadSequence("2004cdr.seq"));
+ _data->player->sequences.push_back(loadSequence("2004chj.seq"));
+ _data->player->sequences.push_back(loadSequence("2004bk.seq"));
+
+ _data->player->countdown = 2;
+}
+
+void Fight::loadSalkoOpponent() {
+ REGISTER_OPPONENT_FUNCTIONS(Salko)
+
+ _data->opponent->sequences.push_back(loadSequence("2004or.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2004oam.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2004oar.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2004okr.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2004ohm.seq"));
+ _data->opponent->sequences.push_back(loadSequence("blank.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS035", SoundManager::kFlagDefault);
+
+ _data->opponent->countdown = 3;
+ _data->opponent->field_38 = 30;
+}
+
+void Fight::handleActionSalko(Fighter *fighter, FightAction action) {
+ switch (action) {
+ default:
+ handleAction(fighter, action);
+ return;
+
+ case kFightAction1:
+ case kFightAction2:
+ if (fighter->sequenceIndex != 1 && CHECK_SEQUENCE2(fighter, 4)) {
+ fighter->field_34 = 0;
+
+ setSequenceAndDraw(fighter, 3, kFightSequenceType1);
+ setSequenceAndDraw(fighter->opponent, (action == kFightAction1 ? 3 : 4), kFightSequenceType1);
+
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+
+ if (action == kFightAction2)
+ fighter->countdown= 0;
+
+ CALL_FUNCTION0(fighter, update);
+ } else {
+ fighter->field_34++;
+ }
+ break;
+
+ case kFightAction5:
+ if (fighter->sequenceIndex != 3) {
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ }
+ break;
+
+ case kFightAction128:
+ setSequenceAndDraw(fighter, 1, kFightSequenceType0);
+ fighter->field_34 = 0;
+ break;
+
+ case kFightAction131:
+ setSequenceAndDraw(fighter, 2, (fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0));
+ break;
+ }
+}
+
+void Fight::updateSalko(Fighter *fighter) {
+ update(fighter);
+
+ // The original doesn't check for currentSequence2 != NULL (might not happen when everything is working properly, but crashes with our current implementation)
+ if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) {
+
+ if (fighter->opponent->countdown <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ bailout(kFightEndWin);
+
+ return;
+ }
+
+ if (fighter->sequenceIndex == 2)
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction2);
+ }
+}
+
+bool Fight::canInteractSalko(Fighter const *fighter, FightAction action) {
+ if (action == kFightAction131) {
+ if (fighter->sequenceIndex == 1) {
+ if (fighter->opponent->countdown <= 0)
+ _engine->getCursor()->setStyle(kCursorHand);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ return canInteract(fighter);
+}
+
+void Fight::handleOpponentActionSalko(Fighter *fighter, FightAction action) {
+ if (action == kFightAction2) {
+ setSequenceAndDraw(fighter, 5, kFightSequenceType1);
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ } else {
+ handleAction(fighter, action);
+ }
+}
+
+void Fight::updateOpponentSalko(Fighter *fighter) {
+ // This is an opponent struct
+ Opponent *opponent = (Opponent *)fighter;
+
+ if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
+
+ switch (rnd(5)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ break;
+
+ case 2:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ break;
+
+ case 3:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 1, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 1, kFightSequenceType2);
+ break;
+ }
+
+ // Update field_38
+ opponent->field_38 = 4 * opponent->countdown;
+ }
+
+ if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
+ if (opponent->opponent->countdown <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ bailout(kFightEndLost);
+
+ // Stop processing
+ return;
+ }
+
+ if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2)
+ CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
+ }
+
+ updateOpponent(opponent);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Vesna
+//////////////////////////////////////////////////////////////////////////
+
+void Fight::loadVesnaPlayer() {
+ REGISTER_PLAYER_FUNCTIONS(Vesna)
+
+ _data->player->sequences.push_back(loadSequence("2005cr.seq"));
+ _data->player->sequences.push_back(loadSequence("2005cdr.seq"));
+ _data->player->sequences.push_back(loadSequence("2005cbr.seq"));
+ _data->player->sequences.push_back(loadSequence("2005bk.seq"));
+ _data->player->sequences.push_back(loadSequence("2005cdm1.seq"));
+ _data->player->sequences.push_back(loadSequence("2005chl.seq"));
+}
+
+void Fight::loadVesnaOpponent() {
+ REGISTER_OPPONENT_FUNCTIONS(Vesna)
+
+ _data->opponent->sequences.push_back(loadSequence("2005or.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2005oam.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2005oar.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2005okml.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2005okr.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2005odm1.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2005csbm.seq"));
+ _data->opponent->sequences.push_back(loadSequence("2005oam4.seq"));
+
+ getSound()->playSound(kEntityTables0, "MUS038", SoundManager::kFlagDefault);
+
+ _data->opponent->countdown = 4;
+ _data->opponent->field_38 = 30;
+}
+
+void Fight::handleActionVesna(Fighter *fighter, FightAction action) {
+ switch (action) {
+ default:
+ handleAction(fighter, action);
+ return;
+
+ case kFightAction1:
+ if (fighter->sequenceIndex != 1) {
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ } else {
+ fighter->field_34++;
+ }
+ break;
+
+ case kFightAction2:
+ if (fighter->sequenceIndex != 2) {
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ } else {
+ fighter->field_34++;
+ }
+ break;
+
+ case kFightAction5:
+ if (fighter->sequenceIndex != 3) {
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ CALL_FUNCTION0(fighter, update);
+ }
+ break;
+
+ case kFightAction128:
+ if (fighter->sequenceIndex == 1 && fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) {
+ setSequenceAndDraw(fighter, 5, kFightSequenceType1);
+ } else {
+ setSequenceAndDraw(fighter, (fighter->opponent->sequenceIndex == 5) ? 3 : 1, kFightSequenceType0);
+ }
+ break;
+
+ case kFightAction132:
+ setSequenceAndDraw(fighter, 2, kFightSequenceType0);
+ break;
+ }
+
+ if (fighter->field_34 > 10) {
+ setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType2);
+ fighter->opponent->countdown = 1;
+ fighter->field_34 = 0;
+ }
+}
+
+void Fight::updateVesna(Fighter *fighter) {
+ if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) {
+
+ if (fighter->sequenceIndex == 3)
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction3);
+
+ if (fighter->opponent->countdown <= 0) {
+ getSound()->removeFromQueue(kEntityTables0);
+ bailout(kFightEndWin);
+ return;
+ }
+
+ if (fighter->sequenceIndex == 5)
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction5);
+ }
+
+ update(fighter);
+}
+
+bool Fight::canInteractVesna(Fighter const *fighter, FightAction action) {
+ if (action != kFightAction128)
+ return canInteract(fighter);
+
+ if (fighter->sequenceIndex != 1) {
+
+ if (fighter->opponent->sequenceIndex == 5) {
+ _engine->getCursor()->setStyle(kCursorDown);
+ return true;
+ }
+
+ return canInteract(fighter);
+ }
+
+ if (fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) {
+ _engine->getCursor()->setStyle(kCursorPunchLeft);
+ return true;
+ }
+
+ return false;
+}
+
+void Fight::handleOpponentActionVesna(Fighter *fighter, FightAction action) {
+ switch (action) {
+ default:
+ handleAction(fighter, action);
+ break;
+
+ case kFightAction3:
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ break;
+
+ case kFightAction5:
+ setSequenceAndDraw(fighter, 7, kFightSequenceType1);
+ CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103);
+ if (fighter->countdown <= 1)
+ fighter->countdown = 1;
+ break;
+
+ case kFightAction131:
+ break;
+ }
+}
+
+void Fight::updateOpponentVesna(Fighter *fighter) {
+ // This is an opponent struct
+ Opponent *opponent = (Opponent *)fighter;
+
+ if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) {
+
+ if (opponent->opponent->field_34 == 1) {
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ } else {
+ switch (rnd(6)) {
+ default:
+ break;
+
+ case 0:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ break;
+
+ case 1:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 1, kFightSequenceType2);
+ break;
+
+ case 2:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ break;
+
+ case 3:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ break;
+
+ case 4:
+ setSequenceAndDraw(opponent, 1, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 2, kFightSequenceType2);
+ break;
+
+ case 5:
+ setSequenceAndDraw(opponent, 2, kFightSequenceType0);
+ setSequenceAndDraw(opponent, 1, kFightSequenceType2);
+ break;
+ }
+ }
+
+ // Update field_38
+ opponent->field_38 = 4 * opponent->countdown;
+ }
+
+ if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) {
+ if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 5)
+ CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex);
+
+ if (opponent->opponent->countdown <= 0) {
+
+ switch (opponent->sequenceIndex) {
+ default:
+ break;
+
+ case 1:
+ setSequenceAndDraw(opponent, 3, kFightSequenceType1);
+ break;
+
+ case 2:
+ setSequenceAndDraw(opponent, 4, kFightSequenceType1);
+ break;
+
+ case 5:
+ setSequenceAndDraw(opponent, 6, kFightSequenceType1);
+ break;
+ }
+
+ setSequenceAndDraw(opponent->opponent, 4, kFightSequenceType1);
+
+ CALL_FUNCTION1(opponent, handleAction, kFightActionLost);
+ CALL_FUNCTION0(opponent->opponent, update);
+ CALL_FUNCTION0(opponent, update);
+
+ getSound()->removeFromQueue(kEntityTables0);
+
+ // Stop processing
+ return;
+ }
+ }
+
+ updateOpponent(opponent);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/fight.h b/engines/lastexpress/game/fight.h
new file mode 100644
index 0000000000..4484017184
--- /dev/null
+++ b/engines/lastexpress/game/fight.h
@@ -0,0 +1,269 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_FIGHT_H
+#define LASTEXPRESS_FIGHT_H
+
+/*
+ Fight structure
+ ---------------
+ uint32 {4} - player struct
+ uint32 {4} - opponent struct
+ uint32 {4} - hasLost flag
+
+ byte {1} - isRunning
+
+ Fight participant structure
+ ---------------------------
+ uint32 {4} - function pointer
+ uint32 {4} - pointer to fight structure
+ uint32 {4} - pointer to opponent (fight participant structure)
+ uint32 {4} - array of sequences
+ uint32 {4} - number of sequences
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint16 {2} - ??
+ uint16 {2} - ?? - only for opponent structure
+ uint32 {4} - ?? - only for opponent structure
+
+*/
+
+#include "lastexpress/shared.h"
+
+#include "lastexpress/eventhandler.h"
+
+#include "common/array.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+class Sequence;
+class SequenceFrame;
+
+//////////////////////////////////////////////////////////////////////////
+// TODO : objectify!
+class Fight : public EventHandler {
+public:
+ enum FightEndType {
+ kFightEndWin = 0,
+ kFightEndLost = 1,
+ kFightEndExit = 2
+ };
+
+ Fight(LastExpressEngine *engine);
+ ~Fight();
+
+ FightEndType setup(FightType type);
+
+ void eventMouse(const Common::Event &ev);
+ void eventTick(const Common::Event &ev);
+
+ void setStopped();
+ void resetState() { _state = 0; }
+
+private:
+ enum FightSequenceType {
+ kFightSequenceType0 = 0,
+ kFightSequenceType1 = 1,
+ kFightSequenceType2 = 2
+ };
+
+ enum FightAction {
+ kFightAction1 = 1,
+ kFightAction2 = 2,
+ kFightAction3 = 3,
+ kFightAction4 = 4,
+ kFightAction5 = 5,
+ kFightAction101 = 101,
+ kFightActionResetFrame = 102,
+ kFightAction103 = 103,
+ kFightActionWin = 104,
+ kFightActionLost = 105,
+ kFightAction128 = 128,
+ kFightAction129 = 129,
+ kFightAction130 = 130,
+ kFightAction131 = 131,
+ kFightAction132 = 132
+ };
+
+ struct Fighter {
+ Common::Functor2<Fighter *, FightAction, void> *handleAction;
+ Common::Functor1<Fighter *, void> *update;
+ Common::Functor2<Fighter const *, FightAction, bool> *canInteract;
+ Fighter *opponent;
+ Common::Array<Sequence *> sequences;
+ uint32 sequenceIndex;
+ Sequence *sequence;
+ SequenceFrame *frame;
+ uint32 frameIndex;
+ uint32 field_24;
+ FightAction action;
+ uint32 sequenceIndex2;
+ int32 countdown; // countdown before loosing ?
+ uint32 field_34;
+
+ Fighter() {
+ handleAction = NULL;
+ update = NULL;
+ canInteract = NULL;
+
+ opponent = NULL;
+
+ sequenceIndex = 0;
+ sequence = NULL;
+ frame = NULL;
+ frameIndex = 0;
+
+ field_24 = 0;
+
+ action = kFightAction101;
+ sequenceIndex2 = 0;
+
+ countdown = 1;
+
+ field_34 = 0;
+ }
+ };
+
+ // Opponent struct
+ struct Opponent : Fighter {
+ int32 field_38;
+
+ Opponent() : Fighter() {
+ field_38 = 0;
+ }
+ };
+
+ struct FightData {
+ Fighter *player;
+ Opponent *opponent;
+ int32 index;
+
+ Sequence *sequences[20];
+ Common::String names[20];
+
+ bool isRunning;
+
+ FightData() {
+ player = new Fighter();
+ opponent = new Opponent();
+
+ // Set opponents
+ player->opponent = opponent;
+ opponent->opponent = player;
+
+ index = 0;
+
+ isRunning = false;
+ }
+ };
+
+ LastExpressEngine *_engine;
+ FightData *_data;
+ FightEndType _endType;
+ int _state;
+
+ bool _handleTimer;
+
+ // Events
+ void handleTick(const Common::Event &ev, bool unknown);
+
+ // State
+ void bailout(FightEndType type);
+
+
+ // Drawing
+ void setSequenceAndDraw(Fighter *fighter, uint32 sequenceIndex, FightSequenceType type) const;
+ void draw(Fighter *fighter) const;
+
+ // Cleanup
+ void clearData();
+ void clearSequences(Fighter *fighter) const;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Loading
+ void loadData(FightType type);
+
+ // Shared
+ void processFighter(Fighter *fighter);
+
+ // Default functions
+ void handleAction(Fighter *fighter, FightAction action);
+ void update(Fighter *fighter);
+ bool canInteract(Fighter const *fighter, FightAction = (FightAction)0);
+ void updateOpponent(Fighter *fighter);
+
+ // Milos
+ void loadMilosPlayer();
+ void loadMilosOpponent();
+ void handleActionMilos(Fighter *fighter, FightAction action);
+ void updateMilos(Fighter *fighter);
+ bool canInteractMilos(Fighter const *fighter, FightAction action);
+ void handleOpponentActionMilos(Fighter *fighter, FightAction action);
+ void updateOpponentMilos(Fighter *fighter);
+
+ // Anna
+ void loadAnnaPlayer();
+ void loadAnnaOpponent();
+ void handleActionAnna(Fighter *fighter, FightAction action);
+ void updateOpponentAnna(Fighter *fighter);
+
+ // Ivo
+ void loadIvoPlayer();
+ void loadIvoOpponent();
+ void handleActionIvo(Fighter *fighter, FightAction action);
+ void updateIvo(Fighter *fighter);
+ bool canInteractIvo(Fighter const *fighter, FightAction action);
+ void handleOpponentActionIvo(Fighter *fighter, FightAction action);
+ void updateOpponentIvo(Fighter *fighter);
+
+ // Salko
+ void loadSalkoPlayer();
+ void loadSalkoOpponent();
+ void handleActionSalko(Fighter *fighter, FightAction action);
+ void updateSalko(Fighter *fighter);
+ bool canInteractSalko(Fighter const *fighter, FightAction action);
+ void handleOpponentActionSalko(Fighter *fighter, FightAction action);
+ void updateOpponentSalko(Fighter *fighter);
+
+ // Vesna
+ void loadVesnaPlayer();
+ void loadVesnaOpponent();
+ void handleActionVesna(Fighter *fighter, FightAction action);
+ void updateVesna(Fighter *fighter);
+ bool canInteractVesna(Fighter const *fighter, FightAction action);
+ void handleOpponentActionVesna(Fighter *fighter, FightAction action);
+ void updateOpponentVesna(Fighter *fighter);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_FIGHT_H
diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp
new file mode 100644
index 0000000000..ae9aca56b6
--- /dev/null
+++ b/engines/lastexpress/game/inventory.cpp
@@ -0,0 +1,599 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/inventory.h"
+
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/scene.h"
+#include "lastexpress/data/snd.h"
+
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/menu.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+
+#define drawItem(x, y, index, brightness) { Icon icon((CursorStyle)(index)); icon.setPosition(x, y); icon.setBrightness(brightness); _engine->getGraphicsManager()->draw(&icon, GraphicsManager::kBackgroundInventory); }
+
+namespace LastExpress {
+
+Inventory::Inventory(LastExpressEngine *engine) : _engine(engine), _selectedItem(kItemNone), _highlightedItem(kItemNone), _opened(false), _visible(false),
+ _showingHourGlass(false), _blinkingEgg(false), _blinkingTime(0), _blinkingInterval(_defaultBlinkingInterval), _blinkingBrightness(100),
+ _flagUseMagnifier(false), _flag1(false), _flag2(false), _flagEggHightlighted(false), _itemScene(NULL) {
+
+ _inventoryRect = Common::Rect(0, 0, 32, 32);
+ _menuRect = Common::Rect(608, 448, 640, 480);
+ _selectedRect = Common::Rect(44, 0, 76, 32);
+
+ init();
+}
+
+Inventory::~Inventory() {
+ _itemScene = NULL;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Inventory handling
+//////////////////////////////////////////////////////////////////////////
+
+// Initialize inventory contents
+void Inventory::init() {
+ // ID
+ _entries[kItemMatchBox].cursor = kCursorMatchBox;
+ _entries[kItemTelegram].cursor = kCursorTelegram;
+ _entries[kItemPassengerList].cursor = kCursorPassengerList;
+ _entries[kItemArticle].cursor = kCursorArticle;
+ _entries[kItemScarf].cursor = kCursorScarf;
+ _entries[kItemPaper].cursor = kCursorPaper;
+ _entries[kItemParchemin].cursor = kCursorParchemin;
+ _entries[kItemMatch].cursor = kCursorMatch;
+ _entries[kItemWhistle].cursor = kCursorWhistle;
+ _entries[kItemKey].cursor = kCursorKey;
+ _entries[kItemBomb].cursor = kCursorBomb;
+ _entries[kItemFirebird].cursor = kCursorFirebird;
+ _entries[kItemBriefcase].cursor = kCursorBriefcase;
+ _entries[kItemCorpse].cursor = kCursorCorpse;
+
+ // Selectable
+ _entries[kItemMatchBox].isSelectable = true;
+ _entries[kItemMatch].isSelectable = true;
+ _entries[kItemTelegram].isSelectable = true;
+ _entries[kItemWhistle].isSelectable = true;
+ _entries[kItemKey].isSelectable = true;
+ _entries[kItemFirebird].isSelectable = true;
+ _entries[kItemBriefcase].isSelectable = true;
+ _entries[kItemCorpse].isSelectable = true;
+ _entries[kItemPassengerList].isSelectable = true;
+
+ // Auto selection
+ _entries[kItem2].manualSelect = false;
+ _entries[kItem3].manualSelect = false;
+ _entries[kItem5].manualSelect = false;
+ _entries[kItem7].manualSelect = false;
+ _entries[kItem9].manualSelect = false;
+ _entries[kItem11].manualSelect = false;
+ _entries[kItemBeetle].manualSelect = false;
+ _entries[kItem17].manualSelect = false;
+ _entries[kItemFirebird].manualSelect = false;
+ _entries[kItemBriefcase].manualSelect = false;
+ _entries[kItemCorpse].manualSelect = false;
+ _entries[kItemGreenJacket].manualSelect = false;
+ _entries[kItem22].manualSelect = false;
+
+ // Scene
+ _entries[kItemMatchBox].scene = kSceneMatchbox;
+ _entries[kItemTelegram].scene = kSceneTelegram;
+ _entries[kItemPassengerList].scene = kScenePassengerList;
+ _entries[kItemScarf].scene = kSceneScarf;
+ _entries[kItemParchemin].scene = kSceneParchemin;
+ _entries[kItemArticle].scene = kSceneArticle;
+ _entries[kItemPaper].scene = kScenePaper;
+ _entries[kItemFirebird].scene = kSceneFirebird;
+ _entries[kItemBriefcase].scene = kSceneBriefcase;
+
+ // Has item
+ _entries[kItemTelegram].isPresent = true;
+ _entries[kItemArticle].isPresent = true;
+
+ _selectedItem = kItemNone;
+}
+
+// FIXME we need to draw cursors with full background opacity so that whatever is in the background is erased
+// this saved us clearing some part of the background when switching between states
+
+// TODO if we draw inventory objects on screen, we need to load a new scene.
+// Signal that the inventory has taken over the screen and stop processing mouse events after we have been called
+bool Inventory::handleMouseEvent(const Common::Event &ev) {
+
+ // Do not show inventory when on the menu screen
+ if (getMenu()->isShown() || !_visible)
+ return false;
+
+ // Flag to know whether to restore the current cursor or not
+ bool insideInventory = false;
+
+ // Egg (menu)
+ if (_menuRect.contains(ev.mouse)) {
+ insideInventory = true;
+ _engine->getCursor()->setStyle(kCursorNormal);
+
+ // If clicked, show the menu
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ getSound()->playSound(kEntityPlayer, "LIB039");
+ getMenu()->show(false, kSavegameTypeIndex, 0);
+
+ // TODO can we return directly or do we need to make sure the state will be "valid" when we come back from the menu
+ return true;
+ } else {
+ // Highlight if needed
+ if (_highlightedItem != getMenu()->getGameId() + 39) {
+ _highlightedItem = (InventoryItem)(getMenu()->getGameId() + 39);
+ drawItem(608, 448, _highlightedItem, 100)
+
+ askForRedraw();
+ }
+ }
+ } else {
+ // remove highlight if needed
+ if (_highlightedItem == getMenu()->getGameId() + 39) {
+ drawItem(608, 448, _highlightedItem, 50)
+ _highlightedItem = kItemNone;
+ askForRedraw();
+ }
+ }
+
+ // Portrait (inventory)
+ if (_inventoryRect.contains(ev.mouse)) {
+ insideInventory = true;
+ _engine->getCursor()->setStyle(kCursorNormal);
+
+ // If clicked, show pressed state and display inventory
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ open();
+ } else {
+ // Highlight if needed
+ if (_highlightedItem != (InventoryItem)getProgress().portrait && !_opened) {
+ _highlightedItem = (InventoryItem)getProgress().portrait;
+ drawItem(0, 0, getProgress().portrait, 100)
+
+ askForRedraw();
+ }
+ }
+ } else {
+ // remove highlight if needed
+ if (_highlightedItem == (InventoryItem)getProgress().portrait && !_opened) {
+ drawItem(0, 0, getProgress().portrait, 50)
+ _highlightedItem = kItemNone;
+ askForRedraw();
+ }
+ }
+
+ // If the inventory is open, check all items rect to see if we need to highlight one / handle click
+ if (_opened) {
+
+ // Always show normal cursor when the inventory is opened
+ insideInventory = true;
+ _engine->getCursor()->setStyle(kCursorNormal);
+
+ bool selected = false;
+
+ // Iterate over items
+ int16 y = 44;
+ for (int i = 1; i < 32; i++) {
+ if (!hasItem((InventoryItem)i))
+ continue;
+
+ if (Common::Rect(0, y, 32, 32 + y).contains(ev.mouse)) {
+
+ // If released with an item highlighted, show this item
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ if (_entries[i].isSelectable) {
+ selected = true;
+ _selectedItem = (InventoryItem)i;
+ drawItem(44, 0, get(_selectedItem)->cursor, 100)
+ }
+
+ examine((InventoryItem)i);
+ break;
+ } else {
+ if (_highlightedItem != i) {
+ drawItem(0, y, _entries[i].cursor, 100)
+ _highlightedItem = (InventoryItem)i;
+ askForRedraw();
+ }
+ }
+ } else {
+ // Remove highlight if necessary
+ if (_highlightedItem == i) {
+ drawItem(0, y, _entries[i].cursor, 50)
+ _highlightedItem = kItemNone;
+ askForRedraw();
+ }
+ }
+
+ y += 40;
+ }
+
+ // Right button is released: we need to close the inventory
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+
+ // Not on a selectable item: unselect the current item
+ if (!selected)
+ unselectItem();
+
+ close();
+ }
+ }
+
+ // Selected item
+ if (_selectedItem != kItemNone && _selectedRect.contains(ev.mouse)) {
+ insideInventory = true;
+
+ // Show magnifier icon
+ _engine->getCursor()->setStyle(kCursorMagnifier);
+
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ examine((InventoryItem)_selectedItem);
+ }
+ }
+
+ // If the egg is blinking, refresh
+ if (_blinkingEgg)
+ drawEgg();
+
+ // Restore cursor
+ //if (!insideInventory)
+ // _engine->getCursor()->setStyle(getLogic()->getCursorStyle());
+
+ return insideInventory;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// UI
+//////////////////////////////////////////////////////////////////////////
+void Inventory::show() {
+ clearBg(GraphicsManager::kBackgroundInventory);
+ askForRedraw();
+
+ // Show portrait (first draw, cannot be highlighted)
+ drawItem(0, 0, getProgress().portrait, 50)
+
+ // Show selected item
+ if (_selectedItem != kItemNone)
+ drawItem(44, 0, _selectedItem, 100)
+
+ drawEgg();
+}
+
+void Inventory::setPortrait(InventoryItem item) const {
+ getProgress().portrait = item;
+ drawItem(0, 0, getProgress().portrait, 50);
+}
+
+void Inventory::blinkEgg(bool enabled) {
+ _blinkingEgg = enabled;
+
+ // Reset state
+ _showingHourGlass = false;
+
+ // Show egg at full brightness for first step if blinking
+ if (_blinkingEgg)
+ drawItem(608, 448, getMenu()->getGameId() + 39, _blinkingBrightness)
+ else {
+ // Reset values
+ _blinkingBrightness = 100;
+ _blinkingInterval = _defaultBlinkingInterval;
+ drawItem(608, 448, getMenu()->getGameId() + 39, 50) // normal egg state
+ }
+
+ askForRedraw();
+}
+
+void Inventory::showHourGlass() const{
+ if (!getFlags()->flag_5) {
+ drawItem(608, 448, kCursorHourGlass, 100);
+ }
+
+ askForRedraw();
+
+ getFlags()->shouldDrawEggOrHourGlass = true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Items
+//////////////////////////////////////////////////////////////////////////
+Inventory::InventoryEntry *Inventory::get(InventoryItem item) {
+ if (item >= kPortraitOriginal)
+ error("Inventory::getEntry: Invalid inventory item!");
+
+ return &_entries[item];
+}
+
+void Inventory::addItem(InventoryItem item) {
+ if (item >= kPortraitOriginal)
+ return;
+
+ get(item)->isPresent = true;
+ get(item)->location = kObjectLocationNone;
+
+ // Auto-select item if necessary
+ if (get(item)->cursor && !get(item)->manualSelect) {
+ _selectedItem = (InventoryItem)get(item)->cursor;
+ drawItem(44, 0, _selectedItem, 100)
+ askForRedraw();
+ }
+}
+
+void Inventory::removeItem(InventoryItem item, ObjectLocation newLocation) {
+ if (item >= kPortraitOriginal)
+ return;
+
+ get(item)->isPresent = false;
+ get(item)->location = newLocation;
+
+ if (get(item)->cursor == (CursorStyle)_selectedItem) {
+ _selectedItem = kItemNone;
+ _engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(44, 0, 44 + 32, 32));
+ askForRedraw();
+ }
+}
+
+bool Inventory::hasItem(InventoryItem item) {
+ if (get(item)->isPresent && item < kPortraitOriginal)
+ return true;
+
+ return false;
+}
+
+void Inventory::selectItem(InventoryItem item) {
+ _selectedItem = item;
+
+ drawItem(44, 0, get(_selectedItem)->cursor, 100)
+ askForRedraw();
+}
+
+void Inventory::unselectItem() {
+ _selectedItem = kItemNone;
+
+ _engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(44, 0, 44 + 32, 32));
+ askForRedraw();
+}
+
+void Inventory::setLocationAndProcess(InventoryItem item, ObjectLocation location) {
+ if (item >= kPortraitOriginal)
+ return;
+
+ if (get(item)->location == location)
+ return;
+
+ get(item)->location = location;
+
+ if (isItemSceneParameter(item) && !getFlags()->flag_0)
+ getScenes()->processScene();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Serializable
+//////////////////////////////////////////////////////////////////////////
+void Inventory::saveLoadWithSerializer(Common::Serializer &s) {
+ for (uint i = 0; i < ARRAYSIZE(_entries); i++)
+ _entries[i].saveLoadWithSerializer(s);
+}
+
+void Inventory::saveSelectedItem(Common::Serializer &s) {
+ s.syncAsUint32LE(_selectedItem);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// toString
+//////////////////////////////////////////////////////////////////////////
+Common::String Inventory::toString() {
+ Common::String ret = "";
+
+ for (int i = 0; i < kPortraitOriginal; i++)
+ ret += Common::String::format("%d : %s\n", i, _entries[i].toString().c_str());
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Private methods
+//////////////////////////////////////////////////////////////////////////
+InventoryItem Inventory::getFirstExaminableItem() const {
+
+ int index = 0;
+ InventoryEntry entry = _entries[index];
+ while (!entry.isPresent || !entry.cursor || entry.manualSelect) {
+ index++;
+ entry = _entries[index];
+
+ if (index >= kPortraitOriginal)
+ return kItemNone;
+ }
+
+ return (InventoryItem)index;
+}
+
+bool Inventory::isItemSceneParameter(InventoryItem item) const {
+ Scene *scene = getScenes()->get(getState()->scene);
+
+ switch(scene->type) {
+ default:
+ return false;
+
+ case Scene::kTypeItem:
+ if (scene->param1 == item)
+ return true;
+ break;
+
+ case Scene::kTypeItem2:
+ if (scene->param1 == item || scene->param2 == item)
+ return true;
+ break;
+
+ case Scene::kTypeObjectItem:
+ if (scene->param2 == item)
+ return true;
+ break;
+
+ case Scene::kTypeItem3:
+ if (scene->param1 == item || scene->param2 == item || scene->param3 == item)
+ return true;
+ break;
+
+ case Scene::kTypeCompartmentsItem:
+ if (scene->param2 == item)
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+// Examine an inventory item
+void Inventory::examine(InventoryItem item) {
+ SceneIndex index = get(item)->scene;
+ if (!index)
+ return;
+
+ /*if (!getState()->sceneUseBackup ||
+ (getState()->sceneBackup2 && getFirstExaminableItem() == _selectedItem))
+ flag = 1;*/
+
+ if (!getState()->sceneUseBackup) {
+ getState()->sceneBackup = getState()->scene;
+ getState()->sceneUseBackup = true;
+
+ getScenes()->loadScene(index);
+ } else {
+
+ if (!getState()->sceneBackup2)
+ return;
+
+ if (getFirstExaminableItem() == _selectedItem) {
+ index = getState()->sceneBackup2;
+ getState()->sceneBackup2 = kSceneNone;
+ getScenes()->loadScene(index);
+ }
+ }
+}
+
+// FIXME: see different callers and adjust
+// - draw with different brightness if mousing over
+void Inventory::drawEgg() const {
+ if (!getFlags()->flag_5)
+ drawItem(608, 448, getMenu()->getGameId() + 39, 50)
+
+ getFlags()->shouldDrawEggOrHourGlass = false;
+}
+
+// Blinking egg: we need to blink the egg for delta time, with the blinking getting faster until it's always lit.
+void Inventory::drawBlinkingEgg() {
+
+ warning("Inventory::drawEgg - blinking not implemented!");
+
+ //// TODO show egg (with or without mouseover)
+
+ //// Play timer sound
+ //if (getGlobalTimer() < 90) {
+ // if (getGlobalTimer() + ticks >= 90)
+ // getSound()->playSoundWithSubtitles("TIMER.SND", 50331664, kEntityPlayer);
+
+ // if (getSound()->isBuffered("TIMER"))
+ // setGlobalTimer(0);
+ //}
+
+ //// Restore egg to standard brightness
+ //if (!getGlobalTimer()) {
+ //
+ //}
+
+
+ //drawItem(608, 448, getMenu()->getGameId() + 39, _blinkingBrightness)
+
+ //// TODO if delta time > _blinkingInterval, update egg & ask for redraw then adjust blinking time and remaining time
+ //
+
+ //// Reset values and stop blinking
+ //if (_blinkingTime == 0)
+ // blinkEgg(false);
+
+ askForRedraw();
+}
+
+// Close inventory: clear items and reset icon
+void Inventory::open() {
+ _opened = true;
+
+ // Show selected state
+ drawItem(0, 0, getProgress().portrait + 1, 100)
+
+ int16 y = 44;
+
+ // Iterate over items
+ for (uint i = 1; i < 32; i++) {
+ if (_entries[i].isPresent) {
+ drawItem(0, y, _entries[i].cursor, 50)
+ y += 40;
+ }
+ }
+
+ askForRedraw();
+}
+
+// Close inventory: clear items and reset icon
+void Inventory::close() {
+ _opened = false;
+
+ // Fallback to unselected state
+ drawItem(0, 0, getProgress().portrait, 100)
+
+ // Erase rectangle for all inventory items
+ int count = 0;
+ for (uint i = 1; i < 32; i++) {
+ if (_entries[i].isPresent) {
+ count++;
+ }
+ }
+
+ _engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(0, 44, 32, (int16)(44 + 44 * count)));
+
+ askForRedraw();
+}
+
+Common::Rect Inventory::getItemRect(int16 index) const{
+ return Common::Rect(0, (int16)((32 + 12) * (index + 1)), 32, (int16)((32 + 12) * (index + 2))); // space between items = 12px
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/inventory.h b/engines/lastexpress/game/inventory.h
new file mode 100644
index 0000000000..bae6c8d261
--- /dev/null
+++ b/engines/lastexpress/game/inventory.h
@@ -0,0 +1,180 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_INVENTORY_H
+#define LASTEXPRESS_INVENTORY_H
+
+/*
+ Inventory entry (32 entries)
+ ----------------------------
+
+ byte {1} - Item ID (set to 0 for "undefined" items)
+ byte {1} - Scene ID
+ byte {1} - ??
+ byte {1} - Selectable (1 if item is selectable, 0 otherwise)
+ byte {1} - Is item in inventory (set to 1 for telegram and article)
+ byte {1} - Auto selection (1 for no auto selection, 0 otherwise)
+ byte {1} - Location
+
+*/
+
+#include "lastexpress/shared.h"
+
+#include "lastexpress/eventhandler.h"
+
+#include "common/events.h"
+#include "common/serializer.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+class Scene;
+
+class Inventory : Common::Serializable, public EventHandler {
+public:
+
+ // Entry
+ struct InventoryEntry : Common::Serializable {
+ CursorStyle cursor;
+ SceneIndex scene;
+ byte field_2;
+ bool isSelectable;
+ bool isPresent;
+ bool manualSelect;
+ ObjectLocation location;
+
+ InventoryEntry() {
+ cursor = kCursorNormal;
+ scene = kSceneNone;
+ field_2 = 0;
+ isSelectable = false;
+ isPresent = false;
+ manualSelect = true;
+ location = kObjectLocationNone;
+ }
+
+ Common::String toString() {
+ return Common::String::format("{ %d - %d - %d - %d - %d - %d - %d }", cursor, scene, field_2, isSelectable, isPresent, manualSelect, location);
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsByte(cursor);
+ s.syncAsByte(scene);
+ s.syncAsByte(field_2);
+ s.syncAsByte(isSelectable);
+ s.syncAsByte(isPresent);
+ s.syncAsByte(manualSelect);
+ s.syncAsByte(location);
+ }
+ };
+
+ Inventory(LastExpressEngine *engine);
+ ~Inventory();
+
+ // Inventory contents
+ void addItem(InventoryItem item);
+ void removeItem(InventoryItem item, ObjectLocation newLocation = kObjectLocationNone);
+ bool hasItem(InventoryItem item);
+ void selectItem(InventoryItem item);
+ void unselectItem();
+ InventoryItem getSelectedItem() { return _selectedItem; }
+
+ InventoryEntry *get(InventoryItem item);
+ InventoryEntry *getSelectedEntry() { return get(_selectedItem); }
+
+ InventoryItem getFirstExaminableItem() const;
+ void setLocationAndProcess(InventoryItem item, ObjectLocation location);
+
+ // UI Control
+ void show();
+ void blinkEgg(bool enabled);
+ void showHourGlass() const;
+ void setPortrait(InventoryItem item) const;
+ void drawEgg() const;
+ void drawBlinkingEgg();
+
+ // Handle inventory UI events.
+ bool handleMouseEvent(const Common::Event &ev);
+
+ // State
+ bool isMagnifierInUse() { return _flagUseMagnifier; }
+ bool isFlag1() { return _flag1; }
+ bool isFlag2() { return _flag2; }
+ bool isEggHighlighted() { return _flagEggHightlighted; }
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &s);
+ void saveSelectedItem(Common::Serializer &s);
+
+ /**
+ * Convert this object into a string representation.
+ *
+ * @return A string representation of this object.
+ */
+ Common::String toString();
+
+private:
+ static const uint32 _defaultBlinkingInterval = 250; ///< Default blinking interval in ms
+
+ LastExpressEngine *_engine;
+
+ InventoryEntry _entries[32];
+ InventoryItem _selectedItem;
+ InventoryItem _highlightedItem;
+ bool _opened;
+ bool _visible;
+
+ bool _showingHourGlass;
+ bool _blinkingEgg;
+ uint32 _blinkingTime;
+ uint32 _blinkingInterval;
+ uint32 _blinkingBrightness;
+
+ // Flags
+ bool _flagUseMagnifier;
+ bool _flag1;
+ bool _flag2;
+ bool _flagEggHightlighted;
+
+ Scene *_itemScene;
+
+ // Important rects
+ Common::Rect _inventoryRect;
+ Common::Rect _menuRect;
+ Common::Rect _selectedRect;
+
+ void init();
+
+ void open();
+ void close();
+ void examine(InventoryItem item);
+ Common::Rect getItemRect(int16 index) const;
+
+ bool isItemSceneParameter(InventoryItem item) const;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_INVENTORY_H
diff --git a/engines/lastexpress/game/logic.cpp b/engines/lastexpress/game/logic.cpp
new file mode 100644
index 0000000000..3ef710a324
--- /dev/null
+++ b/engines/lastexpress/game/logic.cpp
@@ -0,0 +1,593 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/logic.h"
+
+// Data
+#include "lastexpress/data/animation.h"
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/snd.h"
+
+// Entities
+#include "lastexpress/entities/chapters.h"
+
+// Game
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/beetle.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/fight.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/menu.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savegame.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+#define EVENT_TICKS_BEETWEEN_SAVEGAMES 450
+#define GAME_TICKS_BEETWEEN_SAVEGAMES 2700
+
+Logic::Logic(LastExpressEngine *engine) : _engine(engine) {
+ _action = new Action(engine);
+ _beetle = new Beetle(engine);
+ _entities = new Entities(engine);
+ _fight = new Fight(engine);
+ _saveload = new SaveLoad(engine);
+ _state = new State(engine);
+
+ // Flags
+ _flagActionPerformed = false;
+ _ignoreFrameInterval = false;
+ _ticksSinceLastSavegame = EVENT_TICKS_BEETWEEN_SAVEGAMES;
+}
+
+Logic::~Logic() {
+ delete _action;
+ delete _beetle;
+ delete _fight;
+ delete _entities;
+ delete _saveload;
+ delete _state;
+
+ // Zero-out passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Event Handling
+//////////////////////////////////////////////////////////////////////////
+#define REDRAW_CURSOR() { \
+ if (getInventory()->isMagnifierInUse()) \
+ _engine->getCursor()->setStyle(kCursorMagnifier); \
+ if (getInventory()->isFlag1() \
+ || getInventory()->isFlag2() \
+ || getInventory()->isEggHighlighted()) \
+ _engine->getCursor()->setStyle(kCursorNormal); \
+ return; \
+}
+
+void Logic::eventMouse(const Common::Event &ev) {
+ bool hotspotHandled = false;
+
+ // Reset mouse flags
+ getFlags()->mouseLeftClick = false;
+ getFlags()->mouseRightClick = false;
+
+ // Process event flags
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+
+ if (getFlags()->frameInterval)
+ _ignoreFrameInterval = false;
+
+ getFlags()->frameInterval = false;
+ }
+
+ if (getFlags()->flag_0) {
+ if (ev.type == Common::EVENT_LBUTTONUP || ev.type == Common::EVENT_RBUTTONUP) {
+ getFlags()->flag_0 = false;
+ getFlags()->shouldRedraw = true;
+ updateCursor(true);
+ getFlags()->frameInterval = true;
+ }
+ return;
+ }
+
+ if (_ignoreFrameInterval && getScenes()->checkCurrentPosition(true) && _engine->getCursor()->getStyle() == kCursorForward) {
+ getFlags()->shouldRedraw = false;
+ getFlags()->flag_0 = true;
+ return;
+ }
+
+ // Update coordinates
+ getGameState()->setCoordinates(ev.mouse);
+
+ // Handle inventory
+ getInventory()->handleMouseEvent(ev);
+
+ // Stop processing is inside the menu
+ if (getMenu()->isShown())
+ return;
+
+ // Handle whistle case
+ if (getInventory()->getSelectedItem() == kItemWhistle
+ && !getProgress().isEggOpen
+ && !getEntities()->isPlayerPosition(kCarGreenSleeping, 59)
+ && !getEntities()->isPlayerPosition(kCarGreenSleeping, 76)
+ && !getInventory()->isFlag1()
+ && !getInventory()->isFlag2()
+ && !getInventory()->isEggHighlighted()
+ && !getInventory()->isMagnifierInUse()) {
+
+ // Update cursor
+ _engine->getCursor()->setStyle(getInventory()->get(kItemWhistle)->cursor);
+
+ // Check if clicked
+ if (ev.type == Common::EVENT_LBUTTONUP && !getSound()->isBuffered("LIB045")) {
+
+ getSound()->playSoundEvent(kEntityPlayer, 45);
+
+ if (getEntities()->isPlayerPosition(kCarGreenSleeping, 26) || getEntities()->isPlayerPosition(kCarGreenSleeping, 25) || getEntities()->isPlayerPosition(kCarGreenSleeping, 23)) {
+ getSavePoints()->push(kEntityPlayer, kEntityMertens, kAction226078300);
+ } else if (getEntities()->isPlayerPosition(kCarRedSleeping, 26) || getEntities()->isPlayerPosition(kCarRedSleeping, 25) || getEntities()->isPlayerPosition(kCarRedSleeping, 23)) {
+ getSavePoints()->push(kEntityPlayer, kEntityCoudert, kAction226078300);
+ }
+
+ if (!getState()->sceneUseBackup)
+ getInventory()->unselectItem();
+ }
+
+ REDRAW_CURSOR()
+ }
+
+ // Handle match case
+ if (getInventory()->getSelectedItem() == kItemMatch
+ && (getEntities()->isPlayerInCar(kCarGreenSleeping) || getEntities()->isPlayerInCar(kCarRedSleeping))
+ && getProgress().jacket == kJacketGreen
+ && !getInventory()->isFlag1()
+ && !getInventory()->isFlag2()
+ && !getInventory()->isEggHighlighted()
+ && !getInventory()->isMagnifierInUse()
+ && (getInventory()->get(kItem2)->location == kObjectLocationNone || getEntityData(kEntityPlayer)->car != kCarRedSleeping || getEntityData(kEntityPlayer)->entityPosition != kPosition_2300)) {
+
+ // Update cursor
+ _engine->getCursor()->setStyle(getInventory()->get(kItemMatch)->cursor);
+
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+
+ getAction()->playAnimation(isNight() ? kEventCathSmokeNight : kEventCathSmokeDay);
+
+ if (!getState()->sceneUseBackup)
+ getInventory()->unselectItem();
+
+ getScenes()->processScene();
+ }
+
+ REDRAW_CURSOR()
+ }
+
+ // Handle entity item case
+ EntityIndex entityIndex = getEntities()->canInteractWith(ev.mouse);
+ if (entityIndex
+ && !getInventory()->isFlag1()
+ && !getInventory()->isFlag2()
+ && !getInventory()->isEggHighlighted()
+ && !getInventory()->isMagnifierInUse()) {
+
+ InventoryItem item = getEntityData(entityIndex)->inventoryItem;
+ if (getInventory()->hasItem((InventoryItem)(item & kItemToggleHigh))) {
+ hotspotHandled = true;
+
+ _engine->getCursor()->setStyle(getInventory()->get((InventoryItem)(item & kItemToggleHigh))->cursor);
+
+ if (ev.type == Common::EVENT_LBUTTONUP)
+ getSavePoints()->push(kEntityPlayer, entityIndex, kAction1, (InventoryItem)(item & kItemToggleHigh));
+ } else if ((InventoryItem)(item & kItemInvalid)) {
+ hotspotHandled = true;
+
+ _engine->getCursor()->setStyle(kCursorTalk2);
+
+ if (ev.type == Common::EVENT_LBUTTONUP)
+ getSavePoints()->push(kEntityPlayer, entityIndex, kAction1, kCursorNormal);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Handle standard actions
+ if (hotspotHandled || getInventory()->isFlag1() || getInventory()->isFlag2() || getInventory()->isEggHighlighted())
+ return;
+
+ // Magnifier in use
+ if (getInventory()->isMagnifierInUse()) {
+ _engine->getCursor()->setStyle(kCursorMagnifier);
+
+ if (getInventory()->isFlag1()
+ || getInventory()->isFlag2()
+ || getInventory()->isEggHighlighted())
+ _engine->getCursor()->setStyle(kCursorNormal);
+
+ return;
+ }
+
+ // Check hotspots
+ int location = 0;
+ SceneHotspot *hotspot = NULL;
+ Scene *scene = getScenes()->get(getState()->scene);
+
+ for (Common::Array<SceneHotspot *>::iterator it = scene->getHotspots()->begin(); it != scene->getHotspots()->end(); ++it) {
+ if (!(*it)->isInside(ev.mouse))
+ continue;
+
+ if ((*it)->location < location)
+ continue;
+
+ if (!getAction()->getCursor(**it))
+ continue;
+
+ Scene *hotspotScene = getScenes()->get((*it)->scene);
+
+ if (!getEntities()->getPosition(hotspotScene->car, hotspotScene->position)
+ || (*it)->cursor == kCursorTurnRight
+ || (*it)->cursor == kCursorTurnLeft) {
+ location = (*it)->location;
+ hotspot = *it;
+ }
+ }
+
+ // No hotspot found: show the normal cursor
+ if (!hotspot) {
+ _engine->getCursor()->setStyle(kCursorNormal);
+ return;
+ }
+
+ // Found an hotspot: update the cursor and perform the action if the user clicked the mouse
+ _engine->getCursor()->setStyle(getAction()->getCursor(*hotspot));
+
+ if (ev.type != Common::EVENT_LBUTTONUP || _flagActionPerformed)
+ return;
+
+ _flagActionPerformed = true;
+
+ SceneIndex processedScene = getAction()->processHotspot(*hotspot);
+ SceneIndex testScene = (processedScene == kSceneInvalid) ? hotspot->scene : processedScene;
+
+ if (testScene) {
+ getFlags()->shouldRedraw = false;
+
+ getScenes()->setScene(testScene);
+
+ if (getFlags()->shouldDrawEggOrHourGlass)
+ getInventory()->drawEgg();
+
+ getFlags()->shouldRedraw = true;
+ updateCursor(true);
+ }
+
+ // Switch to next chapter if necessary
+ if (hotspot->action == SceneHotspot::kActionSwitchChapter && hotspot->param1 == getState()->progress.chapter)
+ switchChapter();
+}
+
+void Logic::eventTick(const Common::Event &) {
+ uint ticks = 1;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Adjust ticks if an action has been performed
+ if (_flagActionPerformed)
+ ticks = 10;
+
+ _flagActionPerformed = false;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Draw the blinking egg if needed
+ if (getGlobalTimer() && !getFlags()->shouldDrawEggOrHourGlass)
+ getInventory()->drawBlinkingEgg();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Adjust time and save game if needed
+ if (getFlags()->isGameRunning) {
+ getState()->timeTicks += ticks;
+ getState()->time = (TimeValue)(getState()->time + (TimeValue)(ticks * getState()->timeDelta));
+
+ if (getState()->timeDelta) {
+
+ // Auto-save
+ if (!_ticksSinceLastSavegame) {
+ _ticksSinceLastSavegame = EVENT_TICKS_BEETWEEN_SAVEGAMES;
+ getSaveLoad()->saveGame(kSavegameTypeAuto, kEntityChapters, kEventNone);
+ }
+
+ // Save after game ticks interval
+ if ((getState()->timeTicks - getSaveLoad()->getLastSavegameTicks()) > GAME_TICKS_BEETWEEN_SAVEGAMES)
+ getSaveLoad()->saveGame(kSavegameTypeTickInterval, kEntityChapters, kEventNone);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Load scene and process hotspot
+ if (getFlags()->flag_0 && !getFlags()->mouseLeftClick && !getFlags()->mouseRightClick) {
+ Scene *scene = getScenes()->get(getState()->scene);
+
+ if (getScenes()->checkCurrentPosition(true)
+ && !getEntities()->getPosition(scene->car, scene->position)) {
+
+ // Process hotspot
+ SceneHotspot *hotspot = scene->getHotspot();
+ SceneIndex processedScene = getAction()->processHotspot(*hotspot);
+ SceneIndex testScene = (processedScene == kSceneInvalid) ? hotspot->scene : processedScene;
+
+ if (testScene) {
+ getScenes()->setScene(testScene);
+ } else {
+ getFlags()->flag_0 = false;
+ getFlags()->shouldRedraw = true;
+ updateCursor(true);
+ }
+
+ if (getFlags()->isGameRunning)
+ getSavePoints()->callAndProcess();
+
+ } else {
+ getFlags()->flag_0 = false;
+ getFlags()->shouldRedraw = true;
+ updateCursor(true);
+ }
+
+ return;
+ }
+
+ // Stop processing if the game is paused
+ if (!getFlags()->isGameRunning)
+ return;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Update beetle, savepoints, entities and draw frames
+ if (_beetle->isLoaded())
+ _beetle->update();
+
+ getSavePoints()->callAndProcess();
+ getEntities()->updateCallbacks();
+ getScenes()->drawFrames(true);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Update cursor if we can interact with an entity
+ EntityIndex entity = getEntities()->canInteractWith(getCoords());
+ if (!entity) {
+ if (_engine->getCursor()->getStyle() >= kCursorTalk2)
+ updateCursor(false);
+
+ return;
+ }
+
+ // Show item cursor on entity
+ if (getInventory()->hasItem((InventoryItem)(getEntityData(entity)->inventoryItem & kItemToggleHigh)) && (int)getEntityData(entity)->inventoryItem != (int)kCursorTalk2) {
+ _engine->getCursor()->setStyle(getInventory()->get((InventoryItem)(getEntityData(entity)->inventoryItem & kItemToggleHigh))->cursor);
+ return;
+ }
+
+ getLogic()->updateCursor(false);
+ _engine->getCursor()->setStyle(kCursorTalk2);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Game over, Chapters & credits
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Resets the game state.
+ */
+void Logic::resetState() {
+ getState()->scene = kSceneDefault;
+
+ warning("Logic::resetState: not implemented! You need to restart the engine until this is implemented.");
+}
+
+/**
+ * Handle game over
+ *
+ * @param type The savegame type.
+ * @param value The value (event, time, index, ...)
+ * @param sceneIndex Index of the scene to show.
+ * @param showScene true to show a scene, false to return to menu directly
+ */
+void Logic::gameOver(SavegameType type, uint32 value, SceneIndex sceneIndex, bool showScene) const {
+
+ getSound()->processEntries();
+ getEntities()->reset();
+ getFlags()->isGameRunning = false;
+ getSavePoints()->reset();
+ getFlags()->flag_entities_0 = true;
+
+ if (showScene) {
+
+ getSound()->processEntry(SoundManager::kSoundType11);
+
+ if (sceneIndex && !getFlags()->mouseRightClick) {
+ getScenes()->loadScene(sceneIndex);
+
+ while (getSound()->isBuffered(kEntityTables4)) {
+ if (getFlags()->mouseRightClick)
+ break;
+
+ getSound()->updateQueue();
+ }
+ }
+ }
+
+ // Show Menu
+ getMenu()->show(false, type, value);
+}
+
+void Logic::switchChapter() const {
+ getSound()->clearStatus();
+
+ switch(getState()->progress.chapter) {
+ default:
+ break;
+
+ case kChapter1:
+ getInventory()->addItem(kItemParchemin);
+ getInventory()->addItem(kItemMatchBox);
+
+ RESET_ENTITY_STATE(kEntityChapters, Chapters, setup_chapter2);
+ break;
+
+ case kChapter2:
+ getInventory()->addItem(kItemScarf);
+
+ RESET_ENTITY_STATE(kEntityChapters, Chapters, setup_chapter3);
+ break;
+
+ case kChapter3:
+ getInventory()->get(kItemFirebird)->location = kObjectLocation4;
+ getInventory()->get(kItemFirebird)->isPresent = false;
+ getInventory()->get(kItem11)->location = kObjectLocation1;
+ getInventory()->addItem(kItemWhistle);
+ getInventory()->addItem(kItemKey);
+
+ RESET_ENTITY_STATE(kEntityChapters, Chapters, setup_chapter4);
+ break;
+
+ case kChapter4:
+ RESET_ENTITY_STATE(kEntityChapters, Chapters, setup_chapter5);
+ break;
+
+ case kChapter5:
+ playFinalSequence();
+ break;
+ }
+}
+
+void Logic::playFinalSequence() const {
+ getSound()->processEntries();
+
+ _action->playAnimation(kEventFinalSequence);
+ showCredits();
+
+ getEntities()->reset();
+ getSavePoints()->reset();
+ getFlags()->flag_entities_0 = true;
+
+ getMenu()->show(false, kSavegameTypeIndex, 0);
+}
+
+void Logic::showCredits() const {
+ error("Logic::showCredits: not implemented!");
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Misc
+//////////////////////////////////////////////////////////////////////////
+void Logic::updateCursor(bool) const { /* the cursor is always updated, even when we don't want to redraw it */
+ CursorStyle style = kCursorNormal;
+ bool interact = false;
+
+ if (getInventory()->getSelectedItem() != kItemWhistle
+ || getProgress().isEggOpen
+ || getEntities()->isPlayerPosition(kCarGreenSleeping, 59)
+ || getEntities()->isPlayerPosition(kCarGreenSleeping, 76)
+ || getInventory()->isFlag1()
+ || getInventory()->isFlag2()
+ || getInventory()->isEggHighlighted()
+ || getInventory()->isMagnifierInUse()) {
+
+ if (getInventory()->getSelectedItem() != kItemMatch
+ || (!getEntities()->isPlayerInCar(kCarGreenSleeping) && !getEntities()->isPlayerInCar(kCarRedSleeping))
+ || getProgress().jacket != kJacketGreen
+ || getInventory()->isFlag1()
+ || getInventory()->isFlag2()
+ || getInventory()->isEggHighlighted()
+ || getInventory()->isMagnifierInUse()
+ || (getInventory()->get(kItem2)->location
+ && getEntityData(kEntityPlayer)->car == kCarRedSleeping
+ && getEntityData(kEntityPlayer)->entityPosition == kPosition_2300)) {
+
+ EntityIndex entity = getEntities()->canInteractWith(getCoords());
+ if (entity
+ && !getInventory()->isFlag1()
+ && !getInventory()->isFlag2()
+ && !getInventory()->isEggHighlighted()
+ && !getInventory()->isMagnifierInUse()) {
+ if (getInventory()->hasItem((InventoryItem)(getEntityData(entity)->inventoryItem & kItemToggleHigh))) {
+ interact = true;
+ style = getInventory()->get((InventoryItem)(getEntityData(entity)->inventoryItem & kItemToggleHigh))->cursor;
+ } else if ((int)getEntityData(entity)->inventoryItem == kItemInvalid) {
+ interact = true;
+ style = kCursorTalk2;
+ }
+ }
+
+ if (!interact
+ && !getInventory()->isFlag1()
+ && !getInventory()->isFlag2()
+ && !getInventory()->isEggHighlighted()
+ && !getInventory()->isMagnifierInUse()) {
+ int location = 0;
+ SceneHotspot *hotspot = NULL;
+ Scene *scene = getScenes()->get(getState()->scene);
+
+ // Check all hotspots
+ for (Common::Array<SceneHotspot *>::iterator i = scene->getHotspots()->begin(); i != scene->getHotspots()->end(); ++i) {
+ if ((*i)->isInside(getCoords()) && (*i)->location >= location) {
+ if (getAction()->getCursor(**i)) {
+ Scene *hotspotScene = getScenes()->get((*i)->scene);
+
+ if (!getEntities()->getPosition(hotspotScene->car, hotspotScene->position)
+ || (*i)->cursor == kCursorTurnRight
+ || (*i)->cursor == kCursorTurnLeft) {
+ hotspot = *i;
+ location = (*i)->location;
+ }
+ }
+ }
+ }
+
+ style = (hotspot) ? getAction()->getCursor(*hotspot) : kCursorNormal;
+ }
+ } else {
+ style = getInventory()->get(kItemMatch)->cursor;
+ }
+
+ } else {
+ style = getInventory()->get(kItemWhistle)->cursor;
+ }
+
+ if (getInventory()->isMagnifierInUse())
+ style = kCursorMagnifier;
+
+ if (getInventory()->isFlag1() || getInventory()->isFlag2() || getInventory()->isEggHighlighted())
+ style = kCursorNormal;
+
+ _engine->getCursor()->setStyle(style);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/logic.h b/engines/lastexpress/game/logic.h
new file mode 100644
index 0000000000..fc867d7680
--- /dev/null
+++ b/engines/lastexpress/game/logic.h
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_LOGIC_H
+#define LASTEXPRESS_LOGIC_H
+
+#include "lastexpress/shared.h"
+
+#include "lastexpress/game/entities.h"
+
+#include "lastexpress/eventhandler.h"
+
+#include "common/events.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Action;
+class Beetle;
+class Debugger;
+class Entities;
+class Fight;
+class SaveLoad;
+class State;
+
+class Logic : public EventHandler {
+public:
+ Logic(LastExpressEngine *engine);
+ ~Logic();
+
+ void eventMouse(const Common::Event &ev);
+ void eventTick(const Common::Event &ev);
+
+ void resetState();
+ void gameOver(SavegameType type, uint32 value, SceneIndex sceneIndex, bool showScene) const;
+ void playFinalSequence() const;
+ void updateCursor(bool redraw = true) const;
+
+ Action *getGameAction() { return _action; }
+ Beetle *getGameBeetle() { return _beetle; }
+ Entities *getGameEntities() { return _entities; }
+ Fight *getGameFight() { return _fight; }
+ SaveLoad *getGameSaveLoad() { return _saveload; }
+ State *getGameState() { return _state; }
+
+private:
+ LastExpressEngine *_engine;
+
+ Action *_action; ///< Actions
+ Beetle *_beetle; ///< Beetle catching
+ Entities *_entities; ///< Entities
+ Fight *_fight; ///< Fight handling
+ SaveLoad *_saveload; ///< Save & loading
+ State *_state; ///< Game state
+
+ void switchChapter() const;
+ void showCredits() const;
+
+ // Flags & Members
+ bool _flagActionPerformed;
+ bool _ignoreFrameInterval;
+ int _ticksSinceLastSavegame;
+
+ friend class Debugger;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_LOGIC_H
diff --git a/engines/lastexpress/game/menu.cpp b/engines/lastexpress/game/menu.cpp
new file mode 100644
index 0000000000..f6840c28a7
--- /dev/null
+++ b/engines/lastexpress/game/menu.cpp
@@ -0,0 +1,1538 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/menu.h"
+
+// Data
+#include "lastexpress/data/animation.h"
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/snd.h"
+#include "lastexpress/data/scene.h"
+
+#include "lastexpress/game/fight.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/savegame.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+#include "common/rational.h"
+
+#define getNextGameId() (GameId)((_gameId + 1) % 6)
+
+namespace LastExpress {
+
+// Bottom-left buttons (quit.seq)
+enum StartMenuButtons {
+ kButtonVolumeDownPushed,
+ kButtonVolumeDown,
+ kButtonVolume,
+ kButtonVolumeUp,
+ kButtonVolumeUpPushed,
+ kButtonBrightnessDownPushed, // 5
+ kButtonBrightnessDown,
+ kButtonBrightness,
+ kButtonBrightnessUp,
+ kButtonBrightnessUpPushed,
+ kButtonQuit, // 10
+ kButtonQuitPushed
+};
+
+// Egg buttons (buttns.seq)
+enum StartMenuEggButtons {
+ kButtonShield,
+ kButtonRewind,
+ kButtonRewindPushed,
+ kButtonForward,
+ kButtonForwardPushed,
+ kButtonCredits, // 5
+ kButtonCreditsPushed,
+ kButtonContinue
+};
+
+// Tooltips sequence (helpnewr.seq)
+enum StartMenuTooltips {
+ kTooltipInsertCd1,
+ kTooltipInsertCd2,
+ kTooltipInsertCd3,
+ kTooltipContinueGame,
+ kTooltipReplayGame,
+ kTooltipContinueRewoundGame, // 5
+ kTooltipViewGameEnding,
+ kTooltipStartAnotherGame,
+ kTooltipVolumeUp,
+ kTooltipVolumeDown,
+ kTooltipBrightnessUp, // 10
+ kTooltipBrightnessDown,
+ kTooltipQuit,
+ kTooltipRewindParis,
+ kTooltipForwardStrasbourg,
+ kTooltipRewindStrasbourg, // 15
+ kTooltipRewindMunich,
+ kTooltipForwardMunich,
+ kTooltipForwardVienna,
+ kTooltipRewindVienna,
+ kTooltipRewindBudapest, // 20
+ kTooltipForwardBudapest,
+ kTooltipForwardBelgrade,
+ kTooltipRewindBelgrade,
+ kTooltipForwardConstantinople,
+ kTooltipSwitchBlueGame, // 25
+ kTooltipSwitchRedGame,
+ kTooltipSwitchGoldGame,
+ kTooltipSwitchGreenGame,
+ kTooltipSwitchTealGame,
+ kTooltipSwitchPurpleGame, // 30
+ kTooltipPlayNewGame,
+ kTooltipCredits,
+ kTooltipFastForward,
+ kTooltipRewind
+};
+
+//////////////////////////////////////////////////////////////////////////
+// DATA
+//////////////////////////////////////////////////////////////////////////
+
+// Information about the cities on the train line
+static const struct {
+ uint8 frame;
+ TimeValue time;
+} _trainCities[31] = {
+ {0, kTimeCityParis},
+ {9, kTimeCityEpernay},
+ {11, kTimeCityChalons},
+ {16, kTimeCityBarLeDuc},
+ {21, kTimeCityNancy},
+ {25, kTimeCityLuneville},
+ {35, kTimeCityAvricourt},
+ {37, kTimeCityDeutschAvricourt},
+ {40, kTimeCityStrasbourg},
+ {53, kTimeCityBadenOos},
+ {56, kTimeCityKarlsruhe},
+ {60, kTimeCityStuttgart},
+ {63, kTimeCityGeislingen},
+ {66, kTimeCityUlm},
+ {68, kTimeCityAugsburg},
+ {73, kTimeCityMunich},
+ {84, kTimeCitySalzbourg},
+ {89, kTimeCityAttnangPuchheim},
+ {97, kTimeCityWels},
+ {100, kTimeCityLinz},
+ {104, kTimeCityAmstetten},
+ {111, kTimeCityVienna},
+ {120, kTimeCityPoszony},
+ {124, kTimeCityGalanta},
+ {132, kTimeCityBudapest},
+ {148, kTimeCityBelgrade},
+ /* Line 1 ends at 150 - line 2 begins at 0 */
+ {157, kTimeCityNish},
+ {165, kTimeCityTzaribrod},
+ {174, kTimeCitySofia},
+ {198, kTimeCityAdrianople},
+ {210, kTimeCityConstantinople}};
+
+static const struct {
+ TimeValue time;
+ uint index;
+ StartMenuTooltips rewind;
+ StartMenuTooltips forward;
+} _cityButtonsInfo[7] = {
+ {kTimeCityParis, 64, kTooltipRewindParis, kTooltipRewindParis},
+ {kTimeCityStrasbourg, 128, kTooltipRewindStrasbourg, kTooltipForwardStrasbourg},
+ {kTimeCityMunich, 129, kTooltipRewindMunich, kTooltipForwardMunich},
+ {kTimeCityVienna, 130, kTooltipRewindVienna, kTooltipForwardVienna},
+ {kTimeCityBudapest, 131, kTooltipRewindBudapest, kTooltipForwardBudapest},
+ {kTimeCityBelgrade, 132, kTooltipRewindBelgrade, kTooltipForwardBelgrade},
+ {kTimeCityConstantinople, 192, kTooltipForwardConstantinople, kTooltipForwardConstantinople}
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Clock
+//////////////////////////////////////////////////////////////////////////
+class Clock {
+public:
+ Clock(LastExpressEngine *engine);
+ ~Clock();
+
+ void draw(uint32 time);
+ void clear();
+
+private:
+ LastExpressEngine *_engine;
+
+ // Frames
+ SequenceFrame *_frameMinutes;
+ SequenceFrame *_frameHour;
+ SequenceFrame *_frameSun;
+ SequenceFrame *_frameDate;
+};
+
+Clock::Clock(LastExpressEngine *engine) : _engine(engine), _frameMinutes(NULL), _frameHour(NULL), _frameSun(NULL), _frameDate(NULL) {
+ _frameMinutes = new SequenceFrame(loadSequence("eggmin.seq"), 0, true);
+ _frameHour = new SequenceFrame(loadSequence("egghour.seq"), 0, true);
+ _frameSun = new SequenceFrame(loadSequence("sun.seq"), 0, true);
+ _frameDate = new SequenceFrame(loadSequence("datenew.seq"), 0, true);
+}
+
+Clock::~Clock() {
+ delete _frameMinutes;
+ delete _frameHour;
+ delete _frameSun;
+ delete _frameDate;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+void Clock::clear() {
+ getScenes()->removeFromQueue(_frameMinutes);
+ getScenes()->removeFromQueue(_frameHour);
+ getScenes()->removeFromQueue(_frameSun);
+ getScenes()->removeFromQueue(_frameDate);
+}
+
+void Clock::draw(uint32 time) {
+ assert(time >= kTimeCityParis && time <= kTimeCityConstantinople);
+
+ // Check that sequences have been loaded
+ if (!_frameMinutes || !_frameHour || !_frameSun || !_frameDate)
+ error("Clock::process: clock sequences have not been loaded correctly!");
+
+ // Clear existing frames
+ clear();
+
+ // Game starts at: 1037700 = 7:13 p.m. on July 24, 1914
+ // Game ends at: 4941000 = 7:30 p.m. on July 26, 1914
+ // Game lasts for: 3903300 = 2 days + 17 mins = 2897 mins
+
+ // 15 = 1 second
+ // 15 * 60 = 900 = 1 minute
+ // 900 * 60 = 54000 = 1 hour
+ // 54000 * 24 = 1296000 = 1 day
+
+ // Calculate each sequence index from the current time
+
+ uint8 hour = 0;
+ uint8 minute = 0;
+ State::getHourMinutes(time, &hour, &minute);
+ uint32 index_date = 18 * time / 1296000;
+ if (hour == 23)
+ index_date += 18 * minute / 60;
+
+ // Set sequences frames
+ _frameMinutes->setFrame(minute);
+ _frameHour->setFrame((5 * hour + minute / 12) % 60);
+ _frameSun->setFrame((5 * hour + minute / 12) % 120);
+ _frameDate->setFrame((uint16)index_date);
+
+ // Adjust z-order and queue
+ _frameMinutes->getInfo()->location = 1;
+ _frameHour->getInfo()->location = 1;
+ _frameSun->getInfo()->location = 1;
+ _frameDate->getInfo()->location = 1;
+
+ getScenes()->addToQueue(_frameMinutes);
+ getScenes()->addToQueue(_frameHour);
+ getScenes()->addToQueue(_frameSun);
+ getScenes()->addToQueue(_frameDate);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// TrainLine
+//////////////////////////////////////////////////////////////////////////
+class TrainLine {
+public:
+ TrainLine(LastExpressEngine *engine);
+ ~TrainLine();
+
+ void draw(uint32 time);
+ void clear();
+
+private:
+ LastExpressEngine *_engine;
+
+ // Frames
+ SequenceFrame *_frameLine1;
+ SequenceFrame *_frameLine2;
+};
+
+TrainLine::TrainLine(LastExpressEngine *engine) : _engine(engine), _frameLine1(NULL), _frameLine2(NULL) {
+ _frameLine1 = new SequenceFrame(loadSequence("line1.seq"), 0, true);
+ _frameLine2 = new SequenceFrame(loadSequence("line2.seq"), 0, true);
+}
+
+TrainLine::~TrainLine() {
+ delete _frameLine1;
+ delete _frameLine2;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+void TrainLine::clear() {
+ getScenes()->removeFromQueue(_frameLine1);
+ getScenes()->removeFromQueue(_frameLine2);
+}
+
+// Draw the train line at the time
+// line1: 150 frames (=> Belgrade)
+// line2: 61 frames (=> Constantinople)
+void TrainLine::draw(uint32 time) {
+ assert(time >= kTimeCityParis && time <= kTimeCityConstantinople);
+
+ // Check that sequences have been loaded
+ if (!_frameLine1 || !_frameLine2)
+ error("TrainLine::process: Line sequences have not been loaded correctly!");
+
+ // Clear existing frames
+ clear();
+
+ // Get the index of the last city the train has visited
+ uint index = 0;
+ for (uint i = 0; i < ARRAYSIZE(_trainCities); i++)
+ if ((uint32)_trainCities[i].time <= time)
+ index = i;
+
+ uint16 frame;
+ if (time > (uint32)_trainCities[index].time) {
+ // Interpolate linearly to use a frame between the cities
+ uint8 diffFrames = _trainCities[index + 1].frame - _trainCities[index].frame;
+ uint diffTimeCities = (uint)(_trainCities[index + 1].time - _trainCities[index].time);
+ uint traveledTime = (time - (uint)_trainCities[index].time);
+ frame = (uint16)(_trainCities[index].frame + (traveledTime * diffFrames) / diffTimeCities);
+ } else {
+ // Exactly on the city
+ frame = _trainCities[index].frame;
+ }
+
+ // Set frame, z-order and queue
+ if (frame < 150) {
+ _frameLine1->setFrame(frame);
+
+ _frameLine1->getInfo()->location = 1;
+ getScenes()->addToQueue(_frameLine1);
+ } else {
+ // We passed Belgrade
+ _frameLine1->setFrame(149);
+ _frameLine2->setFrame(frame - 150);
+
+ _frameLine1->getInfo()->location = 1;
+ _frameLine2->getInfo()->location = 1;
+
+ getScenes()->addToQueue(_frameLine1);
+ getScenes()->addToQueue(_frameLine2);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Menu
+//////////////////////////////////////////////////////////////////////////
+Menu::Menu(LastExpressEngine *engine) : _engine(engine),
+ _seqTooltips(NULL), _seqEggButtons(NULL), _seqButtons(NULL), _seqAcorn(NULL), _seqCity1(NULL), _seqCity2(NULL), _seqCity3(NULL), _seqCredits(NULL),
+ _gameId(kGameBlue), _hasShownStartScreen(false), _hasShownIntro(false),
+ _isShowingCredits(false), _isGameStarted(false), _isShowingMenu(false),
+ _creditsSequenceIndex(0), _checkHotspotsTicks(15), _mouseFlags(Common::EVENT_INVALID), _lastHotspot(NULL),
+ _currentTime(kTimeNone), _lowerTime(kTimeNone), _time(kTimeNone), _currentIndex(0), _index(0), _lastIndex(0), _delta(0), _handleTimeDelta(false) {
+
+ _clock = new Clock(_engine);
+ _trainLine = new TrainLine(_engine);
+}
+
+Menu::~Menu() {
+ delete _clock;
+ delete _trainLine;
+
+ SAFE_DELETE(_seqTooltips);
+ SAFE_DELETE(_seqEggButtons);
+ SAFE_DELETE(_seqButtons);
+ SAFE_DELETE(_seqAcorn);
+ SAFE_DELETE(_seqCity1);
+ SAFE_DELETE(_seqCity2);
+ SAFE_DELETE(_seqCity3);
+ SAFE_DELETE(_seqCredits);
+
+ _lastHotspot = NULL;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Setup
+void Menu::setup() {
+
+ // Clear drawing queue
+ getScenes()->removeAndRedraw(&_frames[kOverlayAcorn], false);
+ SAFE_DELETE(_seqAcorn);
+
+ // Load Menu scene
+ // + 1 = normal menu with open egg / clock
+ // + 2 = shield menu, when no savegame exists (no game has been started)
+ _isGameStarted = _lowerTime >= kTimeStartGame;
+ getScenes()->loadScene((SceneIndex)(_isGameStarted ? _gameId * 5 + 1 : _gameId * 5 + 2));
+ getFlags()->shouldRedraw = true;
+ getLogic()->updateCursor();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Load Acorn sequence
+ _seqAcorn = loadSequence(getAcornSequenceName(_isGameStarted ? getNextGameId() : kGameBlue));
+
+ //////////////////////////////////////////////////////////////////////////
+ // Check if we loaded sequences before
+ if (_seqTooltips && _seqTooltips->count() > 0)
+ return;
+
+ // Load all static data
+ _seqTooltips = loadSequence("helpnewr.seq");
+ _seqEggButtons = loadSequence("buttns.seq");
+ _seqButtons = loadSequence("quit.seq");
+ _seqCity1 = loadSequence("jlinetl.seq");
+ _seqCity2 = loadSequence("jlinecen.seq");
+ _seqCity3 = loadSequence("jlinebr.seq");
+ _seqCredits = loadSequence("credits.seq");
+
+ _frames[kOverlayTooltip] = new SequenceFrame(_seqTooltips);
+ _frames[kOverlayEggButtons] = new SequenceFrame(_seqEggButtons);
+ _frames[kOverlayButtons] = new SequenceFrame(_seqButtons);
+ _frames[kOverlayAcorn] = new SequenceFrame(_seqAcorn);
+ _frames[kOverlayCity1] = new SequenceFrame(_seqCity1);
+ _frames[kOverlayCity2] = new SequenceFrame(_seqCity2);
+ _frames[kOverlayCity3] = new SequenceFrame(_seqCity3);
+ _frames[kOverlayCredits] = new SequenceFrame(_seqCredits);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Handle events
+void Menu::eventMouse(const Common::Event &ev) {
+ if (!getFlags()->shouldRedraw)
+ return;
+
+ bool redraw = true;
+ getFlags()->shouldRedraw = false;
+
+ // Update coordinates
+ setCoords(ev.mouse);
+ //_mouseFlags = (Common::EventType)(ev.type & Common::EVENT_LBUTTONUP);
+
+ if (_isShowingCredits) {
+ if (ev.type == Common::EVENT_RBUTTONUP) {
+ showFrame(kOverlayCredits, -1, true);
+ _isShowingCredits = false;
+ }
+
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ // Last frame of the credits
+ if (_seqCredits && _creditsSequenceIndex == _seqCredits->count() - 1) {
+ showFrame(kOverlayCredits, -1, true);
+ _isShowingCredits = false;
+ } else {
+ ++_creditsSequenceIndex;
+ showFrame(kOverlayCredits, _creditsSequenceIndex, true);
+ }
+ }
+ } else {
+ // Check for hotspots
+ SceneHotspot *hotspot = NULL;
+ getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot);
+
+ if (_lastHotspot != hotspot || ev.type == Common::EVENT_LBUTTONUP) {
+ _lastHotspot = hotspot;
+
+ if (ev.type == Common::EVENT_MOUSEMOVE) { /* todo check event type */
+ if (!_handleTimeDelta && hasTimeDelta())
+ setTime();
+ }
+
+ if (hotspot) {
+ redraw = handleEvent((StartMenuAction)hotspot->action, ev.type);
+ getFlags()->mouseRightClick = false;
+ getFlags()->mouseLeftClick = false;
+ } else {
+ hideOverlays();
+ }
+ }
+ }
+
+ if (redraw) {
+ getFlags()->shouldRedraw = true;
+ askForRedraw();
+ }
+}
+
+void Menu::eventTick(const Common::Event&) {
+ if (hasTimeDelta())
+ adjustTime();
+ else if (_handleTimeDelta)
+ _handleTimeDelta = false;
+
+ // Check hotspots
+ if (!--_checkHotspotsTicks) {
+ checkHotspots();
+ _checkHotspotsTicks = 15;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Show the intro and load the main menu scene
+void Menu::show(bool doSavegame, SavegameType type, uint32 value) {
+
+ if (_isShowingMenu)
+ return;
+
+ _isShowingMenu = true;
+ getEntities()->reset();
+
+ // If no blue savegame exists, this might be the first time we start the game, so we show the full intro
+ if (!getFlags()->mouseRightClick) {
+ if (!SaveLoad::isSavegameValid(kGameBlue) && _engine->getResourceManager()->loadArchive(kArchiveCd1)) {
+
+ if (!_hasShownIntro) {
+ // Show Broderbrund logo
+ Animation animation;
+ if (animation.load(getArchive("1930.nis")))
+ animation.play();
+
+ getFlags()->mouseRightClick = false;
+
+ // Play intro music
+ getSound()->playSoundWithSubtitles("MUS001.SND", SoundManager::kFlagMusic, kEntityPlayer);
+
+ // Show The Smoking Car logo
+ if (animation.load(getArchive("1931.nis")))
+ animation.play();
+
+ _hasShownIntro = true;
+ }
+ } else {
+ // Only show the quick intro
+ if (!_hasShownStartScreen) {
+ getSound()->playSoundWithSubtitles("MUS018.SND", SoundManager::kFlagMusic, kEntityPlayer);
+ getScenes()->loadScene(kSceneStartScreen);
+
+ // Original game waits 60 frames and loops Sound::unknownFunction1 unless the right button is pressed
+ uint32 nextFrameCount = getFrameCount() + 60;
+ while (getFrameCount() < nextFrameCount) {
+ _engine->pollEvents();
+
+ if (getFlags()->mouseRightClick)
+ break;
+
+ getSound()->updateQueue();
+ }
+ }
+ }
+ }
+
+ _hasShownStartScreen = true;
+
+ // Init Menu
+ init(doSavegame, type, value);
+
+ // Setup sound
+ getSound()->unknownFunction4();
+ getSound()->resetQueue(SoundManager::kSoundType11, SoundManager::kSoundType13);
+ if (getSound()->isBuffered("TIMER"))
+ getSound()->removeFromQueue("TIMER");
+
+ // Init flags & misc
+ _isShowingCredits = false;
+ _handleTimeDelta = hasTimeDelta();
+ getInventory()->unselectItem();
+
+ // Set Cursor type
+ _engine->getCursor()->setStyle(kCursorNormal);
+ _engine->getCursor()->show(true);
+
+ setup();
+ checkHotspots();
+
+ // Set event handlers
+ SET_EVENT_HANDLERS(Menu, this);
+}
+
+bool Menu::handleEvent(StartMenuAction action, Common::EventType type) {
+ bool clicked = (type == Common::EVENT_LBUTTONUP);
+
+ switch(action) {
+ default:
+ hideOverlays();
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuCredits:
+ if (hasTimeDelta()) {
+ hideOverlays();
+ break;
+ }
+
+ if (clicked) {
+ showFrame(kOverlayEggButtons, kButtonCreditsPushed, true);
+ showFrame(kOverlayTooltip, -1, true);
+
+ getSound()->playSound(kEntityPlayer, "LIB046");
+
+ hideOverlays();
+
+ _isShowingCredits = true;
+ _creditsSequenceIndex = 0;
+
+ showFrame(kOverlayCredits, 0, true);
+ } else {
+ // TODO check flags ?
+
+ showFrame(kOverlayEggButtons, kButtonCredits, true);
+ showFrame(kOverlayTooltip, kTooltipCredits, true);
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuQuitGame:
+ showFrame(kOverlayTooltip, kTooltipQuit, true);
+
+ if (clicked) {
+ showFrame(kOverlayButtons, kButtonQuitPushed, true);
+
+ getSound()->clearStatus();
+ getSound()->updateQueue();
+ getSound()->playSound(kEntityPlayer, "LIB046");
+
+ // FIXME uncomment when sound queue is properly implemented
+ /*while (getSound()->isBuffered("LIB046"))
+ getSound()->updateQueue();*/
+
+ getFlags()->shouldRedraw = false;
+
+ Engine::quitGame();
+
+ return false;
+ } else {
+ showFrame(kOverlayButtons, kButtonQuit, true);
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuCase4:
+ if (clicked)
+ _index = 0;
+ // fall down to kMenuContinue
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuContinue: {
+ if (hasTimeDelta()) {
+ hideOverlays();
+ break;
+ }
+
+ // Determine the proper CD archive
+ ArchiveIndex cd = kArchiveCd1;
+ if (getProgress().chapter > kChapter1)
+ cd = (getProgress().chapter > kChapter3) ? kArchiveCd3 : kArchiveCd2;
+
+ // Show tooltips & buttons to start a game, continue a game or load the proper cd
+ if (ResourceManager::isArchivePresent(cd)) {
+ if (_isGameStarted) {
+ showFrame(kOverlayEggButtons, kButtonContinue, true);
+
+ if (_lastIndex == _index) {
+ showFrame(kOverlayTooltip, getSaveLoad()->isGameFinished(_index, _lastIndex) ? kTooltipViewGameEnding : kTooltipContinueGame, true);
+ } else {
+ showFrame(kOverlayTooltip, kTooltipContinueRewoundGame, true);
+ }
+
+ } else {
+ showFrame(kOverlayEggButtons, kButtonShield, true);
+ showFrame(kOverlayTooltip, kTooltipPlayNewGame, true);
+ }
+ } else {
+ showFrame(kOverlayEggButtons, -1, true);
+ showFrame(kOverlayTooltip, cd - 1, true);
+ }
+
+ if (!clicked)
+ break;
+
+ // Try loading the archive file
+ if (!_engine->getResourceManager()->loadArchive(cd))
+ break;
+
+ // Load the train data file and setup game
+ getScenes()->loadSceneDataFile(cd);
+ showFrame(kOverlayTooltip, -1, true);
+ getSound()->playSound(kEntityPlayer, "LIB046");
+
+ // Setup new game
+ getSavePoints()->reset();
+ setLogicEventHandlers();
+
+ if (_index) {
+ getSound()->processEntry(SoundManager::kSoundType11);
+ } else {
+ if (!getFlags()->mouseRightClick) {
+ getScenes()->loadScene((SceneIndex)(5 * _gameId + 3));
+
+ if (!getFlags()->mouseRightClick) {
+ getScenes()->loadScene((SceneIndex)(5 * _gameId + 4));
+
+ if (!getFlags()->mouseRightClick) {
+ getScenes()->loadScene((SceneIndex)(5 * _gameId + 5));
+
+ if (!getFlags()->mouseRightClick) {
+ getSound()->processEntry(SoundManager::kSoundType11);
+
+ // Show intro
+ Animation animation;
+ if (animation.load(getArchive("1601.nis")))
+ animation.play();
+
+ getEvent(kEventIntro) = 1;
+ }
+ }
+ }
+ }
+
+ if (!getEvent(kEventIntro)) {
+ getEvent(kEventIntro) = 1;
+
+ getSound()->processEntry(SoundManager::kSoundType11);
+ }
+ }
+
+ // Setup game
+ getFlags()->isGameRunning = true;
+ startGame();
+
+ if (!_isShowingMenu)
+ getInventory()->show();
+
+ return false;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuSwitchSaveGame:
+ if (hasTimeDelta()) {
+ hideOverlays();
+ break;
+ }
+
+ if (clicked) {
+ showFrame(kOverlayAcorn, 1, true);
+ showFrame(kOverlayTooltip, -1, true);
+ getSound()->playSound(kEntityPlayer, "LIB047");
+
+ // Setup new menu screen
+ switchGame();
+ setup();
+
+ // Set fight state to 0
+ getFight()->resetState();
+
+ return true;
+ }
+
+ // TODO Check for flag
+
+ showFrame(kOverlayAcorn, 0, true);
+
+ if (_isGameStarted) {
+ showFrame(kOverlayTooltip, kTooltipSwitchBlueGame, true);
+ break;
+ }
+
+ if (_gameId == kGameGold) {
+ showFrame(kOverlayTooltip, kTooltipSwitchBlueGame, true);
+ break;
+ }
+
+ if (!SaveLoad::isSavegameValid(getNextGameId())) {
+ showFrame(kOverlayTooltip, kTooltipStartAnotherGame, true);
+ break;
+ }
+
+ // Stupid tooltips ids are not in order, so we can't just increment them...
+ switch(_gameId) {
+ default:
+ break;
+
+ case kGameBlue:
+ showFrame(kOverlayTooltip, kTooltipSwitchRedGame, true);
+ break;
+
+ case kGameRed:
+ showFrame(kOverlayTooltip, kTooltipSwitchGreenGame, true);
+ break;
+
+ case kGameGreen:
+ showFrame(kOverlayTooltip, kTooltipSwitchPurpleGame, true);
+ break;
+
+ case kGamePurple:
+ showFrame(kOverlayTooltip, kTooltipSwitchTealGame, true);
+ break;
+
+ case kGameTeal:
+ showFrame(kOverlayTooltip, kTooltipSwitchGoldGame, true);
+ break;
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuRewindGame:
+ if (!_index || _currentTime < _time) {
+ hideOverlays();
+ break;
+ }
+
+ if (clicked) {
+ if (hasTimeDelta())
+ _handleTimeDelta = false;
+
+ showFrame(kOverlayEggButtons, kButtonRewindPushed, true);
+ showFrame(kOverlayTooltip, -1, true);
+
+ getSound()->playSound(kEntityPlayer, "LIB046");
+
+ rewindTime();
+
+ _handleTimeDelta = false;
+ } else {
+ showFrame(kOverlayEggButtons, kButtonRewind, true);
+ showFrame(kOverlayTooltip, kTooltipRewind, true);
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuForwardGame:
+ if (_lastIndex <= _index || _currentTime > _time) {
+ hideOverlays();
+ break;
+ }
+
+ if (clicked) {
+ if (hasTimeDelta())
+ _handleTimeDelta = false;
+
+ showFrame(kOverlayEggButtons, kButtonForwardPushed, true);
+ showFrame(kOverlayTooltip, -1, true);
+
+ getSound()->playSound(kEntityPlayer, "LIB046");
+
+ forwardTime();
+
+ _handleTimeDelta = false;
+ } else {
+ showFrame(kOverlayEggButtons, kButtonForward, true);
+ showFrame(kOverlayTooltip, kTooltipFastForward, true);
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuParis:
+ moveToCity(kParis, clicked);
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuStrasBourg:
+ moveToCity(kStrasbourg, clicked);
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuMunich:
+ moveToCity(kMunich, clicked);
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuVienna:
+ moveToCity(kVienna, clicked);
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuBudapest:
+ moveToCity(kBudapest, clicked);
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuBelgrade:
+ moveToCity(kBelgrade, clicked);
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuConstantinople:
+ moveToCity(kConstantinople, clicked);
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuDecreaseVolume:
+ if (hasTimeDelta()) {
+ hideOverlays();
+ break;
+ }
+
+ // Cannot decrease volume further
+ if (getVolume() == 0) {
+ showFrame(kOverlayButtons, kButtonVolume, true);
+ showFrame(kOverlayTooltip, -1, true);
+ break;
+ }
+
+ showFrame(kOverlayTooltip, kTooltipVolumeDown, true);
+
+ // Show highlight on button & adjust volume if needed
+ if (clicked) {
+ showFrame(kOverlayButtons, kButtonVolumeDownPushed, true);
+ getSound()->playSound(kEntityPlayer, "LIB046");
+ setVolume(getVolume() - 1);
+
+ getSaveLoad()->saveVolumeBrightness();
+
+ uint32 nextFrameCount = getFrameCount() + 15;
+ while (nextFrameCount > getFrameCount()) {
+ _engine->pollEvents();
+
+ getSound()->updateQueue();
+ }
+ } else {
+ showFrame(kOverlayButtons, kButtonVolumeDown, true);
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuIncreaseVolume:
+ if (hasTimeDelta()) {
+ hideOverlays();
+ break;
+ }
+
+ // Cannot increase volume further
+ if (getVolume() >= 7) {
+ showFrame(kOverlayButtons, kButtonVolume, true);
+ showFrame(kOverlayTooltip, -1, true);
+ break;
+ }
+
+ showFrame(kOverlayTooltip, kTooltipVolumeUp, true);
+
+ // Show highlight on button & adjust volume if needed
+ if (clicked) {
+ showFrame(kOverlayButtons, kButtonVolumeUpPushed, true);
+ getSound()->playSound(kEntityPlayer, "LIB046");
+ setVolume(getVolume() + 1);
+
+ getSaveLoad()->saveVolumeBrightness();
+
+ uint32 nextFrameCount = getFrameCount() + 15;
+ while (nextFrameCount > getFrameCount()) {
+ _engine->pollEvents();
+
+ getSound()->updateQueue();
+ }
+ } else {
+ showFrame(kOverlayButtons, kButtonVolumeUp, true);
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuDecreaseBrightness:
+ if (hasTimeDelta()) {
+ hideOverlays();
+ break;
+ }
+
+ // Cannot increase brightness further
+ if (getBrightness() == 0) {
+ showFrame(kOverlayButtons, kButtonBrightness, true);
+ showFrame(kOverlayTooltip, -1, true);
+ break;
+ }
+
+ showFrame(kOverlayTooltip, kTooltipBrightnessDown, true);
+
+ // Show highlight on button & adjust brightness if needed
+ if (clicked) {
+ showFrame(kOverlayButtons, kButtonBrightnessDownPushed, true);
+ getSound()->playSound(kEntityPlayer, "LIB046");
+ setBrightness(getBrightness() - 1);
+
+ getSaveLoad()->saveVolumeBrightness();
+
+ // Reshow the background and frames (they will pick up the new brightness through the GraphicsManager)
+ _engine->getGraphicsManager()->draw(getScenes()->get((SceneIndex)(_isGameStarted ? _gameId * 5 + 1 : _gameId * 5 + 2)), GraphicsManager::kBackgroundC, true);
+ showFrame(kOverlayTooltip, kTooltipBrightnessDown, false);
+ showFrame(kOverlayButtons, kButtonBrightnessDownPushed, false);
+ } else {
+ showFrame(kOverlayButtons, kButtonBrightnessDown, true);
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////
+ case kMenuIncreaseBrightness:
+ if (hasTimeDelta()) {
+ hideOverlays();
+ break;
+ }
+
+ // Cannot increase brightness further
+ if (getBrightness() >= 6) {
+ showFrame(kOverlayButtons, kButtonBrightness, true);
+ showFrame(kOverlayTooltip, -1, true);
+ break;
+ }
+
+ showFrame(kOverlayTooltip, kTooltipBrightnessUp, true);
+
+ // Show highlight on button & adjust brightness if needed
+ if (clicked) {
+ showFrame(kOverlayButtons, kButtonBrightnessUpPushed, true);
+ getSound()->playSound(kEntityPlayer, "LIB046");
+ setBrightness(getBrightness() + 1);
+
+ getSaveLoad()->saveVolumeBrightness();
+
+ // Reshow the background and frames (they will pick up the new brightness through the GraphicsManager)
+ _engine->getGraphicsManager()->draw(getScenes()->get((SceneIndex)(_isGameStarted ? _gameId * 5 + 1 : _gameId * 5 + 2)), GraphicsManager::kBackgroundC, true);
+ showFrame(kOverlayTooltip, kTooltipBrightnessUp, false);
+ showFrame(kOverlayButtons, kButtonBrightnessUpPushed, false);
+ } else {
+ showFrame(kOverlayButtons, kButtonBrightnessUp, true);
+ }
+ break;
+ }
+
+ return true;
+}
+
+void Menu::setLogicEventHandlers() {
+ SET_EVENT_HANDLERS(Logic, getLogic());
+ clear();
+ _isShowingMenu = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Game-related
+//////////////////////////////////////////////////////////////////////////
+void Menu::init(bool doSavegame, SavegameType type, uint32 value) {
+
+ bool useSameIndex = true;
+
+ if (getGlobalTimer()) {
+ value = 0;
+
+ // Check if the CD file is present
+ ArchiveIndex index = kArchiveCd1;
+ switch (getProgress().chapter) {
+ default:
+ case kChapter1:
+ break;
+
+ case kChapter2:
+ case kChapter3:
+ index = kArchiveCd2;
+ break;
+
+ case kChapter4:
+ case kChapter5:
+ index = kArchiveCd3;
+ break;
+ }
+
+ if (ResourceManager::isArchivePresent(index)) {
+ setGlobalTimer(0);
+ useSameIndex = false;
+
+ // TODO remove existing savegame and reset index & savegame name
+ warning("Menu::initGame: not implemented!");
+ }
+
+ doSavegame = false;
+ } else {
+ // TODO rename saves?
+ }
+
+ // Create a new savegame if needed
+ if (!SaveLoad::isSavegamePresent(_gameId))
+ getSaveLoad()->create(_gameId);
+
+ if (doSavegame)
+ getSaveLoad()->saveGame(kSavegameTypeEvent2, kEntityPlayer, kEventNone);
+
+ if (!getGlobalTimer()) {
+ // TODO: remove existing savegame temp file
+ }
+
+ // Init savegame & menu values
+ _lastIndex = getSaveLoad()->init(_gameId, true);
+ _lowerTime = getSaveLoad()->getTime(_lastIndex);
+
+ if (useSameIndex)
+ _index = _lastIndex;
+
+ //if (!getGlobalTimer())
+ // _index3 = 0;
+
+ if (!getProgress().chapter)
+ getProgress().chapter = kChapter1;
+
+ getState()->time = (TimeValue)getSaveLoad()->getTime(_index);
+ getProgress().chapter = getSaveLoad()->getChapter(_index);
+
+ if (_lowerTime >= kTimeStartGame) {
+ _currentTime = (uint32)getState()->time;
+ _time = (uint32)getState()->time;
+ _clock->draw(_time);
+ _trainLine->draw(_time);
+
+ initTime(type, value);
+ }
+}
+
+// Start a game (or load an existing savegame)
+void Menu::startGame() {
+ // Clear savegame headers
+ getSaveLoad()->clear();
+
+ // Hide menu elements
+ _clock->clear();
+ _trainLine->clear();
+
+ if (_lastIndex == _index) {
+ setGlobalTimer(0);
+ if (_index) {
+ getSaveLoad()->loadGame(_gameId);
+ } else {
+ getLogic()->resetState();
+ getEntities()->setup(true, kEntityPlayer);
+ }
+ } else {
+ getSaveLoad()->loadGame(_gameId, _index);
+ }
+}
+
+// Switch to the next savegame
+void Menu::switchGame() {
+
+ // Switch back to blue game is the current game is not started
+ _gameId = SaveLoad::isSavegameValid(_gameId) ? getNextGameId() : kGameBlue;
+
+ // Initialize savegame if needed
+ if (!SaveLoad::isSavegamePresent(_gameId))
+ getSaveLoad()->create(_gameId);
+
+ getState()->time = kTimeNone;
+
+ // Clear menu elements
+ _clock->clear();
+ _trainLine->clear();
+
+ // Clear loaded savegame data
+ getSaveLoad()->clear(true);
+
+ init(false, kSavegameTypeIndex, 0);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Overlays & elements
+//////////////////////////////////////////////////////////////////////////
+void Menu::checkHotspots() {
+ if (!_isShowingMenu)
+ return;
+
+ if (!getFlags()->shouldRedraw)
+ return;
+
+ if (_isShowingCredits)
+ return;
+
+ SceneHotspot *hotspot = NULL;
+ getScenes()->get(getState()->scene)->checkHotSpot(getCoords(), &hotspot);
+
+ if (hotspot)
+ handleEvent((StartMenuAction)hotspot->action, _mouseFlags);
+ else
+ hideOverlays();
+}
+
+void Menu::hideOverlays() {
+ _lastHotspot = NULL;
+
+ // Hide all menu overlays
+ for (MenuFrames::iterator it = _frames.begin(); it != _frames.end(); it++)
+ showFrame(it->_key, -1, false);
+
+ getScenes()->drawFrames(true);
+}
+
+void Menu::showFrame(StartMenuOverlay overlayType, int index, bool redraw) {
+ if (index == -1) {
+ getScenes()->removeFromQueue(_frames[overlayType]);
+ } else {
+ // Check that the overlay is valid
+ if (!_frames[overlayType])
+ return;
+
+ // Remove the frame and add a new one with the proper index
+ getScenes()->removeFromQueue(_frames[overlayType]);
+ _frames[overlayType]->setFrame((uint16)index);
+ getScenes()->addToQueue(_frames[overlayType]);
+ }
+
+ if (redraw)
+ getScenes()->drawFrames(true);
+}
+
+// Remove all frames from the queue
+void Menu::clear() {
+ for (MenuFrames::iterator it = _frames.begin(); it != _frames.end(); it++)
+ getScenes()->removeAndRedraw(&it->_value, false);
+
+ clearBg(GraphicsManager::kBackgroundOverlay);
+}
+
+// Get the sequence name to use for the acorn highlight, depending of the currently loaded savegame
+Common::String Menu::getAcornSequenceName(GameId id) const {
+ Common::String name = "";
+ switch (id) {
+ default:
+ case kGameBlue:
+ name = "aconblu3.seq";
+ break;
+
+ case kGameRed:
+ name = "aconred.seq";
+ break;
+
+ case kGameGreen:
+ name = "acongren.seq";
+ break;
+
+ case kGamePurple:
+ name = "aconpurp.seq";
+ break;
+
+ case kGameTeal:
+ name = "aconteal.seq";
+ break;
+
+ case kGameGold:
+ name = "acongold.seq";
+ break;
+ }
+
+ return name;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Time
+//////////////////////////////////////////////////////////////////////////
+void Menu::initTime(SavegameType type, uint32 value) {
+ if (!value)
+ return;
+
+ // The savegame entry index
+ uint32 entryIndex = 0;
+
+ switch (type) {
+ default:
+ break;
+
+ case kSavegameTypeIndex:
+ entryIndex = (_index <= value) ? 1 : _index - value;
+ break;
+
+ case kSavegameTypeTime:
+ if (value < kTimeStartGame)
+ break;
+
+ entryIndex = _index;
+ if (!entryIndex)
+ break;
+
+ // Iterate through existing entries
+ do {
+ if (getSaveLoad()->getTime(entryIndex) <= value)
+ break;
+
+ entryIndex--;
+ } while (entryIndex);
+ break;
+
+ case kSavegameTypeEvent:
+ entryIndex = _index;
+ if (!entryIndex)
+ break;
+
+ do {
+ if (getSaveLoad()->getValue(entryIndex) == value)
+ break;
+
+ entryIndex--;
+ } while (entryIndex);
+ break;
+
+ case kSavegameTypeEvent2:
+ // TODO rewrite in a more legible way
+ if (_index > 1) {
+ uint32 index = _index;
+ do {
+ if (getSaveLoad()->getValue(index) == value)
+ break;
+
+ index--;
+ } while (index > 1);
+
+ entryIndex = index - 1;
+ } else {
+ entryIndex = _index - 1;
+ }
+ break;
+ }
+
+ if (entryIndex) {
+ _currentIndex = entryIndex;
+ updateTime(getSaveLoad()->getTime(entryIndex));
+ }
+}
+
+void Menu::updateTime(uint32 time) {
+ if (_currentTime == _time)
+ _delta = 0;
+
+ _currentTime = time;
+
+ if (_time != time) {
+ if (getSound()->isBuffered(kEntityChapters))
+ getSound()->removeFromQueue(kEntityChapters);
+
+ getSound()->playSoundWithSubtitles((_currentTime >= _time) ? "LIB042" : "LIB041", SoundManager::kFlagMenuClock, kEntityChapters);
+ adjustIndex(_currentTime, _time, false);
+ }
+}
+
+void Menu::adjustIndex(uint32 time1, uint32 time2, bool searchEntry) {
+ uint32 index = 0;
+ int32 timeDelta = -1;
+
+ if (time1 != time2) {
+
+ index = _index;
+
+ if (time2 >= time1) {
+ if (searchEntry) {
+ uint32 currentIndex = _index;
+
+ if ((int32)_index >= 0) {
+ do {
+ // Calculate new delta
+ int32 newDelta = time1 - (uint32)getSaveLoad()->getTime(currentIndex);
+
+ if (newDelta >= 0 && timeDelta >= newDelta) {
+ timeDelta = newDelta;
+ index = currentIndex;
+ }
+
+ --currentIndex;
+ } while ((int32)currentIndex >= 0);
+ }
+ } else {
+ index = _index - 1;
+ }
+ } else {
+ if (searchEntry) {
+ uint32 currentIndex = _index;
+
+ if (_lastIndex >= _index) {
+ do {
+ // Calculate new delta
+ int32 newDelta = (uint32)getSaveLoad()->getTime(currentIndex) - time1;
+
+ if (newDelta >= 0 && timeDelta > newDelta) {
+ timeDelta = newDelta;
+ index = currentIndex;
+ }
+
+ ++currentIndex;
+ } while (currentIndex <= _lastIndex);
+ }
+ } else {
+ index = _index + 1;
+ }
+ }
+
+ _index = index;
+ checkHotspots();
+ }
+
+ if (_index == _currentIndex) {
+ if (getProgress().chapter != getSaveLoad()->getChapter(index))
+ getProgress().chapter = getSaveLoad()->getChapter(_index);
+ }
+}
+
+void Menu::goToTime(uint32 time) {
+
+ uint32 entryIndex = 0;
+ uint32 deltaTime = (uint32)ABS((int32)(getSaveLoad()->getTime(0) - time));
+ uint32 index = 0;
+
+ do {
+ uint32 deltaTime2 = (uint32)ABS((int32)(getSaveLoad()->getTime(index) - time));
+ if (deltaTime2 < deltaTime) {
+ deltaTime = deltaTime2;
+ entryIndex = index;
+ }
+
+ ++index;
+ } while (_lastIndex >= index);
+
+ _currentIndex = entryIndex;
+ updateTime(getSaveLoad()->getTime(entryIndex));
+}
+
+void Menu::setTime() {
+ _currentIndex = _index;
+ _currentTime = getSaveLoad()->getTime(_currentIndex);
+
+ if (_time == _currentTime)
+ adjustTime();
+}
+
+void Menu::forwardTime() {
+ if (_lastIndex <= _index)
+ return;
+
+ _currentIndex = _lastIndex;
+ updateTime(getSaveLoad()->getTime(_currentIndex));
+}
+
+void Menu::rewindTime() {
+ if (!_index)
+ return;
+
+ _currentIndex = 0;
+ updateTime(getSaveLoad()->getTime(_currentIndex));
+}
+
+void Menu::adjustTime() {
+ uint32 originalTime = _time;
+
+ // Adjust time delta
+ Common::Rational timeDelta(_delta >= 90 ? 9 : (9 * _delta + 89), _delta >= 90 ? 1 : 90);
+
+ if (_currentTime < _time) {
+ timeDelta *= 900;
+ _time -= timeDelta.toInt();
+
+ if (_currentTime > _time)
+ _time = _currentTime;
+ } else {
+ timeDelta *= 900;
+ _time += timeDelta.toInt();
+
+ if (_currentTime < _time)
+ _time = _currentTime;
+ }
+
+ if (_currentTime == _time && getSound()->isBuffered(kEntityChapters))
+ getSound()->removeFromQueue(kEntityChapters);
+
+ _clock->draw(_time);
+ _trainLine->draw(_time);
+ getScenes()->drawFrames(true);
+
+ adjustIndex(_time, originalTime, true);
+
+ ++_delta;
+}
+
+void Menu::moveToCity(CityButton city, bool clicked) {
+ uint32 time = (uint32)_cityButtonsInfo[city].time;
+
+ // TODO Check if we have access (there seems to be more checks on some internal times) - probably : current_time (menu only) / game time / some other?
+ if (_lowerTime < time || _time == time || _currentTime == time) {
+ hideOverlays();
+ return;
+ }
+
+ // Show city overlay
+ showFrame((StartMenuOverlay)((_cityButtonsInfo[city].index >> 6) + 3), _cityButtonsInfo[city].index & 63, true);
+
+ if (clicked) {
+ showFrame(kOverlayTooltip, -1, true);
+ getSound()->playSound(kEntityPlayer, "LIB046");
+ goToTime(time);
+
+ _handleTimeDelta = true;
+
+ return;
+ }
+
+ // Special case of first and last cities
+ if (city == kParis || city == kConstantinople) {
+ showFrame(kOverlayTooltip, (city == kParis) ? kTooltipRewindParis : kTooltipForwardConstantinople, true);
+ return;
+ }
+
+ showFrame(kOverlayTooltip, (_time <= time) ? _cityButtonsInfo[city].forward : _cityButtonsInfo[city].rewind, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Sound / Brightness
+//////////////////////////////////////////////////////////////////////////
+
+// Get current volume (converted internal ScummVM value)
+uint32 Menu::getVolume() const {
+ return getState()->volume;
+}
+
+// Set the volume (converts to ScummVM values)
+void Menu::setVolume(uint32 volume) const {
+ getState()->volume = volume;
+
+ // Clamp volume
+ uint32 value = volume * Audio::Mixer::kMaxMixerVolume / 7;
+
+ if (value > Audio::Mixer::kMaxMixerVolume)
+ value = Audio::Mixer::kMaxMixerVolume;
+
+ _engine->_mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, (int32)value);
+}
+
+uint32 Menu::getBrightness() const {
+ return getState()->brightness;
+}
+
+void Menu::setBrightness(uint32 brightness) const {
+ getState()->brightness = brightness;
+
+ // TODO reload cursor & font with adjusted brightness
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/menu.h b/engines/lastexpress/game/menu.h
new file mode 100644
index 0000000000..765a611c41
--- /dev/null
+++ b/engines/lastexpress/game/menu.h
@@ -0,0 +1,210 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_MENU_H
+#define LASTEXPRESS_MENU_H
+
+#include "lastexpress/data/sequence.h"
+
+#include "lastexpress/eventhandler.h"
+
+#include "lastexpress/shared.h"
+
+#include "common/hashmap.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+class Scene;
+class SceneHotspot;
+
+class Clock;
+class TrainLine;
+
+class Menu : public EventHandler {
+public:
+ Menu(LastExpressEngine *engine);
+ ~Menu();
+
+ void show(bool doSavegame, SavegameType type, uint32 value);
+
+ // Event handling
+ void eventMouse(const Common::Event &ev);
+ void eventTick(const Common::Event &ev);
+
+ bool isShown() const { return _isShowingMenu; }
+
+ GameId getGameId() const { return _gameId; }
+
+private:
+ // Start menu events
+ enum StartMenuAction {
+ kMenuContinue = 1,
+ kMenuCredits = 2,
+ kMenuQuitGame = 3,
+ kMenuCase4 = 4,
+ kMenuSwitchSaveGame = 6,
+ kMenuRewindGame = 7,
+ kMenuForwardGame = 8,
+ kMenuParis = 10,
+ kMenuStrasBourg = 11,
+ kMenuMunich = 12,
+ kMenuVienna = 13,
+ kMenuBudapest = 14,
+ kMenuBelgrade = 15,
+ kMenuConstantinople = 16,
+ kMenuDecreaseVolume = 17,
+ kMenuIncreaseVolume = 18,
+ kMenuDecreaseBrightness = 19,
+ kMenuIncreaseBrightness = 20
+ };
+
+ // City buttons
+ enum CityButton {
+ kParis = 0,
+ kStrasbourg = 1,
+ kMunich = 2,
+ kVienna = 3,
+ kBudapest = 4,
+ kBelgrade = 5,
+ kConstantinople = 6
+ };
+
+ // Start menu overlay elements
+ enum StartMenuOverlay {
+ kOverlayTooltip, // 0
+ kOverlayEggButtons,
+ kOverlayButtons,
+ kOverlayAcorn,
+ kOverlayCity1,
+ kOverlayCity2, // 5
+ kOverlayCity3,
+ kOverlayCredits
+ };
+
+ LastExpressEngine *_engine;
+
+ // Sequences
+ Sequence *_seqTooltips;
+ Sequence *_seqEggButtons;
+ Sequence *_seqButtons;
+ Sequence *_seqAcorn;
+ Sequence *_seqCity1;
+ Sequence *_seqCity2;
+ Sequence *_seqCity3;
+ Sequence *_seqCredits;
+
+ GameId _gameId;
+
+ // Indicator to know if we need to show the start animation when showMenu is called
+ bool _hasShownStartScreen;
+ bool _hasShownIntro;
+
+ bool _isShowingCredits;
+ bool _isGameStarted;
+ bool _isShowingMenu;
+
+
+ uint16 _creditsSequenceIndex;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Event handling
+ uint32 _checkHotspotsTicks;
+ Common::EventType _mouseFlags;
+ SceneHotspot *_lastHotspot;
+
+ void init(bool doSavegame, SavegameType type, uint32 value);
+ void setup();
+ bool handleEvent(StartMenuAction action, Common::EventType type);
+ void checkHotspots();
+ void setLogicEventHandlers();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Game-related
+ void startGame();
+ void switchGame();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Overlays & elements
+ Clock *_clock;
+ TrainLine *_trainLine;
+
+ struct MenuOverlays_EqualTo {
+ bool operator()(const StartMenuOverlay &x, const StartMenuOverlay &y) const { return x == y; }
+ };
+
+ struct MenuOverlays_Hash {
+ uint operator()(const StartMenuOverlay &x) const { return x; }
+ };
+
+ typedef Common::HashMap<StartMenuOverlay, SequenceFrame *, MenuOverlays_Hash, MenuOverlays_EqualTo> MenuFrames;
+
+ MenuFrames _frames;
+
+ void hideOverlays();
+ void showFrame(StartMenuOverlay overlay, int index, bool redraw);
+
+ void clear();
+
+ // TODO: remove?
+ void moveToCity(CityButton city, bool clicked);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Misc
+ Common::String getAcornSequenceName(GameId id) const;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Time
+ uint32 _currentTime; // current game time
+ uint32 _lowerTime; // lower time value
+ uint32 _time;
+
+ uint32 _currentIndex; // current savegame entry
+ uint32 _index;
+ uint32 _lastIndex;
+ uint32 _delta;
+ bool _handleTimeDelta;
+
+ void initTime(SavegameType type, uint32 val);
+ void updateTime(uint32 time);
+ void adjustTime();
+ void adjustIndex(uint32 time1, uint32 time2, bool searchEntry);
+ void goToTime(uint32 time);
+ void setTime();
+ void forwardTime();
+ void rewindTime();
+ bool hasTimeDelta() { return (_currentTime - _time) >= 1; }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Sound/Brightness related
+ uint32 getVolume() const;
+ void setVolume(uint32 volume) const;
+ uint32 getBrightness() const;
+ void setBrightness(uint32 brightness) const;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_MENU_H
diff --git a/engines/lastexpress/game/object.cpp b/engines/lastexpress/game/object.cpp
new file mode 100644
index 0000000000..4f296debcb
--- /dev/null
+++ b/engines/lastexpress/game/object.cpp
@@ -0,0 +1,109 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/object.h"
+
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+Common::String Objects::Object::toString() {
+ return Common::String::format("{ %s - %d - %d - %d - %d }", ENTITY_NAME(entity), location, cursor, cursor2, location2);
+}
+
+Objects::Objects(LastExpressEngine *engine) : _engine(engine) {}
+
+const Objects::Object Objects::get(ObjectIndex index) const {
+ if (index >= kObjectMax)
+ error("Objects::get - internal error: invalid object index (%d)", index);
+
+ return _objects[index];
+}
+
+void Objects::update(ObjectIndex index, EntityIndex entity, ObjectLocation location, CursorStyle cursor, CursorStyle cursor2) {
+ if (index >= kObjectMax)
+ return;
+
+ Object *object = &_objects[index];
+
+ // Store original location
+ ObjectLocation original_location = object->location;
+
+ // Update entity
+ object->entity = entity;
+ object->location = location;
+
+ if (cursor != kCursorKeepValue || cursor2 != kCursorKeepValue) {
+ if (cursor != kCursorKeepValue)
+ object->cursor = cursor;
+ if (cursor2 != kCursorKeepValue)
+ object->cursor2 = cursor2;
+
+ getLogic()->updateCursor();
+ }
+
+ getFlags()->flag_3 = true;
+
+ // Compartments
+ if (original_location != location && (original_location == kObjectLocation2 || location == kObjectLocation2))
+ if ((index >= kObjectCompartment1 && index <= kObjectCompartment8)
+ || (index >= kObjectCompartmentA && index <= kObjectCompartmentF)) {
+ getScenes()->updateDoorsAndClock();
+ }
+}
+
+void Objects::updateLocation2(ObjectIndex index, ObjectLocation location2) {
+ if (index >= kObjectMax)
+ return;
+
+ _objects[index].location2 = location2;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Serializable
+//////////////////////////////////////////////////////////////////////////
+void Objects::saveLoadWithSerializer(Common::Serializer &s) {
+ for (int i = 0; i < ARRAYSIZE(_objects); i++)
+ _objects[i].saveLoadWithSerializer(s);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// toString
+//////////////////////////////////////////////////////////////////////////
+Common::String Objects::toString() {
+ Common::String ret = "";
+
+ for (int i = 0; i < ARRAYSIZE(_objects); i++)
+ ret += Common::String::format("%d : %s\n", i, _objects[i].toString().c_str());
+
+ return ret;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/object.h b/engines/lastexpress/game/object.h
new file mode 100644
index 0000000000..96af4f07a6
--- /dev/null
+++ b/engines/lastexpress/game/object.h
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_OBJECT_H
+#define LASTEXPRESS_OBJECT_H
+
+#include "lastexpress/shared.h"
+
+#include "common/serializer.h"
+#include "common/system.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Objects : Common::Serializable {
+public:
+
+ struct Object : Common::Serializable { // All fields should be saved as bytes
+ EntityIndex entity;
+ ObjectLocation location;
+ CursorStyle cursor;
+ CursorStyle cursor2;
+ ObjectLocation location2;
+
+ Object() {
+ entity = kEntityPlayer;
+ location = kObjectLocationNone;
+ cursor = kCursorHandKnock;
+ cursor2 = kCursorHandKnock;
+ location2 = kObjectLocationNone;
+ }
+
+ Common::String toString();
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsByte(entity);
+ s.syncAsByte(location);
+ s.syncAsByte(cursor);
+ s.syncAsByte(cursor2);
+ s.syncAsByte(location2);
+ }
+ };
+
+ Objects(LastExpressEngine *engine);
+
+ const Object get(ObjectIndex index) const;
+ void update(ObjectIndex index, EntityIndex entity, ObjectLocation location, CursorStyle cursor, CursorStyle cursor2);
+ void updateLocation2(ObjectIndex index, ObjectLocation location2);
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &s);
+
+ /**
+ * Convert this object into a string representation.
+ *
+ * @return A string representation of this object.
+ */
+ Common::String toString();
+
+private:
+ LastExpressEngine *_engine;
+
+ Object _objects[kObjectMax];
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_OBJECT_H
diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp
new file mode 100644
index 0000000000..224d91eddd
--- /dev/null
+++ b/engines/lastexpress/game/savegame.cpp
@@ -0,0 +1,564 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/savegame.h"
+
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/menu.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/debug.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/helpers.h"
+
+#include "common/file.h"
+#include "common/system.h"
+
+namespace LastExpress {
+
+// Names of savegames
+static const struct {
+ const char *saveFile;
+} gameInfo[6] = {
+ {"blue.egg"},
+ {"red.egg"},
+ {"green.egg"},
+ {"purple.egg"},
+ {"teal.egg"},
+ {"gold.egg"}
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Constructors
+//////////////////////////////////////////////////////////////////////////
+
+SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL), _gameTicksLastSavegame(0) {
+}
+
+SaveLoad::~SaveLoad() {
+ clear(true);
+
+ //Zero passed pointers
+ _engine = NULL;
+}
+
+void SaveLoad::initStream() {
+ delete _savegame;
+ _savegame = new SavegameStream();
+}
+
+void SaveLoad::flushStream(GameId id) {
+ Common::OutSaveFile *save = openForSaving(id);
+ if (!save)
+ error("SaveLoad::flushStream: cannot open savegame (%s)!", getFilename(id).c_str());
+
+ if (!_savegame)
+ error("SaveLoad::flushStream: savegame stream is invalid");
+
+ save->write(_savegame->getData(), (uint32)_savegame->size());
+
+ delete save;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Init
+//////////////////////////////////////////////////////////////////////////
+void SaveLoad::create(GameId id) {
+ initStream();
+
+ Common::Serializer ser(NULL, _savegame);
+ SavegameMainHeader header;
+ header.saveLoadWithSerializer(ser);
+
+ flushStream(id);
+}
+
+uint32 SaveLoad::init(GameId id, bool resetHeaders) {
+ initStream();
+
+ // Load game data
+ loadStream(id);
+
+ // Get the main header
+ Common::Serializer ser(_savegame, NULL);
+ SavegameMainHeader mainHeader;
+ mainHeader.saveLoadWithSerializer(ser);
+ if (!mainHeader.isValid())
+ error("SaveLoad::init - Savegame seems to be corrupted (invalid header)");
+
+ // Reset cached entry headers if needed
+ if (resetHeaders) {
+ clear();
+
+ SavegameEntryHeader *entryHeader = new SavegameEntryHeader();
+ entryHeader->time = kTimeCityParis;
+ entryHeader->chapter = kChapter1;
+
+ _gameHeaders.push_back(entryHeader);
+ }
+
+ // Read the list of entry headers
+ if (_savegame->size() > 32) {
+ while (!_savegame->eos() && !_savegame->err()) {
+
+ // Update sound queue while we go through the savegame
+ getSound()->updateQueue();
+
+ SavegameEntryHeader *entry = new SavegameEntryHeader();
+ entry->saveLoadWithSerializer(ser);
+
+ if (!entry->isValid())
+ break;
+
+ _gameHeaders.push_back(entry);
+
+ _savegame->seek(entry->offset, SEEK_CUR);
+ }
+ }
+
+ // return the index to the current save game entry (we store count + 1 entries, so we're good)
+ return mainHeader.count;
+}
+
+void SaveLoad::loadStream(GameId id) {
+ Common::InSaveFile *save = openForLoading(id);
+ if (save->size() < 32)
+ error("SaveLoad::init - Savegame seems to be corrupted (not enough data: %i bytes)", save->size());
+
+ if (!_savegame)
+ error("SaveLoad::loadStream: savegame stream is invalid");
+
+ // Load all savegame data
+ uint8* buf = new uint8[8192];
+ while (!save->eos() && !save->err()) {
+ uint32 count = save->read(buf, sizeof(buf));
+ if (count) {
+ uint32 w = _savegame->write(buf, count);
+ assert (w == count);
+ }
+ }
+
+ if (save->err())
+ error("SaveLoad::init - Error reading savegame");
+
+ delete[] buf;
+ delete save;
+
+ // Move back to the beginning of the stream
+ _savegame->seek(0);
+}
+
+void SaveLoad::clear(bool clearStream) {
+ for (uint i = 0; i < _gameHeaders.size(); i++)
+ SAFE_DELETE(_gameHeaders[i]);
+
+ _gameHeaders.clear();
+
+ if (clearStream)
+ SAFE_DELETE(_savegame);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Save & Load
+//////////////////////////////////////////////////////////////////////////
+
+// Load game
+void SaveLoad::loadGame(GameId id) {
+ // Rewind current savegame
+ _savegame->seek(0);
+
+ // Validate main header
+ SavegameMainHeader header;
+ if (!loadMainHeader(_savegame, &header)) {
+ debugC(2, kLastExpressDebugSavegame, "SaveLoad::saveGame - Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str());
+ return;
+ }
+
+ // Load the last entry
+ _savegame->seek(header.offsetEntry);
+
+ SavegameType type = kSavegameTypeIndex;
+ EntityIndex entity = kEntityPlayer;
+ uint32 val = 0;
+ readEntry(&type, &entity, &val, header.keepIndex == 1);
+
+ // Setup last loading time
+ _gameTicksLastSavegame = getState()->timeTicks;
+
+ if (header.keepIndex) {
+ getSound()->clearQueue();
+
+ readEntry(&type, &entity, &val, false);
+ }
+
+ getEntities()->reset();
+ getEntities()->setup(false, entity);
+}
+
+// Load a specific game entry
+void SaveLoad::loadGame(GameId id, uint32 index) {
+ error("SaveLoad::loadGame: not implemented! (only loading the last entry is working for now)");
+}
+
+// Save game
+void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) {
+ if (getState()->scene <= kSceneIntro)
+ return;
+
+ // Validate main header
+ SavegameMainHeader header;
+ if (!loadMainHeader(_savegame, &header)) {
+ debugC(2, kLastExpressDebugSavegame, "SaveLoad::saveGame - Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str());
+ return;
+ }
+
+ if (!_savegame)
+ error("SaveLoad::saveGame: savegame stream is invalid");
+
+ // Validate the current entry if it exists
+ if (header.count > 0) {
+ _savegame->seek(header.offsetEntry);
+
+ // Load entry header
+ SavegameEntryHeader entry;
+ Common::Serializer ser(_savegame, NULL);
+ entry.saveLoadWithSerializer(ser);
+
+ if (!entry.isValid()) {
+ warning("SaveLoad::saveGame: Invalid entry. This savegame might be corrupted!");
+ _savegame->seek(header.offset);
+ } else if (getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time)) {
+ // Not ready to save a game, skipping!
+ return;
+ } else if ((type == kSavegameTypeTime || type == kSavegameTypeEvent)
+ && (entry.type == kSavegameTypeTickInterval && (getState()->time - entry.time) < 450)) {
+ _savegame->seek(header.offsetEntry);
+ --header.count;
+ } else {
+ _savegame->seek(header.offset);
+ }
+ } else {
+ // Seek to the next savegame entry
+ _savegame->seek(header.offset);
+ }
+
+ if (type != kSavegameTypeEvent2 && type != kSavegameTypeAuto)
+ header.offsetEntry = (uint32)_savegame->pos();
+
+ // Write the savegame entry
+ writeEntry(type, entity, value);
+
+ if (!header.keepIndex)
+ ++header.count;
+
+ if (type == kSavegameTypeEvent2 || type == kSavegameTypeAuto) {
+ header.keepIndex = 1;
+ } else {
+ header.keepIndex = 0;
+ header.offset = (uint32)_savegame->pos();
+
+ // Save ticks
+ _gameTicksLastSavegame = getState()->timeTicks;
+ }
+
+ // Validate the main header
+ if (!header.isValid())
+ error("SaveLoad::saveGame: main game header is invalid!");
+
+ // Write the main header
+ _savegame->seek(0);
+ Common::Serializer ser(NULL, _savegame);
+ header.saveLoadWithSerializer(ser);
+
+ flushStream(getMenu()->getGameId());
+}
+
+void SaveLoad::saveVolumeBrightness() {
+ warning("SaveLoad::saveVolumeBrightness: not implemented!");
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Headers
+//////////////////////////////////////////////////////////////////////////
+bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *header) {
+ if (!stream)
+ return false;
+
+ // Check there is enough data (32 bytes)
+ if (stream->size() < 32) {
+ debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Savegame seems to be corrupted (not enough data: %i bytes)!", stream->size());
+ return false;
+ }
+
+ // Rewind stream
+ stream->seek(0);
+
+ Common::Serializer ser(stream, NULL);
+ header->saveLoadWithSerializer(ser);
+
+ // Validate the header
+ if (!header->isValid()) {
+ debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Cannot validate main header!");
+ return false;
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Entries
+//////////////////////////////////////////////////////////////////////////
+void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
+#define WRITE_ENTRY(name, func, val) { \
+ uint32 _prevPosition = (uint32)_savegame->pos(); \
+ func; \
+ uint32 _count = (uint32)_savegame->pos() - _prevPosition; \
+ debugC(kLastExpressDebugSavegame, "Savegame: Writing " #name ": %d bytes", _count); \
+ if (_count != val)\
+ error("SaveLoad::writeEntry: Number of bytes written (%d) differ from expected count (%d)", _count, val); \
+}
+
+ if (!_savegame)
+ error("SaveLoad::writeEntry: savegame stream is invalid");
+
+ SavegameEntryHeader header;
+
+ header.type = type;
+ header.time = (uint32)getState()->time;
+ header.chapter = getProgress().chapter;
+ header.value = value;
+
+ // Save position
+ uint32 originalPosition = (uint32)_savegame->pos();
+
+ // Write header
+ Common::Serializer ser(NULL, _savegame);
+ header.saveLoadWithSerializer(ser);
+
+ // Write game data
+ WRITE_ENTRY("entity index", ser.syncAsUint32LE(entity), 4);
+ WRITE_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4);
+ WRITE_ENTRY("selected item", getInventory()->saveSelectedItem(ser), 4);
+ WRITE_ENTRY("positions", getEntities()->savePositions(ser), 4 * 1000);
+ WRITE_ENTRY("compartments", getEntities()->saveCompartments(ser), 4 * 16 * 2);
+ WRITE_ENTRY("progress", getProgress().saveLoadWithSerializer(ser), 4 * 128);
+ WRITE_ENTRY("events", getState()->syncEvents(ser), 512);
+ WRITE_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32);
+ WRITE_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128);
+ WRITE_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40);
+ WRITE_ENTRY("sound", getSound()->saveLoadWithSerializer(ser), 3 * 4 + getSound()->count() * 64);
+ WRITE_ENTRY("savepoints", getSavePoints()->saveLoadWithSerializer(ser), 128 * 16 + 4 + getSavePoints()->count() * 16);
+
+ header.offset = (uint32)_savegame->pos() - (originalPosition + 32);
+
+ // Add padding if necessary
+ while (header.offset & 0xF) {
+ _savegame->writeByte(0);
+ header.offset++;
+ }
+
+ // Save end position
+ uint32 endPosition = (uint32)_savegame->pos();
+
+ // Validate entry header
+ if (!header.isValid())
+ error("SaveLoad::writeEntry: entry header is invalid");
+
+ // Save the header with the updated info
+ _savegame->seek(originalPosition);
+ header.saveLoadWithSerializer(ser);
+
+ // Move back to the end of the entry
+ _savegame->seek(endPosition);
+}
+
+void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex) {
+#define LOAD_ENTRY(name, func, val) { \
+ uint32 _prevPosition = (uint32)_savegame->pos(); \
+ func; \
+ uint32 _count = (uint32)_savegame->pos() - _prevPosition; \
+ debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \
+ if (_count != val) \
+ error("SaveLoad::readEntry: Number of bytes read (%d) differ from expected count (%d)", _count, val); \
+}
+
+#define LOAD_ENTRY_ONLY(name, func) { \
+ uint32 _prevPosition = (uint32)_savegame->pos(); \
+ func; \
+ uint32 _count = (uint32)_savegame->pos() - _prevPosition; \
+ debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \
+}
+
+ if (!type || !entity || !val)
+ error("SaveLoad::readEntry: Invalid parameters passed!");
+
+ // Load entry header
+ SavegameEntryHeader entry;
+ Common::Serializer ser(_savegame, NULL);
+ entry.saveLoadWithSerializer(ser);
+
+ if (!entry.isValid())
+ error("SaveLoad::readEntry: entry header is invalid!");
+
+ // Init type, entity & value
+ *type = entry.type;
+ *val = entry.value;
+
+ // Save position
+ uint32 originalPosition = (uint32)_savegame->pos();
+
+ // Load game data
+ LOAD_ENTRY("entity index", ser.syncAsUint32LE(*entity), 4);
+ LOAD_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4);
+ LOAD_ENTRY("selected item", getInventory()->saveSelectedItem(ser), 4);
+ LOAD_ENTRY("positions", getEntities()->savePositions(ser), 4 * 1000);
+ LOAD_ENTRY("compartments", getEntities()->saveCompartments(ser), 4 * 16 * 2);
+ LOAD_ENTRY("progress", getProgress().saveLoadWithSerializer(ser), 4 * 128);
+ LOAD_ENTRY("events", getState()->syncEvents(ser), 512);
+ LOAD_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32);
+ LOAD_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128);
+ LOAD_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40);
+ LOAD_ENTRY_ONLY("sound", getSound()->saveLoadWithSerializer(ser));
+ LOAD_ENTRY_ONLY("savepoints", getSavePoints()->saveLoadWithSerializer(ser));
+
+ // Update chapter
+ getProgress().chapter = entry.chapter;
+
+ // Skip padding
+ uint32 offset = _savegame->pos() - originalPosition;
+ if (offset & 0xF) {
+ _savegame->seek((~offset & 0xF) + 1, SEEK_SET);
+ }
+}
+
+SaveLoad::SavegameEntryHeader *SaveLoad::getEntry(uint32 index) {
+ if (index >= _gameHeaders.size())
+ error("SaveLoad::getEntry: invalid index (was:%d, max:%d)", index, _gameHeaders.size() - 1);
+
+ return _gameHeaders[index];
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Checks
+//////////////////////////////////////////////////////////////////////////
+
+// Check if a specific savegame exists
+bool SaveLoad::isSavegamePresent(GameId id) {
+ if (g_system->getSavefileManager()->listSavefiles(getFilename(id)).size() == 0)
+ return false;
+
+ return true;
+}
+
+// Check if the game has been started in the specific savegame
+bool SaveLoad::isSavegameValid(GameId id) {
+ if (!isSavegamePresent(id)) {
+ debugC(2, kLastExpressDebugSavegame, "SaveLoad::isSavegameValid - Savegame does not exist: %s", getFilename(id).c_str());
+ return false;
+ }
+
+ SavegameMainHeader header;
+
+ Common::InSaveFile *save = openForLoading(id);
+ return loadMainHeader(save, &header);
+}
+
+bool SaveLoad::isGameFinished(uint32 menuIndex, uint32 savegameIndex) {
+ SavegameEntryHeader *data = getEntry(menuIndex);
+
+ if (savegameIndex != menuIndex)
+ return false;
+
+ if (data->type != kSavegameTypeEvent)
+ return false;
+
+ return (data->value == kEventAnnaKilled
+ || data->value == kEventKronosHostageAnnaNoFirebird
+ || data->value == kEventKahinaPunchBaggageCarEntrance
+ || data->value == kEventKahinaPunchBlue
+ || data->value == kEventKahinaPunchYellow
+ || data->value == kEventKahinaPunchSalon
+ || data->value == kEventKahinaPunchKitchen
+ || data->value == kEventKahinaPunchBaggageCar
+ || data->value == kEventKahinaPunchCar
+ || data->value == kEventKahinaPunchSuite4
+ || data->value == kEventKahinaPunchRestaurant
+ || data->value == kEventKahinaPunch
+ || data->value == kEventKronosGiveFirebird
+ || data->value == kEventAugustFindCorpse
+ || data->value == kEventMertensBloodJacket
+ || data->value == kEventMertensCorpseFloor
+ || data->value == kEventMertensCorpseBed
+ || data->value == kEventCoudertBloodJacket
+ || data->value == kEventGendarmesArrestation
+ || data->value == kEventAbbotDrinkGiveDetonator
+ || data->value == kEventMilosCorpseFloor
+ || data->value == kEventLocomotiveAnnaStopsTrain
+ || data->value == kEventTrainStopped
+ || data->value == kEventCathVesnaRestaurantKilled
+ || data->value == kEventCathVesnaTrainTopKilled
+ || data->value == kEventLocomotiveConductorsDiscovered
+ || data->value == kEventViennaAugustUnloadGuns
+ || data->value == kEventViennaKronosFirebird
+ || data->value == kEventVergesAnnaDead
+ || data->value == kEventTrainExplosionBridge
+ || data->value == kEventKronosBringNothing);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Private methods
+//////////////////////////////////////////////////////////////////////////
+
+// Get the file name from the savegame ID
+Common::String SaveLoad::getFilename(GameId id) {
+ if (id >= 6)
+ error("SaveLoad::getName - attempting to use an invalid game id. Valid values: 0 - 5, was %d", id);
+
+ return gameInfo[id].saveFile;
+}
+
+Common::InSaveFile *SaveLoad::openForLoading(GameId id) {
+ Common::InSaveFile *load = g_system->getSavefileManager()->openForLoading(getFilename(id));
+
+ if (!load)
+ debugC(2, kLastExpressDebugSavegame, "SaveLoad::openForLoading - Cannot open savegame for loading: %s", getFilename(id).c_str());
+
+ return load;
+}
+
+Common::OutSaveFile *SaveLoad::openForSaving(GameId id) {
+ Common::OutSaveFile *save = g_system->getSavefileManager()->openForSaving(getFilename(id));
+
+ if (!save)
+ debugC(2, kLastExpressDebugSavegame, "SaveLoad::openForSaving - Cannot open savegame for writing: %s", getFilename(id).c_str());
+
+ return save;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h
new file mode 100644
index 0000000000..d3ba5d13af
--- /dev/null
+++ b/engines/lastexpress/game/savegame.h
@@ -0,0 +1,288 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SAVELOAD_H
+#define LASTEXPRESS_SAVELOAD_H
+
+/*
+ Savegame format
+ ---------------
+
+ header: 32 bytes
+ uint32 {4} - signature: 0x12001200
+ uint32 {4} - chapter - needs to be [0; 5]
+ uint32 {4} - time - needs to be >= 32 [1061100; timeMax]
+ uint32 {4} - ?? needs to be >= 32
+ uint32 {4} - ?? needs to be = 1
+ uint32 {4} - Brightness (needs to be [0-6])
+ uint32 {4} - Volume (needs to be [0-7])
+ uint32 {4} - ?? needs to be = 9
+
+ Game data Format
+ -----------------
+
+ uint32 {4} - entity
+ uint32 {4} - current time
+ uint32 {4} - time delta (how much a tick is in "real" time)
+ uint32 {4} - time ticks
+ uint32 {4} - scene Index max: 2500
+ byte {1} - use backup scene
+ uint32 {4} - backup Scene Index 1 max: 2500
+ uint32 {4} - backup Scene Index 2 max: 2500
+ uint32 {4} - selected inventory item max: 32
+ uint32 {4*100*10} - positions (by car)
+ uint32 {4*16} - compartments
+ uint32 {4*16} - compartments ??
+ uint32 {4*128} - game progress
+ byte {512} - game events
+ byte {7*32} - inventory
+ byte {5*128} - objects
+ byte {1262*40} - entities (characters and train entities)
+
+ uint32 {4} - sound queue state
+ uint32 {4} - ??
+ uint32 {4} - number of sound entries
+ byte {count*68} - sound entries
+
+ byte {16*128} - save point data
+ uint32 {4} - number of save points (max: 128)
+ byte {count*16} - save points
+
+ ... more unknown stuff
+
+*/
+
+#include "lastexpress/shared.h"
+
+#include "common/savefile.h"
+#include "common/serializer.h"
+
+namespace LastExpress {
+
+// Savegame signatures
+#define SAVEGAME_SIGNATURE 0x12001200
+#define SAVEGAME_ENTRY_SIGNATURE 0xE660E660
+
+class LastExpressEngine;
+
+class SaveLoad {
+public:
+ SaveLoad(LastExpressEngine *engine);
+ ~SaveLoad();
+
+ // Init
+ void create(GameId id);
+ void clear(bool clearStream = false);
+ uint32 init(GameId id, bool resetHeaders);
+
+ // Save & Load
+ void loadGame(GameId id);
+ void loadGame(GameId id, uint32 index);
+ void saveGame(SavegameType type, EntityIndex entity, uint32 value);
+
+ void loadVolumeBrightness();
+ void saveVolumeBrightness();
+
+ // Getting information
+ static bool isSavegamePresent(GameId id);
+ static bool isSavegameValid(GameId id);
+
+ bool isGameFinished(uint32 menuIndex, uint32 savegameIndex);
+
+ // Accessors
+ uint32 getTime(uint32 index) { return getEntry(index)->time; }
+ ChapterIndex getChapter(uint32 index) { return getEntry(index)->chapter; }
+ uint32 getValue(uint32 index) { return getEntry(index)->value; }
+ uint32 getLastSavegameTicks() const { return _gameTicksLastSavegame; }
+
+private:
+ class SavegameStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream {
+ public:
+ SavegameStream() : MemoryWriteStreamDynamic(DisposeAfterUse::YES),
+ _eos(false) {}
+
+ int32 pos() const { return MemoryWriteStreamDynamic::pos(); }
+ int32 size() const { return MemoryWriteStreamDynamic::size(); }
+ bool seek(int32 offset, int whence = SEEK_SET) { return MemoryWriteStreamDynamic::seek(offset, whence); }
+ bool eos() const { return _eos; }
+ uint32 read(void *dataPtr, uint32 dataSize) {
+ if ((int32)dataSize > size() - pos()) {
+ dataSize = size() - pos();
+ _eos = true;
+ }
+ memcpy(dataPtr, getData() + pos(), dataSize);
+
+ seek(dataSize, SEEK_CUR);
+
+ return dataSize;
+ }
+ private:
+ bool _eos;
+ };
+
+ LastExpressEngine *_engine;
+
+ struct SavegameMainHeader : Common::Serializable {
+ uint32 signature;
+ uint32 count;
+ uint32 offset;
+ uint32 offsetEntry;
+ uint32 keepIndex;
+ int32 brightness;
+ int32 volume;
+ uint32 field_1C;
+
+ SavegameMainHeader() {
+ signature = SAVEGAME_SIGNATURE;
+ count = 0;
+ offset = 32;
+ offsetEntry = 32;
+ keepIndex = 0;
+ brightness = 3;
+ volume = 7;
+ field_1C = 9;
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(signature);
+ s.syncAsUint32LE(count);
+ s.syncAsUint32LE(offset);
+ s.syncAsUint32LE(offsetEntry);
+ s.syncAsUint32LE(keepIndex);
+ s.syncAsUint32LE(brightness);
+ s.syncAsUint32LE(volume);
+ s.syncAsUint32LE(field_1C);
+ }
+
+ bool isValid() {
+ if (signature != SAVEGAME_SIGNATURE)
+ return false;
+
+ /* Check not needed as it can never be < 0
+ if (header.chapter < 0)
+ return false;*/
+
+ if (offset < 32)
+ return false;
+
+ if (offsetEntry < 32)
+ return false;
+
+ if (keepIndex != 1 && keepIndex != 0)
+ return false;
+
+ if (brightness < 0 || brightness > 6)
+ return false;
+
+ if (volume < 0 || volume > 7)
+ return false;
+
+ if (field_1C != 9)
+ return false;
+
+ return true;
+ }
+ };
+
+ struct SavegameEntryHeader : Common::Serializable {
+ uint32 signature;
+ SavegameType type;
+ uint32 time;
+ int offset;
+ ChapterIndex chapter;
+ uint32 value;
+ int field_18;
+ int field_1C;
+
+ SavegameEntryHeader() {
+ signature = SAVEGAME_ENTRY_SIGNATURE;
+ type = kSavegameTypeIndex;
+ time = kTimeNone;
+ offset = 0;
+ chapter = kChapterAll;
+ value = 0;
+ field_18 = 0;
+ field_1C = 0;
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(signature);
+ s.syncAsUint32LE(type);
+ s.syncAsUint32LE(time);
+ s.syncAsUint32LE(offset);
+ s.syncAsUint32LE(chapter);
+ s.syncAsUint32LE(value);
+ s.syncAsUint32LE(field_18);
+ s.syncAsUint32LE(field_1C);
+ }
+
+ bool isValid() {
+ if (signature != SAVEGAME_ENTRY_SIGNATURE)
+ return false;
+
+ if (type < kSavegameTypeTime || type > kSavegameTypeTickInterval)
+ return false;
+
+ if (time < kTimeStartGame || time > kTimeCityConstantinople)
+ return false;
+
+ if (offset <= 0 || offset & 15)
+ return false;
+
+ /* No check for < 0, as it cannot happen normaly */
+ if (chapter == 0)
+ return false;
+
+ return true;
+ }
+ };
+
+ SavegameStream *_savegame;
+ Common::Array<SavegameEntryHeader *> _gameHeaders;
+ uint32 _gameTicksLastSavegame;
+
+ // Headers
+ static bool loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *header);
+
+ // Entries
+ void writeEntry(SavegameType type, EntityIndex entity, uint32 val);
+ void readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex);
+
+ SavegameEntryHeader *getEntry(uint32 index);
+
+ // Opening save files
+ static Common::String getFilename(GameId id);
+ static Common::InSaveFile *openForLoading(GameId id);
+ static Common::OutSaveFile *openForSaving(GameId id);
+
+ // Savegame stream
+ void initStream();
+ void loadStream(GameId id);
+ void flushStream(GameId id);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SAVELOAD_H
diff --git a/engines/lastexpress/game/savepoint.cpp b/engines/lastexpress/game/savepoint.cpp
new file mode 100644
index 0000000000..30467f8368
--- /dev/null
+++ b/engines/lastexpress/game/savepoint.cpp
@@ -0,0 +1,296 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/savepoint.h"
+
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+
+
+namespace LastExpress {
+
+SavePoints::SavePoints(LastExpressEngine *engine) : _engine(engine) {
+ for (int i = 0; i < 40; i++)
+ _callbacks[i] = NULL;
+}
+
+SavePoints::~SavePoints() {
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Savepoints
+//////////////////////////////////////////////////////////////////////////
+void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param) {
+ if (_savepoints.size() >= _savePointsMaxSize)
+ return;
+
+ SavePoint point;
+ point.entity1 = entity1;
+ point.action = action;
+ point.entity2 = entity2;
+ point.param.intValue = param;
+
+ _savepoints.push_back(point);
+}
+
+void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) {
+ if (_savepoints.size() >= _savePointsMaxSize)
+ return;
+
+ SavePoint point;
+ point.entity1 = entity1;
+ point.action = action;
+ point.entity2 = entity2;
+ strcpy((char *)&point.param.charValue, param);
+
+ _savepoints.push_back(point);
+}
+
+SavePoint SavePoints::pop() {
+ SavePoint point = _savepoints.front();
+ _savepoints.pop_front();
+ return point;
+}
+
+
+void SavePoints::pushAll(EntityIndex entity, ActionIndex action, uint32 param) {
+ for (uint32 index = 1; index < 40; index++) {
+ if ((EntityIndex)index != entity)
+ push(entity, (EntityIndex)index, action, param);
+ }
+}
+
+// Process all savepoints
+void SavePoints::process() {
+ while (_savepoints.size() > 0 && getFlags()->isGameRunning) {
+ SavePoint savepoint = pop();
+
+ // If this is a data savepoint, update the entity
+ // otherwise, execute the callback
+ if (!updateEntityFromData(savepoint)) {
+
+ // Call requested callback
+ Entity::Callback *callback = getCallback(savepoint.entity1);
+ if (callback && callback->isValid()) {
+ debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s", ENTITY_NAME(savepoint.entity1), ACTION_NAME(savepoint.action), ENTITY_NAME(savepoint.entity2));
+ (*callback)(savepoint);
+ }
+ }
+ }
+}
+
+void SavePoints::reset() {
+ _savepoints.clear();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Data
+//////////////////////////////////////////////////////////////////////////
+void SavePoints::addData(EntityIndex entity, ActionIndex action, uint32 param) {
+ if (_data.size() >= _savePointsMaxSize)
+ return;
+
+ SavePointData data;
+ data.entity1 = entity;
+ data.action = action;
+ data.param = param;
+
+ _data.push_back(data);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Callbacks
+//////////////////////////////////////////////////////////////////////////
+void SavePoints::setCallback(EntityIndex index, Entity::Callback *callback) {
+ if (index >= 40)
+ error("SavePoints::setCallback - attempting to use an invalid entity index. Valid values 0-39, was %d", index);
+
+ if (!callback || !callback->isValid())
+ error("SavePoints::setCallback - attempting to set an invalid callback for entity %s", ENTITY_NAME(index));
+
+ _callbacks[index] = callback;
+}
+
+Entity::Callback *SavePoints::getCallback(EntityIndex index) const {
+ if (index >= 40)
+ error("SavePoints::getCallback - attempting to use an invalid entity index. Valid values 0-39, was %d", index);
+
+ return _callbacks[index];
+}
+
+void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param) const {
+ SavePoint point;
+ point.entity1 = entity1;
+ point.action = action;
+ point.entity2 = entity2;
+ point.param.intValue = param;
+
+ Entity::Callback *callback = getCallback(entity1);
+ if (callback != NULL && callback->isValid()) {
+ debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s, param=%d", ENTITY_NAME(entity1), ACTION_NAME(action), ENTITY_NAME(entity2), param);
+ (*callback)(point);
+ }
+}
+
+void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) const {
+ SavePoint point;
+ point.entity1 = entity1;
+ point.action = action;
+ point.entity2 = entity2;
+ strcpy((char *)&point.param.charValue, param);
+
+ Entity::Callback *callback = getCallback(entity1);
+ if (callback != NULL && callback->isValid()) {
+ debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s, param=%s", ENTITY_NAME(entity1), ACTION_NAME(action), ENTITY_NAME(entity2), param);
+ (*callback)(point);
+ }
+}
+
+void SavePoints::callAndProcess() {
+ SavePoint savepoint; // empty parameters
+
+ // We ignore the kEntityPlayer callback in the list
+ EntityIndex index = kEntityAnna;
+
+ // Call all callbacks with empty parameters
+ bool isRunning = getFlags()->isGameRunning;
+ while (isRunning) {
+
+ Entity::Callback *callback = getCallback(index);
+ if (callback != NULL && callback->isValid()) {
+ (*callback)(savepoint);
+ isRunning = getFlags()->isGameRunning;
+ }
+
+ index = (EntityIndex)(index + 1);
+
+ // Process all savepoints when done
+ if (index >= 40) {
+ if (isRunning)
+ process();
+
+ return;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Misc
+//////////////////////////////////////////////////////////////////////////
+bool SavePoints::updateEntityFromData(const SavePoint &savepoint) {
+ for (int i = 0; i < (int)_data.size(); i++) {
+
+ // Not a data savepoint!
+ if (!_data[i].entity1)
+ return false;
+
+ // Found our data!
+ if (_data[i].entity1 == savepoint.entity1 && _data[i].action == savepoint.action) {
+ debugC(8, kLastExpressDebugLogic, "Update entity from data: entity1=%s, action=%s, param=%d", ENTITY_NAME(_data[i].entity1), ACTION_NAME(_data[i].action), _data[i].param);
+
+ // the SavePoint param value is the index of the entity call parameter to update
+ getEntities()->get(_data[i].entity1)->getParamData()->updateParameters(_data[i].param);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Serializable
+//////////////////////////////////////////////////////////////////////////
+void SavePoints::saveLoadWithSerializer(Common::Serializer &s) {
+
+ // Serialize savepoint data
+ uint32 dataSize = (s.isLoading() ? _savePointsMaxSize : _data.size());
+ for (uint i = 0; i < dataSize; i++) {
+ if (s.isLoading()) {
+ SavePointData data;
+ _data.push_back(data);
+ }
+
+ s.syncAsUint32LE(_data[i].entity1);
+ s.syncAsUint32LE(_data[i].action);
+ s.syncAsUint32LE(_data[i].entity2);
+ s.syncAsUint32LE(_data[i].param);
+ }
+
+ // Skip uninitialized data if any
+ s.skip((_savePointsMaxSize - dataSize) * 16);
+
+ // Number of savepoints
+ uint32 numSavepoints = _savepoints.size();
+ s.syncAsUint32LE(numSavepoints);
+
+ // Savepoints
+ if (s.isLoading()) {
+ for (uint i = 0; i < numSavepoints; i++) {
+ SavePoint point;
+ s.syncAsUint32LE(point.entity1);
+ s.syncAsUint32LE(point.action);
+ s.syncAsUint32LE(point.entity2);
+ s.syncAsUint32LE(point.param.intValue);
+
+ _savepoints.push_back(point);
+
+ if (_savepoints.size() >= _savePointsMaxSize)
+ break;
+ }
+ } else {
+ for (Common::List<SavePoint>::iterator it = _savepoints.begin(); it != _savepoints.end(); ++it) {
+ s.syncAsUint32LE((*it).entity1);
+ s.syncAsUint32LE((*it).action);
+ s.syncAsUint32LE((*it).entity2);
+ s.syncAsUint32LE((*it).param.intValue);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// toString
+//////////////////////////////////////////////////////////////////////////
+Common::String SavePoints::toString() {
+ Common::String ret = "";
+
+ ret += "Savepoint Data\n";
+ for (uint i = 0; i < _data.size(); i++)
+ ret += _data[i].toString() + "\n";
+
+ ret += "\nSavepoints\n";
+ for (Common::List<SavePoint>::iterator it = _savepoints.begin(); it != _savepoints.end(); ++it)
+ ret += (*it).toString() + "\n";
+
+ return ret;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/savepoint.h b/engines/lastexpress/game/savepoint.h
new file mode 100644
index 0000000000..ca507ab8ab
--- /dev/null
+++ b/engines/lastexpress/game/savepoint.h
@@ -0,0 +1,151 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SAVEPOINT_H
+#define LASTEXPRESS_SAVEPOINT_H
+
+#include "lastexpress/entities/entity.h"
+
+#include "lastexpress/helpers.h"
+
+#include "common/array.h"
+#include "common/list.h"
+#include "common/serializer.h"
+
+/*
+ Savepoint format
+ ----------------
+
+ Save point: max: 127 - FIFO list (ie. goes back and overwrites first save point when full)
+ uint32 {4} - Entity 1
+ uint32 {4} - Action
+ uint32 {4} - Entity 2
+ uint32 {4} - Parameter
+
+ Save point Data
+ uint32 {4} - Entity 1
+ uint32 {4} - Action
+ uint32 {4} - Entity 2
+ uint32 {4} - function pointer to ??
+
+*/
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+struct SavePoint {
+ EntityIndex entity1;
+ ActionIndex action;
+ EntityIndex entity2;
+ union {
+ uint32 intValue;
+ char charValue[5];
+ } param;
+
+ SavePoint() {
+ entity1 = kEntityPlayer;
+ action = kActionNone;
+ entity2 = kEntityPlayer;
+ param.intValue = 0;
+ }
+
+ Common::String toString() {
+ return Common::String::format("{ %s - %d - %s - %s }", ENTITY_NAME(entity1), action, ENTITY_NAME(entity2), param.charValue);
+ }
+};
+
+class SavePoints : Common::Serializable {
+private:
+ typedef Common::Functor1<const SavePoint&, void> Callback;
+
+public:
+
+ struct SavePointData {
+ EntityIndex entity1;
+ ActionIndex action;
+ EntityIndex entity2;
+ uint32 param;
+
+ SavePointData() {
+ entity1 = kEntityPlayer;
+ action = kActionNone;
+ entity2 = kEntityPlayer;
+ param = 0;
+ }
+
+ Common::String toString() {
+ return Common::String::format(" { %s - %d - %s - %d }", ENTITY_NAME(entity1), action, ENTITY_NAME(entity2), param);
+ }
+ };
+
+ SavePoints(LastExpressEngine *engine);
+ ~SavePoints();
+
+ // Savepoints
+ void push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param = 0);
+ void push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param);
+ void pushAll(EntityIndex entity, ActionIndex action, uint32 param = 0);
+ void process();
+ void reset();
+
+ // Data
+ void addData(EntityIndex entity, ActionIndex action, uint32 param);
+
+ // Callbacks
+ void setCallback(EntityIndex index, Entity::Callback *callback);
+ Callback *getCallback(EntityIndex entity) const;
+ void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param = 0) const;
+ void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) const;
+ void callAndProcess();
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &s);
+
+ /**
+ * Convert this object into a string representation.
+ *
+ * @return A string representation of this object.
+ */
+ Common::String toString();
+
+ uint32 count() { return _savepoints.size(); }
+
+private:
+ static const uint32 _savePointsMaxSize = 128;
+
+ LastExpressEngine *_engine;
+
+ Common::List<SavePoint> _savepoints; ///< could be a queue, but we need to be able to iterate on the items
+ Common::Array<SavePointData> _data;
+ Callback *_callbacks[40];
+
+ SavePoint pop();
+ bool updateEntityFromData(const SavePoint &point);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SAVEPOINT_H
diff --git a/engines/lastexpress/game/scenes.cpp b/engines/lastexpress/game/scenes.cpp
new file mode 100644
index 0000000000..cf50d3e425
--- /dev/null
+++ b/engines/lastexpress/game/scenes.cpp
@@ -0,0 +1,1195 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/scenes.h"
+
+#include "lastexpress/data/scene.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/beetle.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+SceneManager::SceneManager(LastExpressEngine *engine) : _engine(engine),
+ _flagNoEntity(false), _flagDrawEntities(false), _flagDrawSequences(false), _flagCoordinates(false),
+ _coords(0, 0, 480, 640), _clockHours(NULL), _clockMinutes(NULL) {
+ _sceneLoader = new SceneLoader();
+}
+
+SceneManager::~SceneManager() {
+ delete _sceneLoader;
+
+ // Clear frames
+ for (Common::List<SequenceFrame *>::iterator door = _doors.begin(); door != _doors.end(); ++door)
+ SAFE_DELETE(*door);
+
+ _doors.clear();
+
+ SAFE_DELETE(_clockHours);
+ SAFE_DELETE(_clockMinutes);
+
+ // Zero-out passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Scene cache
+//////////////////////////////////////////////////////////////////////////
+void SceneManager::loadSceneDataFile(ArchiveIndex archive) {
+ // Demo only has CD2TRAIN.DAT file
+ if (_engine->isDemo())
+ archive = kArchiveCd2;
+
+ switch(archive) {
+ case kArchiveCd1:
+ case kArchiveCd2:
+ case kArchiveCd3:
+ if (!_sceneLoader->load(getArchive(Common::String::format("CD%iTRAIN.DAT", archive))))
+ error("SceneManager::loadSceneDataFile: cannot load data file CD%iTRAIN.DAT", archive);
+ break;
+
+ default:
+ case kArchiveAll:
+ error("SceneManager::loadSceneDataFile: Invalid archive index (must be [1-3], was %d", archive);
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Scene loading
+//////////////////////////////////////////////////////////////////////////
+void SceneManager::loadScene(SceneIndex index) {
+ getFlags()->flag_0 = false;
+ getFlags()->flag_4 = true;
+
+ if (getState()->sceneUseBackup) {
+ Scene *scene = getScenes()->get(index);
+
+ if (scene->param3 != 255) {
+ getState()->sceneUseBackup = false;
+ getState()->sceneBackup2 = kSceneNone;
+ }
+ }
+
+ // Save shouldRedraw state and redraw if necessary
+ bool shouldRedraw = getFlags()->shouldRedraw;
+ if (shouldRedraw) {
+ shouldRedraw = false;
+ // TODO check whether we need to do that here
+ askForRedraw();
+ //redrawScreen();
+ }
+
+ // Set the scene
+ setScene(index);
+
+ // TODO Events method call (might be a low level graphic that we don't need)
+
+ if (getFlags()->isGameRunning && getFlags()->shouldDrawEggOrHourGlass)
+ getInventory()->drawEgg();
+
+ getFlags()->shouldRedraw = shouldRedraw;
+
+ getLogic()->updateCursor();
+}
+
+void SceneManager::loadSceneFromObject(ObjectIndex object, bool alternate) {
+ switch (object) {
+ default:
+ break;
+
+ case kObjectCompartment1:
+ case kObjectCompartment2:
+ case kObjectCompartment3:
+ case kObjectCompartment4:
+ case kObjectCompartment5:
+ case kObjectCompartment6:
+ case kObjectCompartment7:
+ if (alternate)
+ loadSceneFromPosition(kCarGreenSleeping, (Position)(17 - (object - 1) * 2));
+ else
+ loadSceneFromPosition(kCarGreenSleeping, (Position)(38 - (object - 1) * 2));
+ break;
+
+ case kObjectCompartmentA:
+ case kObjectCompartmentB:
+ case kObjectCompartmentC:
+ case kObjectCompartmentD:
+ case kObjectCompartmentE:
+ case kObjectCompartmentF:
+ case kObjectCompartmentG:
+ if (alternate)
+ loadSceneFromPosition(kCarGreenSleeping, (Position)(17 - (object - 32) * 2));
+ else
+ loadSceneFromPosition(kCarRedSleeping, (Position)(38 - (object - 32) * 2));
+ break;
+
+ case kObjectCompartment8:
+ case kObjectCompartmentH:
+ loadSceneFromPosition(object == kObjectCompartment8 ? kCarGreenSleeping : kCarRedSleeping, alternate ? 3 : 25);
+ break;
+ }
+}
+
+void SceneManager::loadSceneFromItem(InventoryItem item) {
+ if (item >= kPortraitOriginal)
+ return;
+
+ // Get the scene index from the item
+ SceneIndex index = getInventory()->get(item)->scene;
+ if (!index)
+ return;
+
+ if (!getState()->sceneUseBackup) {
+ getState()->sceneUseBackup = true;
+ getState()->sceneBackup = getState()->scene;
+ }
+
+ loadScene(index);
+}
+
+void SceneManager::loadSceneFromPosition(CarIndex car, Position position, int param3) {
+ loadScene(getSceneIndexFromPosition(car, position, param3));
+}
+
+void SceneManager::loadSceneFromItemPosition(InventoryItem item) {
+ if (item >= kPortraitOriginal)
+ return;
+
+ // Check item location
+ Inventory::InventoryEntry *entry = getInventory()->get(item);
+ if (!entry->location)
+ return;
+
+ // Reset location
+ entry->location = kObjectLocationNone;
+
+ if (item != kItem3 && item != kItem5 && item != kItem7)
+ return;
+
+ // Set field value
+ CarIndex car = kCarRestaurant;
+ if (item == kItem5) car = kCarRedSleeping;
+ if (item == kItem7) car = kCarGreenSleeping;
+
+ if (!getEntities()->isInsideTrainCar(kEntityPlayer, car))
+ return;
+
+ if (getFlags()->flag_0)
+ return;
+
+ // Get current scene position
+ Scene *scene = getScenes()->get(getState()->scene);
+ Position position = scene->position;
+
+ if (getState()->sceneUseBackup) {
+ Scene *sceneBackup = getScenes()->get(getState()->sceneBackup);
+ position = sceneBackup->position;
+ }
+
+ // Checks are different for each item
+ if ((item == kItem3 && position == 56)
+ || (item == kItem5 && (position >= 23 && position <= 32))
+ || (item == kItem7 && (position == 1 || (position >= 22 && position <= 33)))) {
+ if (getState()->sceneUseBackup)
+ getState()->sceneBackup = getSceneIndexFromPosition(car, position);
+ else
+ loadSceneFromPosition(car, position);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Scene drawing & processing
+//////////////////////////////////////////////////////////////////////////
+void SceneManager::setScene(SceneIndex index) {
+ _flagNoEntity = false;
+
+ if (_flagDrawEntities) {
+ // TODO Setup screen size (0, 80)x(480x480) (is it necessary for our animations?)
+ drawScene(index);
+ _flagNoEntity = true;
+ } else {
+ _flagDrawEntities = true;
+ drawScene(index);
+ _flagDrawEntities = false;
+ }
+}
+
+void SceneManager::drawScene(SceneIndex index) {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Preprocess
+ preProcessScene(&index);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Draw background
+ debugC(9, kLastExpressDebugScenes, "== Drawing scene: %d ==", index);
+
+ // Update scene
+ _engine->getGraphicsManager()->draw(get(index), GraphicsManager::kBackgroundC, true);
+ getState()->scene = index;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Update entities
+ Scene *scene = (getState()->sceneUseBackup ? get(getState()->sceneBackup) : get(index));
+
+ getEntityData(kEntityPlayer)->entityPosition = scene->entityPosition;
+ getEntityData(kEntityPlayer)->car = scene->car;
+
+ getFlags()->flag_3 = true;
+
+ if (getFlags()->isGameRunning) {
+ getSavePoints()->pushAll(kEntityPlayer, kActionDrawScene);
+ getSavePoints()->process();
+
+ if (_flagNoEntity)
+ return;
+
+ getEntities()->updateFields();
+ getEntities()->updateSequences();
+ getEntities()->updateCallbacks();
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Show the scene
+ askForRedraw();
+ redrawScreen();
+
+ ////////////////////////////////////////////////////////////
+ // Post process scene
+ postProcessScene();
+}
+
+void SceneManager::processScene() {
+ if (!getState()->sceneUseBackup) {
+ loadScene(getState()->scene);
+ return;
+ }
+
+ getState()->sceneUseBackup = false;
+
+ // Select item if needed
+ InventoryItem item = getInventory()->getFirstExaminableItem();
+ if (item && getInventory()->getSelectedItem() == item)
+ getInventory()->selectItem(item);
+
+ Scene *backup = getScenes()->get(getState()->sceneBackup);
+
+ if (getEntities()->getPosition(backup->car, backup->position))
+ loadScene(processIndex(getState()->sceneBackup));
+ else
+ loadScene(getState()->sceneBackup);
+}
+
+LastExpress::SceneIndex SceneManager::processIndex(SceneIndex index) {
+ Scene *scene = get(index);
+ CarIndex car = scene->car;
+
+ switch (car) {
+ default:
+ break;
+
+ case kCarRedSleeping:
+ if (checkPosition(index, kCheckPositionLookingAtDoors)) {
+ Position position = (Position)(scene->position + (checkPosition(kSceneNone, kCheckPositionLookingUp) ? -1 : 1));
+
+ if (position == 4)
+ position = 3;
+
+ if (position == 24)
+ position = 25;
+
+ if (getEntities()->getPosition(car, position))
+ return index;
+ else
+ return getSceneIndexFromPosition(car, position);
+ } else {
+ switch (scene->position) {
+ default:
+ break;
+
+ case 41:
+ case 51:
+ if (!getEntities()->getPosition(car, 39))
+ return getSceneIndexFromPosition(car, 39);
+ // Fallback to next case
+
+ case 42:
+ case 52:
+ if (!getEntities()->getPosition(car, 14))
+ return getSceneIndexFromPosition(car, 14);
+ // Fallback to next case
+
+ case 43:
+ case 53:
+ if (!getEntities()->getPosition(car, 35))
+ return getSceneIndexFromPosition(car, 35);
+ // Fallback to next case
+
+ case 44:
+ case 54:
+ if (!getEntities()->getPosition(car, 10))
+ return getSceneIndexFromPosition(car, 10);
+ // Fallback to next case
+
+ case 45:
+ case 55:
+ if (!getEntities()->getPosition(car, 32))
+ return getSceneIndexFromPosition(car, 32);
+ // Fallback to next case
+
+ case 46:
+ case 56:
+ if (!getEntities()->getPosition(car, 7))
+ return getSceneIndexFromPosition(car, 7);
+ // Fallback to next case
+
+ case 47:
+ case 57:
+ if (!getEntities()->getPosition(car, 27))
+ return getSceneIndexFromPosition(car, 27);
+ // Fallback to next case
+
+ case 48:
+ case 58:
+ if (!getEntities()->getPosition(car, 2))
+ return getSceneIndexFromPosition(car, 2);
+ break;
+ }
+ }
+ break;
+
+ case kCarRestaurant:
+ switch (scene->position) {
+ default:
+ break;
+
+ case 52:
+ case 53:
+ case 54:
+ if (!getEntities()->getPosition(car, 51))
+ return getSceneIndexFromPosition(car, 51);
+ // Fallback to next case
+
+ case 50:
+ case 56:
+ case 57:
+ case 58:
+ if (!getEntities()->getPosition(car, 55))
+ return getSceneIndexFromPosition(car, 55);
+ // Fallback to next case
+
+ case 59:
+ if (!getEntities()->getPosition(car, 60))
+ return getSceneIndexFromPosition(car, 60);
+ // Fallback to next case
+
+ case 60:
+ if (!getEntities()->getPosition(car, 59))
+ return getSceneIndexFromPosition(car, 59);
+ // Fallback to next case
+
+ case 62:
+ case 63:
+ case 64:
+ if (!getEntities()->getPosition(car, 61))
+ return getSceneIndexFromPosition(car, 61);
+ // Fallback to next case
+
+ case 66:
+ case 67:
+ case 68:
+ if (!getEntities()->getPosition(car, 65))
+ return getSceneIndexFromPosition(car, 65);
+ // Fallback to next case
+
+ case 69:
+ case 71:
+ if (!getEntities()->getPosition(car, 70))
+ return getSceneIndexFromPosition(car, 70);
+ break;
+ }
+ break;
+ }
+
+ return index;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Checks
+//////////////////////////////////////////////////////////////////////////
+bool SceneManager::checkPosition(SceneIndex index, CheckPositionType type) const {
+ Scene *scene = getScenes()->get((index ? index : getState()->scene));
+
+ CarIndex car = (CarIndex)scene->car;
+ Position position = scene->position;
+
+ bool isInSleepingCar = (car == kCarGreenSleeping || car == kCarRedSleeping);
+
+ switch (type) {
+ default:
+ error("SceneManager::checkPosition: Invalid position type: %d", type);
+
+ case kCheckPositionLookingUp:
+ return isInSleepingCar && (position >= 1 && position <= 19);
+
+ case kCheckPositionLookingDown:
+ return isInSleepingCar && (position >= 21 && position <= 40);
+
+ case kCheckPositionLookingAtDoors:
+ return isInSleepingCar && ((position >= 2 && position <= 17) || (position >= 23 && position <= 39));
+
+ case kCheckPositionLookingAtClock:
+ return car == kCarRestaurant && position == 81;
+ }
+}
+
+bool SceneManager::checkCurrentPosition(bool doCheckOtherCars) const {
+ Scene *scene = getScenes()->get(getState()->scene);
+
+ Position position = scene->position;
+ CarIndex car = (CarIndex)scene->car;
+
+ if (!doCheckOtherCars)
+ return (car == kCarGreenSleeping || car == kCarRedSleeping)
+ && ((position >= 41 && position <= 48) || (position >= 51 && position <= 58));
+
+ if (position == 99)
+ return true;
+
+ switch (car){
+ default:
+ break;
+
+ case kCarGreenSleeping:
+ case kCarRedSleeping:
+ case kCarLocomotive:
+ if ((position >= 1 && position <= 18) || (position >= 22 && position <= 40))
+ return true;
+ break;
+
+ case kCarRestaurant:
+ if (position >= 73 && position <= 80)
+ return true;
+
+ if (position == 10 || position == 11)
+ return true;
+
+ break;
+
+ case kCarBaggage:
+ switch (position) {
+ default:
+ break;
+
+ case 10:
+ case 11:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ case 90:
+ case 91:
+ return true;
+ }
+ break;
+
+ case kCarCoalTender:
+ if (position == 2 || position == 10 || position == 11)
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Train
+//////////////////////////////////////////////////////////////////////////
+void SceneManager::updateDoorsAndClock() {
+ // Clear all sequences from the list
+ for (Common::List<SequenceFrame *>::iterator door = _doors.begin(); door != _doors.end(); ++door) {
+ removeFromQueue(*door);
+ setCoordinates(*door);
+ SAFE_DELETE(*door);
+ }
+
+ // Cleanup doors sequences
+ _doors.clear();
+
+ if (_clockHours) {
+ removeFromQueue(_clockHours);
+ setCoordinates(_clockHours);
+ SAFE_DELETE(_clockHours);
+ }
+
+ if (_clockMinutes) {
+ removeFromQueue(_clockMinutes);
+ setCoordinates(_clockMinutes);
+ SAFE_DELETE(_clockMinutes);
+ }
+
+ // Queue doors sequences for display
+ if (checkPosition(kSceneNone, kCheckPositionLookingAtDoors)) {
+
+ ObjectIndex firstIndex = kObjectNone;
+
+ // Init objectIndex (or exit if not in one of the two compartment cars
+ if (getEntityData(kEntityPlayer)->car == kCarGreenSleeping)
+ firstIndex = kObjectCompartment1;
+ else if (getEntityData(kEntityPlayer)->car == kCarRedSleeping)
+ firstIndex = kObjectCompartmentA;
+ else
+ return;
+
+ // Iterate over each door
+ for (ObjectIndex index = firstIndex; index < (ObjectIndex)(firstIndex + 8); index = (ObjectIndex)(index + 1)) {
+
+ // Doors is not open, nothing to do
+ if (getObjects()->get(index).location != kObjectLocation2)
+ continue;
+
+ // Load door sequence
+ Scene *scene = getScenes()->get(getState()->scene);
+ Common::String name = Common::String::format("633X%c-%02d.seq", (index - firstIndex) + 65, scene->position);
+ Sequence *sequence = loadSequence1(name, 255);
+
+ // If the sequence doesn't exists, skip
+ if (!sequence || !sequence->isLoaded())
+ continue;
+
+ // Adjust frame data and store in frame list
+ SequenceFrame *frame = new SequenceFrame(sequence, 0, true);
+ frame->getInfo()->location = (checkPosition(kSceneNone, kCheckPositionLookingUp) ? (firstIndex - index) - 1 : (index - firstIndex) - 8);
+
+ _doors.push_back(frame);
+
+ // Add frame to list
+ addToQueue(frame);
+ }
+ }
+
+ // Queue clock sequences for display
+ if (checkPosition(kSceneNone, kCheckPositionLookingAtClock)) {
+ // Only used in scene 349 to show the hands on the clock
+
+ Sequence *sequenceHours = loadSequence1("SCLKH-81.seq", 255);
+ Sequence *sequenceMinutes = loadSequence1("SCLKM-81.seq", 255);
+
+ // Compute hours and minutes indexes
+ uint16 hoursIndex = (uint)getState()->time % 1296000 % 54000 / 900;
+
+ uint hours = ((uint)getState()->time % 1296000) / 54000;
+ if (hours >= 12)
+ hours -= 12;
+
+ uint16 minutesIndex = (uint16)(5 * hours + hoursIndex / 12);
+
+ // Adjust z-order and store sequences to list
+ _clockHours = new SequenceFrame(sequenceHours, hoursIndex, true);
+ _clockHours->getInfo()->location = 65534;
+
+ _clockMinutes = new SequenceFrame(sequenceMinutes, minutesIndex, true);
+ _clockMinutes->getInfo()->location = 65535;
+
+ addToQueue(_clockHours);
+ addToQueue(_clockMinutes);
+ }
+}
+
+void SceneManager::resetDoorsAndClock() {
+ for (Common::List<SequenceFrame *>::iterator door = _doors.begin(); door != _doors.end(); ++door)
+ SAFE_DELETE(*door);
+
+ _doors.clear();
+
+ SAFE_DELETE(_clockHours);
+ SAFE_DELETE(_clockMinutes);
+
+ // Remove the beetle sequences too if needed
+ getBeetle()->unload();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Sequence list
+//////////////////////////////////////////////////////////////////////////
+void SceneManager::drawFrames(bool refreshScreen) {
+ if (!_flagDrawSequences)
+ return;
+
+ // TODO handle flag coordinates
+
+ clearBg(GraphicsManager::kBackgroundOverlay);
+
+ for (Common::List<SequenceFrame *>::iterator i = _queue.begin(); i != _queue.end(); ++i)
+ _engine->getGraphicsManager()->draw(*i, GraphicsManager::kBackgroundOverlay);
+
+ if (refreshScreen) {
+ askForRedraw();
+ //redrawScreen();
+
+ _flagDrawSequences = false;
+ }
+}
+
+void SceneManager::addToQueue(SequenceFrame * const frame) {
+ if (!frame)
+ return;
+
+ // First check that the frame is not already in the queue
+ for (Common::List<SequenceFrame *>::iterator i = _queue.begin(); i != _queue.end(); ++i) {
+ if (frame->equal(*i))
+ return;
+ }
+
+ debugC(8, kLastExpressDebugGraphics, "Adding frame: %s / %d", frame->getName().c_str(), frame->getFrame());
+
+ // Set flag
+ _flagDrawSequences = true;
+
+ // Queue empty: just insert the frame
+ if (_queue.empty()) {
+ _queue.push_back(frame);
+ return;
+ }
+
+ // Frame is closer: insert in first place
+ if (frame->getInfo()->location > _queue.front()->getInfo()->location) {
+ _queue.push_front(frame);
+ return;
+ }
+
+ // Insert the frame in the queue based on location
+ for (Common::List<SequenceFrame *>::iterator i = _queue.begin(); i != _queue.end(); ++i) {
+ if (frame->getInfo()->location > (*i)->getInfo()->location) {
+ _queue.insert(i, frame);
+ return;
+ }
+ }
+
+ // We are the last frame in location order, insert at the back of the queue
+ _queue.push_back(frame);
+}
+
+void SceneManager::removeFromQueue(SequenceFrame *frame) {
+ if (!frame)
+ return;
+
+ debugC(8, kLastExpressDebugGraphics, "Removing frame: %s / %d", frame->getName().c_str(), frame->getFrame());
+
+ // Check that the frame is in the queue and remove it
+ for (Common::List<SequenceFrame *>::iterator i = _queue.begin(); i != _queue.end(); ++i) {
+ if (frame->equal(*i)) {
+ _queue.erase(i);
+ _flagDrawSequences = true;
+ break;
+ }
+ }
+}
+
+void SceneManager::removeAndRedraw(SequenceFrame **frame, bool doRedraw) {
+ if (!frame)
+ return;
+
+ removeFromQueue(*frame);
+
+ if (doRedraw)
+ drawFrames(true);
+
+ SAFE_DELETE(*frame);
+}
+
+void SceneManager::resetQueue() {
+ _flagDrawSequences = true;
+
+ // The original engine only deletes decompressed data, not the "sequences" since they are just pointers to a memory pool
+ _queue.clear();
+}
+
+void SceneManager::setCoordinates(SequenceFrame *frame) {
+
+ if (!frame || frame->getInfo()->subType == 3)
+ return;
+
+ _flagCoordinates = true;
+
+ if (_coords.right > (int)frame->getInfo()->xPos1)
+ _coords.right = (int16)frame->getInfo()->xPos1;
+
+ if (_coords.bottom > (int)frame->getInfo()->yPos1)
+ _coords.bottom = (int16)frame->getInfo()->yPos1;
+
+ if (_coords.left < (int)frame->getInfo()->xPos2)
+ _coords.left = (int16)frame->getInfo()->xPos2;
+
+ if (_coords.top < (int)frame->getInfo()->yPos2)
+ _coords.top = (int16)frame->getInfo()->yPos2;
+}
+
+void SceneManager::resetCoordinates() {
+ _coords.top = 0;
+ _coords.left = 0;
+ _coords.bottom = 480;
+ _coords.right = 640;
+
+ _flagCoordinates = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Helpers
+//////////////////////////////////////////////////////////////////////////
+SceneIndex SceneManager::getSceneIndexFromPosition(CarIndex car, Position position, int param3) {
+ // Probably can't happen (can we be called during cd-swap?)
+ if (_sceneLoader->count() <= 1)
+ return getState()->scene;
+
+ SceneIndex index = kSceneMenu;
+
+ Scene *firstScene = getScenes()->get(index);
+
+ while (firstScene->car != car
+ || firstScene->position != position
+ || ((param3 != -1 || firstScene->param3) && firstScene->param3 != param3 && firstScene->type != Scene::kTypeItem3)) {
+
+ // Increment index and look at the next scene
+ index = (SceneIndex)(index + 1);
+
+ if (index >= _sceneLoader->count())
+ return getState()->scene;
+
+ // Load the next scene
+ firstScene = getScenes()->get(index);
+ }
+
+ // Process index if necessary
+ Scene *scene = getScenes()->get(index);
+ if (getEntities()->getPosition(scene->car, scene->position))
+ return processIndex(index);
+
+ return index;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Scene processing
+//////////////////////////////////////////////////////////////////////////
+
+// Process hotspots
+// - if it returns kSceneInvalid, the hotspot scene has not been modified
+// - if it returns kSceneNone, it has been modified
+//
+// Note: we use the original hotspot scene to pre-process again
+#define PROCESS_HOTSPOT_SCENE(hotspot, index) { \
+ SceneIndex processedScene = getAction()->processHotspot(*hotspot); \
+ SceneIndex testScene = (processedScene == kSceneInvalid) ? (hotspot)->scene : processedScene; \
+ if (testScene) { \
+ *index = (hotspot)->scene; \
+ preProcessScene(index); \
+ } \
+}
+
+void SceneManager::preProcessScene(SceneIndex *index) {
+
+ // Check index validity
+ if (*index == 0 || *index > 2500)
+ *index = kSceneMenu;
+
+ Scene *scene = getScenes()->get(*index);
+
+ switch (scene->type) {
+ case Scene::kTypeObject: {
+ ObjectIndex object = (ObjectIndex)scene->param1;
+
+ if (object >= kObjectMax)
+ break;
+
+ if (getObjects()->get(object).location == kObjectLocationNone)
+ break;
+
+ for (Common::Array<SceneHotspot *>::iterator it = scene->getHotspots()->begin(); it != scene->getHotspots()->end(); ++it) {
+ if (getObjects()->get(object).location != (*it)->location)
+ continue;
+
+ PROCESS_HOTSPOT_SCENE(*it, index);
+ break;
+ }
+ break;
+ }
+
+ case Scene::kTypeItem: {
+ InventoryItem item = (InventoryItem)scene->param1;
+
+ if (item >= kPortraitOriginal)
+ break;
+
+ if (getInventory()->get(item)->location == kObjectLocationNone)
+ break;
+
+ for (Common::Array<SceneHotspot *>::iterator it = scene->getHotspots()->begin(); it != scene->getHotspots()->end(); ++it) {
+ if (getInventory()->get(item)->location != (*it)->location)
+ continue;
+
+ PROCESS_HOTSPOT_SCENE(*it, index);
+ break;
+ }
+ break;
+ }
+
+ case Scene::kTypeItem2: {
+ InventoryItem item1 = (InventoryItem)scene->param1;
+ InventoryItem item2 = (InventoryItem)scene->param2;
+
+ if (item1 >= kPortraitOriginal || item2 >= kPortraitOriginal)
+ break;
+
+ int location = kObjectLocationNone;
+
+ if (getInventory()->get(item1)->location != kObjectLocationNone)
+ location = kObjectLocation1;
+
+ if (getInventory()->get(item2)->location != kObjectLocationNone)
+ location |= kObjectLocation2;
+
+ if (!location)
+ break;
+
+ for (Common::Array<SceneHotspot *>::iterator it = scene->getHotspots()->begin(); it != scene->getHotspots()->end(); ++it) {
+ if (location != (*it)->location)
+ continue;
+
+ if (getInventory()->get(item1)->location != (*it)->param1)
+ continue;
+
+ if (getInventory()->get(item2)->location != (*it)->param2)
+ continue;
+
+ PROCESS_HOTSPOT_SCENE(*it, index);
+ break;
+ }
+ break;
+ }
+
+ case Scene::kTypeObjectItem: {
+ ObjectIndex object = (ObjectIndex)scene->param1;
+ InventoryItem item = (InventoryItem)scene->param2;
+
+ if (object >= kObjectMax)
+ break;
+
+ if (item >= kPortraitOriginal)
+ break;
+
+ int location = kObjectLocationNone;
+
+ if (getObjects()->get(object).location == kObjectLocation2)
+ location = kObjectLocation1;
+
+ if (getInventory()->get(item)->location != kObjectLocationNone)
+ location |= kObjectLocation2;
+
+ if (!location)
+ break;
+
+ for (Common::Array<SceneHotspot *>::iterator it = scene->getHotspots()->begin(); it != scene->getHotspots()->end(); ++it) {
+ if (location != (*it)->location)
+ continue;
+
+ if (getObjects()->get(object).location != (*it)->param1)
+ continue;
+
+ if (getInventory()->get(item)->location != (*it)->param2)
+ continue;
+
+ PROCESS_HOTSPOT_SCENE(*it, index);
+ break;
+ }
+ break;
+ }
+
+ case Scene::kTypeItem3: {
+ InventoryItem item1 = (InventoryItem)scene->param1;
+ InventoryItem item2 = (InventoryItem)scene->param2;
+ InventoryItem item3 = (InventoryItem)scene->param3;
+
+ if (item1 >= kPortraitOriginal || item2 >= kPortraitOriginal || item3 >= kPortraitOriginal)
+ break;
+
+ int location = kObjectLocationNone;
+
+ if (getInventory()->get(item1)->location != kObjectLocationNone)
+ location = kObjectLocation1;
+
+ if (getInventory()->get(item2)->location != kObjectLocationNone)
+ location |= kObjectLocation2;
+
+ if (getInventory()->get(item3)->location != kObjectLocationNone)
+ location |= kObjectLocation4;
+
+ if (!location)
+ break;
+
+ for (Common::Array<SceneHotspot *>::iterator it = scene->getHotspots()->begin(); it != scene->getHotspots()->end(); ++it) {
+ if (location != (*it)->location)
+ continue;
+
+ if (getInventory()->get(item1)->location != (*it)->param1)
+ continue;
+
+ if (getInventory()->get(item2)->location != (*it)->param2)
+ continue;
+
+ if (getInventory()->get(item3)->location != (*it)->param3)
+ continue;
+
+ PROCESS_HOTSPOT_SCENE(*it, index);
+ break;
+ }
+ break;
+ }
+
+ case Scene::kTypeObjectLocation2: {
+ ObjectIndex object = (ObjectIndex)scene->param1;
+
+ if (object >= kObjectMax)
+ break;
+
+ bool found = false;
+ for (Common::Array<SceneHotspot *>::iterator it = scene->getHotspots()->begin(); it != scene->getHotspots()->end(); ++it) {
+ if (getObjects()->get(object).location2 != (*it)->location)
+ continue;
+
+ PROCESS_HOTSPOT_SCENE(*it, index);
+ found = true;
+ break;
+ }
+
+ // If we haven't found a proper hotspot, use the first hotspot from the current scene
+ if (!found) {
+ Scene *sceneHotspot = getScenes()->get(*index);
+ SceneHotspot *hotspot = sceneHotspot->getHotspot();
+
+ PROCESS_HOTSPOT_SCENE(hotspot, index);
+ }
+ break;
+ }
+
+ case Scene::kTypeCompartments:
+ case Scene::kTypeCompartmentsItem:
+ if (scene->param1 >= 16)
+ break;
+
+ if (getEntities()->getCompartments(scene->param1) || getEntities()->getCompartments1(scene->param1)) {
+
+ Scene *currentScene = getScenes()->get(getState()->scene);
+
+ if ((checkPosition(getState()->scene, kCheckPositionLookingUp) && checkPosition(*index, kCheckPositionLookingUp) && currentScene->entityPosition < scene->entityPosition)
+ || (checkPosition(getState()->scene, kCheckPositionLookingDown) && checkPosition(*index, kCheckPositionLookingDown) && currentScene->entityPosition > scene->entityPosition)) {
+
+ if (State::getPowerOfTwo((uint32)getEntities()->getCompartments(scene->param1)) != 30
+ && State::getPowerOfTwo((uint32)getEntities()->getCompartments1(scene->param1)) != 30 )
+ getSound()->playSound(kEntityPlayer, "CAT1126A");
+
+ *index = scene->getHotspot()->scene;
+ } else {
+ *index = scene->getHotspot(1)->scene;
+ }
+
+ preProcessScene(index);
+ } else {
+ // Stop processing here for kTypeCompartments
+ if (scene->type == Scene::kTypeCompartments)
+ break;
+
+ InventoryItem item = (InventoryItem)scene->param2;
+ if (item >= kPortraitOriginal)
+ break;
+
+ if (getInventory()->get(item)->location == kObjectLocationNone)
+ break;
+
+ for (Common::Array<SceneHotspot *>::iterator it = scene->getHotspots()->begin(); it != scene->getHotspots()->end(); ++it) {
+ if (getInventory()->get(item)->location != (*it)->location)
+ continue;
+
+ PROCESS_HOTSPOT_SCENE(*it, index);
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Sound processing
+ Scene *newScene = getScenes()->get(*index);
+ if (getSound()->isBuffered(kEntityTables4)) {
+ if (newScene->type != Scene::kTypeReadText || newScene->param1)
+ getSound()->processEntry(kEntityTables4);
+ }
+
+ // Cleanup beetle sequences
+ if (getBeetle()->isLoaded()) {
+ if (newScene->type != Scene::kTypeLoadBeetleSequences)
+ getBeetle()->unload();
+ }
+}
+
+void SceneManager::postProcessScene() {
+
+ Scene *scene = getScenes()->get(getState()->scene);
+
+ switch (scene->type) {
+ case Scene::kTypeList: {
+
+ // Adjust time
+ getState()->time = (TimeValue)(getState()->time + (TimeValue)((scene->param1 + 10) * getState()->timeDelta));
+ getState()->timeTicks += (scene->param1 + 10);
+
+ // Wait for a number of frames unless right mouse is clicked
+ uint32 nextFrameCount = getFrameCount() + 4 * scene->param1;
+ if (!getFlags()->mouseRightClick) {
+ while (nextFrameCount > getFrameCount()) {
+ _engine->pollEvents();
+
+ if (getFlags()->mouseRightClick)
+ break;
+
+ getSound()->updateQueue();
+ getSound()->updateSubtitles();
+ }
+ }
+
+ // Process hotspots and load scenes in the list
+ SceneHotspot *hotspot = scene->getHotspot();
+ SceneIndex processedScene = getAction()->processHotspot(*hotspot);
+ SceneIndex testScene = (processedScene == kSceneInvalid) ? hotspot->scene : processedScene;
+
+ if (getFlags()->mouseRightClick) {
+
+ while (getScenes()->get(testScene)->type == Scene::kTypeList) {
+ hotspot = getScenes()->get(testScene)->getHotspot();
+ processedScene = getAction()->processHotspot(*hotspot);
+ testScene = (processedScene == kSceneInvalid) ? hotspot->scene : processedScene;
+ }
+ }
+
+ // If several entities are there, choose one to sound "Excuse me"
+ EntityPosition entityPosition = getEntityData(kEntityPlayer)->entityPosition;
+ if (getEntityData(kEntityPlayer)->car == kCar9 && (entityPosition == kPosition_4 || entityPosition == kPosition_3)) {
+ EntityIndex entities[39];
+
+ // Init entities
+ entities[0] = kEntityPlayer;
+
+ uint progress = 0;
+
+ for (uint i = 1; i < 40 /* number of entities */; i++) {
+ CarIndex car = getEntityData((EntityIndex)i)->car;
+ EntityPosition position = getEntityData((EntityIndex)i)->entityPosition;
+
+ if (entityPosition == kPosition_4) {
+ if ((car == kCarRedSleeping && position > kPosition_9270) || (car == kCarRestaurant && position < kPosition_1540))
+ entities[progress++] = (EntityIndex)i;
+ } else {
+ if ((car == kCarGreenSleeping && position > kPosition_9270) || (car == kCarRedSleeping && position < kPosition_850))
+ entities[progress++] = (EntityIndex)i;
+ }
+ }
+
+ if (progress)
+ getSound()->excuseMe((progress == 1) ? entities[0] : entities[rnd(progress)], kEntityPlayer, SoundManager::kFlagDefault);
+ }
+
+ if (hotspot->scene)
+ setScene(hotspot->scene);
+ break;
+ }
+
+ case Scene::kTypeSavePointChapter:
+ if (getProgress().field_18 == 2)
+ getSavePoints()->push(kEntityPlayer, kEntityChapters, kActionEndChapter);
+ break;
+
+ case Scene::kTypeLoadBeetleSequences:
+ if ((getProgress().chapter == kChapter2 || getProgress().chapter == kChapter3)
+ && getInventory()->get(kItemBeetle)->location == kObjectLocation3) {
+ if (!getBeetle()->isLoaded())
+ getBeetle()->load();
+ }
+ break;
+
+ case Scene::kTypeGameOver:
+ if (getState()->time >= kTimeCityGalanta || getProgress().field_18 == 4)
+ break;
+
+ getSound()->processEntry(SoundManager::kSoundType7);
+ getSound()->playSound(kEntityTrain, "LIB050", SoundManager::kFlagDefault);
+
+ switch (getProgress().chapter) {
+ default:
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneGameOverPolice2, true);
+ break;
+
+ case kChapter1:
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneGameOverAlarm, true);
+ break;
+
+ case kChapter4:
+ getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneGameOverAlarm2, true);
+ break;
+ }
+ break;
+
+ case Scene::kTypeReadText:
+ getSound()->readText(scene->param1);
+ break;
+
+ case Scene::kType133:
+ if (getFlags()->flag_0) {
+ getFlags()->flag_0 = false;
+ getFlags()->shouldRedraw = true;
+ getLogic()->updateCursor();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/scenes.h b/engines/lastexpress/game/scenes.h
new file mode 100644
index 0000000000..b70526839f
--- /dev/null
+++ b/engines/lastexpress/game/scenes.h
@@ -0,0 +1,120 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SCENEMANAGER_H
+#define LASTEXPRESS_SCENEMANAGER_H
+
+#include "lastexpress/data/scene.h"
+
+#include "common/hashmap.h"
+#include "common/list.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+class SceneLoader;
+class Sequence;
+class SequenceFrame;
+
+class SceneManager {
+public:
+ enum CheckPositionType {
+ kCheckPositionLookingUp,
+ kCheckPositionLookingDown,
+ kCheckPositionLookingAtDoors,
+ kCheckPositionLookingAtClock
+ };
+
+ SceneManager(LastExpressEngine *engine);
+ ~SceneManager();
+
+ // Scene cache
+ void loadSceneDataFile(ArchiveIndex archive);
+ Scene *get(SceneIndex sceneIndex) { return _sceneLoader->get(sceneIndex); }
+
+ // Scene loading
+ void setScene(SceneIndex sceneIndex);
+ void loadScene(SceneIndex sceneIndex);
+ void loadSceneFromObject(ObjectIndex object, bool alternate = false);
+ void loadSceneFromItem(InventoryItem item);
+ void loadSceneFromItemPosition(InventoryItem item);
+ void loadSceneFromPosition(CarIndex car, Position position, int param3 = -1);
+
+ // Scene drawing & processing
+ void drawScene(SceneIndex sceneIndex);
+ void processScene();
+ SceneIndex processIndex(SceneIndex sceneIndex);
+
+ // Checks
+ bool checkPosition(SceneIndex sceneIndex, CheckPositionType type) const;
+ bool checkCurrentPosition(bool doCheckOtherCars) const;
+
+ // Train
+ void updateDoorsAndClock();
+ void resetDoorsAndClock();
+
+ // Sequence queue
+ void drawFrames(bool refreshScreen);
+ void addToQueue(SequenceFrame * const frame);
+ void removeFromQueue(SequenceFrame *frame);
+ void removeAndRedraw(SequenceFrame **frame, bool doRedraw);
+ void resetQueue();
+ void setCoordinates(SequenceFrame *frame);
+
+ // Helpers
+ SceneIndex getSceneIndexFromPosition(CarIndex car, Position position, int param3 = -1);
+
+ void setFlagDrawSequences() { _flagDrawSequences = true; }
+
+private:
+ LastExpressEngine *_engine;
+ SceneLoader *_sceneLoader; ///< Scene loader
+
+ // Flags
+ bool _flagNoEntity;
+ bool _flagDrawEntities;
+ bool _flagDrawSequences;
+ bool _flagCoordinates;
+
+ Common::Rect _coords;
+
+ // Train sequences
+ Common::List<SequenceFrame *> _doors;
+ SequenceFrame *_clockHours;
+ SequenceFrame *_clockMinutes;
+
+ // Sequence queue
+ Common::List<SequenceFrame *> _queue;
+
+ // Scene processing
+ void preProcessScene(SceneIndex *index);
+ void postProcessScene();
+
+ void resetCoordinates();
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SCENEMANAGER_H
diff --git a/engines/lastexpress/game/sound.cpp b/engines/lastexpress/game/sound.cpp
new file mode 100644
index 0000000000..0dfc38b1b0
--- /dev/null
+++ b/engines/lastexpress/game/sound.cpp
@@ -0,0 +1,1734 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/data/snd.h"
+#include "lastexpress/data/subtitle.h"
+
+#include "lastexpress/game/action.h"
+#include "lastexpress/game/entities.h"
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+namespace LastExpress {
+
+// Letters & messages
+const char *messages[24] = {
+ "",
+ "TXT1001", // 1
+ "TXT1001A", // 2
+ "TXT1011", // 3
+ "TXT1012", // 4
+ "TXT1013", // 5
+ "TXT1014", // 6
+ "TXT1020", // 7
+ "TXT1030", // 8
+ "END1009B", // 50
+ "END1046", // 51
+ "END1047", // 52
+ "END1112", // 53
+ "END1112A", // 54
+ "END1503", // 55
+ "END1505A", // 56
+ "END1505B", // 57
+ "END1610", // 58
+ "END1612A", // 59
+ "END1612C", // 61
+ "END1612D", // 62
+ "ENDALRM1", // 63
+ "ENDALRM2", // 64
+ "ENDALRM3" // 65
+};
+
+const char *cities[17] = {
+ "EPERNAY",
+ "CHALONS",
+ "BARLEDUC",
+ "NANCY",
+ "LUNEVILL",
+ "AVRICOUR",
+ "DEUTSCHA",
+ "STRASBOU",
+ "BADENOOS",
+ "SALZBURG",
+ "ATTNANG",
+ "WELS",
+ "LINZ",
+ "VIENNA",
+ "POZSONY",
+ "GALANTA",
+ "POLICE"
+};
+
+const char *locomotiveSounds[5] = {
+ "ZFX1005",
+ "ZFX1006",
+ "ZFX1007",
+ "ZFX1007A",
+ "ZFX1007B"
+};
+
+static const SoundManager::FlagType soundFlags[32] = {
+ SoundManager::kFlagDefault, SoundManager::kFlag15, SoundManager::kFlag14, SoundManager::kFlag13, SoundManager::kFlag12,
+ SoundManager::kFlag11, SoundManager::kFlag11, SoundManager::kFlag10, SoundManager::kFlag10, SoundManager::kFlag9, SoundManager::kFlag9, SoundManager::kFlag8, SoundManager::kFlag8,
+ SoundManager::kFlag7, SoundManager::kFlag7, SoundManager::kFlag7, SoundManager::kFlag6, SoundManager::kFlag6, SoundManager::kFlag6,
+ SoundManager::kFlag5, SoundManager::kFlag5, SoundManager::kFlag5, SoundManager::kFlag5, SoundManager::kFlag4, SoundManager::kFlag4, SoundManager::kFlag4, SoundManager::kFlag4,
+ SoundManager::kFlag3, SoundManager::kFlag3, SoundManager::kFlag3, SoundManager::kFlag3, SoundManager::kFlag3
+};
+
+SoundManager::SoundManager(LastExpressEngine *engine) : _engine(engine), _state(0), _currentType(kSoundType16), _flag(0) {
+ _soundStream = new StreamedSound();
+
+ // Initialize unknown data
+ _data0 = 0;
+ _data1 = 0;
+ _data2 = 0;
+
+ memset(&_buffer, 0, sizeof(_buffer));
+ memset(&_lastWarning, 0, sizeof(_lastWarning));
+}
+
+SoundManager::~SoundManager() {
+ delete _soundStream;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Timer
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::handleTimer() {
+
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
+ SoundEntry *entry = (*i);
+ if (entry->stream == NULL) {
+ i = _cache.reverse_erase(i);
+ continue;
+ } else if (!entry->isStreamed) {
+ entry->isStreamed = true;
+ _soundStream->load(entry->stream);
+ }
+ }
+
+ // TODO: stream any sound in the queue after filtering
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Sound queue management
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::updateQueue() {
+ //warning("Sound::unknownFunction1: not implemented!");
+}
+
+void SoundManager::resetQueue(SoundType type1, SoundType type2) {
+ if (!type2)
+ type2 = type1;
+
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
+ if ((*i)->type != type1 && (*i)->type != type2)
+ resetEntry(*i);
+ }
+}
+
+void SoundManager::removeFromQueue(EntityIndex entity) {
+ SoundEntry *entry = getEntry(entity);
+
+ if (entry)
+ resetEntry(entry);
+}
+
+void SoundManager::removeFromQueue(Common::String filename) {
+ SoundEntry *entry = getEntry(filename);
+
+ if (entry)
+ resetEntry(entry);
+}
+
+void SoundManager::clearQueue() {
+ _flag |= 4;
+
+ // Wait a while for a flag to be set
+ for (int i = 0; i < 3000000; i++)
+ if (_flag & 8)
+ break;
+
+ _flag |= 8;
+
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
+ SoundEntry *entry = (*i);
+
+ // Delete entry
+ removeEntry(entry);
+ delete entry;
+
+ i = _cache.reverse_erase(i);
+ }
+
+ updateSubtitles();
+}
+
+bool SoundManager::isBuffered(EntityIndex entity) {
+ return (getEntry(entity) != NULL);
+}
+
+bool SoundManager::isBuffered(Common::String filename, bool testForEntity) {
+ SoundEntry *entry = getEntry(filename);
+
+ if (testForEntity)
+ return entry != NULL && !entry->entity;
+
+ return (entry != NULL);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Entry
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::setupEntry(SoundEntry *entry, Common::String name, FlagType flag, int a4) {
+ if (!entry)
+ error("SoundManager::setupEntry: Invalid entry!");
+
+ entry->field_4C = a4;
+ setEntryType(entry, flag);
+ setEntryStatus(entry, flag);
+
+ // Add entry to cache
+ _cache.push_back(entry);
+
+ setupCache(entry);
+ loadSoundData(entry, name);
+}
+
+void SoundManager::setEntryType(SoundEntry *entry, FlagType flag) {
+ switch (flag & kFlagType7) {
+ default:
+ case kFlagNone:
+ entry->type = _currentType;
+ _currentType = (SoundType)(_currentType + 1);
+ break;
+
+ case kFlagType1_2: {
+ SoundEntry *previous2 = getEntry(kSoundType2);
+ if (previous2)
+ updateEntry(previous2, 0);
+
+ SoundEntry *previous = getEntry(kSoundType1);
+ if (previous) {
+ previous->type = kSoundType2;
+ updateEntry(previous, 0);
+ }
+
+ entry->type = kSoundType1;
+ }
+ break;
+
+ case kFlagType3: {
+ SoundEntry *previous = getEntry(kSoundType3);
+ if (previous) {
+ previous->type = kSoundType4;
+ updateEntry(previous, 0);
+ }
+
+ entry->type = kSoundType11;
+ }
+ break;
+
+ case kFlagType7: {
+ SoundEntry *previous = getEntry(kSoundType7);
+ if (previous)
+ previous->type = kSoundType8;
+
+ entry->type = kSoundType7;
+ }
+ break;
+
+ case kFlagType9: {
+ SoundEntry *previous = getEntry(kSoundType9);
+ if (previous)
+ previous->type = kSoundType10;
+
+ entry->type = kSoundType9;
+ }
+ break;
+
+ case kFlagType11: {
+ SoundEntry *previous = getEntry(kSoundType11);
+ if (previous)
+ previous->type = kSoundType14;
+
+ entry->type = kSoundType11;
+ }
+ break;
+
+ case kFlagType13: {
+ SoundEntry *previous = getEntry(kSoundType13);
+ if (previous)
+ previous->type = kSoundType14;
+
+ entry->type = kSoundType13;
+ }
+ break;
+ }
+}
+
+void SoundManager::setEntryStatus(SoundEntry *entry, FlagType flag) const {
+ SoundStatus status = (SoundStatus)flag;
+ if (!((status & 0xFF) & kSoundStatusClear1))
+ status = (SoundStatus)(status | kSoundStatusClear2);
+
+ if (((status & 0xFF00) >> 8) & kSoundStatusClear0)
+ entry->status.status = (uint32)status;
+ else
+ entry->status.status = (status | kSoundStatusClear4);
+}
+
+bool SoundManager::setupCache(SoundEntry *entry) {
+ warning("Sound::setupCache: not implemented!");
+ return true;
+}
+
+void SoundManager::clearStatus() {
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i)
+ (*i)->status.status |= kSoundStatusClear3;
+}
+
+void SoundManager::loadSoundData(SoundEntry *entry, Common::String name) {
+ entry->name2 = name;
+
+ // Load sound data
+ entry->stream = getArchive(name);
+
+ if (!entry->stream)
+ entry->stream = getArchive("DEFAULT.SND");
+
+ if (entry->stream) {
+ warning("Sound::loadSoundData: not implemented!");
+ } else {
+ entry->status.status = kSoundStatusRemoved;
+ }
+}
+
+void SoundManager::resetEntry(SoundEntry *entry) const {
+ entry->status.status |= kSoundStatusRemoved;
+ entry->entity = kEntityPlayer;
+
+ if (entry->stream) {
+ if (!entry->isStreamed)
+ SAFE_DELETE(entry->stream);
+
+ entry->stream = NULL;
+ }
+}
+
+
+void SoundManager::removeEntry(SoundEntry *entry) {
+ entry->status.status |= kSoundStatusRemoved;
+
+ // Loop until ready
+ while (!(entry->status.status1 & 4) && !(_flag & 8) && (_flag & 1))
+ ; // empty loop body
+
+ // The original game remove the entry from the cache here,
+ // but since we are called from within an iterator loop
+ // we will remove the entry there
+ // removeFromCache(entry);
+
+ if (entry->subtitle) {
+ drawSubtitles(entry->subtitle);
+ SAFE_DELETE(entry->subtitle);
+ }
+
+ if (entry->entity) {
+ if (entry->entity == kEntitySteam)
+ playLoopingSound();
+ else if (entry->entity != kEntityTrain)
+ getSavePoints()->push(kEntityPlayer, entry->entity, kActionEndSound);
+ }
+}
+
+void SoundManager::updateEntry(SoundEntry *entry, uint value) const {
+ if (!(entry->status.status3 & 64)) {
+
+ int value2 = value;
+
+ entry->status.status |= kSoundStatus_100000;
+
+ if (value) {
+ if (_flag & 32) {
+ entry->field_40 = value;
+ value2 = value * 2 + 1;
+ }
+
+ entry->field_3C = value2;
+ } else {
+ entry->field_3C = 0;
+ entry->status.status |= kSoundStatus_40000000;
+ }
+ }
+}
+
+void SoundManager::updateEntryState(SoundEntry *entry) const {
+ if (_flag & 32) {
+ if (entry->type != kSoundType9 && entry->type != kSoundType7 && entry->type != kSoundType5) {
+ uint32 status = entry->status.status & kSoundStatusClear1;
+
+ entry->status.status &= kSoundStatusClearAll;
+
+ entry->field_40 = status;
+ entry->status.status |= status * 2 + 1;
+ }
+ }
+
+ entry->status.status |= kSoundStatus_20;
+}
+
+void SoundManager::processEntry(EntityIndex entity) {
+ SoundEntry *entry = getEntry(entity);
+
+ if (entry) {
+ updateEntry(entry, 0);
+ entry->entity = kEntityPlayer;
+ }
+}
+
+void SoundManager::processEntry(SoundType type) {
+ SoundEntry *entry = getEntry(type);
+
+ if (entry)
+ updateEntry(entry, 0);
+}
+
+void SoundManager::setupEntry(SoundType type, EntityIndex index) {
+ SoundEntry *entry = getEntry(type);
+
+ if (entry)
+ entry->entity = index;
+}
+
+void SoundManager::processEntry(Common::String filename) {
+ SoundEntry *entry = getEntry(filename);
+
+ if (entry) {
+ updateEntry(entry, 0);
+ entry->entity = kEntityPlayer;
+ }
+}
+
+void SoundManager::processEntries() {
+ _state = 0;
+
+ processEntry(kSoundType1);
+ processEntry(kSoundType2);
+}
+
+uint32 SoundManager::getEntryTime(EntityIndex index) {
+ SoundEntry *entry = getEntry(index);
+
+ if (!entry)
+ return 0;
+
+ return entry->time;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Misc
+//////////////////////////////////////////////////////////////////////////
+
+void SoundManager::unknownFunction4() {
+ warning("Sound::unknownFunction4: not implemented!");
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Entry search
+//////////////////////////////////////////////////////////////////////////
+SoundManager::SoundEntry *SoundManager::getEntry(EntityIndex index) {
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
+ if ((*i)->entity == index)
+ return *i;
+ }
+
+ return NULL;
+}
+
+SoundManager::SoundEntry *SoundManager::getEntry(Common::String name) {
+ if (!name.contains('.'))
+ name += ".SND";
+
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
+ if ((*i)->name2 == name)
+ return *i;
+ }
+
+ return NULL;
+}
+
+SoundManager::SoundEntry *SoundManager::getEntry(SoundType type) {
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
+ if ((*i)->type == type)
+ return *i;
+ }
+
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Savegame
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(_state);
+ s.syncAsUint32LE(_currentType);
+
+ // Compute the number of entries to save
+ uint32 numEntries = count();
+ s.syncAsUint32LE(numEntries);
+
+ // Save or load each entry data
+ if (s.isSaving()) {
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
+ SoundEntry *entry = *i;
+ if (entry->name2.matchString("NISSND?") && (entry->status.status & kFlagType7) != kFlag3) {
+ s.syncAsUint32LE(entry->status.status); // status;
+ s.syncAsUint32LE(entry->type); // type;
+ s.syncAsUint32LE(entry->field_1C); // field_8;
+ s.syncAsUint32LE(entry->time); // time;
+ s.syncAsUint32LE(entry->field_34); // field_10;
+ s.syncAsUint32LE(entry->field_38); // field_14;
+ s.syncAsUint32LE(entry->entity); // entity;
+
+ uint32 field_1C = (uint32)entry->field_48 - _data2;
+ if (field_1C > kFlag8)
+ field_1C = 0;
+ s.syncAsUint32LE(field_1C); // field_1C;
+
+ s.syncAsUint32LE(entry->field_4C); // field_20;
+
+ char name1[16];
+ strcpy((char *)&name1, entry->name1.c_str());
+ s.syncBytes((byte *)&name1, 16);
+
+ char name2[16];
+ strcpy((char *)&name2, entry->name2.c_str());
+ s.syncBytes((byte *)&name2, 16);
+ }
+ }
+ } else {
+ warning("Sound::saveLoadWithSerializer: not implemented!");
+ s.skip(numEntries * 64);
+ }
+}
+
+uint32 SoundManager::count() {
+ uint32 numEntries = 0;
+ for (Common::List<SoundEntry *>::iterator i = _cache.begin(); i != _cache.end(); ++i)
+ if ((*i)->name2.matchString("NISSND?"))
+ ++numEntries;
+
+ return numEntries;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Game-related functions
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::playSound(EntityIndex entity, Common::String filename, FlagType flag, byte a4) {
+ if (isBuffered(entity) && entity)
+ removeFromQueue(entity);
+
+ FlagType currentFlag = (flag == -1) ? getSoundFlag(entity) : (FlagType)(flag | 0x80000);
+
+ // Add .SND at the end of the filename if needed
+ if (!filename.contains('.'))
+ filename += ".SND";
+
+ if (!playSoundWithSubtitles(filename, currentFlag, entity, a4))
+ if (entity)
+ getSavePoints()->push(kEntityPlayer, entity, kActionEndSound);
+}
+
+SoundManager::SoundType SoundManager::playSoundWithSubtitles(Common::String filename, FlagType flag, EntityIndex entity, byte a4) {
+ SoundEntry *entry = new SoundEntry();
+ setupEntry(entry, filename, flag, 30);
+ entry->entity = entity;
+
+ if (a4) {
+ entry->field_48 = _data2 + 2 * a4;
+ entry->status.status |= kSoundStatus_8000;
+ } else {
+ // Get subtitles name
+ while (filename.size() > 4)
+ filename.deleteLastChar();
+
+ showSubtitles(entry, filename);
+ updateEntryState(entry);
+ }
+
+ return entry->type;
+}
+
+void SoundManager::playSoundEvent(EntityIndex entity, byte action, byte a3) {
+ char filename[12];
+ int values[5];
+
+ if (getEntityData(entity)->car != getEntityData(kEntityPlayer)->car)
+ return;
+
+ if (getEntities()->isInSalon(entity) != getEntities()->isInSalon(kEntityPlayer))
+ return;
+
+ int _action = (int)action;
+ FlagType flag = getSoundFlag(entity);
+
+ switch (action) {
+ case 36: {
+ int _param3 = (flag <= 9) ? flag + 7 : 16;
+
+ if (_param3 > 7) {
+ _data0 = (uint)_param3;
+ _data1 = _data2 + 2 * a3;
+ }
+ break;
+ }
+
+ case 37:
+ _data0 = 7;
+ _data1 = _data2 + 2 * a3;
+ break;
+
+ case 150:
+ case 156:
+ case 162:
+ case 168:
+ case 188:
+ case 198:
+ _action += 1 + (int)rnd(5);
+ break;
+
+ case 174:
+ case 184:
+ case 194:
+ _action += 1 + (int)rnd(3);
+ break;
+
+ case 180:
+ _action += 1 + (int)rnd(4);
+ break;
+
+ case 246:
+ values[0] = 0;
+ values[1] = 104;
+ values[2] = 105;
+ values[3] = 106;
+ values[4] = 116;
+ _action = values[rnd(5)];
+ break;
+
+ case 247:
+ values[0] = 11;
+ values[1] = 123;
+ values[2] = 124;
+ _action = values[rnd(3)];
+ break;
+
+ case 248:
+ values[0] = 0;
+ values[1] = 103;
+ values[2] = 108;
+ values[3] = 109;
+ _action = values[rnd(4)];
+ break;
+
+ case 249:
+ values[0] = 0;
+ values[1] = 56;
+ values[2] = 112;
+ values[3] = 113;
+ _action = values[rnd(4)];
+ break;
+
+ case 250:
+ values[0] = 0;
+ values[1] = 107;
+ values[2] = 115;
+ values[3] = 117;
+ _action = values[rnd(4)];
+ break;
+
+ case 251:
+ values[0] = 0;
+ values[1] = 11;
+ values[2] = 56;
+ values[3] = 113;
+ _action = values[rnd(4)];
+ break;
+
+ case 252:
+ values[0] = 0;
+ values[1] = 6;
+ values[2] = 109;
+ values[3] = 121;
+ _action = values[rnd(4)];
+ break;
+
+ case 254:
+ values[0] = 0;
+ values[1] = 104;
+ values[2] = 120;
+ values[3] = 121;
+ _action = values[rnd(4)];
+ break;
+
+ case 255:
+ values[0] = 0;
+ values[1] = 106;
+ values[2] = 115;
+ _action = values[rnd(3)];
+ break;
+
+ default:
+ break;
+ }
+
+ if (_action) {
+ sprintf((char *)&filename, "LIB%03d.SND", _action);
+
+ if (flag)
+ playSoundWithSubtitles((char*)&filename, flag, kEntityPlayer, a3);
+ }
+}
+
+void SoundManager::playSteam(CityIndex index) {
+ if (index >= ARRAYSIZE(cities))
+ error("SoundManager::playSteam: invalid city index (was %d, max %d)", index, ARRAYSIZE(cities));
+
+ _state |= kSoundState2;
+
+ if (!getEntry(kSoundType1))
+ playSoundWithSubtitles("STEAM.SND", kFlagSteam, kEntitySteam);
+
+ // Get the new sound entry and show subtitles
+ SoundEntry *entry = getEntry(kSoundType1);
+ if (entry)
+ showSubtitles(entry, cities[index]);
+}
+
+void SoundManager::playFightSound(byte action, byte a4) {
+ int _action = (int)action;
+ char filename[12];
+ int values[5];
+
+ switch (action) {
+ default:
+ break;
+
+ case 174:
+ case 184:
+ case 194:
+ values[0] = action + 1;
+ values[1] = action + 2;
+ values[2] = action + 3;
+ _action = values[rnd(3)];
+ break;
+
+ case 180:
+ values[0] = action + 1;
+ values[1] = action + 2;
+ values[2] = action + 3;
+ values[3] = action + 4;
+ _action = values[rnd(4)];
+ break;
+
+ case 150:
+ case 156:
+ case 162:
+ case 168:
+ case 188:
+ case 198:
+ values[0] = action + 1;
+ values[1] = action + 2;
+ values[2] = action + 3;
+ values[3] = action + 4;
+ values[4] = action + 5;
+ _action = values[rnd(5)];
+ break;
+ }
+
+ if (_action) {
+ sprintf((char *)&filename, "LIB%03d.SND", _action);
+ playSound(kEntityTrain, (char*)&filename, kFlagDefault, a4);
+ }
+}
+
+void SoundManager::playDialog(EntityIndex entity, EntityIndex entityDialog, FlagType flag, byte a4) {
+ if (isBuffered(getDialogName(entityDialog)))
+ removeFromQueue(getDialogName(entityDialog));
+
+ playSound(entity, getDialogName(entityDialog), flag, a4);
+}
+
+void SoundManager::playLocomotiveSound() {
+ playSound(kEntityPlayer, locomotiveSounds[rnd(5)], (FlagType)(rnd(15) + 2));
+}
+
+const char *SoundManager::getDialogName(EntityIndex entity) const {
+ switch (entity) {
+ case kEntityAnna:
+ if (getEvent(kEventAnnaDialogGoToJerusalem))
+ return "XANN12";
+
+ if (getEvent(kEventLocomotiveRestartTrain))
+ return "XANN11";
+
+ if (getEvent(kEventAnnaBaggageTies) || getEvent(kEventAnnaBaggageTies2) || getEvent(kEventAnnaBaggageTies3) || getEvent(kEventAnnaBaggageTies4))
+ return "XANN10";
+
+ if (getEvent(kEventAnnaTired) || getEvent(kEventAnnaTiredKiss))
+ return "XANN9";
+
+ if (getEvent(kEventAnnaBaggageArgument))
+ return "XANN8";
+
+ if (getEvent(kEventKronosVisit))
+ return "XANN7";
+
+ if (getEvent(kEventAbbotIntroduction))
+ return "XANN6A";
+
+ if (getEvent(kEventVassiliSeizure))
+ return "XANN6";
+
+ if (getEvent(kEventAugustPresentAnna) || getEvent(kEventAugustPresentAnnaFirstIntroduction))
+ return "XANN5";
+
+ if (getProgress().field_60)
+ return "XANN4";
+
+ if (getEvent(kEventAnnaGiveScarf) || getEvent(kEventAnnaGiveScarfDiner) || getEvent(kEventAnnaGiveScarfSalon)
+ || getEvent(kEventAnnaGiveScarfMonogram) || getEvent(kEventAnnaGiveScarfDinerMonogram) || getEvent(kEventAnnaGiveScarfSalonMonogram))
+ return "XANN3";
+
+ if (getEvent(kEventDinerMindJoin))
+ return "XANN2";
+
+ if (getEvent(kEventGotALight) || getEvent(kEventGotALightD))
+ return "XANN1";
+
+ break;
+
+ case kEntityAugust:
+ if (getEvent(kEventAugustTalkCigar))
+ return "XAUG6";
+
+ if (getEvent(kEventAugustBringBriefcase))
+ return "XAUG5";
+
+ // Getting closer to Vienna...
+ if (getState()->time > kTime2200500 && !getEvent(kEventAugustMerchandise))
+ return "XAUG4A";
+
+ if (getEvent(kEventAugustMerchandise))
+ return "XAUG4";
+
+ if (getEvent(kEventDinerAugust) || getEvent(kEventDinerAugustAlexeiBackground) || getEvent(kEventMeetAugustTylerCompartment)
+ || getEvent(kEventMeetAugustTylerCompartmentBed) || getEvent(kEventMeetAugustHisCompartment) || getEvent(kEventMeetAugustHisCompartmentBed))
+ return "XAUG3";
+
+ if (getEvent(kEventAugustPresentAnnaFirstIntroduction))
+ return "XAUG2";
+
+ if (getProgress().eventMertensAugustWaiting)
+ return "XAUG1";
+
+ break;
+
+ case kEntityTatiana:
+ if (getEvent(kEventTatianaTylerCompartment))
+ return "XTAT6";
+
+ if (getEvent(kEventTatianaCompartmentStealEgg))
+ return "XTAT5";
+
+ if (getEvent(kEventTatianaGivePoem))
+ return "XTAT3";
+
+ if (getProgress().field_64)
+ return "XTAT1";
+
+ break;
+
+ case kEntityVassili:
+ if (getEvent(kEventCathFreePassengers))
+ return "XVAS4";
+
+ if (getEvent(kEventVassiliCompartmentStealEgg))
+ return "XVAS3";
+
+ if (getEvent(kEventAbbotIntroduction))
+ return "XVAS2";
+
+ if (getEvent(kEventVassiliSeizure))
+ return "XVAS1A";
+
+ if (getProgress().field_64)
+ return "XVAS1";
+
+ break;
+
+ case kEntityAlexei:
+ if (getProgress().field_88)
+ return "XALX6";
+
+ if (getProgress().field_8C)
+ return "XALX5";
+
+ if (getProgress().field_90)
+ return "XALX4A";
+
+ if (getProgress().field_68)
+ return "XALX4";
+
+ if (getEvent(kEventAlexeiSalonPoem))
+ return "XALX3";
+
+ if (getEvent(kEventAlexeiSalonVassili))
+ return "XALX2";
+
+ if (getEvent(kEventAlexeiDiner) || getEvent(kEventAlexeiDinerOriginalJacket))
+ return "XALX1";
+
+ break;
+
+ case kEntityAbbot:
+ if (getEvent(kEventAbbotDrinkDefuse))
+ return "XABB4";
+
+ if (getEvent(kEventAbbotInvitationDrink) || getEvent(kEventDefuseBomb))
+ return "XABB3";
+
+ if (getEvent(kEventAbbotWrongCompartment) || getEvent(kEventAbbotWrongCompartmentBed))
+ return "XABB2";
+
+ if (getEvent(kEventAbbotIntroduction))
+ return "XABB1";
+
+ break;
+
+ case kEntityMilos:
+ if (getEvent(kEventLocomotiveMilosDay) || getEvent(kEventLocomotiveMilosNight))
+ return "XMIL5";
+
+ if (getEvent(kEventMilosCompartmentVisitTyler) && (getProgress().chapter == kChapter3 || getProgress().chapter == kChapter4))
+ return "XMIL4";
+
+ if (getEvent(kEventMilosCorridorThanks) || getProgress().chapter == kChapter5)
+ return "XMIL3";
+
+ if (getEvent(kEventMilosCompartmentVisitAugust))
+ return "XMIL2";
+
+ if (getEvent(kEventMilosTylerCompartmentDefeat))
+ return "XMIL1";
+
+ break;
+
+ case kEntityVesna:
+ if (getProgress().field_94)
+ return "XVES2";
+
+ if (getProgress().field_98)
+ return "XVES1";
+
+ break;
+
+ case kEntityKronos:
+ if (getEvent(kEventKronosReturnBriefcase))
+ return "XKRO6";
+
+ if (getEvent(kEventKronosBringEggCeiling) || getEvent(kEventKronosBringEgg))
+ return "XKRO5";
+
+ if (getEvent(kEventKronosConversation) || getEvent(kEventKronosConversationFirebird)) {
+ ObjectLocation location = getInventory()->get(kItemFirebird)->location;
+ if (location != kObjectLocation6 && location != kObjectLocation5 && location != kObjectLocation2 && location != kObjectLocation1)
+ return "XKRO4A";
+ }
+
+ if (getEvent(kEventKronosConversationFirebird))
+ return "XKRO4";
+
+ if (getEvent(kEventKronosConversation)) {
+ if (!getEvent(kEventMilosCompartmentVisitAugust))
+ return "XKRO3";
+ else
+ return "XKRO2";
+ }
+
+ if (getProgress().eventMertensKronosInvitation)
+ return "XKRO1";
+
+ break;
+
+ case kEntityFrancois:
+ if (getProgress().field_9C)
+ return "XFRA3";
+
+ if (getProgress().field_A0
+ || getEvent(kEventFrancoisWhistle) || getEvent(kEventFrancoisWhistleD)
+ || getEvent(kEventFrancoisWhistleNight) || getEvent(kEventFrancoisWhistleNightD))
+ return "XFRA2";
+
+ if (getState()->time > kTimeParisEpernay) // Between Paris and Epernay
+ return "XFRA1";
+
+ break;
+
+ case kEntityMmeBoutarel:
+ if (getProgress().field_A4)
+ return "XMME4";
+
+ if (getProgress().field_A8)
+ return "XMME3";
+
+ if (getProgress().field_A0)
+ return "XMME2";
+
+ if (getProgress().field_AC)
+ return "XMME1";
+
+ break;
+
+ case kEntityBoutarel:
+ if (getProgress().eventMetBoutarel)
+ return "XMRB1";
+
+ break;
+
+ case kEntityRebecca:
+ if (getProgress().field_B4)
+ return "XREB1A";
+
+ if (getProgress().field_B8)
+ return "XREB1";
+
+ break;
+
+ case kEntitySophie:
+ if (getProgress().field_B0)
+ return "XSOP2";
+
+ if (getProgress().field_BC)
+ return "XSOP1B";
+
+ if (getProgress().field_B4)
+ return "XSOP1A";
+
+ if (getProgress().field_B8)
+ return "XSOP1";
+
+ break;
+
+ case kEntityMahmud:
+ if (getProgress().field_C4)
+ return "XMAH1";
+
+ break;
+
+ case kEntityYasmin:
+ if (getProgress().eventMetYasmin)
+ return "XHAR2";
+
+ break;
+
+ case kEntityHadija:
+ if (getProgress().eventMetHadija)
+ return "XHAR1";
+
+ break;
+
+ case kEntityAlouan:
+ if (getProgress().field_DC)
+ return "XHAR3";
+
+ break;
+
+ case kEntityGendarmes:
+ if (getProgress().field_E0)
+ return "XHAR4";
+
+ break;
+
+ case kEntityChapters:
+ if (getEvent(kEventCathDream) || getEvent(kEventCathWakingUp))
+ return "XTYL3";
+
+ return "XTYL1";
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Letters & Messages
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::readText(int id){
+ if (!isBuffered(kEntityTables4))
+ return;
+
+ if (id < 0 || (id > 8 && id < 50) || id > 64)
+ error("Sound::readText - attempting to use invalid id. Valid values [1;8] - [50;64], was %d", id);
+
+ // Get proper message file (names are stored in sequence in the array but id is [1;8] - [50;64])
+ const char *text = messages[id <= 8 ? id : id - 41];
+
+ // Check if file is in cache for id [1;8]
+ if (id <= 8)
+ if (isBuffered(text))
+ removeFromQueue(text);
+
+ playSound(kEntityTables4, text, kFlagDefault);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Sound bites
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::playWarningCompartment(EntityIndex entity, ObjectIndex compartment) {
+
+#define PLAY_WARNING(index, sound1, sound2, sound3, sound4, sound5, sound6) { \
+ if (_lastWarning[index] + 450 >= getState()->timeTicks) { \
+ if (rnd(2)) \
+ playSound(kEntityMertens, sound1, kFlagDefault); \
+ else \
+ playSound(kEntityMertens, rnd(2) ? sound2 : sound3, kFlagDefault); \
+ } else { \
+ if (rnd(2)) \
+ playSound(kEntityMertens, sound4, kFlagDefault); \
+ else \
+ playSound(kEntityMertens, rnd(2) ? sound5 : sound6, kFlagDefault); \
+ } \
+ _lastWarning[index] = getState()->timeTicks; \
+}
+
+ if (entity != kEntityMertens && entity != kEntityCoudert)
+ return;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Mertens
+ if (entity == kEntityMertens) {
+
+ switch (compartment) {
+ default:
+ break;
+
+ case kObjectCompartment2:
+ PLAY_WARNING(0, "Con1502A", "Con1500B", "Con1500C", "Con1502", "Con1500", "Con1500A");
+ break;
+
+ case kObjectCompartment3:
+ PLAY_WARNING(1, "Con1501A", "Con1500B", "Con1500C", "Con1501", "Con1500", "Con1500A");
+ break;
+
+ case kObjectCompartment4:
+ PLAY_WARNING(2, "Con1503", "Con1500B", "Con1500C", "Con1503", "Con1500", "Con1500A");
+ break;
+
+ case kObjectCompartment5:
+ case kObjectCompartment6:
+ case kObjectCompartment7:
+ case kObjectCompartment8:
+ ++_lastWarning[3];
+
+ switch (_lastWarning[3]) {
+ default:
+ break;
+
+ case 1:
+ getSound()->playSound(kEntityMertens, "Con1503C", kFlagDefault);
+ break;
+
+ case 2:
+ getSound()->playSound(kEntityMertens, rnd(2) ? "Con1503E" : "Con1503A", kFlagDefault);
+ break;
+
+ case 3:
+ getSound()->playSound(kEntityMertens, rnd(2) ? "Con1503B" : "Con1503D", kFlagDefault);
+ _lastWarning[3] = 0;
+ break;
+ }
+ }
+
+ return;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Coudert
+ switch (compartment) {
+ default:
+ break;
+
+ case kObjectCompartmentA:
+ if (_lastWarning[4] + 450 >= getState()->timeTicks) {
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ break;
+ }
+
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1508" : "Jac1508A", kFlagDefault);
+ break;
+
+ case kObjectCompartmentB:
+ if (_lastWarning[5] + 450 >= getState()->timeTicks) {
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ break;
+ }
+
+ if (getProgress().field_40 || (getState()->time > kTimeCityLinz && getState()->time < kTime2133000))
+ getSound()->playSound(kEntityCoudert, "Jac1507A", kFlagDefault);
+ else
+ getSound()->playSound(kEntityCoudert, "Jac1507", kFlagDefault);
+ break;
+
+ case kObjectCompartmentC:
+ if (_lastWarning[6] + 450 >= getState()->timeTicks) {
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ break;
+ }
+
+ if (getProgress().chapter < kChapter3)
+ getSound()->playSound(kEntityCoudert, "Jac1506", kFlagDefault);
+ else
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1506A" : "Jac1506B", kFlagDefault);
+ break;
+
+ case kObjectCompartmentD:
+ if (_lastWarning[7] + 450 >= getState()->timeTicks) {
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ break;
+ }
+
+ getSound()->playSound(kEntityCoudert, "Jac1505", kFlagDefault);
+ break;
+
+ case kObjectCompartmentE:
+ if (_lastWarning[8] + 450 >= getState()->timeTicks) {
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ break;
+ }
+
+ if (getProgress().field_40 || (getState()->time > kTime2115000 && getState()->time < kTime2133000)) {
+ getSound()->playSound(kEntityCoudert, "Jac1504B", kFlagDefault);
+ break;
+ }
+
+ if (getEntities()->isInsideCompartment(kEntityRebecca, kCarRedSleeping, kPosition_4840))
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ else
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1504" : "Jac1504A", kFlagDefault);
+ break;
+
+ case kObjectCompartmentF:
+ if (_lastWarning[9] + 450 >= getState()->timeTicks) {
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ break;
+ }
+
+ if (getProgress().field_40 || (getState()->time > kTime2083500 && getState()->time < kTime2133000)) {
+ getSound()->playSound(kEntityCoudert, "Jac1503B", kFlagDefault);
+ break;
+ }
+
+ if (rnd(2) || getEntities()->isInsideCompartment(kEntityAnna, kCarRedSleeping, kPosition_4070))
+ getSound()->playSound(kEntityCoudert, "Jac1503", kFlagDefault);
+ else
+ getSound()->playSound(kEntityCoudert, "Jac1503A", kFlagDefault);
+ break;
+
+ case kObjectCompartmentG:
+ if (_lastWarning[10] + 450 >= getState()->timeTicks) {
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ break;
+ }
+
+ if (rnd(2) || getEntities()->isInsideCompartment(kEntityMilos, kCarRedSleeping, kPosition_3050))
+ getSound()->playSound(kEntityCoudert, "Jac1502", kFlagDefault);
+ else
+ getSound()->playSound(kEntityCoudert, "Jac1502A", kFlagDefault);
+ break;
+
+ case kObjectCompartmentH:
+ if (_lastWarning[11] + 450 >= getState()->timeTicks) {
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ break;
+ }
+
+ if (getEntities()->isInsideCompartment(kEntityIvo, kCarRedSleeping, kPosition_2740))
+ getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault);
+ else
+ getSound()->playSound(kEntityCoudert, "Jac1501", kFlagDefault);
+ break;
+ }
+
+ // Update ticks (Compartments A - H are indexes 4 - 11)
+ _lastWarning[compartment - 28] = getState()->timeTicks;
+}
+
+void SoundManager::excuseMe(EntityIndex entity, EntityIndex entity2, FlagType flag) {
+ if (isBuffered(entity) && entity != kEntityPlayer && entity != kEntityChapters && entity != kEntityTrain)
+ return;
+
+ if (entity2 == kEntityFrancois || entity2 == kEntityMax)
+ return;
+
+ if (entity == kEntityFrancois && getEntityData(kEntityFrancois)->field_4A3 != 30)
+ return;
+
+ if (flag == kFlagNone)
+ flag = getSoundFlag(entity);
+
+ switch (entity) {
+ default:
+ break;
+
+ case kEntityAnna:
+ playSound(kEntityPlayer, "ANN1107A", flag);
+ break;
+
+ case kEntityAugust:
+ switch(rnd(4)) {
+ default:
+ break;
+
+ case 0:
+ playSound(kEntityPlayer, "AUG1100A", flag);
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, "AUG1100B", flag);
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, "AUG1100C", flag);
+ break;
+
+ case 3:
+ playSound(kEntityPlayer, "AUG1100D", flag);
+ break;
+ }
+ break;
+
+ case kEntityMertens:
+ if (Entities::isFemale(entity2)) {
+ playSound(kEntityPlayer, (rnd(2) ? "CON1111" : "CON1111A"), flag);
+ } else {
+ if (entity2 || getProgress().jacket != kJacketGreen || !rnd(2)) {
+ switch(rnd(3)) {
+ default:
+ break;
+
+ case 0:
+ playSound(kEntityPlayer, "CON1110A", flag);
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, "CON1110C", flag);
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, "CON1110", flag);
+ break;
+ }
+ } else {
+ if (isNight()) {
+ playSound(kEntityPlayer, (getProgress().field_18 == 2 ? "CON1110F" : "CON1110E"));
+ } else {
+ playSound(kEntityPlayer, "CON1110D");
+ }
+ }
+ }
+ break;
+
+ case kEntityCoudert:
+ if (Entities::isFemale(entity2)) {
+ playSound(kEntityPlayer, "JAC1111D", flag);
+ } else {
+ if (entity2 || getProgress().jacket != kJacketGreen || !rnd(2)) {
+ switch(rnd(4)) {
+ default:
+ break;
+
+ case 0:
+ playSound(kEntityPlayer, "JAC1111", flag);
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, "JAC1111A", flag);
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, "JAC1111B", flag);
+ break;
+
+ case 3:
+ playSound(kEntityPlayer, "JAC1111C", flag);
+ break;
+ }
+ } else {
+ playSound(kEntityPlayer, "JAC1113B", flag);
+ }
+ }
+ break;
+
+ case kEntityPascale:
+ playSound(kEntityPlayer, (rnd(2) ? "HDE1002" : "HED1002A"), flag);
+ break;
+
+ case kEntityServers0:
+ case kEntityServers1:
+ switch(rnd(3)) {
+ default:
+ break;
+
+ case 0:
+ playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002" : "WAT1003", flag);
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002A" : "WAT1003A", flag);
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002B" : "WAT1003B", flag);
+ break;
+ }
+ break;
+
+ case kEntityVerges:
+ if (Entities::isFemale(entity2)) {
+ playSound(kEntityPlayer, (rnd(2) ? "TRA1113A" : "TRA1113B"));
+ } else {
+ playSound(kEntityPlayer, "TRA1112", flag);
+ }
+ break;
+
+ case kEntityTatiana:
+ playSound(kEntityPlayer, (rnd(2) ? "TAT1102A" : "TAT1102B"), flag);
+ break;
+
+ case kEntityAlexei:
+ playSound(kEntityPlayer, (rnd(2) ? "ALX1099C" : "ALX1099D"), flag);
+ break;
+
+ case kEntityAbbot:
+ if (Entities::isFemale(entity2)) {
+ playSound(kEntityPlayer, "ABB3002C", flag);
+ } else {
+ switch(rnd(3)) {
+ default:
+ break;
+
+ case 0:
+ playSound(kEntityPlayer, "ABB3002", flag);
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, "ABB3002A", flag);
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, "ABB3002B", flag);
+ break;
+ }
+ }
+ break;
+
+ case kEntityVesna:
+ switch(rnd(3)) {
+ default:
+ break;
+
+ case 0:
+ playSound(kEntityPlayer, "VES1109A", flag);
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, "VES1109B", flag);
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, "VES1109C", flag);
+ break;
+ }
+ break;
+
+ case kEntityKahina:
+ playSound(kEntityPlayer, (rnd(2) ? "KAH1001" : "KAH1001A"), flag);
+ break;
+
+ case kEntityFrancois:
+ case kEntityMmeBoutarel:
+ switch(rnd(4)) {
+ default:
+ break;
+
+ case 0:
+ playSound(kEntityPlayer, (entity == kEntityFrancois) ? "FRA1001" : "MME1103A", flag);
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, (entity == kEntityFrancois) ? "FRA1001A" : "MME1103B", flag);
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, (entity == kEntityFrancois) ? "FRA1001B" : "MME1103C", flag);
+ break;
+
+ case 3:
+ playSound(kEntityPlayer, (entity == kEntityFrancois) ? "FRA1001C" : "MME1103D", flag);
+ break;
+ }
+ break;
+
+ case kEntityBoutarel:
+ playSound(kEntityPlayer, "MRB1104", flag);
+ if (flag > 2)
+ getProgress().eventMetBoutarel = true;
+ break;
+
+ case kEntityRebecca:
+ playSound(kEntityPlayer, (rnd(2) ? "REB1106" : "REB110A"), flag);
+ break;
+
+ case kEntitySophie: {
+ switch(rnd(3)) {
+ default:
+ break;
+
+ case 0:
+ playSound(kEntityPlayer, "SOP1105", flag);
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, Entities::isFemale(entity2) ? "SOP1105C" : "SOP1105A", flag);
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, Entities::isFemale(entity2) ? "SOP1105D" : "SOP1105B", flag);
+ break;
+ }
+ break;
+ }
+
+ case kEntityMahmud:
+ playSound(kEntityPlayer, "MAH1101", flag);
+ break;
+
+ case kEntityYasmin:
+ playSound(kEntityPlayer, "HAR1002", flag);
+ if (flag > 2)
+ getProgress().eventMetYasmin = true;
+ break;
+
+ case kEntityHadija:
+ playSound(kEntityPlayer, (rnd(2) ? "HAR1001" : "HAR1001A"), flag);
+ if (flag > 2)
+ getProgress().eventMetHadija = true;
+ break;
+
+ case kEntityAlouan:
+ playSound(kEntityPlayer, "HAR1004", flag);
+ break;
+ }
+}
+
+void SoundManager::excuseMeCath() {
+ switch(rnd(3)) {
+ default:
+ playSound(kEntityPlayer, "CAT1126B");
+ break;
+
+ case 1:
+ playSound(kEntityPlayer, "CAT1126C");
+ break;
+
+ case 2:
+ playSound(kEntityPlayer, "CAT1126D");
+ break;
+ }
+}
+
+const char *SoundManager::justCheckingCath() const {
+ switch(rnd(4)) {
+ default:
+ break;
+
+ case 0:
+ return "CAT5001";
+
+ case 1:
+ return "CAT5001A";
+
+ case 2:
+ return "CAT5001B";
+
+ case 3:
+ return "CAT5001C";
+ }
+
+ return "CAT5001";
+}
+
+const char *SoundManager::wrongDoorCath() const {
+ switch(rnd(5)) {
+ default:
+ break;
+
+ case 0:
+ return "CAT1125";
+
+ case 1:
+ return "CAT1125A";
+
+ case 2:
+ return "CAT1125B";
+
+ case 3:
+ return "CAT1125C";
+
+ case 4:
+ return "CAT1125D";
+ }
+
+ return "CAT1125";
+}
+
+const char *SoundManager::justAMinuteCath() const {
+ switch(rnd(3)) {
+ default:
+ break;
+
+ case 0:
+ return "CAT1520";
+
+ case 1:
+ return "CAT1521";
+
+ case 2:
+ return "CAT1125"; // ?? is this a bug in the original?
+ }
+
+ return "CAT1520";
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Sound flags
+//////////////////////////////////////////////////////////////////////////
+SoundManager::FlagType SoundManager::getSoundFlag(EntityIndex entity) const {
+ if (entity == kEntityPlayer)
+ return kFlagDefault;
+
+ if (getEntityData(entity)->car != getEntityData(kEntityPlayer)->car)
+ return kFlagNone;
+
+ // Compute sound value
+ FlagType ret = kFlag2;
+
+ // Get default value if valid
+ int index = ABS(getEntityData(entity)->entityPosition - getEntityData(kEntityPlayer)->entityPosition) / 230;
+ if (index < 32)
+ ret = soundFlags[index];
+
+ if (getEntityData(entity)->location == kLocationOutsideTrain) {
+ if (getEntityData(entity)->car != kCarKronos
+ && !getEntities()->isOutsideAlexeiWindow()
+ && !getEntities()->isOutsideAnnaWindow())
+ return kFlagNone;
+
+ return (FlagType)(ret / 6);
+ }
+
+ switch (getEntityData(entity)->car) {
+ default:
+ break;
+
+ case kCarKronos:
+ if (getEntities()->isInKronosSalon(entity) != getEntities()->isInKronosSalon(kEntityPlayer))
+ ret = (FlagType)(ret * 2);
+ break;
+
+ case kCarGreenSleeping:
+ case kCarRedSleeping:
+ if (getEntities()->isInGreenCarEntrance(kEntityPlayer) && !getEntities()->isInKronosSalon(entity))
+ ret = (FlagType)(ret * 2);
+
+ if (getEntityData(kEntityPlayer)->location
+ && (getEntityData(entity)->entityPosition != kPosition_1 || !getEntities()->isDistanceBetweenEntities(kEntityPlayer, entity, 400)))
+ ret = (FlagType)(ret * 2);
+ break;
+
+ case kCarRestaurant:
+ if (getEntities()->isInSalon(entity) == getEntities()->isInSalon(kEntityPlayer)
+ && (getEntities()->isInRestaurant(entity) != getEntities()->isInRestaurant(kEntityPlayer)))
+ ret = (FlagType)(ret * 2);
+ else
+ ret = (FlagType)(ret * 4);
+ break;
+ }
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Subtitles
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::updateSubtitles() {
+ //warning("SoundManager::updateSubtitles: not implemented!");
+}
+
+void SoundManager::showSubtitles(SoundEntry *entry, Common::String filename) {
+ warning("SoundManager::showSubtitles: not implemented!");
+}
+
+void SoundManager::drawSubtitles(SubtitleManager *subtitle) {
+ warning("SoundManager::drawSubtitles: not implemented!");
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Misc
+//////////////////////////////////////////////////////////////////////////
+void SoundManager::playLoopingSound() {
+ warning("SoundManager::playLoopingSound: not implemented!");
+}
+
+void SoundManager::stopAllSound() const {
+ _soundStream->stop();
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/sound.h b/engines/lastexpress/game/sound.h
new file mode 100644
index 0000000000..8c5c6aea0d
--- /dev/null
+++ b/engines/lastexpress/game/sound.h
@@ -0,0 +1,343 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SOUND_H
+#define LASTEXPRESS_SOUND_H
+
+/*
+
+ Sound entry: 68 bytes (this is what appears in the savegames)
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - entity
+ uint32 {4} - ??
+ uint32 {4} - ??
+ char {16} - name 1
+ char {16} - name 2
+
+ Sound queue entry: 120 bytes
+ uint16 {2} - status
+ byte {1} - ??
+ byte {1} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - file data pointer
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - archive structure pointer
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - ??
+ uint32 {4} - entity
+ uint32 {4} - ??
+ uint32 {4} - ??
+ char {16} - name 1
+ char {16} - name 2
+ uint32 {4} - pointer to next entry in the queue
+ uint32 {4} - subtitle data pointer
+
+*/
+
+#include "lastexpress/shared.h"
+
+#include "common/list.h"
+#include "common/system.h"
+#include "common/serializer.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+class StreamedSound;
+class SubtitleManager;
+
+class SoundManager : Common::Serializable {
+public:
+ enum SoundType {
+ kSoundTypeNone = 0,
+ kSoundType1,
+ kSoundType2,
+ kSoundType3,
+ kSoundType4,
+ kSoundType5,
+ kSoundType6,
+ kSoundType7,
+ kSoundType8,
+ kSoundType9,
+ kSoundType10,
+ kSoundType11,
+ kSoundType12,
+ kSoundType13,
+ kSoundType14,
+ kSoundType15,
+ kSoundType16
+ };
+
+ enum FlagType {
+ kFlagInvalid = -1,
+ kFlagNone = 0x0,
+ kFlag2 = 0x2,
+ kFlag3 = 0x3,
+ kFlag4 = 0x4,
+ kFlag5 = 0x5,
+ kFlag6 = 0x6,
+ kFlag7 = 0x7,
+ kFlag8 = 0x8,
+ kFlag9 = 0x9,
+ kFlag10 = 0xA,
+ kFlag11 = 0xB,
+ kFlag12 = 0xC,
+ kFlag13 = 0xD,
+ kFlag14 = 0xE,
+ kFlag15 = 0xF,
+ kFlagDefault = 0x10,
+
+ kFlagType1_2 = 0x1000000,
+ kFlagSteam = 0x1001007,
+ kFlagType13 = 0x3000000,
+ kFlagMenuClock = 0x3080010,
+ kFlagType7 = 0x4000000,
+ kFlagType11 = 0x5000000,
+ kFlagMusic = 0x5000010,
+ kFlagType3 = 0x6000000,
+ kFlagLoop = 0x6001008,
+ kFlagType9 = 0x7000000
+ };
+
+ SoundManager(LastExpressEngine *engine);
+ ~SoundManager();
+
+ // Timer
+ void handleTimer();
+
+ // State
+ void resetState() { _state |= kSoundType1; }
+
+ // Sound queue
+ void updateQueue();
+ void resetQueue(SoundType type1, SoundType type2 = kSoundTypeNone);
+ void clearQueue();
+
+ // Subtitles
+ void updateSubtitles();
+
+ // Entry
+ bool isBuffered(Common::String filename, bool testForEntity = false);
+ bool isBuffered(EntityIndex entity);
+ void setupEntry(SoundType type, EntityIndex index);
+ void processEntry(EntityIndex entity);
+ void processEntry(SoundType type);
+ void processEntry(Common::String filename);
+ void processEntries();
+ void removeFromQueue(Common::String filename);
+ void removeFromQueue(EntityIndex entity);
+ uint32 getEntryTime(EntityIndex index);
+
+ // Misc
+ void unknownFunction4();
+ void clearStatus();
+
+ // Sound playing
+ void playSound(EntityIndex entity, Common::String filename, FlagType flag = kFlagInvalid, byte a4 = 0);
+ SoundType playSoundWithSubtitles(Common::String filename, FlagType flag, EntityIndex entity, byte a4 = 0);
+ void playSoundEvent(EntityIndex entity, byte action, byte a3 = 0);
+ void playDialog(EntityIndex entity, EntityIndex entityDialog, FlagType flag, byte a4);
+ void playSteam(CityIndex index);
+ void playFightSound(byte action, byte a4);
+ void playLocomotiveSound();
+ void playWarningCompartment(EntityIndex entity, ObjectIndex compartment);
+
+ // Dialog & Letters
+ void readText(int id);
+ const char *getDialogName(EntityIndex entity) const;
+
+ // Sound bites
+ void excuseMe(EntityIndex entity, EntityIndex entity2 = kEntityPlayer, FlagType flag = kFlagNone);
+ void excuseMeCath();
+ const char *justCheckingCath() const;
+ const char *wrongDoorCath() const;
+ const char *justAMinuteCath() const;
+
+ // FLags
+ SoundManager::FlagType getSoundFlag(EntityIndex index) const;
+
+ // Debug
+ void stopAllSound() const;
+
+ // Serializable
+ void saveLoadWithSerializer(Common::Serializer &ser);
+ uint32 count();
+
+private:
+ typedef int32 *SoundBuffer;
+
+ enum SoundStatus {
+ kSoundStatus_20 = 0x20,
+ kSoundStatusRemoved = 0x200,
+
+ kSoundStatus_8000 = 0x8000,
+ kSoundStatus_100000 = 0x100000,
+ kSoundStatus_40000000 = 0x40000000,
+
+ kSoundStatusClear0 = 0x10,
+ kSoundStatusClear1 = 0x1F,
+ kSoundStatusClear2 = 0x80,
+ kSoundStatusClear3 = 0x200,
+ kSoundStatusClear4 = 0x800,
+ kSoundStatusClearAll = 0xFFFFFFE0
+ };
+
+ enum SoundState {
+ kSoundState0 = 0,
+ kSoundState1 = 1,
+ kSoundState2 = 2
+ };
+
+ union SoundStatusUnion {
+ uint32 status;
+ byte status1;
+ byte status2;
+ byte status3;
+ byte status4;
+
+ SoundStatusUnion() {
+ status = 0;
+ }
+ };
+
+ struct SoundEntry {
+ SoundStatusUnion status;
+ SoundType type; // int
+ //int field_8;
+ //int field_C;
+ //int field_10;
+ //int fileData;
+ //int field_18;
+ int field_1C;
+ uint32 time;
+ //int field_24;
+ //int field_28;
+ Common::SeekableReadStream *stream; // int
+ //int field_30;
+ int field_34;
+ int field_38;
+ int field_3C;
+ int field_40;
+ EntityIndex entity;
+ int field_48;
+ int field_4C;
+ Common::String name1; //char[16];
+ Common::String name2; //char[16];
+ //int next; // offset to the next structure in the list (not used)
+ SubtitleManager *subtitle;
+
+ bool isStreamed; // TEMPORARY
+
+ SoundEntry() {
+ status.status = 0;
+ type = kSoundTypeNone;
+
+ field_1C = 0;
+ time = 0;
+
+ stream = NULL;
+
+ field_34 = 0;
+ field_38 = 0;
+ field_3C = 0;
+ field_40 = 0;
+ entity = kEntityPlayer;
+ field_48 = 0;
+ field_4C = 0;
+
+ subtitle = NULL;
+
+ isStreamed = false;
+ }
+ };
+
+ // Engine
+ LastExpressEngine *_engine;
+
+ // State flag
+ int _state;
+ SoundType _currentType;
+
+ // Sound stream
+ StreamedSound *_soundStream;
+
+ // Unknown data
+ uint32 _data0;
+ uint32 _data1;
+ uint32 _data2;
+ uint32 _flag;
+
+ // Filters
+
+ int32 _buffer[2940]; ///< Static sound buffer
+
+ // Compartment warnings by Mertens or Coudert
+ uint32 _lastWarning[12];
+
+ // Looping sound
+ void playLoopingSound();
+
+ // Sound cache
+ Common::List<SoundEntry *> _cache;
+
+ SoundEntry *getEntry(EntityIndex index);
+ SoundEntry *getEntry(Common::String name);
+ SoundEntry *getEntry(SoundType type);
+
+ void setupEntry(SoundEntry *entry, Common::String name, FlagType flag, int a4);
+ void setEntryType(SoundEntry *entry, FlagType flag);
+ void setEntryStatus(SoundEntry *entry, FlagType flag) const;
+ bool setupCache(SoundEntry *entry);
+ void loadSoundData(SoundEntry *entry, Common::String name);
+
+ void updateEntry(SoundEntry *entry, uint value) const;
+ void updateEntryState(SoundEntry *entry) const ;
+ void resetEntry(SoundEntry *entry) const;
+ void removeEntry(SoundEntry *entry);
+
+ // Subtitles
+ void showSubtitles(SoundEntry *entry, Common::String filename);
+ void drawSubtitles(SubtitleManager *subtitle);
+
+ // Sound filter
+ void applyFilter(SoundEntry *entry, SoundBuffer buffer);
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SOUND_H
diff --git a/engines/lastexpress/game/state.cpp b/engines/lastexpress/game/state.cpp
new file mode 100644
index 0000000000..9586c58ceb
--- /dev/null
+++ b/engines/lastexpress/game/state.cpp
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/game/inventory.h"
+#include "lastexpress/game/object.h"
+#include "lastexpress/game/savepoint.h"
+
+#include "lastexpress/lastexpress.h"
+
+namespace LastExpress {
+
+State::State(LastExpressEngine *engine) : _engine(engine), _timer(0) {
+ _inventory = new Inventory(engine);
+ _objects = new Objects(engine);
+ _savepoints = new SavePoints(engine);
+ _state = new GameState();
+ _flags = new Flags();
+}
+
+State::~State() {
+ delete _inventory;
+ delete _objects;
+ delete _savepoints;
+ delete _state;
+ delete _flags;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+bool State::isNightTime() const {
+ return (_state->progress.chapter == kChapter1
+ || _state->progress.chapter == kChapter4
+ || (_state->progress.chapter == kChapter5 && !_state->progress.isNightTime));
+}
+
+void State::getHourMinutes(uint32 time, uint8 *hours, uint8 *minutes) {
+ if (hours == NULL || minutes == NULL)
+ error("State::getHourMinutes: invalid parameters passed!");
+
+ *hours = (uint8)((time % 1296000) / 54000);
+ *minutes = (uint8)((time % 54000) / 900);
+}
+
+uint32 State::getPowerOfTwo(uint32 x) {
+ if (!x || (x & 1))
+ return 0;
+
+ uint32 num = 0;
+ do {
+ x >>= 1;
+ num++;
+ } while ((x & 1) == 0);
+
+ return num;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/state.h b/engines/lastexpress/game/state.h
new file mode 100644
index 0000000000..da81794ce1
--- /dev/null
+++ b/engines/lastexpress/game/state.h
@@ -0,0 +1,657 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_STATE_H
+#define LASTEXPRESS_STATE_H
+
+#include "lastexpress/shared.h"
+
+#include "common/serializer.h"
+#include "common/system.h"
+
+namespace LastExpress {
+
+class LastExpressEngine;
+
+class Inventory;
+class Objects;
+class SavePoints;
+
+class State {
+public:
+ struct GameProgress : public Common::Serializable {
+ uint32 field_0;
+ JacketType jacket;
+ bool eventCorpseMovedFromFloor;
+ uint32 field_C;
+ bool eventCorpseFound;
+ uint32 field_14; ///< EntityIndex (used in Gendarmes)
+ uint32 field_18;
+ uint32 portrait;
+ bool eventCorpseThrown;
+ uint32 field_24;
+ uint32 field_28;
+ ChapterIndex chapter;
+ uint32 field_30;
+ bool eventMetAugust;
+ bool isNightTime;
+ uint32 field_3C;
+ uint32 field_40;
+ uint32 field_44;
+ uint32 field_48;
+ uint32 field_4C;
+ bool isTrainRunning;
+ uint32 field_54;
+ uint32 field_58;
+ uint32 field_5C;
+ uint32 field_60;
+ uint32 field_64;
+ uint32 field_68;
+ bool eventMertensAugustWaiting;
+ bool eventMertensKronosInvitation;
+ bool isEggOpen;
+ uint32 field_78; // time?
+ uint32 field_7C;
+ uint32 field_80;
+ uint32 field_84;
+ uint32 field_88;
+ uint32 field_8C;
+ uint32 field_90;
+ uint32 field_94;
+ uint32 field_98;
+ uint32 field_9C;
+ uint32 field_A0;
+ uint32 field_A4;
+ uint32 field_A8;
+ uint32 field_AC;
+ uint32 field_B0;
+ uint32 field_B4;
+ uint32 field_B8;
+ uint32 field_BC;
+ uint32 field_C0;
+ uint32 field_C4;
+ uint32 field_C8;
+ uint32 field_CC;
+ bool eventMetBoutarel;
+ bool eventMetHadija;
+ bool eventMetYasmin;
+ uint32 field_DC;
+ uint32 field_E0;
+ uint32 field_E4;
+ uint32 field_E8;
+ uint32 field_EC;
+ uint32 field_F0;
+ uint32 field_F4;
+ uint32 field_F8;
+ uint32 field_FC;
+ uint32 field_100;
+ uint32 field_104;
+ uint32 field_108;
+ uint32 field_10C;
+ uint32 field_110;
+ uint32 field_114;
+ uint32 field_118;
+ uint32 field_11C;
+ uint32 field_120;
+ uint32 field_124;
+ uint32 field_128;
+ uint32 field_12C;
+ uint32 field_130;
+ uint32 field_134;
+ uint32 field_138;
+ uint32 field_13C;
+ uint32 field_140;
+ uint32 field_144;
+ uint32 field_148;
+ uint32 field_14C;
+ uint32 field_150;
+ uint32 field_154;
+ uint32 field_158;
+ uint32 field_15C;
+ uint32 field_160;
+ uint32 field_164;
+ uint32 field_168;
+ uint32 field_16C;
+ uint32 field_170;
+ uint32 field_174;
+ uint32 field_178;
+ uint32 field_17C;
+ uint32 field_180;
+ uint32 field_184;
+ uint32 field_188;
+ uint32 field_18C;
+ uint32 field_190;
+ uint32 field_194;
+ uint32 field_198;
+ uint32 field_19C;
+ uint32 field_1A0;
+ uint32 field_1A4;
+ uint32 field_1A8;
+ uint32 field_1AC;
+ uint32 field_1B0;
+ uint32 field_1B4;
+ uint32 field_1B8;
+ uint32 field_1BC;
+ uint32 field_1C0;
+ uint32 field_1C4;
+ uint32 field_1C8;
+ uint32 field_1CC;
+ uint32 field_1D0;
+ uint32 field_1D4;
+ uint32 field_1D8;
+ uint32 field_1DC;
+ uint32 field_1E0;
+ uint32 field_1E4;
+ uint32 field_1E8;
+ uint32 field_1EC;
+ uint32 field_1F0;
+ uint32 field_1F4;
+ uint32 field_1F8;
+ uint32 field_1FC;
+
+ GameProgress() {
+ field_0 = 0;
+ jacket = kJacketOriginal;
+ eventCorpseMovedFromFloor = false;
+ field_C = 0;
+ eventCorpseFound = false;
+ field_14 = 0; // 5
+ field_18 = 0;
+ portrait = _defaultPortrait;
+ eventCorpseThrown = false;
+ field_24 = 0;
+ field_28 = 0; // 10
+ chapter = kChapter1;
+ field_30 = 0;
+ eventMetAugust = false;
+ isNightTime = false;
+ field_3C = 0; // 15
+ field_40 = 0;
+ field_44 = 0;
+ field_48 = 0;
+ field_4C = 0;
+ isTrainRunning = false; // 20
+ field_54 = 0;
+ field_58 = 0;
+ field_5C = 0;
+ field_60 = 0;
+ field_64 = 0; // 25
+ field_68 = 0;
+ eventMertensAugustWaiting = false;
+ eventMertensKronosInvitation = false;
+ isEggOpen = false;
+ field_78 = 0; // 30
+ field_7C = 0;
+ field_80 = 0;
+ field_84 = 0;
+ field_88 = 0;
+ field_8C = 0; // 35
+ field_90 = 0;
+ field_94 = 0;
+ field_98 = 0;
+ field_9C = 0;
+ field_A0 = 0; // 40
+ field_A4 = 0;
+ field_A8 = 0;
+ field_AC = 0;
+ field_B0 = 0;
+ field_B4 = 0; // 45
+ field_B8 = 0;
+ field_BC = 0;
+ field_C0 = 0;
+ field_C4 = 0;
+ field_C8 = 0; // 50
+ field_CC = 0;
+ eventMetBoutarel = false;
+ eventMetHadija = false;
+ eventMetYasmin = false;
+ field_DC = 0; // 55
+ field_E0 = 0;
+ field_E4 = 0;
+ field_E8 = 0;
+ field_EC = 0;
+ field_F0 = 0; // 60
+ field_F4 = 0;
+ field_F8 = 0;
+ field_FC = 0;
+ field_100 = 0;
+ field_104 = 0; // 65
+ field_108 = 0;
+ field_10C = 0;
+ field_110 = 0;
+ field_114 = 0;
+ field_118 = 0; // 70
+ field_11C = 0;
+ field_120 = 0;
+ field_124 = 0;
+ field_128 = 0;
+ field_12C = 0; // 75
+ field_130 = 0;
+ field_134 = 0;
+ field_138 = 0;
+ field_13C = 0;
+ field_140 = 0; // 80
+ field_144 = 0;
+ field_148 = 0;
+ field_14C = 0;
+ field_150 = 0;
+ field_154 = 0; // 85
+ field_158 = 0;
+ field_15C = 0;
+ field_160 = 0;
+ field_164 = 0;
+ field_168 = 0; // 90
+ field_16C = 0;
+ field_170 = 0;
+ field_174 = 0;
+ field_178 = 0;
+ field_17C = 0; // 95
+ field_180 = 0;
+ field_184 = 0;
+ field_188 = 0;
+ field_18C = 0;
+ field_190 = 0; // 100
+ field_194 = 0;
+ field_198 = 0;
+ field_19C = 0;
+ field_1A0 = 0;
+ field_1A4 = 0; // 105
+ field_1A8 = 0;
+ field_1AC = 0;
+ field_1B0 = 0;
+ field_1B4 = 0;
+ field_1B8 = 0; // 110
+ field_1BC = 0;
+ field_1C0 = 0;
+ field_1C4 = 0;
+ field_1C8 = 0;
+ field_1CC = 0; // 115
+ field_1D0 = 0;
+ field_1D4 = 0;
+ field_1D8 = 0;
+ field_1DC = 0;
+ field_1E0 = 0; // 120
+ field_1E4 = 0;
+ field_1E8 = 0;
+ field_1EC = 0;
+ field_1F0 = 0;
+ field_1F4 = 0; // 125
+ field_1F8 = 0;
+ field_1FC = 0;
+ }
+
+ /**
+ * Query if if a progress value is equal to the specified value.
+ *
+ * Note: This is necessary because we store different types in the progress structure
+ * and need to test a value based on an index in Action::getCursor()
+ *
+ * @param index Zero-based index of the progress structure entry
+ * @param val The value.
+ *
+ * @return true if equal, false if not.
+ */
+ bool isEqual(uint index, uint val) {
+ return getValueName(index) == val;
+ }
+
+ uint32 getValueName(uint index, Common::String *name = NULL) {
+ #define EXPOSE_VALUE(idx, entryName) \
+ case idx: { \
+ if (name) (*name) = "" #entryName; \
+ return (uint32)entryName; \
+ }
+
+ switch (index) {
+ default:
+ error("GameProgress::isEqual: invalid index value (was: %d, max:127)", index);
+ break;
+
+ EXPOSE_VALUE(0, field_0);
+ EXPOSE_VALUE(1, jacket);
+ EXPOSE_VALUE(2, eventCorpseMovedFromFloor);
+ EXPOSE_VALUE(3, field_C);
+ EXPOSE_VALUE(4, eventCorpseFound);
+ EXPOSE_VALUE(5, field_14);
+ EXPOSE_VALUE(6, field_18);
+ EXPOSE_VALUE(7, portrait);
+ EXPOSE_VALUE(8, eventCorpseThrown);
+ EXPOSE_VALUE(9, field_24);
+ EXPOSE_VALUE(10, field_28);
+ EXPOSE_VALUE(11, chapter);
+ EXPOSE_VALUE(12, field_30);
+ EXPOSE_VALUE(13, eventMetAugust);
+ EXPOSE_VALUE(14, isNightTime);
+ EXPOSE_VALUE(15, field_3C);
+ EXPOSE_VALUE(16, field_40);
+ EXPOSE_VALUE(17, field_44);
+ EXPOSE_VALUE(18, field_48);
+ EXPOSE_VALUE(19, field_4C);
+ EXPOSE_VALUE(20, isTrainRunning);
+ EXPOSE_VALUE(21, field_54);
+ EXPOSE_VALUE(22, field_58);
+ EXPOSE_VALUE(23, field_5C);
+ EXPOSE_VALUE(24, field_60);
+ EXPOSE_VALUE(25, field_64);
+ EXPOSE_VALUE(26, field_68);
+ EXPOSE_VALUE(27, eventMertensAugustWaiting);
+ EXPOSE_VALUE(28, eventMertensKronosInvitation);
+ EXPOSE_VALUE(29, isEggOpen);
+ EXPOSE_VALUE(30, field_78);
+ EXPOSE_VALUE(31, field_7C);
+ EXPOSE_VALUE(32, field_80);
+ EXPOSE_VALUE(33, field_84);
+ EXPOSE_VALUE(34, field_88);
+ EXPOSE_VALUE(35, field_8C);
+ EXPOSE_VALUE(36, field_90);
+ EXPOSE_VALUE(37, field_94);
+ EXPOSE_VALUE(38, field_98);
+ EXPOSE_VALUE(39, field_9C);
+ EXPOSE_VALUE(40, field_A0);
+ EXPOSE_VALUE(41, field_A4);
+ EXPOSE_VALUE(42, field_A8);
+ EXPOSE_VALUE(43, field_AC);
+ EXPOSE_VALUE(44, field_B0);
+ EXPOSE_VALUE(45, field_B4);
+ EXPOSE_VALUE(46, field_B8);
+ EXPOSE_VALUE(47, field_BC);
+ EXPOSE_VALUE(48, field_C0);
+ EXPOSE_VALUE(49, field_C4);
+ EXPOSE_VALUE(50, field_C8);
+ EXPOSE_VALUE(51, field_CC);
+ EXPOSE_VALUE(52, eventMetBoutarel);
+ EXPOSE_VALUE(53, eventMetHadija);
+ EXPOSE_VALUE(54, eventMetYasmin);
+ EXPOSE_VALUE(55, field_DC);
+ EXPOSE_VALUE(56, field_E0);
+ EXPOSE_VALUE(57, field_E4);
+ EXPOSE_VALUE(58, field_E8);
+ EXPOSE_VALUE(59, field_EC);
+ EXPOSE_VALUE(60, field_F0);
+ EXPOSE_VALUE(61, field_F4);
+ EXPOSE_VALUE(62, field_F8);
+ EXPOSE_VALUE(63, field_FC);
+ EXPOSE_VALUE(64, field_100);
+ EXPOSE_VALUE(65, field_104);
+ EXPOSE_VALUE(66, field_108);
+ EXPOSE_VALUE(67, field_10C);
+ EXPOSE_VALUE(68, field_110);
+ EXPOSE_VALUE(69, field_114);
+ EXPOSE_VALUE(70, field_118);
+ EXPOSE_VALUE(71, field_11C);
+ EXPOSE_VALUE(72, field_120);
+ EXPOSE_VALUE(73, field_124);
+ EXPOSE_VALUE(74, field_128);
+ EXPOSE_VALUE(75, field_12C);
+ EXPOSE_VALUE(76, field_130);
+ EXPOSE_VALUE(77, field_134);
+ EXPOSE_VALUE(78, field_138);
+ EXPOSE_VALUE(79, field_13C);
+ EXPOSE_VALUE(80, field_140);
+ EXPOSE_VALUE(81, field_144);
+ EXPOSE_VALUE(82, field_148);
+ EXPOSE_VALUE(83, field_14C);
+ EXPOSE_VALUE(84, field_150);
+ EXPOSE_VALUE(85, field_154);
+ EXPOSE_VALUE(86, field_158);
+ EXPOSE_VALUE(87, field_15C);
+ EXPOSE_VALUE(88, field_160);
+ EXPOSE_VALUE(89, field_164);
+ EXPOSE_VALUE(90, field_168);
+ EXPOSE_VALUE(91, field_16C);
+ EXPOSE_VALUE(92, field_170);
+ EXPOSE_VALUE(93, field_174);
+ EXPOSE_VALUE(94, field_178);
+ EXPOSE_VALUE(95, field_17C);
+ EXPOSE_VALUE(96, field_180);
+ EXPOSE_VALUE(97, field_184);
+ EXPOSE_VALUE(98, field_188);
+ EXPOSE_VALUE(99, field_18C);
+ EXPOSE_VALUE(100, field_190);
+ EXPOSE_VALUE(101, field_194);
+ EXPOSE_VALUE(102, field_198);
+ EXPOSE_VALUE(103, field_19C);
+ EXPOSE_VALUE(104, field_1A0);
+ EXPOSE_VALUE(105, field_1A4);
+ EXPOSE_VALUE(106, field_1A8);
+ EXPOSE_VALUE(107, field_1AC);
+ EXPOSE_VALUE(108, field_1B0);
+ EXPOSE_VALUE(109, field_1B4);
+ EXPOSE_VALUE(110, field_1B8);
+ EXPOSE_VALUE(111, field_1BC);
+ EXPOSE_VALUE(112, field_1C0);
+ EXPOSE_VALUE(113, field_1C4);
+ EXPOSE_VALUE(114, field_1C8);
+ EXPOSE_VALUE(115, field_1CC);
+ EXPOSE_VALUE(116, field_1D0);
+ EXPOSE_VALUE(117, field_1D4);
+ EXPOSE_VALUE(118, field_1D8);
+ EXPOSE_VALUE(119, field_1DC);
+ EXPOSE_VALUE(120, field_1E0);
+ EXPOSE_VALUE(121, field_1E4);
+ EXPOSE_VALUE(122, field_1E8);
+ EXPOSE_VALUE(123, field_1EC);
+ EXPOSE_VALUE(124, field_1F0);
+ EXPOSE_VALUE(125, field_1F4);
+ EXPOSE_VALUE(126, field_1F8);
+ EXPOSE_VALUE(127, field_1FC);
+ }
+ }
+
+ Common::String toString() {
+ Common::String ret = "";
+
+ for (uint i = 0; i < 128; i++) {
+ Common::String name = "";
+ uint val = getValueName(i, &name);
+ ret += Common::String::format("(%03d) %s = %d\n", i, name.c_str(), val);
+ }
+
+ return ret;
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ for (uint i = 0; i < 128; i++) {
+ uint32 val = getValueName(i);
+ s.syncAsUint32LE(val);
+ }
+ }
+ };
+
+ struct GameState : public Common::Serializable {
+ // Header
+ uint32 brightness;
+ uint32 volume;
+
+ // Game data
+ uint32 field_0;
+ TimeValue time;
+ uint32 timeDelta;
+ uint32 timeTicks;
+ bool sceneUseBackup; // byte
+ SceneIndex scene; // uint32
+ SceneIndex sceneBackup; // uint32
+ SceneIndex sceneBackup2; // uin32
+
+ GameProgress progress;
+ byte events[512];
+
+ GameState() {
+ brightness = _defaultBrigthness;
+ volume = _defaultVolume;
+
+ //Game data
+ time = kTimeCityParis;
+ timeDelta = _defaultTimeDelta;
+ timeTicks = 0;
+ sceneUseBackup = false;
+ scene = kSceneDefault;
+ sceneBackup = kSceneNone;
+ sceneBackup2 = kSceneNone;
+
+ // Clear game events
+ memset(events, 0, 512*sizeof(byte));
+ }
+
+ /**
+ * Convert this object into a string representation.
+ *
+ * @return A string representation of this object.
+ */
+ Common::String toString() {
+ Common::String ret = "";
+
+ uint8 hours = 0;
+ uint8 minutes = 0;
+ getHourMinutes(time, &hours, &minutes);
+
+ ret += Common::String::format("Time: %d (%d:%d) - Time delta: %d - Ticks: %d\n", time, hours, minutes, timeDelta, timeTicks);
+ ret += Common::String::format("Brightness: %d - Volume: %d - UseBackup: %d\n", brightness, volume, sceneUseBackup);
+ ret += Common::String::format("Scene: %d - Scene backup: %d - Scene backup 2: %d\n", scene, sceneBackup, sceneBackup2);
+
+ return ret;
+ }
+
+ void saveLoadWithSerializer(Common::Serializer &s) {
+ s.syncAsUint32LE(time);
+ s.syncAsUint32LE(timeDelta);
+ s.syncAsUint32LE(timeTicks);
+ s.syncAsUint32LE(scene);
+ s.syncAsByte(sceneUseBackup);
+ s.syncAsUint32LE(sceneBackup);
+ s.syncAsUint32LE(sceneBackup2);
+ }
+
+ void syncEvents(Common::Serializer &s) {
+ for (uint i = 0; i < ARRAYSIZE(events); i++)
+ s.syncAsByte(events[i]);
+ }
+ };
+
+ struct Flags {
+ bool flag_0;
+ bool flag_3;
+ bool flag_4;
+ bool flag_5;
+
+ bool frameInterval;
+
+ bool isGameRunning;
+
+ // Mouse flags
+ bool mouseLeftClick;
+ bool mouseRightClick;
+
+ bool flag_entities_0;
+ bool flag_entities_1;
+
+ bool shouldRedraw;
+ bool shouldDrawEggOrHourGlass;
+
+ Flags() {
+ flag_0 = false;
+ flag_3 = false;
+ flag_4 = false;
+ flag_5 = false;
+
+ frameInterval = false;
+
+ isGameRunning = false;
+
+ mouseRightClick = false;
+ mouseLeftClick = false;
+
+ flag_entities_0 = false;
+ flag_entities_1 = false;
+
+ shouldRedraw = false;
+ shouldDrawEggOrHourGlass = false;
+ }
+
+ /**
+ * Convert this object into a string representation.
+ *
+ * @return A string representation of this object.
+ */
+ Common::String toString() {
+ Common::String ret = "";
+
+ ret += Common::String::format("Unknown: 0:%02d - 3:%02d - 4:%02d - 5:%02d\n", flag_0, flag_3, flag_4, flag_5);
+ ret += Common::String::format("FrameInterval: %02d - ShouldRedraw:%02d - ShouldDrawEggOrHourGlass:%02d\n", frameInterval, shouldRedraw, shouldDrawEggOrHourGlass);
+ ret += Common::String::format("IsGameRunning: %02d\n", isGameRunning);
+ ret += Common::String::format("Mouse: RightClick:%02d - LeftClick:%02d\n", mouseRightClick, mouseLeftClick);
+ ret += Common::String::format("Entities: 0:%02d - 1:%02d\n", flag_entities_0, flag_entities_1);
+
+ return ret;
+ }
+ };
+
+ State(LastExpressEngine *engine);
+ ~State();
+
+ // Accessors
+ Inventory *getGameInventory() { return _inventory; }
+ Objects *getGameObjects() { return _objects; }
+ SavePoints *getGameSavePoints() { return _savepoints; }
+ GameState *getGameState() { return _state; }
+ Flags *getGameFlags() { return _flags; }
+
+ // Time checks
+ bool isNightTime() const;
+
+ // Timer
+ int getTimer() { return _timer; }
+ void setTimer(int val) { _timer = val; }
+
+ // Coordinates
+ void setCoordinates(Common::Point coords) { _coords = coords; }
+ const Common::Point getCoordinates() { return _coords; }
+
+ // Helpers
+ static uint32 getPowerOfTwo(uint32 x);
+ static void getHourMinutes(uint32 time, uint8 *hours, uint8 *minutes);
+
+private:
+ static const uint32 _defaultBrigthness = 3;
+ static const uint32 _defaultVolume = 7;
+ static const uint32 _defaultTimeDelta = 3;
+ static const uint32 _defaultPortrait = 32;
+
+ LastExpressEngine *_engine;
+
+ // Timer
+ int _timer;
+
+ Flags *_flags; ///< Flags
+ Inventory *_inventory; ///< Inventory
+ Objects *_objects; ///< Objects
+ SavePoints *_savepoints; ///< SavePoints
+ GameState *_state; ///< State
+ Common::Point _coords; ///< Current coordinates
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_STATE_H
diff --git a/engines/lastexpress/graphics.cpp b/engines/lastexpress/graphics.cpp
new file mode 100644
index 0000000000..e5a69d16ea
--- /dev/null
+++ b/engines/lastexpress/graphics.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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/graphics.h"
+
+#include "common/system.h"
+
+namespace LastExpress {
+
+#define COLOR_KEY 0xFFFF
+
+GraphicsManager::GraphicsManager() : _changed(false) {
+ _screen.create(640, 480, 2);
+
+ // Create the game surfaces
+ _backgroundA.create(640, 480, 2);
+ _backgroundC.create(640, 480, 2);
+ _overlay.create(640, 480, 2);
+ _inventory.create(640, 480, 2);
+
+ clear(kBackgroundAll);
+}
+
+GraphicsManager::~GraphicsManager() {
+ // Free the game surfaces
+ _screen.free();
+ _backgroundA.free();
+ _backgroundC.free();
+ _overlay.free();
+ _inventory.free();
+}
+
+void GraphicsManager::update() {
+ // Update the screen if needed and reset the status
+ if (_changed) {
+ mergePlanes();
+ updateScreen();
+ _changed = false;
+ }
+}
+
+void GraphicsManager::change() {
+ _changed = true;
+}
+
+void GraphicsManager::clear(BackgroundType type) {
+ clear(type, Common::Rect(640, 480));
+}
+
+void GraphicsManager::clear(BackgroundType type, const Common::Rect &rect) {
+ switch (type) {
+ default:
+ error("GraphicsManager::clear() - Unknown background type: %d", type);
+ break;
+
+ case kBackgroundA:
+ case kBackgroundC:
+ case kBackgroundOverlay:
+ case kBackgroundInventory:
+ getSurface(type)->fillRect(rect, COLOR_KEY);
+ break;
+
+ case kBackgroundAll:
+ _backgroundA.fillRect(rect, COLOR_KEY);
+ _backgroundC.fillRect(rect, COLOR_KEY);
+ _overlay.fillRect(rect, COLOR_KEY);
+ _inventory.fillRect(rect, COLOR_KEY);
+ break;
+ }
+}
+
+bool GraphicsManager::draw(Drawable *drawable, BackgroundType type, bool transition) {
+ // TODO handle transition properly
+ if (transition)
+ clear(type);
+
+ // TODO store rect for later use
+ Common::Rect rect = drawable->draw(getSurface(type));
+
+ return (!rect.isEmpty());
+}
+
+Graphics::Surface *GraphicsManager::getSurface(BackgroundType type) {
+ switch (type) {
+ default:
+ error("GraphicsManager::getSurface() - Unknown surface type: %d", type);
+ break;
+
+ case kBackgroundA:
+ return &_backgroundA;
+
+ case kBackgroundC:
+ return &_backgroundC;
+
+ case kBackgroundOverlay:
+ return &_overlay;
+
+ case kBackgroundInventory:
+ return &_inventory;
+
+ case kBackgroundAll:
+ error("GraphicsManager::getSurface() - cannot return a surface for kBackgroundAll!");
+ break;
+ }
+}
+
+// TODO optimize to only merge dirty rects
+void GraphicsManager::mergePlanes() {
+ // Clear screen surface
+ _screen.fillRect(Common::Rect(640, 480), 0);
+
+ uint16 *screen = (uint16 *)_screen.pixels;
+ uint16 *inventory = (uint16 *)_inventory.pixels;
+ uint16 *overlay = (uint16 *)_overlay.pixels;
+ uint16 *backgroundC = (uint16 *)_backgroundC.pixels;
+ uint16 *backgroundA = (uint16 *)_backgroundA.pixels;
+
+ for (int i = 0; i < 640 * 480; i++) {
+
+ if (*inventory != COLOR_KEY)
+ *screen = *inventory;
+ else if (*overlay != COLOR_KEY)
+ *screen = *overlay;
+ else if (*backgroundA != COLOR_KEY)
+ *screen = *backgroundA;
+ else if (*backgroundC != COLOR_KEY)
+ *screen = *backgroundC;
+ else
+ *screen = 0;
+
+ inventory++;
+ screen++;
+ overlay++;
+ backgroundA++;
+ backgroundC++;
+ }
+}
+
+void GraphicsManager::updateScreen() {
+ g_system->fillScreen(0);
+ g_system->copyRectToScreen((byte *)_screen.getBasePtr(0, 0), 640 * 2, 0, 0, 640, 480);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/graphics.h b/engines/lastexpress/graphics.h
new file mode 100644
index 0000000000..5231d00f6f
--- /dev/null
+++ b/engines/lastexpress/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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_GRAPHICS_H
+#define LASTEXPRESS_GRAPHICS_H
+
+#include "lastexpress/drawable.h"
+
+namespace LastExpress {
+
+class GraphicsManager {
+public:
+ enum BackgroundType {
+ kBackgroundA,
+ kBackgroundC,
+ kBackgroundOverlay,
+ kBackgroundInventory,
+ kBackgroundAll
+ };
+
+ GraphicsManager();
+ ~GraphicsManager();
+
+ // Update the screen
+ void update();
+
+ // Signal a change to the screen, will cause the planes to be remerged
+ void change();
+
+ // Clear some screen parts
+ void clear(BackgroundType type);
+ void clear(BackgroundType type, const Common::Rect &rect);
+
+ // FIXME this is there for animation until we change it to use the graphic surface here instead of its private ones.
+ Graphics::Surface _screen; // Actual screen surface
+
+ bool draw(Drawable *drawable, BackgroundType type, bool transition = false);
+
+private:
+ Graphics::Surface _backgroundA; // Background A
+ Graphics::Surface _backgroundC; // Background C
+ Graphics::Surface _overlay; // Overlay
+ Graphics::Surface _inventory; // Overlay
+
+ void mergePlanes();
+ void updateScreen();
+ Graphics::Surface *getSurface(BackgroundType type);
+
+ bool _changed;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_GRAPHICS_H
diff --git a/engines/lastexpress/helpers.h b/engines/lastexpress/helpers.h
new file mode 100644
index 0000000000..fa8eeb25e5
--- /dev/null
+++ b/engines/lastexpress/helpers.h
@@ -0,0 +1,102 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_HELPERS_H
+#define LASTEXPRESS_HELPERS_H
+
+//////////////////////////////////////////////////////////////////////////
+// Misc helpers
+//////////////////////////////////////////////////////////////////////////
+
+// Misc
+#define getArchive(name) _engine->getResourceManager()->getFileStream(name)
+#define rnd(value) _engine->getRandom().getRandomNumber(value - 1)
+
+// Engine subclasses
+#define getLogic() _engine->getGameLogic()
+#define getMenu() _engine->getGameMenu()
+
+// Logic
+#define getAction() getLogic()->getGameAction()
+#define getBeetle() getLogic()->getGameBeetle()
+#define getFight() getLogic()->getGameFight()
+#define getEntities() getLogic()->getGameEntities()
+#define getSaveLoad() getLogic()->getGameSaveLoad()
+#define isNight() getLogic()->getGameState()->isNightTime()
+
+// State
+#define getState() getLogic()->getGameState()->getGameState()
+#define getEvent(id) getState()->events[id]
+#define getFlags() getLogic()->getGameState()->getGameFlags()
+#define getInventory() getLogic()->getGameState()->getGameInventory()
+#define getObjects() getLogic()->getGameState()->getGameObjects()
+#define getProgress() getState()->progress
+#define getSavePoints() getLogic()->getGameState()->getGameSavePoints()
+#define getGlobalTimer() getLogic()->getGameState()->getTimer()
+#define setGlobalTimer(timer) getLogic()->getGameState()->setTimer(timer)
+#define setCoords(coords) getLogic()->getGameState()->setCoordinates(coords)
+#define getCoords() getLogic()->getGameState()->getCoordinates()
+#define setFrameCount(count) _engine->setFrameCounter(count)
+#define getFrameCount() _engine->getFrameCounter()
+
+// Scenes
+#define getScenes() _engine->getSceneManager()
+
+// Sound
+#define getSound() _engine->getSoundManager()
+
+// Others
+#define getEntityData(entity) getEntities()->getData(entity)
+
+//////////////////////////////////////////////////////////////////////////
+// Graphics
+//////////////////////////////////////////////////////////////////////////
+
+// Sequences
+#define loadSequence(name) Sequence::load(name, getArchive(name))
+#define loadSequence1(name, field30) Sequence::load(name, getArchive(name), field30)
+
+#define clearBg(type) _engine->getGraphicsManager()->clear(type)
+#define showScene(index, type) _engine->getGraphicsManager()->draw(getScenes()->get(index), type);
+
+#define askForRedraw() _engine->getGraphicsManager()->change();
+#define redrawScreen() _engine->getGraphicsManager()->update(); _engine->_system->updateScreen();
+
+// Used to delete entity sequences
+#define SAFE_DELETE(_p) { if(_p) { delete (_p); (_p) = NULL; } }
+
+//////////////////////////////////////////////////////////////////////////
+// Output
+//////////////////////////////////////////////////////////////////////////
+extern const char *g_actionNames[];
+extern const char *g_directionNames[];
+extern const char *g_entityNames[];
+
+#define ACTION_NAME(action) (action > 18 ? Common::String::format("%d", action).c_str() : g_actionNames[action])
+#define DIRECTION_NAME(direction) (direction >= 6 ? "INVALID" : g_directionNames[direction])
+#define ENTITY_NAME(index) (index >= 40 ? "INVALID" : g_entityNames[index])
+
+
+#endif // LASTEXPRESS_HELPERS_H
diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp
new file mode 100644
index 0000000000..2ccdc14fbd
--- /dev/null
+++ b/engines/lastexpress/lastexpress.cpp
@@ -0,0 +1,310 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/lastexpress.h"
+
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/font.h"
+
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/menu.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/state.h"
+#include "lastexpress/game/sound.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/resource.h"
+
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/EventRecorder.h"
+
+#include "engines/util.h"
+
+const char *g_actionNames[] = {"None", "Action1", "Action2", "ExitCompartment", "Action4", "ExcuseMeCath", "ExcuseMe", "INVALID", "Knock", "OpenDoor", "Action10", "Action11", "Default", "INVALID", "INVALID", "INVALID", "Action16", "DrawScene", "Callback"};
+const char *g_directionNames[] = { "None", "Up", "Down", "Left", "Right", "Switch"};
+const char *g_entityNames[] = { "Player", "Anna", "August", "Mertens", "Coudert", "Pascale", "Servers0", "Servers1", "Cooks", "Verges", "Tatiana", "Vassili", "Alexei", "Abbot", "Milos", "Vesna", "Ivo", "Salko", "Kronos", "Kahina", "Francois", "MmeBoutarel", "Boutarel", "Rebecca", "Sophie", "Mahmud", "Yasmin", "Hadija", "Alouan", "Gendarmes", "Max", "Chapters", "Train", "Tables0", "Tables1", "Tables2", "Tables3", "Tables4", "Tables5", "Entity39"};
+
+
+namespace LastExpress {
+
+LastExpressEngine::LastExpressEngine(OSystem *syst, const ADGameDescription *gd) :
+ Engine(syst), _gameDescription(gd), _debugger(NULL), _cursor(NULL),
+ _font(NULL), _logic(NULL), _menu(NULL), _frameCounter(0), _lastFrameCount(0),
+ _graphicsMan(NULL), _resMan(NULL), _sceneMan(NULL), _soundMan(NULL),
+ eventMouse(NULL), eventTick(NULL), eventMouseBackup(NULL), eventTickBackup(NULL) {
+
+ // Adding the default directories
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.addSubDirectoryMatching(gameDataDir, "data");
+
+ // Initialize the custom debug levels
+ DebugMan.addDebugChannel(kLastExpressDebugAll, "All", "Debug everything");
+ DebugMan.addDebugChannel(kLastExpressDebugGraphics, "Graphics", "Debug graphics & animation/sequence playback");
+ DebugMan.addDebugChannel(kLastExpressDebugResource, "Resource", "Debug resource management");
+ DebugMan.addDebugChannel(kLastExpressDebugCursor, "Cursor", "Debug cursor handling");
+ DebugMan.addDebugChannel(kLastExpressDebugSound, "Sound", "Debug sound playback");
+ DebugMan.addDebugChannel(kLastExpressDebugSubtitle, "Subtitle", "Debug subtitles");
+ DebugMan.addDebugChannel(kLastExpressDebugSavegame, "Savegame", "Debug savegames");
+ DebugMan.addDebugChannel(kLastExpressDebugLogic, "Logic", "Debug logic");
+ DebugMan.addDebugChannel(kLastExpressDebugScenes, "Scenes", "Debug scenes & hotspots");
+ DebugMan.addDebugChannel(kLastExpressDebugUnknown, "Unknown", "Debug unknown data");
+
+ g_eventRec.registerRandomSource(_random, "lastexpress");
+}
+
+LastExpressEngine::~LastExpressEngine() {
+ _timer->removeTimerProc(&soundTimer);
+
+ // Delete the remaining objects
+ delete _cursor;
+ delete _font;
+ delete _logic;
+ delete _menu;
+ delete _graphicsMan;
+ delete _resMan;
+ delete _sceneMan;
+ delete _soundMan;
+ delete _debugger;
+
+ // Cleanup event handlers
+ SAFE_DELETE(eventMouse);
+ SAFE_DELETE(eventTick);
+ SAFE_DELETE(eventMouseBackup);
+ SAFE_DELETE(eventTickBackup);
+
+ // Zero passed pointers
+ _gameDescription = NULL;
+}
+
+// TODO: which error should we return when some game files are missing/corrupted?
+Common::Error LastExpressEngine::run() {
+ // Initialize the graphics
+ const Graphics::PixelFormat dataPixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
+ initGraphics(640, 480, true, &dataPixelFormat);
+
+ // We do not support color conversion
+ if (_system->getScreenFormat() != dataPixelFormat)
+ return Common::kUnsupportedColorMode;
+
+ // Create debugger. It requires GFX to be initialized
+ _debugger = new Debugger(this);
+
+ // Start the resource and graphics managers
+ _resMan = new ResourceManager(isDemo());
+ if (!_resMan->loadArchive(kArchiveCd1))
+ return Common::kNoGameDataFoundError;
+
+ _graphicsMan = new GraphicsManager();
+
+ // Load the cursor data
+ _cursor = _resMan->loadCursor();
+ if (!_cursor)
+ return Common::kNoGameDataFoundError;
+
+ // Load the font data
+ _font = _resMan->loadFont();
+ if (!_font)
+ return Common::kNoGameDataFoundError;
+
+ // Start scene manager
+ _sceneMan = new SceneManager(this);
+ _sceneMan->loadSceneDataFile(kArchiveCd1);
+
+ // Game logic
+ _logic = new Logic(this);
+
+ // Start sound manager and setup timer
+ _soundMan = new SoundManager(this);
+ _timer->installTimerProc(&soundTimer, 17, this);
+
+ // Menu
+ _menu = new Menu(this);
+ _menu->show(false, kSavegameTypeIndex, 0);
+
+ while (!shouldQuit()) {
+ _soundMan->updateQueue();
+ _soundMan->updateSubtitles();
+
+ if (handleEvents())
+ continue;
+ }
+
+ return Common::kNoError;
+}
+
+void LastExpressEngine::pollEvents() {
+ Common::Event ev;
+ _eventMan->pollEvent(ev);
+
+ switch (ev.type) {
+
+ case Common::EVENT_LBUTTONUP:
+ getGameLogic()->getGameState()->getGameFlags()->mouseLeftClick = true;
+ break;
+
+ case Common::EVENT_RBUTTONUP:
+ getGameLogic()->getGameState()->getGameFlags()->mouseRightClick = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool LastExpressEngine::handleEvents() {
+ // Make sure all the subsystems have been initialized
+ if (!_debugger || !_graphicsMan)
+ error("LastExpressEngine::handleEvents: called before the required subsystems have been initialized!");
+
+ // Execute stored commands
+ if (_debugger->hasCommand()) {
+ _debugger->callCommand();
+
+ // re-attach the debugger
+ _debugger->attach();
+ }
+
+ // Show the debugger if required
+ _debugger->onFrame();
+
+ // Handle input
+ Common::Event ev;
+ while (_eventMan->pollEvent(ev)) {
+ switch (ev.type) {
+
+ case Common::EVENT_KEYDOWN:
+ // CTRL-D: Attach the debugger
+ if ((ev.kbd.flags & Common::KBD_CTRL) && ev.kbd.keycode == Common::KEYCODE_d)
+ _debugger->attach();
+
+ //// DEBUG: Quit game on escape
+ //if (ev.kbd.keycode == Common::KEYCODE_ESCAPE)
+ // quitGame();
+
+ break;
+
+ case Common::EVENT_MAINMENU:
+ // Closing the GMM
+
+ case Common::EVENT_LBUTTONUP:
+ getGameLogic()->getGameState()->getGameFlags()->mouseLeftClick = true;
+
+ // Adjust frameInterval flag
+ if (_frameCounter < _lastFrameCount + 30)
+ getGameLogic()->getGameState()->getGameFlags()->frameInterval = true;
+ _lastFrameCount = _frameCounter;
+
+ if (eventMouse && eventMouse->isValid())
+ (*eventMouse)(ev);
+ break;
+
+ case Common::EVENT_RBUTTONUP:
+ getGameLogic()->getGameState()->getGameFlags()->mouseRightClick = true;
+ if (eventMouse && eventMouse->isValid())
+ (*eventMouse)(ev);
+ break;
+
+ case Common::EVENT_MOUSEMOVE:
+ if (eventMouse && eventMouse->isValid())
+ (*eventMouse)(ev);
+ break;
+
+ case Common::EVENT_QUIT:
+ quitGame();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Game tick event
+ if (eventTick && eventTick->isValid())
+ (*eventTick)(ev);
+
+ // Update the screen
+ _graphicsMan->update();
+ _system->updateScreen();
+ _system->delayMillis(50);
+
+ // The event loop may have triggered the quit status. In this case,
+ // stop the execution.
+ if (shouldQuit()) {
+ return true;
+ }
+
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+/// Timer
+///////////////////////////////////////////////////////////////////////////////////
+void LastExpressEngine::soundTimer(void *refCon) {
+ ((LastExpressEngine *)refCon)->handleSoundTimer();
+}
+
+void LastExpressEngine::handleSoundTimer() {
+ if (_frameCounter & 1)
+ if (_soundMan)
+ _soundMan->handleTimer();
+
+ _frameCounter++;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+/// Event Handling
+///////////////////////////////////////////////////////////////////////////////////
+void LastExpressEngine::backupEventHandlers() {
+ eventMouseBackup = eventMouse;
+ eventTickBackup = eventTick;
+}
+
+void LastExpressEngine::restoreEventHandlers() {
+ if (eventMouseBackup == NULL || eventTickBackup == NULL)
+ error("LastExpressEngine::restoreEventHandlers: restore called before backing up the event handlers!");
+
+ eventMouse = eventMouseBackup;
+ eventTick = eventTickBackup;
+}
+
+void LastExpressEngine::setEventHandlers(EventHandler::EventFunction *mouse, EventHandler::EventFunction *tick) {
+ eventMouse = mouse;
+ eventTick = tick;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+/// Misc Engine
+///////////////////////////////////////////////////////////////////////////////////
+bool LastExpressEngine::hasFeature(EngineFeature f) const {
+ return (f == kSupportsRTL);
+}
+
+void LastExpressEngine::errorString(const char *buf_input, char *buf_output, int buf_output_size) {
+ snprintf(buf_output, (uint)buf_output_size, "%s", buf_input);
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/lastexpress.h b/engines/lastexpress/lastexpress.h
new file mode 100644
index 0000000000..ac05c5a405
--- /dev/null
+++ b/engines/lastexpress/lastexpress.h
@@ -0,0 +1,153 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_H
+#define LASTEXPRESS_H
+
+#include "lastexpress/debug.h"
+#include "lastexpress/eventhandler.h"
+
+#include "common/random.h"
+#include "common/timer.h"
+
+#include "engines/advancedDetector.h"
+#include "engines/engine.h"
+
+#include "graphics/pixelformat.h"
+
+/**
+ * This is the namespace of the LastExpress engine.
+ *
+ * Status of this engine:
+ * The game is playable but still very buggy and missing crucial functionality:
+ * - Resources: classes for the resource formats used by the game are mostly
+ * complete (subtitles integration/cursor transparency are missing)
+ * - Display: basic graphic manager functionality is implemented (transitions
+ * and dirty rects handling are missing)
+ * - Menu/Navigation: menu is done and navigation/hotspot handling are also
+ * mostly implemented (with remaining bugs)
+ * - Logic: all the hardcoded AI logic has been implemented, as well as the
+ * shared entity code for drawing/handling of entities.
+ * - Sound: most of the sound queue functionality is still missing
+ * - Savegame: almost all the savegame code is still missing.
+ *
+ * Maintainers:
+ * littleboy, jvprat, clone2727
+ *
+ * Supported games:
+ * - The Last Express
+ */
+namespace LastExpress {
+
+class Cursor;
+class Font;
+class GraphicsManager;
+class Logic;
+class Menu;
+class ResourceManager;
+class SceneManager;
+class SoundManager;
+
+class LastExpressEngine : public Engine {
+protected:
+ // Engine APIs
+ Common::Error run();
+ virtual void errorString(const char *buf_input, char *buf_output, int buf_output_size);
+ virtual bool hasFeature(EngineFeature f) const;
+ virtual Debugger *getDebugger() { return _debugger; }
+
+public:
+ LastExpressEngine(OSystem *syst, const ADGameDescription *gd);
+ ~LastExpressEngine();
+
+ // Misc
+ Common::RandomSource getRandom() const {return _random; }
+
+ // Game
+ Cursor *getCursor() const { return _cursor; }
+ Font *getFont() const { return _font; }
+ Logic *getGameLogic() const { return _logic; }
+ Menu *getGameMenu() const { return _menu; }
+
+ // Managers
+ GraphicsManager *getGraphicsManager() const { return _graphicsMan; }
+ ResourceManager *getResourceManager() const { return _resMan; }
+ SceneManager *getSceneManager() const { return _sceneMan; }
+ SoundManager *getSoundManager() const { return _soundMan; }
+
+ // Event handling
+ bool handleEvents();
+ void pollEvents();
+
+ void backupEventHandlers();
+ void restoreEventHandlers();
+ void setEventHandlers(EventHandler::EventFunction *eventMouse, EventHandler::EventFunction *eventTick);
+
+ bool isDemo() const { return (bool)(_gameDescription->flags & ADGF_DEMO); }
+
+ // Frame Counter
+ uint32 getFrameCounter() { return _frameCounter; }
+ void setFrameCounter(uint32 count) { _frameCounter = count; }
+
+protected:
+ // Sound Timer
+ static void soundTimer(void *ptr);
+ void handleSoundTimer();
+
+private:
+ const ADGameDescription *_gameDescription;
+ Graphics::PixelFormat _pixelFormat;
+
+ // Misc
+ Debugger *_debugger;
+ Common::RandomSource _random;
+
+ // Game
+ Cursor *_cursor;
+ Font *_font;
+ Logic *_logic;
+ Menu *_menu;
+
+ // Frame counter
+ uint32 _frameCounter;
+ uint32 _lastFrameCount;
+
+ // Managers
+ GraphicsManager *_graphicsMan;
+ ResourceManager *_resMan;
+ SceneManager *_sceneMan;
+ SoundManager *_soundMan;
+
+ // Event handlers
+ EventHandler::EventFunction *eventMouse;
+ EventHandler::EventFunction *eventTick;
+
+ EventHandler::EventFunction *eventMouseBackup;
+ EventHandler::EventFunction *eventTickBackup;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_H
diff --git a/engines/lastexpress/module.mk b/engines/lastexpress/module.mk
new file mode 100644
index 0000000000..12fbb4f85b
--- /dev/null
+++ b/engines/lastexpress/module.mk
@@ -0,0 +1,73 @@
+MODULE := engines/lastexpress
+
+MODULE_OBJS := \
+ data/animation.o \
+ data/archive.o \
+ data/background.o \
+ data/cursor.o \
+ data/font.o \
+ data/scene.o \
+ data/sequence.o \
+ data/snd.o \
+ data/subtitle.o \
+ entities/entity.o \
+ entities/abbot.o \
+ entities/alexei.o \
+ entities/alouan.o \
+ entities/anna.o \
+ entities/august.o \
+ entities/boutarel.o \
+ entities/chapters.o \
+ entities/cooks.o \
+ entities/coudert.o \
+ entities/entity39.o \
+ entities/francois.o \
+ entities/gendarmes.o \
+ entities/hadija.o \
+ entities/ivo.o \
+ entities/kahina.o \
+ entities/kronos.o \
+ entities/mahmud.o \
+ entities/max.o \
+ entities/mertens.o \
+ entities/milos.o \
+ entities/mmeboutarel.o \
+ entities/pascale.o \
+ entities/rebecca.o \
+ entities/salko.o \
+ entities/servers0.o \
+ entities/servers1.o \
+ entities/sophie.o \
+ entities/tables.o \
+ entities/tatiana.o \
+ entities/train.o \
+ entities/vassili.o \
+ entities/verges.o \
+ entities/vesna.o \
+ entities/yasmin.o \
+ game/action.o \
+ game/beetle.o \
+ game/entities.o \
+ game/fight.o \
+ game/inventory.o \
+ game/logic.o \
+ game/menu.o \
+ game/object.o \
+ game/savegame.o \
+ game/savepoint.o \
+ game/scenes.o \
+ game/sound.o \
+ game/state.o \
+ debug.o \
+ detection.o \
+ graphics.o \
+ lastexpress.o \
+ resource.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_LASTEXPRESS), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk \ No newline at end of file
diff --git a/engines/lastexpress/resource.cpp b/engines/lastexpress/resource.cpp
new file mode 100644
index 0000000000..57bc12a185
--- /dev/null
+++ b/engines/lastexpress/resource.cpp
@@ -0,0 +1,248 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/resource.h"
+
+#include "lastexpress/data/background.h"
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/font.h"
+
+#include "lastexpress/debug.h"
+
+#include "common/debug.h"
+#include "common/file.h"
+
+namespace LastExpress {
+
+const char *archiveDemoPath = "demo.hpf";
+const char *archiveHDPath = "hd.hpf";
+const char *archiveCD1Path = "cd1.hpf";
+const char *archiveCD2Path = "cd2.hpf";
+const char *archiveCD3Path = "cd3.hpf";
+
+ResourceManager::ResourceManager(bool isDemo) : _isDemo(isDemo) {
+}
+
+ResourceManager::~ResourceManager() {
+ reset();
+}
+
+bool ResourceManager::isArchivePresent(ArchiveIndex type) {
+ switch (type) {
+ default:
+ case kArchiveAll:
+ error("ResourceManager::isArchivePresent: Only checks for single CDs are valid!");
+
+ case kArchiveCd1:
+ return Common::File::exists(archiveCD1Path);
+
+ case kArchiveCd2:
+ return Common::File::exists(archiveCD2Path);
+
+ case kArchiveCd3:
+ return Common::File::exists(archiveCD3Path);
+ }
+}
+
+// Load a specific archive collection
+// - type is ignored in the demo version
+// - use ArchiveAll to load all three cds
+// - HD.hpf is always loaded along with the selected archive(s)
+// - will remove all other archives
+bool ResourceManager::loadArchive(ArchiveIndex type) {
+ // Unload all archives
+ reset();
+
+ // Demo version
+ if (_isDemo)
+ return loadArchive(archiveDemoPath);
+
+ // Load HD
+ if (!loadArchive(archiveHDPath))
+ return false;
+
+ switch(type) {
+ case kArchiveCd1:
+ return loadArchive(archiveCD1Path);
+
+ case kArchiveCd2:
+ return loadArchive(archiveCD2Path);
+
+ case kArchiveCd3:
+ return loadArchive(archiveCD3Path);
+
+ case kArchiveAll:
+ default:
+ if (loadArchive(archiveCD1Path))
+ if (loadArchive(archiveCD2Path))
+ return loadArchive(archiveCD3Path);
+ break;
+ }
+
+ return false;
+}
+
+void ResourceManager::reset() {
+ // Free the loaded archives
+ for (Common::Array<HPFArchive *>::iterator it = _archives.begin(); it != _archives.end(); ++it)
+ delete (*it);
+
+ _archives.clear();
+}
+
+bool ResourceManager::loadArchive(const Common::String &name) {
+ HPFArchive *archive = new HPFArchive(name);
+
+ if (archive->count() == 0) {
+ debugC(2, kLastExpressDebugResource, "Error opening archive: %s", name.c_str());
+
+ delete archive;
+
+ return false;
+ }
+
+ _archives.push_back(archive);
+
+ return true;
+}
+
+// Get a stream to file in the archive
+// - same as createReadStreamForMember except it checks if the file exists and will assert / output a debug message if not
+Common::SeekableReadStream *ResourceManager::getFileStream(const Common::String &name) {
+
+ // Check if the file exits in the archive
+ if (!hasFile(name)) {
+//#ifdef _DEBUG
+// error("ResourceManager::getFileStream: cannot open file: %s", name.c_str());
+//#endif
+ debugC(2, kLastExpressDebugResource, "Error opening file: %s", name.c_str());
+ return NULL;
+ }
+
+ debugC(2, kLastExpressDebugResource, "Opening file: %s", name.c_str());
+
+ return createReadStreamForMember(name);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Archive functions
+//////////////////////////////////////////////////////////////////////////
+bool ResourceManager::hasFile(const Common::String &name) {
+ for (Common::Array<HPFArchive *>::iterator it = _archives.begin(); it != _archives.end(); ++it) {
+ if ((*it)->hasFile(name))
+ return true;
+ }
+
+ return false;
+}
+
+int ResourceManager::listMembers(Common::ArchiveMemberList &list) {
+ int count = 0;
+
+ for (Common::Array<HPFArchive *>::iterator it = _archives.begin(); it != _archives.end(); ++it) {
+
+ Common::ArchiveMemberList members;
+ count += (*it)->listMembers(members);
+
+ list.insert(list.end(), members.begin(), members.end());
+ }
+
+ return count;
+}
+
+Common::ArchiveMemberPtr ResourceManager::getMember(const Common::String &name) {
+ if (!hasFile(name))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *ResourceManager::createReadStreamForMember(const Common::String &name) const {
+ for (Common::Array<HPFArchive *>::const_iterator it = _archives.begin(); it != _archives.end(); ++it) {
+
+ Common::SeekableReadStream *stream = (*it)->createReadStreamForMember(name);
+
+ if (stream)
+ return stream;
+ }
+
+ return NULL;
+}
+
+
+// Resource loading
+
+Background *ResourceManager::loadBackground(const Common::String &name) const {
+ // Open the resource
+ Common::SeekableReadStream *stream = createReadStreamForMember(name + ".bg");
+ if (!stream)
+ return NULL;
+
+ // Create the new background & load the data
+ Background *bg = new Background();
+ if (!bg->load(stream)) {
+ delete bg;
+ // stream should be freed by the Background instance
+ return NULL;
+ }
+
+ return bg;
+}
+
+Cursor *ResourceManager::loadCursor() const {
+ // Open the resource
+ Common::SeekableReadStream *stream = createReadStreamForMember("cursors.tbm");
+ if (!stream)
+ return NULL;
+
+ // Create the new background
+ Cursor *c = new Cursor();
+ if (!c->load(stream)) {
+ delete c;
+ // stream should be freed by the Cursor instance
+ return NULL;
+ }
+
+ return c;
+}
+
+Font *ResourceManager::loadFont() const {
+ // Open the resource
+ Common::SeekableReadStream *stream = createReadStreamForMember("font.dat");
+ if (!stream)
+ return NULL;
+
+ // Create the new background
+ Font *f = new Font();
+ if (!f->load(stream)) {
+ delete f;
+ // stream should be freed by the Font instance
+ return NULL;
+ }
+
+ return f;
+}
+
+} // End of namespace LastExpress
diff --git a/engines/lastexpress/resource.h b/engines/lastexpress/resource.h
new file mode 100644
index 0000000000..ea6508edc3
--- /dev/null
+++ b/engines/lastexpress/resource.h
@@ -0,0 +1,72 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_RESOURCE_H
+#define LASTEXPRESS_RESOURCE_H
+
+#include "lastexpress/data/archive.h"
+#include "lastexpress/shared.h"
+
+namespace LastExpress {
+
+class Background;
+class Cursor;
+class Font;
+
+class ResourceManager : public Common::Archive {
+public:
+ ResourceManager(bool demo);
+ ~ResourceManager();
+
+ // Loading
+ bool loadArchive(ArchiveIndex type);
+ static bool isArchivePresent(ArchiveIndex type);
+ Common::SeekableReadStream *getFileStream(const Common::String &name);
+
+ // Archive functions
+ bool hasFile(const Common::String &name);
+ int listMembers(Common::ArchiveMemberList &list);
+ Common::ArchiveMemberPtr getMember(const Common::String &name);
+ Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+
+ // Resource loading
+ Background *loadBackground(const Common::String &name) const;
+ Cursor *loadCursor() const;
+ Font *loadFont() const;
+
+private:
+ bool _isDemo;
+
+ bool loadArchive(const Common::String &name);
+ void reset();
+
+ Common::Array<HPFArchive *> _archives;
+
+ friend class Debugger;
+};
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_RESOURCE_H
diff --git a/engines/lastexpress/shared.h b/engines/lastexpress/shared.h
new file mode 100644
index 0000000000..80e227e6a7
--- /dev/null
+++ b/engines/lastexpress/shared.h
@@ -0,0 +1,1716 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef LASTEXPRESS_SHARED_H
+#define LASTEXPRESS_SHARED_H
+
+#include "common/func.h"
+
+namespace LastExpress {
+
+//////////////////////////////////////////////////////////////////////////
+// Time values
+//////////////////////////////////////////////////////////////////////////
+
+// Time is measured in ticks, with 15 ticks per second. One minute is 900
+// ticks, one hour is 54,000 ticks, and one day is 1,296,000 ticks.
+
+enum TimeValue {
+ kTimeNone = 0,
+ kTime5933 = 5933,
+
+ kTimeCityParis = 1037700, // Day 1, 19:13
+ kTime1039500 = 1039500, // Day 1, 19:15
+ kTimeStartGame = 1061100, // Day 1, 19:39
+
+ // Chapter 1
+ kTimeChapter1 = 1062000, // Day 1, 19:40
+ kTime1071000 = 1071000, // Day 1, 19:50
+ kTimeParisEpernay = 1075500, // Day 1, 19:55
+ kTime1080000 = 1080000, // Day 1, 20:00
+ kTime1084500 = 1084500, // Day 1, 20:05
+ kTime1089000 = 1089000, // Day 1, 20:10
+ kTime1093500 = 1093500, // Day 1, 20:15
+ kTime1094400 = 1094400, // Day 1, 20:16
+ kTime1096200 = 1096200, // Day 1, 20:18
+ kTime1098000 = 1098000, // Day 1, 20:20
+ kTime1102500 = 1102500, // Day 1, 20:25
+ kTime1107000 = 1107000, // Day 1, 20:30
+ kTime1111500 = 1111500, // Day 1, 20:35
+ kTime1120500 = 1120500, // Day 1, 20:45
+ kTime1125000 = 1125000, // Day 1, 20:50
+ kTime1134000 = 1134000, // Day 1, 21:00
+ kTime1138500 = 1138500, // Day 1, 21:05
+ kTime1143000 = 1143000, // Day 1, 21:10
+ kTimeEnterEpernay = 1147500, // Day 1, 21:15
+ kTimeCityEpernay = 1148400, // Day 1, 21:16
+ kTimeExitEpernay = 1150200, // Day 1, 21:18
+ kTime1156500 = 1156500, // Day 1, 21:25
+ kTime1161000 = 1161000, // Day 1, 21:30
+ kTime1162800 = 1162800, // Day 1, 21:32
+ kTime1165500 = 1165500, // Day 1, 21:35
+ kTime1167300 = 1167300, // Day 1, 21:37
+ kTimeEnterChalons = 1170000, // Day 1, 21:40
+ kTimeCityChalons = 1170900, // Day 1, 21:41
+ kTimeExitChalons = 1173600, // Day 1, 21:44
+ kTime1174500 = 1174500, // Day 1, 21:45
+ kTime1179000 = 1179000, // Day 1, 21:50
+ kTime1183500 = 1183500, // Day 1, 21:55
+ kTime1184400 = 1184400, // Day 1, 21:56
+ kTime1188000 = 1188000, // Day 1, 22:00
+ kTime1189800 = 1189800, // Day 1, 22:02
+ kTime1192500 = 1192500, // Day 1, 22:05
+ kTime1197000 = 1197000, // Day 1, 22:10
+ kTime1201500 = 1201500, // Day 1, 22:15
+ kTime1206000 = 1206000, // Day 1, 22:20
+ kTime1215000 = 1215000, // Day 1, 22:30
+ kTime1224000 = 1224000, // Day 1, 22:40
+ kTime1225800 = 1225800, // Day 1, 22:42
+ kTimeCityBarLeDuc = 1228500, // Day 1, 22:45
+ kTimeExitBarLeDuc = 1231200, // Day 1, 22:48
+ kTime1233000 = 1233000, // Day 1, 22:50
+ kTime1242000 = 1242000, // Day 1, 23:00
+ kTime1260000 = 1260000, // Day 1, 23:20
+ kTimeCityNancy = 1303200, // Day 2, 00:08
+ kTimeExitNancy = 1307700, // Day 2, 00:13
+ kTime1323000 = 1323000, // Day 2, 00:30
+ kTimeCityLuneville = 1335600, // Day 2, 00:44
+ kTimeExitLuneville = 1338300, // Day 2, 00:47
+ kTimeCityAvricourt = 1359900, // Day 2, 01:11
+ kTimeExitAvricourt = 1363500, // Day 2, 01:15
+ kTimeCityDeutschAvricourt = 1367100, // Day 2, 01:19
+ kTimeExitDeutschAvricourt = 1370700, // Day 2, 01:23
+ kTime1386000 = 1386000, // Day 2, 01:40
+ kTimeBedTime = 1404000, // Day 2, 02:00
+ kTime1417500 = 1417500, // Day 2, 02:15
+ kTimeEnterStrasbourg = 1424700, // Day 2, 02:23
+ kTime1449000 = 1449000, // Day 2, 02:50
+ kTime1458000 = 1458000, // Day 2, 03:00
+ kTime1485000 = 1485000, // Day 2, 03:30
+ kTime1489500 = 1489500, // Day 2, 03:35
+ kTimeCityStrasbourg = 1490400, // Day 2, 03:36
+ kTime1492200 = 1492200, // Day 2, 03:38
+ kTimeExitStrasbourg = 1493100, // Day 2, 03:39
+ kTimeChapter1End = 1494000, // Day 2, 03:40
+ kTime1503000 = 1503000, // Day 2, 03:50
+ kTime1512000 = 1512000, // Day 2, 04:00
+ kTimeCityBadenOos = 1539000, // Day 2, 04:30
+ kTimeExitBadenOos = 1541700, // Day 2, 04:33
+ kTimeCityKarlsruhe = 1563300, // Day 2, 04:57
+ kTimeCityStuttgart = 1656000, // Day 2, 06:40
+ kTimeChapter1End2 = 1647000, // Day 2, 06:30
+ kTimeChapter1End3 = 1674000, // Day 2, 07:00
+ kTimeCityGeislingen = 1713600, // Day 2, 07:44
+ kTime1714500 = 1714500, // Day 2, 07:45
+ kTimeCityUlm = 1739700, // Day 2, 08:13
+
+ // Chapter 2
+ kTimeChapter2 = 1750500, // Day 2, 08:25
+ kTime1759500 = 1759500, // Day 2, 08:35
+ kTime1755000 = 1755000, // Day 2, 08:30
+ kTime1764000 = 1764000, // Day 2, 08:40
+ kTime1768500 = 1768500, // Day 2, 08:45
+ kTime1773000 = 1773000, // Day 2, 08:50
+ kTime1777500 = 1777500, // Day 2, 08:55
+ kTime1782000 = 1782000, // Day 2, 09:00
+ kTime1786500 = 1786500, // Day 2, 09:05
+ kTime1791000 = 1791000, // Day 2, 09:10
+ kTime1800000 = 1800000, // Day 2, 09:20
+ kTime1801800 = 1801800, // Day 2, 09:22
+ kTime1806300 = 1806300, // Day 2, 09:27
+ kTime1809000 = 1809000, // Day 2, 09:30
+ kTimeCityAugsburg = 1809900, // Day 2, 09:31
+ kTime1813500 = 1813500, // Day 2, 09:35
+ kTime1818000 = 1818000, // Day 2, 09:40
+ kTime1818900 = 1818900, // Day 2, 09:41
+ kTime1820700 = 1820700, // Day 2, 09:43
+ kTime1822500 = 1822500, // Day 2, 09:45
+ kTime1827000 = 1827000, // Day 2, 09:50
+ kTime1831500 = 1831500, // Day 2, 09:55
+ kTime1836000 = 1836000, // Day 2, 10:00
+ kTime1845000 = 1845000, // Day 2, 10:10
+ kTime1849500 = 1849500, // Day 2, 10:15
+ kTimeCityMunich = 1852200, // Day 2, 10:18
+
+ // Chapter 3
+ kTimeChapter3 = 1944000, // Day 2, 12:00
+ kTime1953000 = 1953000, // Day 2, 12:10
+ kTime1966500 = 1966500, // Day 2, 12:25
+ kTime1969200 = 1969200, // Day 2, 12:28
+ kTime1971000 = 1971000, // Day 2, 12:30
+ kTimeEnterSalzbourg = 1982700, // Day 2, 12:43
+ kTime1983600 = 1983600, // Day 2, 12:44
+ kTimeCitySalzbourg = 1984500, // Day 2, 12:45
+ kTime1989000 = 1989000, // Day 2, 12:50
+ kTimeExitSalzbourg = 1989900, // Day 2, 12:51
+ kTime1993500 = 1993500, // Day 2, 12:55
+ kTime1998000 = 1998000, // Day 2, 13:00
+ kTime2002500 = 2002500, // Day 2, 13:05
+ kTime2011500 = 2011500, // Day 2, 13:15
+ kTime2016000 = 2016000, // Day 2, 13:20
+ kTime2020500 = 2020500, // Day 2, 13:25
+ kTime2025000 = 2025000, // Day 2, 13:30
+ kTime2034000 = 2034000, // Day 2, 13:40
+ kTime2038500 = 2038500, // Day 2, 13:45
+ kTime2040300 = 2040300, // Day 2, 13:47
+ kTime2043000 = 2043000, // Day 2, 13:50
+ kTimeEnterAttnangPuchheim = 2047500, // Day 2, 13:55
+ kTimeCityAttnangPuchheim = 2049300, // Day 2, 13:57
+ kTime2052000 = 2052000, // Day 2, 14:00
+ kTimeExitAttnangPuchheim = 2052900, // Day 2, 14:01
+ kTime2056500 = 2056500, // Day 2, 14:05
+ kTime2061000 = 2061000, // Day 2, 14:10
+ kTime2062800 = 2062800, // Day 2, 14:12
+ kTime2065500 = 2065500, // Day 2, 14:15
+ kTime2070000 = 2070000, // Day 2, 14:20
+ kTimeEnterWels = 2073600, // Day 2, 14:24
+ kTimeCityWels = 2075400, // Day 2, 14:26
+ kTime2079000 = 2079000, // Day 2, 14:30
+ kTimeExitWels = 2079900, // Day 2, 14:31
+ kTime2083500 = 2083500, // Day 2, 14:35
+ kTime2088000 = 2088000, // Day 2, 14:40
+ kTime2088900 = 2088900, // Day 2, 14:41
+ kTime2092500 = 2092500, // Day 2, 14:45
+ kTime2097000 = 2097000, // Day 2, 14:50
+ kTimeEnterLinz = 2099700, // Day 2, 14:53
+ kTimeCityLinz = 2101500, // Day 2, 14:55
+ kTime2106000 = 2106000, // Day 2, 15:00
+ kTime2110500 = 2110500, // Day 2, 15:05
+ kTime2115000 = 2115000, // Day 2, 15:10
+ kTime2117700 = 2117700, // Day 2, 15:13
+ kTime2119500 = 2119500, // Day 2, 15:15
+ kTime2124000 = 2124000, // Day 2, 15:20
+ kTime2133000 = 2133000, // Day 2, 15:30
+ kTime2138400 = 2138400, // Day 2, 15:36
+ kTime2142000 = 2142000, // Day 2, 15:40
+ kTime2146500 = 2146500, // Day 2, 15:45
+ kTime2147400 = 2147400, // Day 2, 15:46
+ kTime2151000 = 2151000, // Day 2, 15:50
+ kTimeCityAmstetten = 2154600, // Day 2, 15:54
+ kTime2155500 = 2155500, // Day 2, 15:55
+ kTime2160000 = 2160000, // Day 2, 16:00
+ kTime2169000 = 2169000, // Day 2, 16:10
+ kTime2173500 = 2173500, // Day 2, 16:15
+ kTime2187000 = 2187000, // Day 2, 16:30
+ kTime2182500 = 2182500, // Day 2, 16:25
+ kTime2196000 = 2196000, // Day 2, 16:40
+ kTime2200500 = 2200500, // Day 2, 16:45
+ kTime2205000 = 2205000, // Day 2, 16:50
+ kTime2214000 = 2214000, // Day 2, 17:00
+ kTime2218500 = 2218500, // Day 2, 17:05
+ kTime2223000 = 2223000, // Day 2, 17:10
+ kTime2227500 = 2227500, // Day 2, 17:15
+ kTime2241000 = 2241000, // Day 2, 17:30
+ kTime2248200 = 2248200, // Day 2, 17:38
+ kTime2250000 = 2250000, // Day 2, 17:40
+ kTime2254500 = 2254500, // Day 2, 17:45
+ kTime2259000 = 2259000, // Day 2, 17:50
+ kTime2263500 = 2263500, // Day 2, 17:55
+ kTime2266200 = 2266200, // Day 2, 17:58
+ kTimeCityVienna = 2268000, // Day 2, 18:00
+
+ // Chapter 4
+ kTime2349000 = 2349000, // Day 2, 19:30
+ kTimeChapter4 = 2353500, // Day 2, 19:35
+ kTime2354400 = 2354400, // Day 2, 19:36
+ kTime2356200 = 2356200, // Day 2, 19:38
+ kTime2358000 = 2358000, // Day 2, 19:40
+ kTime2360700 = 2360700, // Day 2, 19:43
+ kTime2362500 = 2362500, // Day 2, 19:45
+ kTime2361600 = 2361600, // Day 2, 19:44
+ kTime2367000 = 2367000, // Day 2, 19:50
+ kTime2370600 = 2370600, // Day 2, 19:54
+ kTime2378700 = 2378700, // Day 2, 20:03
+ kTimeEnterPoszony = 2381400, // Day 2, 20:06
+ kTimeCityPoszony = 2383200, // Day 2, 20:08
+ kTime2385000 = 2385000, // Day 2, 20:10
+ kTimeExitPoszony = 2386800, // Day 2, 20:12
+ kTime2389500 = 2389500, // Day 2, 20:15
+ kTime2394000 = 2394000, // Day 2, 20:20
+ kTime2398500 = 2398500, // Day 2, 20:25
+ kTime2403000 = 2403000, // Day 2, 20:30
+ kTime2407500 = 2407500, // Day 2, 20:35
+ kTime2410200 = 2410200, // Day 2, 20:38
+ kTime2412000 = 2412000, // Day 2, 20:40
+ kTime2414700 = 2414700, // Day 2, 20:43
+ kTime2415600 = 2415600, // Day 2, 20:44
+ kTimeEnterGalanta = 2416500, // Day 2, 20:45
+ kTimeCityGalanta = 2418300, // Day 2, 20:47
+ kTime2421000 = 2421000, // Day 2, 20:50
+ kTimeExitGalanta = 2421900, // Day 2, 20:51
+ kTime2422800 = 2422800, // Day 2, 20:52
+ kTime2428200 = 2428200, // Day 2, 20:58
+ kTime2425500 = 2425500, // Day 2, 20:55
+ kTime2430000 = 2430000, // Day 2, 21:00
+ kTime2434500 = 2434500, // Day 2, 21:05
+ kTime2439000 = 2439000, // Day 2, 21:10
+ kTime2443500 = 2443500, // Day 2, 21:15
+ kTime2448000 = 2448000, // Day 2, 21:20
+ kTime2452500 = 2452500, // Day 2, 21:25
+ kTime2455200 = 2455200, // Day 2, 21:28
+ kTime2457000 = 2457000, // Day 2, 21:30
+ kTime2466000 = 2466000, // Day 2, 21:40
+ kTime2470500 = 2470500, // Day 2, 21:45
+ kTime2475000 = 2475000, // Day 2, 21:50
+ kTime2479500 = 2479500, // Day 2, 21:55
+ kTime2484000 = 2484000, // Day 2, 22:00
+ kTime2488500 = 2488500, // Day 2, 22:05
+ kTime2493000 = 2493000, // Day 2, 22:10
+ kTime2506500 = 2506500, // Day 2, 22:25
+ kTime2507400 = 2507400, // Day 2, 22:26
+ kTime2511000 = 2511000, // Day 2, 22:30
+ kTime2511900 = 2511900, // Day 2, 22:31
+ kTime2517300 = 2517300, // Day 2, 22:37
+ kTime2519100 = 2519100, // Day 2, 22:39
+ kTime2520000 = 2520000, // Day 2, 22:40
+ kTime2533500 = 2533500, // Day 2, 22:55
+ kTime2535300 = 2535300, // Day 2, 22:57
+ kTime2538000 = 2538000, // Day 2, 23:00
+ kTimeCityBudapest = 2551500, // Day 2, 23:15
+
+ // Chapter 5
+ kTimeChapter5 = 2844000, // Day 3, 04:40
+ kTimeTrainStopped = 2898000, // Day 3, 05:40
+ kTime2907000 = 2907000, // Day 3, 05:50
+ kTime2916000 = 2916000, // Day 3, 06:00
+ kTimeCityBelgrade = 2952000, // Day 3, 06:40
+ kTimeTrainStopped2 = 2943000, // Day 3, 06:30
+ kTime2983500 = 2983500, // Day 3, 07:15
+ kTimeCityNish = 3205800, // Day 3, 11:22
+ kTimeCityTzaribrod = 3492000, // Day 3, 16:40
+ kTime3645000 = 3645000, // Day 3, 19:30
+ kTimeCitySofia = 3690000, // Day 3, 20:20
+ kTimeCityAdrianople = 4320900, // Day 4, 08:01
+ kTime4923000 = 4923000, // Day 4, 19:10
+ kTime4929300 = 4929300, // Day 4, 19:17
+ kTimeCityConstantinople = 4941000, // Day 4, 19:30
+
+
+ kTime10881000 = 10881000,
+ kTimeEnd = 15803100,
+ kTime16451100 = 16451100,
+
+ kTimeInvalid = 2147483647,
+ kTimeInvalid2 = 0xFFFFFEDA
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Archive & Chapter ID
+//////////////////////////////////////////////////////////////////////////
+enum ArchiveIndex {
+ kArchiveAll = 0,
+ kArchiveCd1 = 1,
+ kArchiveCd2 = 2,
+ kArchiveCd3 = 3
+};
+
+enum ChapterIndex {
+ kChapterAll = 0,
+ kChapter1 = 1,
+ kChapter2 = 2,
+ kChapter3 = 3,
+ kChapter4 = 4,
+ kChapter5 = 5
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Index of scenes
+//////////////////////////////////////////////////////////////////////////
+enum SceneIndex {
+ kSceneNone = 0,
+ kSceneMenu = 1,
+
+ kSceneIntro = 30,
+
+ // Inventory
+ kSceneMatchbox = 31,
+ kSceneTelegram = 32,
+ kScenePassengerList = 33,
+ kSceneScarf = 34,
+ kSceneParchemin = 35,
+ kSceneArticle = 36,
+ kScenePaper = 37,
+ kSceneFirebird = 38,
+ kSceneBriefcase = 39,
+
+ // Normal scenes
+ kSceneDefault = 40,
+ kScene41 = 41,
+ kSceneCompartmentCorpse = 42, // Tyler compartment with corpse on floor
+
+ // Fight
+ kSceneFightMilos = 43,
+ kSceneFightMilosBedOpened = 44,
+ kSceneFightAnna = 45,
+ kSceneFightIvo = 46,
+ kSceneFightSalko = 47,
+ kSceneFightVesna = 48,
+
+ kSceneEuropeMap = 49,
+
+ // Game over
+ kSceneGameOverStopPolice = 50,
+ kSceneGameOverTrainStopped = 51,
+ kSceneGameOverTrainStopped2 = 52,
+ kSceneGameOverTrainExplosion = 53,
+ kSceneGameOverTrainExplosion2 = 54,
+ kSceneGameOverBloodJacket = 55,
+ kSceneGameOverPolice = 56,
+ kSceneGameOverPolice1 = 57,
+ kSceneGameOverAnnaDied = 58,
+ kSceneGameOverVienna = 59,
+ kSceneGameOverVienna1 = 60,
+ kSceneGameOverVienna2 = 61,
+ kSceneGameOverAlarm = 62,
+ kSceneGameOverPolice2 = 63,
+ kSceneGameOverAlarm2 = 64,
+
+ // Start screen
+ kSceneStartScreen = 65,
+
+ kSceneBeetle = 128,
+
+ kSceneFightDefault = 820,
+
+ kSceneInvalid = 0xffffffff
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Jacket
+//////////////////////////////////////////////////////////////////////////
+enum JacketType {
+ kJacketOriginal = 0,
+ kJacketBlood = 1,
+ kJacketGreen = 2
+};
+
+//////////////////////////////////////////////////////////////////////////
+// City
+//////////////////////////////////////////////////////////////////////////
+enum CityIndex {
+ kCityEpernay = 0,
+ kCityChalons,
+ kCityBarleduc,
+ kCityNancy,
+ kCityLuneville,
+ kCityAvricourt, // 5
+ kCityDeutschAvricourt,
+ kCityStrasbourg,
+ kCityBadenOos,
+ kCitySalzbourg,
+ kCityAttnangPuchheim, // 10
+ kCityWels,
+ kCityLinz,
+ kCityVienna,
+ kCityPoszony,
+ kCityGalanta, // 15
+ kCityPolice
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Savegame ID
+//////////////////////////////////////////////////////////////////////////
+enum GameId {
+ kGameBlue,
+ kGameRed,
+ kGameGreen,
+ kGamePurple,
+ kGameTeal,
+ kGameGold
+};
+
+enum SavegameType {
+ kSavegameTypeIndex = 0,
+ kSavegameTypeTime = 1,
+ kSavegameTypeEvent = 2,
+ kSavegameTypeEvent2 = 3,
+ kSavegameTypeAuto = 4,
+ kSavegameTypeTickInterval = 5
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Cursor style
+//////////////////////////////////////////////////////////////////////////
+enum CursorStyle {
+ kCursorNormal,
+ kCursorForward,
+ kCursorBackward,
+ kCursorTurnRight,
+ kCursorTurnLeft,
+ kCursorUp,
+ kCursorDown,
+ kCursorLeft,
+ kCursorRight,
+ kCursorHand,
+ kCursorHandKnock, // 10
+ kCursorMagnifier,
+ kCursorHandPointer,
+ kCursorSleep,
+ kCursorTalk,
+ kCursorTalk2, // Need better name
+
+ // Items
+ kCursorMatchBox,
+ kCursorTelegram,
+ kCursorPassengerList,
+ kCursorArticle,
+ kCursorScarf, // 20
+ kCursorPaper,
+ kCursorParchemin,
+ kCursorMatch,
+ kCursorWhistle,
+ kCursorKey,
+ kCursorBomb,
+ kCursorFirebird,
+ kCursorBriefcase,
+ kCursorCorpse,
+
+ // Combat
+ kCursorPunchLeft, // 30
+ kCursorPunchRight,
+
+ // Portraits
+ kCursorPortrait, // 32
+ kCursorPortraitSelected,
+ kCursorPortraitGreen,
+ kCursorPortraitGreenSelected,
+ kCursorPortraitYellow,
+ kCursorPortraitYellowSelected,
+ kCursorHourGlass,
+ kCursorEggBlue,
+ kCursorEggRed, // 40
+ kCursorEggGreen,
+ kCursorEggPurple,
+ kCursorEggTeal,
+ kCursorEggGold,
+ kCursorEggClock,
+ kCursorNormal2,
+ kCursorBlank,
+ kCursorMAX,
+
+ // Special
+ kCursorProcess = 128,
+ kCursorKeepValue = 255
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Position - should be between 0 & 100
+//////////////////////////////////////////////////////////////////////////
+typedef unsigned char Position;
+
+//////////////////////////////////////////////////////////////////////////
+// EntityPosition
+//////////////////////////////////////////////////////////////////////////
+enum EntityPosition {
+ kPositionNone = 0,
+ kPosition_1 = 1,
+ kPosition_3 = 3,
+ kPosition_4 = 4,
+ kPosition_500 = 500,
+ kPosition_540 = 540,
+ kPosition_750 = 750,
+ kPosition_849 = 849,
+ kPosition_850 = 850,
+ kPosition_851 = 851,
+ kPosition_1200 = 1200,
+ kPosition_1430 = 1430,
+ kPosition_1500 = 1500,
+ kPosition_1540 = 1540,
+ kPosition_1750 = 1750,
+ kPosition_2000 = 2000,
+ kPosition_2087 = 2087,
+ kPosition_2086 = 2086,
+ kPosition_2088 = 2088,
+ kPosition_2110 = 2110,
+ kPosition_2300 = 2300,
+ kPosition_2330 = 2330,
+ kPosition_2410 = 2410,
+ kPosition_2436 = 2436,
+ kPosition_2490 = 2490,
+ kPosition_2500 = 2500,
+ kPosition_2587 = 2587,
+ kPosition_2588 = 2588,
+ kPosition_2690 = 2690,
+ kPosition_2740 = 2740,
+ kPosition_2830 = 2830,
+ kPosition_2980 = 2980,
+ kPosition_3050 = 3050,
+ kPosition_3110 = 3110,
+ kPosition_3390 = 3390,
+ kPosition_3450 = 3450,
+ kPosition_3500 = 3500,
+ kPosition_3550 = 3550,
+ kPosition_3650 = 3650,
+ kPosition_3760 = 3760,
+ kPosition_3820 = 3820,
+ kPosition_3890 = 3890,
+ kPosition_3969 = 3969,
+ kPosition_3970 = 3970,
+ kPosition_4070 = 4070,
+ kPosition_4100 = 4100,
+ kPosition_4370 = 4370,
+ kPosition_4455 = 4455,
+ kPosition_4460 = 4460,
+ kPosition_4500 = 4500,
+ kPosition_4590 = 4590,
+ kPosition_4680 = 4680,
+ kPosition_4689 = 4689,
+ kPosition_4690 = 4690,
+ kPosition_4691 = 4691,
+ kPosition_4770 = 4470,
+ kPosition_4840 = 4840,
+ kPosition_5000 = 5000,
+ kPosition_5090 = 5090,
+ kPosition_5140 = 5140,
+ kPosition_5419 = 5419,
+ kPosition_5420 = 5420,
+ kPosition_5440 = 5440,
+ kPosition_5500 = 5500,
+ kPosition_5540 = 5540,
+ kPosition_5610 = 5610,
+ kPosition_5790 = 5790,
+ kPosition_5799 = 5799,
+ kPosition_5800 = 5800,
+ kPosition_5810 = 5810,
+ kPosition_5890 = 5890,
+ kPosition_5900 = 5900,
+ kPosition_5970 = 5970,
+ kPosition_6000 = 6000,
+ kPosition_6130 = 6130,
+ kPosition_6160 = 6160,
+ kPosition_6220 = 6220,
+ kPosition_6410 = 6410,
+ kPosition_6460 = 6460,
+ kPosition_6469 = 6469,
+ kPosition_6470 = 6470,
+ kPosition_6471 = 6471,
+ kPosition_6800 = 6800,
+ kPosition_6850 = 6850,
+ kPosition_7000 = 7000,
+ kPosition_7160 = 7160,
+ kPosition_7250 = 7250,
+ kPosition_7320 = 7320,
+ kPosition_7500 = 7500,
+ kPosition_7510 = 7510,
+ kPosition_7850 = 7850,
+ kPosition_7870 = 7870,
+ kPosition_7900 = 7900,
+ kPosition_7950 = 7950,
+ kPosition_8000 = 8000,
+ kPosition_8012 = 8012,
+ kPosition_8013 = 8013,
+ kPosition_8160 = 8160,
+ kPosition_8200 = 8200,
+ kPosition_8500 = 8500,
+ kPosition_8512 = 8512,
+ kPosition_8513 = 8513,
+ kPosition_8514 = 8514,
+ kPosition_8800 = 8800,
+ kPosition_9020 = 9020,
+ kPosition_9269 = 9269,
+ kPosition_9250 = 9250,
+ kPosition_9270 = 9270,
+ kPosition_9271 = 9271,
+ kPosition_9460 = 9460,
+ kPosition_9500 = 9500,
+ kPosition_9510 = 9510,
+ kPosition_30000 = 30000
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Location
+//////////////////////////////////////////////////////////////////////////
+enum Location {
+ kLocationOutsideCompartment = 0,
+ kLocationInsideCompartment = 1,
+ kLocationOutsideTrain = 2
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Car
+//////////////////////////////////////////////////////////////////////////
+enum CarIndex {
+ kCarNone = 0,
+ kCarBaggageRear = 1,
+ kCarKronos = 2,
+ kCarGreenSleeping = 3,
+ kCarRedSleeping = 4,
+ kCarRestaurant = 5,
+ kCarBaggage = 6,
+ kCarCoalTender = 7,
+ kCarLocomotive = 8,
+ kCar9 = 9
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Clothes
+//////////////////////////////////////////////////////////////////////////
+enum ClothesIndex {
+ kClothesDefault = 0,
+ kClothes1 = 1,
+ kClothes2 = 2,
+ kClothes3 = 3,
+
+ kClothesInvalid
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Location of objects
+//////////////////////////////////////////////////////////////////////////
+enum ObjectLocation {
+ kObjectLocationNone = 0,
+ kObjectLocation1 = 1, // Floor?
+ kObjectLocation2 = 2, // Bed ?
+ kObjectLocation3 = 3,
+ kObjectLocation4 = 4, // Window ?
+ kObjectLocation5 = 5,
+ kObjectLocation6 = 6,
+ kObjectLocation7 = 7,
+ kObjectLocation8 = 8,
+ kObjectLocation9 = 9,
+ kObjectLocation10 = 10,
+ kObjectLocation18 = 18
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Entity direction
+//////////////////////////////////////////////////////////////////////////
+enum EntityDirection {
+ kDirectionNone = 0,
+ kDirectionUp = 1,
+ kDirectionDown = 2,
+ kDirectionLeft = 3,
+ kDirectionRight = 4,
+ kDirectionSwitch = 5
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Combat
+//////////////////////////////////////////////////////////////////////////
+enum FightType {
+ kFightMilos = 2001,
+ kFightAnna = 2002,
+ kFightIvo = 2003,
+ kFightSalko = 2004,
+ kFightVesna = 2005
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Index of items in inventory data
+//////////////////////////////////////////////////////////////////////////
+enum InventoryItem {
+ kItemNone,
+ kItemMatchBox,
+ kItem2,
+ kItem3,
+ kItemTelegram,
+ kItem5, // 5
+ kItemPassengerList,
+ kItem7,
+ kItemScarf,
+ kItem9,
+ kItemParchemin, // 10
+ kItem11,
+ kItemMatch,
+ kItemWhistle,
+ kItemBeetle,
+ kItemKey, // 15
+ kItemBomb,
+ kItem17,
+ kItemFirebird,
+ kItemBriefcase,
+ kItemCorpse, // 20
+ kItemGreenJacket,
+ kItem22,
+ kItemPaper,
+ kItemArticle,
+ kItem25, // 25
+ kItem26,
+ kItem27,
+ kItem28,
+ kItem29,
+ kItem30, // 30
+ kItem31,
+
+ // Portrait (not an index)
+ kPortraitOriginal = 32,
+ kPortraitGreen = 34,
+ kPortraitYellow = 36,
+
+ kItemInvalid = 128,
+
+ kItem146 = 146,
+ kItem147 = 147,
+
+ // Toggles
+ kItemToggleHigh = 0x7F,
+ kItemToggleLow = 0xF7
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Object ID
+//////////////////////////////////////////////////////////////////////////
+enum ObjectIndex {
+ kObjectNone,
+ kObjectCompartment1,
+ kObjectCompartment2,
+ kObjectCompartment3,
+ kObjectCompartment4,
+ kObjectCompartment5, // 5
+ kObjectCompartment6,
+ kObjectCompartment7,
+ kObjectCompartment8,
+ kObjectOutsideTylerCompartment,
+ kObject10, // 10
+ kObject11,
+ kObject12,
+ kObject13,
+ kObject14,
+ kObject15, // 15
+ kObject16,
+ kObjectHandleBathroom,
+ kObjectHandleInsideBathroom,
+ kObjectKitchen,
+ kObject20, // 20
+ kObject21,
+ kObject22,
+ kObjectTrainTimeTable,
+ kObjectRedSleepingCar,
+ kObject25, // 25
+ kObjectHandleOutsideLeft,
+ kObjectHandleOutsideRight,
+ kObject28,
+ kObject29,
+ kObject30, // 30
+ kObject31,
+ kObjectCompartmentA,
+ kObjectCompartmentB,
+ kObjectCompartmentC,
+ kObjectCompartmentD, // 35
+ kObjectCompartmentE,
+ kObjectCompartmentF,
+ kObjectCompartmentG,
+ kObjectCompartmentH,
+ kObject40, // 40
+ kObject41,
+ kObject42,
+ kObject43,
+ kObjectOutsideBetweenCompartments,
+ kObjectOutsideAnnaCompartment, // 45
+ kObject46,
+ kObject47,
+ kObject48, // might be the egg
+ kObject49,
+ kObject50, // 50
+ kObject51,
+ kObject52,
+ kObject53,
+ kObject54,
+ kObjectRestaurantCar, // 55
+ kObject56,
+ kObject57,
+ kObject58,
+ kObject59,
+ kObject60, // 60
+ kObject61,
+ kObject62,
+ kObject63,
+ kObject64,
+ kObject65, // 65
+ kObject66,
+ kObject67,
+ kObject68,
+ kObject69,
+ kObject70, // 70
+ kObject71,
+ kObject72,
+ kObjectCeiling,
+ kObject74,
+ kObjectCompartmentKronos, // 75
+ kObject76,
+ kObject77,
+ kObject78,
+ kObject79,
+ kObject80, // 80
+ kObject81,
+ kObject82,
+ kObject83,
+ kObject84,
+ kObject85, // 85
+ kObject86,
+ kObject87,
+ kObject88,
+ kObject89,
+ kObject90, // 90
+ kObject91,
+ kObject92,
+ kObject93,
+ kObject94,
+ kObject95, // 95
+ kObject96,
+ kObject97,
+ kObject98,
+ kObject99,
+ kObject100, // 100
+ kObject101,
+ kObject102,
+ kObject103,
+ kObject104,
+ kObject105, // 105
+ kObject106,
+ kObject107,
+ kObject108,
+ kObjectCageMax,
+ kObject110, // 110
+ kObject111,
+ kObject112,
+ kObject113,
+ kObject114,
+ kObject115, // 115
+ kObject116,
+ kObject117,
+ kObject118,
+ kObject119,
+ kObject120, // 120
+ kObject121,
+ kObject122,
+ kObject123,
+ kObject124,
+ kObject125, // 125
+ kObject126,
+ kObject127,
+ kObjectMax
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Entity ID
+//////////////////////////////////////////////////////////////////////////
+enum EntityIndex {
+ kEntityPlayer,
+ kEntityAnna,
+ kEntityAugust,
+ kEntityMertens,
+ kEntityCoudert,
+ kEntityPascale, // 5
+ kEntityServers0,
+ kEntityServers1,
+ kEntityCooks,
+ kEntityVerges,
+ kEntityTatiana, // 10
+ kEntityVassili,
+ kEntityAlexei,
+ kEntityAbbot,
+ kEntityMilos,
+ kEntityVesna, // 15
+ kEntityIvo,
+ kEntitySalko,
+ kEntityKronos,
+ kEntityKahina,
+ kEntityFrancois, // 20
+ kEntityMmeBoutarel,
+ kEntityBoutarel,
+ kEntityRebecca,
+ kEntitySophie,
+ kEntityMahmud, // 25
+ kEntityYasmin,
+ kEntityHadija,
+ kEntityAlouan,
+ kEntityGendarmes,
+ kEntityMax, // 30
+ kEntityChapters,
+ kEntityTrain,
+ kEntityTables0,
+ kEntityTables1,
+ kEntityTables2, // 35
+ kEntityTables3,
+ kEntityTables4,
+ kEntityTables5,
+ kEntity39,
+
+ kEntitySteam = 255
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Events
+// - a single D at the end means that Cath is on the right of the "scene" (D = Down the train, U = Up the train)
+// - DD: during the day, coming down the train
+// - DU: during the day, coming up the train
+// - ND: during the night, coming down the train
+// - NU: during the night, coming up the train
+//////////////////////////////////////////////////////////////////////////
+enum EventIndex {
+ kEventNone = 0,
+ kEventGotALight = 1,
+ kEventGotALightD = 2,
+ kEventDinerMindJoin = 3,
+ kEventDinerAugustOriginalJacket = 4,
+ kEventDinerAugust = 5,
+ kEventDinerAugustAlexeiBackground = 6,
+ kEventMeetAugustTylerCompartment = 7,
+ kEventMeetAugustTylerCompartmentBed = 8,
+ kEventMeetAugustHisCompartment = 9,
+ kEventMeetAugustHisCompartmentBed = 10,
+ kEventAugustFindCorpse = 11,
+ kEventAugustPresentAnna = 12,
+ kEventAugustPresentAnnaFirstIntroduction = 13,
+ kEventAnnaIntroductionRejected = 14,
+ kEventAnnaConversationGoodNight = 15,
+ kEventAnnaVisitToCompartmentGun = 16,
+ kEventInvalid_17 = 17,
+ kEventAnnaGoodNight = 18,
+ kEventAnnaGoodNightInverse = 19,
+ kEventAugustGoodMorning = 20,
+ kEventAugustMerchandise = 21,
+ kEventAugustTalkGold = 22,
+ kEventAugustTalkGoldDay = 23,
+ kEventAugustTalkCompartmentDoor = 24,
+ kEventAugustTalkCompartmentDoorBlueRedingote = 25,
+ kEventAugustLunch = 26,
+ kEventKronosVisit = 27,
+ kEventAnnaSearchingCompartment = 28,
+ kEventAugustBringEgg = 29,
+ kEventAugustBringBriefcase = 30,
+ kEventAugustTalkCigar = 31,
+ kEventAnnaBaggageArgument = 32,
+ kEventAnnaBagagePart2 = 33,
+ kEventAnnaConversation_34 = 34,
+ kEventAugustDrink = 35,
+ kEventAnnaTired = 36,
+ kEventAnnaTiredKiss = 37,
+ kEventAnnaBaggageTies = 38,
+ kEventAnnaBaggageTies2 = 39,
+ kEventAnnaBaggageTies3 = 40,
+ kEventAnnaBaggageTies4 = 41,
+ kEventAugustUnhookCarsBetrayal = 42,
+ kEventAugustUnhookCars = 43,
+ kEventLocomotiveAnnaStopsTrain = 44,
+ kEventInvalid_45 = 45,
+ kEventTrainStopped = 46,
+ kEventAnnaKissTrainHijacked = 47,
+ kEventTrainHijacked = 48,
+ kEventAnnaKilled = 49,
+ kEventKronosGoingToInvitation = 50,
+ kEventKronosConversation = 51,
+ kEventKahinaAskSpeakFirebird = 52,
+ kEventKahinaAskSpeak = 53,
+ kEventKronosConversationFirebird = 54,
+ kEventKahinaGunYellow = 55,
+ kEventKahinaGunBlue = 56,
+ kEventKahinaGun = 57,
+ kEventKronosBringEggCeiling = 58,
+ kEventKronosBringEgg = 59,
+ kEventKronosBringNothing = 60,
+ kEventKronosReturnBriefcase = 61,
+ kEventKronosHostageAnna = 62,
+ kEventKronosGiveFirebird = 63,
+ kEventKahinaPunchBaggageCarEntrance = 64,
+ kEventKahinaPunchBlue = 65,
+ kEventKahinaPunchYellow = 66,
+ kEventKahinaPunchSalon = 67,
+ kEventKahinaPunchKitchen = 68,
+ kEventKahinaPunchBaggageCar = 69,
+ kEventKahinaPunchCar = 70,
+ kEventKahinaPunchSuite4 = 71,
+ kEventKahinaPunchRestaurant = 72,
+ kEventKronosHostageAnnaNoFirebird = 73,
+ kEventKahinaPunch = 74,
+ kEventKahinaWrongDoor = 75,
+ kEventAlexeiDiner = 76,
+ kEventAlexeiDinerOriginalJacket = 77,
+ kEventAlexeiSalonVassili = 78,
+ kEventAlexeiSalonCath = 79,
+ kEventAlexeiSalonPoem = 80,
+ kEventTatianaAskMatchSpeakRussian = 81,
+ kEventTatianaAskMatch = 82,
+ kEventTatianaGivePoem = 83,
+ kEventVassiliSeizure = 84,
+ kEventTatianaBreakfastAlexei = 85,
+ kEventTatianaBreakfast = 86,
+ kEventTatianaBreakfastGivePoem = 87,
+ kEventTatianaAlexei = 88,
+ kEventTatianaCompartmentStealEgg = 89,
+ kEventTatianaCompartment = 90,
+ kEventVassiliCompartmentStealEgg = 91,
+ kEventTatianaTylerCompartment = 92,
+ kEventTylerCastleDream= 93,
+ kEventVassiliDeadAlexei = 94,
+ kEventCathFreePassengers = 95,
+ kEventTatianaVassiliTalk = 96,
+ kEventTatianaVassiliTalkNight = 97,
+ kEventMilosTylerCompartmentVisit = 98,
+ kEventMilosTylerCompartmentBedVisit = 99,
+ kEventMilosTylerCompartment = 100,
+ kEventMilosTylerCompartmentBed = 101,
+ kEventMilosTylerCompartmentDefeat = 102,
+ kEventMilosCorpseFloor = 103,
+ kEventMilosCompartmentVisitAugust = 104,
+ kEventMilosCorridorThanks = 105,
+ kEventMilosCorridorThanksD = 106,
+ kEventMilosCompartmentVisitTyler = 107,
+ kEventLocomotiveMilosDay = 108,
+ kEventLocomotiveMilosNight = 109,
+ kEventAbbotIntroduction = 110,
+ kEventAbbotWrongCompartment = 111,
+ kEventAbbotWrongCompartmentBed = 112,
+ kEventAbbotInvitationDrink = 113,
+ kEventAbbotDrinkGiveDetonator = 114,
+ kEventTrainExplosionBridge = 115,
+ kEventDefuseBomb = 116,
+ kEventAbbotDrinkDefuse = 117,
+ kEventMertensLastCar = 118,
+ kEventMertensLastCarOriginalJacket = 119,
+ kEventMertensKronosInvitation = 120,
+ kEventMertensKronosInvitationCompartment = 121,
+ kEventMertensKronosInvitationClosedWindows = 122,
+ kEventMertensBloodJacket = 123,
+ kEventCoudertBloodJacket = 124,
+ kEventMertensCorpseFloor = 125,
+ kEventMertensCorpseBed = 126,
+ kEventMertensDontMakeBed = 127,
+ kEventInvalid_128 = 128,
+ kEventGendarmesArrestation = 129,
+ kEventVergesSuitcase = 130,
+ kEventVergesSuitcaseStart = 131,
+ kEventVergesSuitcaseOtherEntry = 132,
+ kEventVergesSuitcaseOtherEntryStart = 133,
+ kEventVergesSuitcaseNight = 134,
+ kEventVergesSuitcaseNightStart = 135,
+ kEventVergesSuitcaseNightOtherEntry = 136,
+ kEventVergesSuitcaseNightOtherEntryStart = 137,
+ kEventMertensAskTylerCompartment = 138,
+ kEventMertensAskTylerCompartmentD = 139,
+ kEventMertensPushCall = 140,
+ kEventMertensPushCallNight = 141,
+ kEventMertensAugustWaiting = 142,
+ kEventMertensAugustWaitingCompartment = 143,
+ kEventIntroBroderbrund = 144,
+ kEventCoudertAskTylerCompartment = 145,
+ kEventMertensKronosConcertInvitation = 146,
+ kEventCoudertGoingOutOfVassiliCompartment = 147,
+ kEventLocomotiveConductorsDiscovered = 148,
+ kEventLocomotiveConductorsLook = 149,
+ kEventMahmudWrongDoor = 150,
+ kEventMahmudWrongDoorOriginalJacket = 151,
+ kEventMahmudWrongDoorDay = 152,
+ kEventVergesEscortToDiningCar = 153,
+ kEventVergesBaggageCarOffLimits = 154,
+ kEventVergesCanIHelpYou = 155,
+ kEventCoudertBaggageCar = 156,
+ kEventCathTurningDay = 157,
+ kEventCathTurningNight = 158,
+ kEventIntro = 159,
+ kEventCathDream = 160,
+ kEventCorpseDropBridge = 161,
+ kEventTrainPassing = 162,
+ kEventVergesAnnaDead = 163,
+ kEventViennaAugustUnloadGuns = 164,
+ kEventViennaKronosFirebird = 165,
+ kEventViennaContinueGame = 166,
+ kEventCathVesnaRestaurantKilled = 167,
+ kEventCathMaxCage = 168,
+ kEventCathMaxFree = 169,
+ kEventCathMaxLickHand = 170,
+ kEventCathIvoFight = 171,
+ kEventCathSalkoTrainTopFight = 172,
+ kEventCathVesnaTrainTopFight = 173,
+ kEventCathVesnaTrainTopKilled = 174,
+ kEventCathVesnaTrainTopWin = 175,
+ kEventCathSalkoTrainTopWin = 176,
+ kEventFrancoisWhistle = 177,
+ kEventFrancoisWhistleD = 178,
+ kEventFrancoisWhistleNight = 179,
+ kEventFrancoisWhistleNightD = 180,
+ kEventFrancoisShowBeetle = 181,
+ kEventFrancoisShowBeetleD = 182,
+ kEventFrancoisTradeWhistle = 183,
+ kEventFrancoisTradeWhistleD = 184,
+ kEventFrancoisShowEgg = 185,
+ kEventFrancoisShowEggD = 186,
+ kEventFrancoisShowEggNight = 187,
+ kEventFrancoisShowEggNightD = 188,
+ kEventKronosBringFirebird = 189,
+ kEventKronosOpenFirebird = 190,
+ kEventFinalSequence = 191,
+ kEventLocomotiveRestartTrain = 192,
+ kEventLocomotiveOldBridge = 193,
+ kEventLocomotiveAbbotGetSomeRest = 194,
+ kEventLocomotiveAbbotShoveling = 195,
+ kEventLocomotiveMilosShovelingDay = 196,
+ kEventLocomotiveMilosShovelingNight = 197,
+ kEventAnnaGiveScarf = 198,
+ kEventAnnaGiveScarfDiner = 199,
+ kEventAnnaGiveScarfSalon = 200,
+ kEventAnnaGiveScarfMonogram = 201,
+ kEventAnnaGiveScarfDinerMonogram = 202,
+ kEventAnnaGiveScarfSalonMonogram = 203,
+ kEventAnnaGiveScarfAsk = 204,
+ kEventAnnaGiveScarfDinerAsk = 205,
+ kEventAnnaGiveScarfSalonAsk = 206,
+ kEventAugustArrivalInMunich = 207,
+ kEventAnnaDialogGoToJerusalem = 208,
+ kEventConcertStart = 209,
+ kEventConcertEnd = 210,
+ kEventCathFallingAsleep = 211,
+ kEventCathWakingUp = 212,
+ kEventConcertCough = 213,
+ kEventConcertSit = 214,
+ kEventConcertLeaveWithBriefcase = 215,
+ kEventCorpseDropFloorOriginal = 216,
+ kEventCorpseDropFloorGreen = 217,
+ kEventCorpsePickFloorOriginal = 218,
+ kEventCorpsePickFloorGreen = 219,
+ kEventCorpsePickFloorOpenedBedOriginal = 220,
+ kEventCorpsePickBedOriginal = 221,
+ kEventCorpsePickBedGreen = 222,
+ kEventCorpseDropBedOriginal = 223,
+ kEventCorpseDropBedGreen = 224,
+ kEventCorpseDropWindowOriginal = 225,
+ kEventCorpseDropWindowGreen = 226,
+ kEventCathFindCorpse = 227,
+ kEventCathLookOutsideWindowDay = 228,
+ kEventCathLookOutsideWindowNight = 229,
+ kEventCathGoOutsideTylerCompartmentDay = 230,
+ kEventCathGoOutsideTylerCompartmentNight = 231,
+ kEventCathGoOutsideDay = 232,
+ kEventCathGoOutsideNight = 233,
+ kEventCathSlipTylerCompartmentDay = 234,
+ kEventCathSlipTylerCompartmentNight = 235,
+ kEventCathSlipDay = 236,
+ kEventCathSlipNight = 237,
+ kEventCathGetInsideTylerCompartmentDay = 238,
+ kEventCathGetInsideTylerCompartmentNight = 239,
+ kEventCathGetInsideDay = 240,
+ kEventCathGetInsideNight = 241,
+ kEventCathGettingInsideAnnaCompartment = 242,
+ kEventCathClimbUpTrainGreenJacket = 243,
+ kEventCathClimbUpTrainNoJacketNight = 244,
+ kEventCathClimbUpTrainNoJacketDay = 245,
+ kEventCathClimbDownTrainGreenJacket = 246,
+ kEventCathClimbDownTrainNoJacketNight = 247,
+ kEventCathClimbDownTrainNoJacketDay= 248,
+ kEventCathTopTrainGreenJacket = 249,
+ kEventCathTopTrainNoJacketNight = 250,
+ kEventCathTopTrainNoJacketDay = 251,
+ kEventCathBreakCeiling = 252,
+ kEventCathJumpDownCeiling = 253,
+ kEventCathJumpUpCeilingBriefcase = 254,
+ kEventCathJumpUpCeiling = 255,
+ kEventPickGreenJacket = 256,
+ kEventPickScarfGreen = 257,
+ kEventPickScarfOriginal = 258,
+ kEventCloseMatchbox = 259,
+ kEventCathStruggleWithBonds = 260,
+ kEventCathBurnRope = 261,
+ kEventCathRemoveBonds = 262,
+ kEventCathStruggleWithBonds2 = 263,
+ kEventCathDefusingBomb = 264,
+ kEventCathSmokeNight = 265,
+ kEventCathSmokeDay = 266,
+ kEventCathOpenEgg = 267,
+ kEventCathOpenEggNoBackground = 268,
+ kEventCathCloseEgg = 269,
+ kEventCathCloseEggNoBackground = 270,
+ kEventCathUseWhistleOpenEgg = 271,
+ kEventCathUseWhistleOpenEggNoBackground = 272
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Action ID (used by entity logic)
+//////////////////////////////////////////////////////////////////////////
+enum ActionIndex {
+ kActionNone = 0,
+ kAction1 = 1,
+ kActionEndSound = 2,
+ kActionExitCompartment = 3,
+ kAction4 = 4,
+ kActionExcuseMeCath = 5,
+ kActionExcuseMe = 6,
+ kActionKnock = 8,
+ kActionOpenDoor = 9,
+ kAction10 = 10,
+ kAction11 = 11,
+ kActionDefault = 12,
+ kAction16 = 16,
+ kActionDrawScene = 17,
+ kActionCallback = 18,
+
+ /////////////////////////////
+ // Abbot
+ /////////////////////////////
+ kAction100969180 = 100969180, // Anna
+ kAction101169422 = 101169422,
+ kAction104060776 = 104060776,
+ kAction135600432 = 135600432,
+ kAction136196244 = 136196244,
+ kAction157159392 = 157159392,
+ kAction157489665 = 157489665,
+ kAction158480160 = 158480160,
+ kAction192054567 = 192054567,
+ kAction203073664 = 203073664,
+ kAction222609266 = 222609266,
+
+ /////////////////////////////
+ // Alexei
+ /////////////////////////////
+ kAction100906246 = 100906246,
+ kAction123536024 = 123536024,
+ kAction124697504 = 124697504,
+ kAction135664192 = 135664192,
+ kAction135854208 = 135854208,
+ kAction188784532 = 188784532,
+ kAction221617184 = 221617184,
+
+ /////////////////////////////
+ // Alouan
+ /////////////////////////////
+ kAction189489753 = 189489753,
+ kAction190219584 = 190219584, // Francois
+
+ /////////////////////////////
+ // Anna
+ /////////////////////////////
+ kAction136702400 = 136702400,
+ kAction139254416 = 139254416,
+ kAction156049968 = 156049968,
+ kAction157370960 = 157370960,
+ kAction157894320 = 157894320,
+ kAction159332865 = 159332865, // August
+ kAction189299008 = 189299008,
+ kAction191668032 = 191668032, // some action during or before concert?
+ kAction201437056 = 201437056,
+ kAction235856512 = 235856512,
+ kAction236060709 = 236060709,
+ kAction238936000 = 238936000,
+ kAction259136835 = 259136835,
+ kAction291662081 = 291662081,
+
+
+ /////////////////////////////
+ // August
+ /////////////////////////////
+ kAction123793792 = 123793792,
+ kAction134611040 = 134611040,
+ kAction168046720 = 168046720,
+ kAction168627977 = 168627977,
+ kAction169032608 = 169032608,
+ kAction189426612 = 189426612,
+ kAction203859488 = 203859488,
+ kAction219522616 = 219522616, // Servers0
+ kAction225182640 = 225182640,
+ kAction235257824 = 235257824,
+
+ /////////////////////////////
+ // Boutarel
+ /////////////////////////////
+ kAction125039808 = 125039808,
+ kAction134466544 = 134466544,
+ kAction135854206 = 135854206,
+ kAction159003408 = 159003408,
+ kAction203520448 = 203520448,
+ kAction237889408 = 237889408,
+
+ /////////////////////////////
+ // Chapters
+ /////////////////////////////
+ kAction135800432 = 135800432,
+ kActionChapter3 = 139122728,
+ kActionChapter5 = 139254416,
+ kAction156435676 = 156435676,
+ kAction169629818 = 169629818,
+ kAction171843264 = 171843264,
+ kAction190346110 = 190346110,
+
+ /////////////////////////////
+ // Cooks
+ /////////////////////////////
+ kAction101632192 = 101632192,
+ kAction224849280 = 224849280,
+ kAction236976550 = 236976550,
+
+ /////////////////////////////
+ // Coudert
+ /////////////////////////////
+ kAction123733488 = 123733488,
+ kAction154005632 = 154005632,
+ kAction155991520 = 155991520,
+ kAction157026693 = 157026693,
+ kAction168253822 = 168253822,
+ kAction168254872 = 168254872,
+ kAction168316032 = 168316032, // Tatiana
+ kAction169557824 = 169557824,
+ kAction171394341 = 171394341, // Mertens
+ kAction185671840 = 185671840,
+ kAction185737168 = 185737168,
+ kAction188570113 = 188570113,
+ kAction189026624 = 189026624,
+ kAction189750912 = 189750912,
+ kAction192063264 = 192063264, // Anna
+ kAction201431954 = 201431954, // Mertens / Verges
+ kAction201439712 = 201439712,
+ kAction205033696 = 205033696,
+ kAction205346192 = 205346192, // Francois
+ kAction219971920 = 219971920, // Anna
+ kAction223068211 = 223068211, // MmeBoutarel
+ kAction225932896 = 225932896,
+ kAction226031488 = 226031488, // Verges
+ kAction235061888 = 235061888, // Tatiana
+ kAction238358920 = 238358920, // Anna
+ kAction253868128 = 253868128, // Anna
+ kAction285528346 = 285528346, // Rebecca
+ kAction292048641 = 292048641,
+ kAction305159806 = 305159806,
+ kAction326348944 = 326348944,
+ kAction339669520 = 339669520, // Verges
+
+ /////////////////////////////
+ // Francois
+ /////////////////////////////
+ kAction100901266 = 100901266,
+ kAction100957716 = 100957716,
+ kAction101107728 = 101107728,
+ kAction189872836 = 189872836,
+ kAction190390860 = 190390860,
+
+ /////////////////////////////
+ // Gendarmes
+ /////////////////////////////
+ kAction168710784 = 168710784,
+ kAction169499649 = 169499649,
+
+ /////////////////////////////
+ // Kahina
+ /////////////////////////////
+ kAction92186062 = 92186062,
+ kAction137503360 = 137503360,
+ kAction237555748 = 237555748,
+
+ /////////////////////////////
+ // Kronos
+ /////////////////////////////
+ kAction137685712 = 137685712,
+ kAction138085344 = 138085344,
+ kAction171849314 = 171849314,
+ kAction235599361 = 235599361,
+
+ /////////////////////////////
+ // Mahmud
+ /////////////////////////////
+ kAction102227384 = 102227384, // Mertens
+ kAction156567128 = 156567128,
+ kAction170483072 = 170483072,
+ kAction225563840 = 225563840,
+
+ /////////////////////////////
+ // Max
+ /////////////////////////////
+ kAction71277948 = 71277948,
+ kAction158007856 = 158007856,
+ kAction101687594 = 101687594,
+ kAction122358304 = 122358304, // also Servers1/Boutarel?
+ kActionMaxFreeFromCage = 135204609,
+ kAction156622016 = 156622016,
+
+ /////////////////////////////
+ // Mertens
+ /////////////////////////////
+ kAction155604840 = 155604840, // MmeBoutarel
+ kAction169633856 = 169633856,
+ kAction188635520 = 188635520,
+ kAction190082817 = 190082817,
+ kAction192849856 = 192849856,
+ kAction204379649 = 204379649,
+ kAction224122407 = 224122407,
+ kAction238732837 = 238732837,
+ kAction238790488 = 238790488, // Tatiana
+ kAction269436673 = 269436673,
+ kAction269624833 = 269624833,
+ kAction302614416 = 302614416,
+ kAction303343617 = 303343617,
+
+ /////////////////////////////
+ // Milos
+ /////////////////////////////
+ kAction88652208 = 88652208, // Coudert
+ kAction122865568 = 122865568,
+ kAction123852928 = 123852928,
+ kAction123199584 = 123199584, // Coudert
+ kAction157691176 = 157691176,
+ kAction208228224 = 208228224,
+ kAction221683008 = 221683008,
+ kAction259125998 = 259125998,
+
+ /////////////////////////////
+ // Mme Boutarel
+ /////////////////////////////
+ kAction102484312 = 102484312,
+ kAction102752636 = 102752636,
+ kAction134289824 = 134289824,
+ kAction168986720 = 168986720,
+ kAction202221040 = 202221040,
+ kAction242526416 = 242526416,
+
+ /////////////////////////////
+ // Pascale
+ /////////////////////////////
+ kAction101824388 = 101824388,
+ kAction136059947 = 136059947,
+ kAction169750080 = 169750080,
+ kAction190605184 = 190605184,
+ kAction191604416 = 191604416,
+ kAction207769280 = 207769280,
+ kAction223262556 = 223262556,
+ kAction239072064 = 239072064,
+ kAction257489762 = 257489762,
+ kAction269479296 = 269479296,
+ kAction352703104 = 352703104,
+ kAction352768896 = 352768896,
+
+ /////////////////////////////
+ // Rebecca
+ /////////////////////////////
+ kAction125496184 = 125496184,
+ kAction155465152 = 155465152,
+ kAction155980128 = 155980128,
+ kAction169358379 = 169358379,
+ kAction224253538 = 224253538,
+ kAction254915200 = 254915200,
+
+ /////////////////////////////
+ // Salko
+ /////////////////////////////
+ kAction55996766 = 55996766,
+ kAction101169464 = 101169464,
+ kAction102675536 = 102675536, // Ivo
+ kAction136184016 = 136184016,
+
+ /////////////////////////////
+ // Servers 0
+ /////////////////////////////
+ kAction170016384 = 170016384,
+ kAction188893625 = 188893625,
+ kAction201964801 = 201964801, // August
+ kAction204704037 = 204704037,
+ kAction207330561 = 207330561,
+ kAction218128129 = 218128129,
+ kAction218586752 = 218586752,
+ kAction218983616 = 218983616,
+ kAction223712416 = 223712416,
+ kAction237485916 = 237485916,
+ kAction252568704 = 252568704,
+ kAction268773672 = 268773672, // Anna / August
+ kAction270068760 = 270068760,
+ kAction270410280 = 270410280,
+ kAction286403504 = 286403504,
+ kAction286534136 = 286534136,
+ kAction292758554 = 292758554,
+ kAction304061224 = 304061224,
+ kAction337548856 = 337548856,
+
+ /////////////////////////////
+ // Servers 1
+ /////////////////////////////
+ kAction101106391 = 101106391,
+ kAction122288808 = 122288808, // Boutarel
+ kAction123712592 = 123712592, // Ivo
+ kAction125826561 = 125826561, // August
+ kAction134486752 = 134486752, // August
+ kAction168717392 = 168717392, // Boutarel
+ kAction189688608 = 189688608,
+ kAction219377792 = 219377792,
+ kAction223002560 = 223002560,
+ kAction236237423 = 236237423,
+ kAction256200848 = 256200848,
+ kAction258136010 = 258136010,
+ kAction269485588 = 269485588,
+ kAction291721418 = 291721418,
+ kAction302203328 = 302203328,
+ kAction302996448 = 302996448,
+ kAction326144276 = 326144276,
+
+ /////////////////////////////
+ // Sophie
+ /////////////////////////////
+ kActionProceedChapter5 = 70549068,
+ kAction123668192 = 123668192,
+ kAction125242096 = 125242096,
+ kAction136654208 = 136654208,
+ kAction259921280 = 259921280,
+ kAction292775040 = 292775040,
+
+ /////////////////////////////
+ // Tables
+ /////////////////////////////
+ kActionDrawTablesWithChairs = 103798704,
+ kAction136455232 = 136455232,
+
+ /////////////////////////////
+ // Tatiana
+ /////////////////////////////
+ kAction69239528 = 69239528,
+ kAction123857088 = 123857088,
+ kAction124973510 = 124973510,
+ kAction154071333 = 154071333,
+ kAction156444784 = 156444784,
+ kAction169360385 = 169360385,
+ kAction191198209 = 191198209,
+ kAction223183000 = 223183000, // August
+ kAction236053296 = 236053296, // Alexei
+ kAction236241630 = 236241630, // Anna
+ kAction236517970 = 236517970, // Anna
+ kAction268620864 = 268620864, // August
+ kAction290869168 = 290869168,
+
+ /////////////////////////////
+ // Train
+ /////////////////////////////
+ kAction191070912 = 191070912,
+ kActionTrainStopRunning = 191350523,
+ kActionCatchBeetle = 202613084,
+ kAction203339360 = 203339360,
+ kActionTrainStartRunning = 203419131,
+ kAction203863200 = 203863200,
+ kAction222746496 = 222746496,
+ kActionBreakCeiling = 225056224,
+ kAction290410610 = 290410610,
+ kActionJumpDownCeiling = 338494260,
+
+ /////////////////////////////
+ // Verges
+ /////////////////////////////
+ kAction125233040 = 125233040, // Abbot
+ kAction125499160 = 125499160,
+ kAction155853632 = 155853632,
+ kAction158617345 = 158617345,
+ kAction167854368 = 167854368,
+ kAction168187490 = 168187490,
+ kAction168255788 = 168255788,
+ kActionDeliverMessageToTyler = 191337656,
+ kAction202558662 = 202558662,
+
+ /////////////////////////////
+ // Vassili
+ /////////////////////////////
+ kAction122732000 = 122732000,
+ kAction168459827 = 168459827,
+ kAction191477936 = 191477936,
+
+ /////////////////////////////
+ // Vesna
+ /////////////////////////////
+ kAction124190740 = 124190740,
+ kAction134427424 = 134427424,
+ kAction135024800 = 135024800,
+ kAction137165825 = 137165825,
+ kAction155913424 = 155913424,
+ kAction190412928 = 190412928,
+ kAction203663744 = 203663744,
+ kAction204832737 = 204832737,
+
+ /////////////////////////////
+ // Misc
+ /////////////////////////////
+ kAction158610240 = 158610240,
+ kAction167992577 = 167992577,
+ kAction168646401 = 168646401,
+ kAction169300225 = 169300225,
+ kAction169773228 = 169773228,
+ kActionEndChapter = 190346110,
+ kAction191001984 = 191001984,
+ kAction192637492 = 192637492,
+ kAction201959744 = 201959744,
+ kAction202621266 = 202621266,
+ kAction202884544 = 202884544,
+ kAction203078272 = 203078272,
+ kAction205034665 = 205034665,
+ kAction205294778 = 205294778,
+ kActionUseWhistle = 270751616,
+ kAction272177921 = 272177921,
+ kAction224309120 = 224309120,
+ kAction225358684 = 225358684,
+ kAction225367984 = 225367984,
+ kAction226078300 = 226078300, // Whistle
+
+ kActionEnd
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Functors classes used by the engine
+//////////////////////////////////////////////////////////////////////////
+
+// FIXME is this achievable with the existing Functor1Mem function
+template<class Arg, class Res, class T>
+class Functor1MemConst : public Common::Functor1<Arg, Res> {
+public:
+ typedef Res (T::*FuncType)(Arg) const;
+
+ Functor1MemConst(T *t, const FuncType &func) : _t(t), _func(func) {}
+
+ bool isValid() const { return _func != 0 && _t != 0; }
+ Res operator()(Arg v1) const {
+ return (_t->*_func)(v1);
+ }
+private:
+ mutable T *_t;
+ const FuncType _func;
+};
+
+// FIXME move this to existing func.h file
+template<class Arg1, class Arg2, class Arg3, class Arg4, class Result>
+struct QuaternaryFunction {
+ typedef Arg1 FirstArgumentType;
+ typedef Arg2 SecondArgumentType;
+ typedef Arg3 ThirdArgumentType;
+ typedef Arg4 FourthArgumentType;
+ typedef Result ResultType;
+};
+
+template<class Arg1, class Arg2, class Arg3, class Arg4, class Res>
+struct Functor4 : public QuaternaryFunction<Arg1, Arg2, Arg3, Arg4, Res> {
+ virtual ~Functor4() {}
+
+ virtual bool isValid() const = 0;
+ virtual Res operator()(Arg1, Arg2, Arg3, Arg4) const = 0;
+};
+
+template<class Arg1, class Arg2, class Arg3, class Arg4, class Res, class T>
+class Functor4Mem : public Functor4<Arg1, Arg2, Arg3, Arg4, Res> {
+public:
+ typedef Res (T::*FuncType)(Arg1, Arg2, Arg3, Arg4);
+
+ Functor4Mem(T *t, const FuncType &func) : _t(t), _func(func) {}
+
+ bool isValid() const { return _func != 0 && _t != 0; }
+ Res operator()(Arg1 v1, Arg2 v2, Arg3 v3, Arg4 v4) const {
+ return (_t->*_func)(v1, v2, v3, v4);
+ }
+private:
+ mutable T *_t;
+ const FuncType _func;
+};
+
+
+} // End of namespace LastExpress
+
+#endif // LASTEXPRESS_SHARED_H
diff --git a/engines/lure/debugger.cpp b/engines/lure/debugger.cpp
index 1cfe0804e4..9b1bb743e4 100644
--- a/engines/lure/debugger.cpp
+++ b/engines/lure/debugger.cpp
@@ -23,7 +23,6 @@
*
*/
-
#include "common/config-manager.h"
#include "common/endian.h"
#include "lure/luredefs.h"
@@ -323,7 +322,7 @@ bool Debugger::cmd_hotspot(int argc, const char **argv) {
if (h != NULL) {
DebugPrintf("Frame Number = %d of %d\n", h->frameNumber(), h->numFrames());
- DebugPrintf("Persistant = %s\n", h->persistant() ? "true" : "false");
+ DebugPrintf("Persistent = %s\n", h->persistant() ? "true" : "false");
}
} else if (strcmp(argv[2], "actions") == 0) {
@@ -353,15 +352,13 @@ bool Debugger::cmd_hotspot(int argc, const char **argv) {
} else {
if (strcmp(argv[2], "schedule") == 0) {
// List any current schedule for the character
- hs->npcSchedule.list(buffer);
- DebugPrintf("%s", buffer);
+ DebugPrintf("%s", hs->npcSchedule.getDebugInfo().c_str());
}
if (!h)
DebugPrintf("The specified hotspot is not currently active\n");
else if (strcmp(argv[2], "paths") == 0) {
// List any paths for a charcter
- h->pathFinder().list(buffer);
- DebugPrintf("%s", buffer);
+ DebugPrintf("%s", h->pathFinder().getDebugInfo().c_str());
}
else if (strcmp(argv[2], "pixels") == 0) {
// List the pixel data for the hotspot
diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp
index 30b6f840fc..bce98b28fd 100644
--- a/engines/lure/hotspots.cpp
+++ b/engines/lure/hotspots.cpp
@@ -2496,10 +2496,9 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) {
bool bumpedPlayer;
if (h.currentActions().action() != WALKING) {
- char buffer[MAX_DESC_SIZE];
- h.currentActions().list(buffer);
+ Common::String buffer = h.currentActions().getDebugInfo();
debugC(ERROR_DETAILED, kLureDebugAnimations, "Hotspot standard character p=(%d,%d,%d) bs=%d\n%s",
- h.x(), h.y(), h.roomNumber(), h.blockedState(), buffer);
+ h.x(), h.y(), h.roomNumber(), h.blockedState(), buffer.c_str());
}
// Handle any active talk dialog
@@ -2902,12 +2901,12 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
Action hsAction;
uint16 hotspotId;
HotspotData *hotspot;
- char buffer[MAX_DESC_SIZE];
+ Common::String buffer;
- h.currentActions().list(buffer);
+ buffer = h.currentActions().getDebugInfo();
debugC(ERROR_DETAILED, kLureDebugAnimations,
"Hotspot player anim handler p=(%d,%d,%d) bs=%d\n%s",
- h.x(), h.y(), h.roomNumber(), h.blockedState(), buffer);
+ h.x(), h.y(), h.roomNumber(), h.blockedState(), buffer.c_str());
h.handleTalkDialog();
@@ -3037,10 +3036,10 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
if (pfResult == PF_UNFINISHED) break;
// Pathfinding is now complete
- pathFinder.list(buffer);
+ buffer = pathFinder.getDebugInfo();
debugC(ERROR_DETAILED, kLureDebugAnimations,
"Pathfind processing done; result=%d, walkFlag=%d\n%s",
- pfResult, h.walkFlag(), buffer);
+ pfResult, h.walkFlag(), buffer.c_str());
if ((pfResult != PF_OK) && (h.walkFlag() || (pfResult != PF_DEST_OCCUPIED))) {
@@ -4170,6 +4169,7 @@ PathFinderResult PathFinder::process() {
_inProgress = true;
initVars();
+ Common::Point diff(_destX - _xCurrent, _destY - _yCurrent);
_xCurrent >>= 3; _yCurrent >>= 3;
_xDestCurrent >>= 3; _yDestCurrent >>= 3;
if ((_xCurrent == _xDestCurrent) && (_yCurrent == _yDestCurrent)) {
@@ -4178,6 +4178,10 @@ PathFinderResult PathFinder::process() {
add(RIGHT, _xDestPos);
else if (_xDestPos < 0)
add(LEFT, -_xDestPos);
+ else if (diff.y > 0)
+ add(DOWN, diff.y);
+ else
+ add(UP, -diff.y);
_inProgress = false;
result = PF_OK;
@@ -4353,7 +4357,7 @@ PathFinderResult PathFinder::process() {
break;
}
- // Add a final move if necessary
+ // Add final movement if necessary
if (result == PF_OK) {
if (_xDestPos < 0)
@@ -4369,25 +4373,17 @@ final_step:
return result;
}
-void PathFinder::list(char *buffer) {
- if (buffer) {
- sprintf(buffer, "Pathfinder::list\n");
- buffer += strlen(buffer);
- }
- else {
- printf("Pathfinder::list\n");
- }
+Common::String PathFinder::getDebugInfo() const {
+ Common::String buffer;
+ buffer += "Pathfinder::list(\n";
- WalkingActionList::iterator i;
+ WalkingActionList::const_iterator i;
for (i = _list.begin(); i != _list.end(); ++i) {
WalkingActionEntry *e = (*i).get();
- if (buffer) {
- sprintf(buffer, "Direction=%d, numSteps=%d\n", e->direction(), e->numSteps());
- buffer += strlen(buffer);
- }
- else
- printf("Direction=%d, numSteps=%d\n", e->direction(), e->numSteps());
+ buffer += Common::String::format("Direction=%d, numSteps=%d\n", e->direction(), e->numSteps());
}
+
+ return buffer;
}
void PathFinder::processCell(uint16 *p) {
diff --git a/engines/lure/hotspots.h b/engines/lure/hotspots.h
index 5ff0ec563f..2ae2e91ecf 100644
--- a/engines/lure/hotspots.h
+++ b/engines/lure/hotspots.h
@@ -158,8 +158,7 @@ public:
void clear();
void reset(RoomPathsData &src);
PathFinderResult process();
- void list(char *buffer);
- void list() { list(NULL); }
+ Common::String getDebugInfo() const;
void pop() { _list.erase(_list.begin()); }
WalkingActionEntry &top() { return **_list.begin(); }
diff --git a/engines/lure/lure.h b/engines/lure/lure.h
index 15336a3507..297fb20f59 100644
--- a/engines/lure/lure.h
+++ b/engines/lure/lure.h
@@ -46,10 +46,10 @@
/**
* This is the namespace of the Lure engine.
*
- * Status of this engine: ???
+ * Status of this engine: Complete
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Lure of the Temptress
*/
namespace Lure {
diff --git a/engines/lure/res.cpp b/engines/lure/res.cpp
index 4342a1d6ad..90c2b67b85 100644
--- a/engines/lure/res.cpp
+++ b/engines/lure/res.cpp
@@ -33,8 +33,6 @@
namespace Lure {
-using namespace Common;
-
static Resources *int_resources = NULL;
Resources &Resources::getReference() {
diff --git a/engines/lure/res_struct.cpp b/engines/lure/res_struct.cpp
index a75ba6eac8..f6a2092ddc 100644
--- a/engines/lure/res_struct.cpp
+++ b/engines/lure/res_struct.cpp
@@ -875,7 +875,7 @@ CharacterScheduleEntry::CharacterScheduleEntry(CharacterScheduleEntry *src) {
_parent = src->_parent;
_action = src->_action;
_numParams = src->_numParams;
- Common::copy(src->_params, src->_params + MAX_TELL_COMMANDS * 3 * sizeof(uint16), _params);
+ Common::copy(src->_params, src->_params + MAX_TELL_COMMANDS * 3, _params);
}
uint16 CharacterScheduleEntry::param(int index) {
@@ -1439,77 +1439,42 @@ CurrentActionEntry *CurrentActionEntry::loadFromStream(Common::ReadStream *strea
return result;
}
-void CurrentActionStack::list(char *buffer) {
- ActionsList::iterator i;
+Common::String CurrentActionStack::getDebugInfo() const {
+ Common::String buffer;
+ ActionsList::const_iterator i;
- if (buffer) {
- sprintf(buffer, "CurrentActionStack::list num_actions=%d\n", size());
- buffer += strlen(buffer);
- }
- else
- printf("CurrentActionStack::list num_actions=%d\n", size());
+ buffer += Common::String::format("CurrentActionStack::list num_actions=%d\n", size());
for (i = _actions.begin(); i != _actions.end(); ++i) {
CurrentActionEntry *entry = (*i).get();
- if (buffer) {
- sprintf(buffer, "style=%d room#=%d", entry->action(), entry->roomNumber());
- buffer += strlen(buffer);
- }
- else
- printf("style=%d room#=%d", entry->action(), entry->roomNumber());
+ buffer += Common::String::format("style=%d room#=%d", entry->action(), entry->roomNumber());
if (entry->hasSupportData()) {
CharacterScheduleEntry &rec = entry->supportData();
- if (buffer) {
- sprintf(buffer, ", action=%d params=", rec.action());
- buffer += strlen(buffer);
- }
- else
- printf(", action=%d params=", rec.action());
+ buffer += Common::String::format(", action=%d params=", rec.action());
if (rec.numParams() == 0)
- if (buffer) {
- strcat(buffer, "none");
- buffer += strlen(buffer);
- }
- else
- printf("none");
+ buffer += "none";
else {
- for (int ctr = 0; ctr < rec.numParams(); ++ctr) {
- if (ctr != 0) {
- if (buffer) {
- strcpy(buffer, ", ");
- buffer += strlen(buffer);
- }
- else
- printf(", ");
- }
-
- if (buffer) {
- sprintf(buffer, "%d", rec.param(ctr));
- buffer += strlen(buffer);
- } else
- printf("%d", rec.param(ctr));
+ buffer += Common::String::format("%d", rec.param(0));
+ for (int ctr = 1; ctr < rec.numParams(); ++ctr) {
+ buffer += Common::String::format(", %d", rec.param(ctr));
}
}
}
- if (buffer) {
- sprintf(buffer, "\n");
- buffer += strlen(buffer);
- }
- else
- printf("\n");
+ buffer += "\n";
}
+
+ return buffer;
}
void CurrentActionStack::saveToStream(Common::WriteStream *stream) {
ActionsList::iterator i;
debugC(ERROR_DETAILED, kLureDebugAnimations, "Saving hotspot action stack");
- char buffer[MAX_DESC_SIZE];
- list(buffer);
- debugC(ERROR_DETAILED, kLureDebugAnimations, "%s", buffer);
+ Common::String buffer = getDebugInfo();
+ debugC(ERROR_DETAILED, kLureDebugAnimations, "%s", buffer.c_str());
for (i = _actions.begin(); i != _actions.end(); ++i) {
CurrentActionEntry *rec = (*i).get();
diff --git a/engines/lure/res_struct.h b/engines/lure/res_struct.h
index afb8ee9153..9b2a4c79f8 100644
--- a/engines/lure/res_struct.h
+++ b/engines/lure/res_struct.h
@@ -464,7 +464,7 @@ private:
public:
CurrentActionStack() { _actions.clear(); }
- bool isEmpty() { return _actions.begin() == _actions.end(); }
+ bool isEmpty() const { return _actions.begin() == _actions.end(); }
void clear() { _actions.clear(); }
CurrentActionEntry &top() { return **_actions.begin(); }
CurrentActionEntry &bottom() {
@@ -474,9 +474,8 @@ public:
}
CurrentAction action() { return isEmpty() ? NO_ACTION : top().action(); }
void pop() { _actions.erase(_actions.begin()); }
- int size() { return _actions.size(); }
- void list(char *buffer);
- void list() { list(NULL); }
+ int size() const { return _actions.size(); }
+ Common::String getDebugInfo() const;
void addBack(CurrentAction newAction, uint16 roomNum) {
_actions.push_back(ActionsList::value_type(new CurrentActionEntry(newAction, roomNum)));
diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp
index 23122eb960..07cbff5bf1 100644
--- a/engines/m4/assets.cpp
+++ b/engines/m4/assets.cpp
@@ -147,9 +147,9 @@ void SpriteAsset::loadM4SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream
uint32 header = _stream->readUint32LE();
if (header == HEAD_M4SS) {
- printf("LE-encoded sprite\n");
+ debugC(kDebugGraphics, "LE-encoded sprite\n");
} else {
- printf("BE-encoded sprite\n");
+ debugC(kDebugGraphics, "BE-encoded sprite\n");
isBigEndian = true;
}
@@ -163,7 +163,7 @@ void SpriteAsset::loadM4SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream
_stream->skip(6 * 4);
_frameCount = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
- printf("SpriteAsset::SpriteAsset() srcSize = %d; frameRate = %04X; pixelSpeed = %04X; maxWidth = %d; maxHeight = %d; frameCount = %d\n", _srcSize, _frameRate, _pixelSpeed, _maxWidth, _maxHeight, _frameCount);
+ debugC(kDebugGraphics, "SpriteAsset::SpriteAsset() srcSize = %d; frameRate = %04X; pixelSpeed = %04X; maxWidth = %d; maxHeight = %d; frameCount = %d\n", _srcSize, _frameRate, _pixelSpeed, _maxWidth, _maxHeight, _frameCount);
for (int curFrame = 0; curFrame < _frameCount; curFrame++) {
frameOffset = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
@@ -345,7 +345,7 @@ int32 SpriteAsset::parseSprite(bool isBigEndian) {
if (chunkType == CELS___SS) {
chunkSize = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
} else {
- warning("SpriteAsset::parseSprite() Expected chunk type %08X, got %08X", CELS___SS, chunkType);
+ debugC(kDebugGraphics, "SpriteAsset::parseSprite() Expected chunk type %08X, got %08X", CELS___SS, chunkType);
}
return chunkSize;
@@ -362,14 +362,14 @@ void SpriteAsset::loadFrameHeader(SpriteAssetFrame &frameHeader, bool isBigEndia
frameHeader.comp = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
frameHeader.frame = NULL;
_stream->seek(8 * 4, SEEK_CUR);
- //printf("SpriteAsset::loadFrameHeader() stream = %d; x = %d; y = %d; w = %d; h = %d; comp = %d\n", frameHeader.stream, frameHeader.x, frameHeader.y, frameHeader.w, frameHeader.h, frameHeader.comp);
+ //debugC(kDebugGraphics, "SpriteAsset::loadFrameHeader() stream = %d; x = %d; y = %d; w = %d; h = %d; comp = %d\n", frameHeader.stream, frameHeader.x, frameHeader.y, frameHeader.w, frameHeader.h, frameHeader.comp);
}
M4Sprite *SpriteAsset::getFrame(int frameIndex) {
if ((uint)frameIndex < _frames.size()) {
return _frames[frameIndex].frame;
} else {
- warning("SpriteAsset::getFrame: Invalid frame %d, out of %d", frameIndex, _frames.size());
+ debugC(kDebugGraphics, "SpriteAsset::getFrame: Invalid frame %d, out of %d", frameIndex, _frames.size());
return _frames[_frames.size() - 1].frame;
}
}
@@ -486,7 +486,7 @@ bool AssetManager::clearAssets(AssetType assetType, int32 minHash, int32 maxHash
bool AssetManager::loadAsset(const char *assetName, RGB8 *palette) {
- printf("AssetManager::loadAsset() %s\n", assetName);
+ debugC(kDebugGraphics, "AssetManager::loadAsset() %s\n", assetName);
// TODO, better use MemoryReadStreamEndian?
//convertAssetToLE(assetData, assetSize);
@@ -500,34 +500,34 @@ bool AssetManager::loadAsset(const char *assetName, RGB8 *palette) {
chunkSize = assetS->readUint32LE() - 12; // sub 12 for the chunk header
chunkHash = assetS->readUint32LE();
- printf("hash = %d\n", chunkHash);
+ debugC(kDebugGraphics, "hash = %d\n", chunkHash);
// Until loading code is complete, so that chunks not fully read are skipped correctly
uint32 nextOfs = assetS->pos() + chunkSize;
switch (chunkType) {
case CHUNK_MACH:
- printf("MACH\n");
+ debugC(kDebugGraphics, "MACH\n");
clearAssets(kAssetTypeMACH, chunkHash, chunkHash);
_MACH[chunkHash] = new MachineAsset(_vm, assetS, chunkSize, assetName);
break;
case CHUNK_SEQU:
- printf("SEQU\n");
+ debugC(kDebugGraphics, "SEQU\n");
clearAssets(kAssetTypeSEQU, chunkHash, chunkHash);
_SEQU[chunkHash] = new SequenceAsset(_vm, assetS, chunkSize, assetName);
break;
case CHUNK_DATA:
- printf("DATA\n");
+ debugC(kDebugGraphics, "DATA\n");
clearAssets(kAssetTypeDATA, chunkHash, chunkHash);
_DATA[chunkHash] = new DataAsset(_vm, assetS, chunkSize, assetName);
break;
case CHUNK_CELS:
- printf("CELS\n");
+ debugC(kDebugGraphics, "CELS\n");
clearAssets(kAssetTypeCELS, chunkHash, chunkHash);
_CELS[chunkHash] = new SpriteAsset(_vm, assetS, chunkSize, assetName);
break;
default:
- printf("AssetManager::loadAsset() Unknown chunk type %08X\n", chunkType);
+ debugC(kDebugGraphics, "AssetManager::loadAsset() Unknown chunk type %08X\n", chunkType);
}
// Until loading code is complete (see above)
@@ -568,7 +568,7 @@ int32 AssetManager::addSpriteAsset(const char *assetName, int32 hash, RGB8 *pale
if (!alreadyLoaded) {
- printf("AssetManager::addSpriteAsset() asset %s not loaded, loading into %d\n", assetName, hash);
+ debugC(kDebugGraphics, "AssetManager::addSpriteAsset() asset %s not loaded, loading into %d\n", assetName, hash);
clearAssets(kAssetTypeCELS, hash, hash);
@@ -578,7 +578,7 @@ int32 AssetManager::addSpriteAsset(const char *assetName, int32 hash, RGB8 *pale
} else {
- printf("AssetManager::addSpriteAsset() asset %s already loaded in %d\n", assetName, hash);
+ debugC(kDebugGraphics, "AssetManager::addSpriteAsset() asset %s already loaded in %d\n", assetName, hash);
/* TODO/FIXME
if (_CELS[hash].palOffset >= 0 && palette)
diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp
index 71c70e3e1b..88b4240901 100644
--- a/engines/m4/console.cpp
+++ b/engines/m4/console.cpp
@@ -61,8 +61,10 @@ static int strToInt(const char *s) {
return atoi(s);
// Hexadecimal string
- uint tmp;
- sscanf(s, "%xh", &tmp);
+ uint tmp = 0;
+ int read = sscanf(s, "%xh", &tmp);
+ if (read < 1)
+ error("strToInt failed on string \"%s\"", s);
return (int)tmp;
}
@@ -121,7 +123,7 @@ bool Console::cmdPlaySound(int argc, const char **argv) {
bool Console::cmdPlayDSRSound(int argc, const char **argv) {
if (argc != 2 && argc != 3) {
DebugPrintf("Usage: %s <sound index> <DSR file>\n", argv[0]);
- DebugPrintf("The DSR file parameter is optional, and specifies which DSR to load\n", argv[0]);
+ DebugPrintf("The DSR file parameter is optional, and specifies which DSR to load\n");
} else {
if (argc == 3)
_vm->_sound->loadDSRFile(argv[2]);
@@ -319,17 +321,25 @@ bool MadsConsole::cmdMessage(int argc, const char **argv) {
DebugPrintf("message 'objnum'\n");
} else if (!strcmp(argv[1], "list_quotes")) {
// Dump the quotes list
+#if 0
+ // FIXME: The following code is not portable and hence has been disabled.
+ // Try replacing FILE by Common::DumpFile.
FILE *destFile = fopen("mads_quotes.txt", "wb");
for (uint i = 0; i < _vm->globals()->getQuotesSize(); ++i)
fprintf(destFile, "%.3d - %s\n", i, _vm->globals()->getQuote(i));
fclose(destFile);
+#endif
} else if (!strcmp(argv[1], "list_vocab")) {
// Dump the vocab list
+#if 0
+ // FIXME: The following code is not portable and hence has been disabled.
+ // Try replacing FILE by Common::DumpFile.
FILE *destFile = fopen("mads_vocab.txt", "wb");
for (uint i = 1; i <= _vm->globals()->getVocabSize(); ++i)
fprintf(destFile, "%.3d/%.3x - %s\n", i, i, _vm->globals()->getVocab(i));
fclose(destFile);
+#endif
} else {
int messageIdx = strToInt(argv[1]);
diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp
index af26a86313..0e10e5e89d 100644
--- a/engines/m4/converse.cpp
+++ b/engines/m4/converse.cpp
@@ -118,7 +118,7 @@ void ConversationView::setNode(int32 nodeIndex) {
_activeItems.push_back(node->entries[i]);
if (node->entries[i]->autoSelect || strlen(node->entries[i]->text) == 0) {
- //printf("Auto selecting entry %i of node %i\n", i, nodeIndex);
+ //warning(kDebugConversations, "Auto selecting entry %i of node %i\n", i, nodeIndex);
selectEntry(i);
return;
}
@@ -134,11 +134,11 @@ void ConversationView::setNode(int32 nodeIndex) {
// Fallthrough
if (node->fallthroughMinEntries >= 0 && node->fallthroughOffset >= 0) {
- //printf("Current node falls through node at offset %i when entries are less or equal than %i\n",
+ //warning(kDebugConversations, "Current node falls through node at offset %i when entries are less or equal than %i\n",
// node->fallthroughOffset, node->fallthroughMinEntries);
if (_activeItems.size() <= (uint32)node->fallthroughMinEntries) {
const EntryInfo *entryInfo = _m4Vm->_converse->getEntryInfo(node->fallthroughOffset);
- //printf("Entries are less than or equal to %i, falling through to node at offset %i, index %i\n",
+ //warning(kDebugConversations, "Entries are less than or equal to %i, falling through to node at offset %i, index %i\n",
// node->fallthroughMinEntries, node->fallthroughOffset, entryInfo->nodeIndex);
setNode(entryInfo->nodeIndex);
return;
@@ -227,10 +227,10 @@ void ConversationView::selectEntry(int entryIndex) {
// Hide selected entry, unless it has a persistent flag set
if (!(_activeItems[entryIndex]->flags & kEntryPersists)) {
- //printf("Hiding selected entry\n");
+ //debugCN(kDebugConversations, "Hiding selected entry\n");
_m4Vm->_converse->getNode(_currentNodeIndex)->entries[entryIndex]->visible = false;
} else {
- //printf("Selected entry is persistent, not hiding it\n");
+ //debugCN(kDebugConversations, "Selected entry is persistent, not hiding it\n");
}
}
@@ -286,7 +286,7 @@ void ConversationView::playNextReply() {
}
} else {
int selectedWeight = _vm->_random->getRandomNumber(currentEntry->totalWeight - 1) + 1;
- //printf("Selected weight: %i\n", selectedWeight);
+ //debugCN(kDebugConversations, "Selected weight: %i\n", selectedWeight);
int previousWeight = 1;
int currentWeight = 0;
@@ -313,7 +313,7 @@ void ConversationView::playNextReply() {
// If we reached here, there are no more replies, so perform the active entry's actions
- //printf("Current selection does %i actions\n", _activeItems[entryIndex]->actions.size());
+ //debugCN(kDebugConversations, "Current selection does %i actions\n", _activeItems[entryIndex]->actions.size());
for (uint32 i = 0; i < _activeItems[_highlightedIndex]->actions.size(); i++) {
if (!_m4Vm->_converse->performAction(_activeItems[_highlightedIndex]->actions[i]))
break;
@@ -399,30 +399,30 @@ void Converse::loadConversation(const char *convName) {
return;
}
size = convS->readUint32LE(); // is this used at all?
- if (debugFlag) printf("Conv chunk size (external header): %i\n", size);
+ if (debugFlag) debugCN(kDebugConversations, "Conv chunk size (external header): %i\n", size);
// Conversation name, which is the conversation file's name
// without the extension
convS->read(buffer, 8);
- if (debugFlag) printf("Conversation name: %s\n", buffer);
+ if (debugFlag) debugCN(kDebugConversations, "Conversation name: %s\n", buffer);
while (true) {
chunkPos = convS->pos();
chunk = convS->readUint32LE(); // read chunk
if (convS->eos()) break;
- if (debugFlag) printf("***** Pos: %i -> ", chunkPos);
+ if (debugFlag) debugC(kDebugConversations, "***** Pos: %i -> ", chunkPos);
switch (chunk) {
case CHUNK_DECL: // Declare
- if (debugFlag) printf("DECL chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "DECL chunk\n");
data = convS->readUint32LE();
- if (debugFlag) printf("Tag: %i\n", data);
+ if (debugFlag) debugCN(kDebugConversations, "Tag: %i\n", data);
if (data > 0)
warning("Tag > 0 in DECL chunk, value is: %i", data); // TODO
val = convS->readUint32LE();
- if (debugFlag) printf("Value: %i\n", val);
+ if (debugFlag) debugCN(kDebugConversations, "Value: %i\n", val);
data = convS->readUint32LE();
- if (debugFlag) printf("Flags: %i\n", data);
+ if (debugFlag) debugCN(kDebugConversations, "Flags: %i\n", data);
if (data > 0)
warning("Flags != 0 in DECL chunk, value is %i", data); // TODO
setValue(chunkPos, val);
@@ -437,23 +437,23 @@ void Converse::loadConversation(const char *convName) {
curEntry->fallthroughMinEntries = -1;
curEntry->fallthroughOffset = -1;
if (chunk == CHUNK_NODE) {
- if (debugFlag) printf("NODE chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "NODE chunk\n");
} else {
- if (debugFlag) printf("LNOD chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "LNOD chunk\n");
}
curNode = convS->readUint32LE();
- if (debugFlag) printf("Node number: %i\n", curNode);
+ if (debugFlag) debugCN(kDebugConversations, "Node number: %i\n", curNode);
data = convS->readUint32LE();
- if (debugFlag) printf("Tag: %i\n", data);
+ if (debugFlag) debugCN(kDebugConversations, "Tag: %i\n", data);
if (chunk == CHUNK_LNOD) {
autoSelectIndex = convS->readUint32LE();
- if (debugFlag) printf("Autoselect entry number: %i\n", autoSelectIndex);
+ if (debugFlag) debugCN(kDebugConversations, "Autoselect entry number: %i\n", autoSelectIndex);
}
size = convS->readUint32LE();
- if (debugFlag) printf("Number of entries: %i\n", size);
+ if (debugFlag) debugCN(kDebugConversations, "Number of entries: %i\n", size);
for (i = 0; i < size; i++) {
data = convS->readUint32LE();
- if (debugFlag) printf("Entry %i: %i\n", i + 1, data);
+ if (debugFlag) debugCN(kDebugConversations, "Entry %i: %i\n", i + 1, data);
}
_convNodes.push_back(curEntry);
setEntryInfo(curEntry->offset, curEntry->entryType, curNode, -1);
@@ -465,14 +465,14 @@ void Converse::loadConversation(const char *convName) {
curEntry->entryType = kEntry;
strcpy(curEntry->voiceFile, "");
strcpy(curEntry->text, "");
- if (debugFlag) printf("ETRY chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "ETRY chunk\n");
data = convS->readUint32LE();
- if (debugFlag) printf("Unknown (attributes perhaps?): %i\n", data);
+ if (debugFlag) debugCN(kDebugConversations, "Unknown (attributes perhaps?): %i\n", data);
data = convS->readUint32LE();
- if (debugFlag) printf("Entry flags: ");
- if (debugFlag) if (data & kEntryInitial) printf ("Initial ");
- if (debugFlag) if (data & kEntryPersists) printf ("Persists ");
- if (debugFlag) printf("\n");
+ if (debugFlag) debugCN(kDebugConversations, "Entry flags: ");
+ if (debugFlag) if (data & kEntryInitial) debugCN(kDebugConversations, "Initial ");
+ if (debugFlag) if (data & kEntryPersists) debugCN(kDebugConversations, "Persists ");
+ if (debugFlag) debugCN(kDebugConversations, "\n");
curEntry->flags = data;
curEntry->visible = (curEntry->flags & kEntryInitial) ? true : false;
if (autoSelectIndex >= 0) {
@@ -517,30 +517,33 @@ void Converse::loadConversation(const char *convName) {
if (chunk == CHUNK_WPRL || chunk == CHUNK_WRPL) {
replyEntry->entryType = kWeightedReply;
replyEntry->totalWeight = 0;
- if (debugFlag) printf("WRPL chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "WRPL chunk\n");
size = convS->readUint32LE();
- if (debugFlag) printf("Weighted reply %i - %i entries:\n", i, size);
+ if (debugFlag) debugCN(kDebugConversations, "Weighted reply %i - %i entries:\n", i, size);
for (i = 0; i < size; i++) {
weightedEntry = new ConvEntry();
weightedEntry->offset = chunkPos;
strcpy(weightedEntry->voiceFile, "");
weightedEntry->entryType = kWeightedReply;
data = convS->readUint32LE();
- if (debugFlag) printf("- Weight: %i ", data);
+ if (debugFlag) debugCN(kDebugConversations, "- Weight: %i ", data);
weightedEntry->weight = data;
replyEntry->totalWeight += weightedEntry->weight;
data = convS->readUint32LE();
- if (debugFlag) printf("offset: %i\n", data);
+ if (debugFlag) debugCN(kDebugConversations, "offset: %i\n", data);
replyEntry->entries.push_back(weightedEntry);
}
currentWeightedEntry = 0;
} else {
replyEntry->entryType = kReply;
- if (debugFlag) printf("RPLY chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "RPLY chunk\n");
data = convS->readUint32LE();
- if (debugFlag) printf("Reply data offset: %i\n", data);
+ if (debugFlag) debugCN(kDebugConversations, "Reply data offset: %i\n", data);
}
+ if (!curEntry)
+ error("Converse::loadConversation(): curEntry is NULL while adding a reply");
+
curEntry->entries.push_back(replyEntry);
setEntryInfo(replyEntry->offset, replyEntry->entryType,
curNode, _convNodes[curNode]->entries.size() - 1);
@@ -560,9 +563,9 @@ void Converse::loadConversation(const char *convName) {
{
ConvEntry* parentEntry = NULL;
if (chunk == CHUNK_TEXT) {
- if (debugFlag) printf("TEXT chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "TEXT chunk\n");
} else {
- if (debugFlag) printf("MESG chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "MESG chunk\n");
}
if (replyEntry == NULL) {
@@ -572,25 +575,27 @@ void Converse::loadConversation(const char *convName) {
} else if (replyEntry != NULL && replyEntry->entryType == kWeightedReply) {
parentEntry = replyEntry->entries[currentWeightedEntry];
currentWeightedEntry++;
+ } else {
+ error("Converse::loadConversation(): Unexpected reply entry while processing TEXT/MESG chunk");
}
size = convS->readUint32LE();
- if (debugFlag) printf("Entry data size: %i\n", size);
+ if (debugFlag) debugCN(kDebugConversations, "Entry data size: %i\n", size);
convS->read(buffer, 8);
size -= 8; // subtract maximum length of voice file name
// If the file name is 8 characters, it will not be 0-terminated, so use strncpy
strncpy(parentEntry->voiceFile, buffer, 8);
parentEntry->voiceFile[8] = '\0';
- if (debugFlag) printf("Voice file: %s\n", parentEntry->voiceFile);
+ if (debugFlag) debugCN(kDebugConversations, "Voice file: %s\n", parentEntry->voiceFile);
if (chunk == CHUNK_TEXT) {
convS->read(buffer, size);
- if (debugFlag) printf("Text: %s\n", buffer);
+ if (debugFlag) debugCN(kDebugConversations, "Text: %s\n", buffer);
sprintf(parentEntry->text, "%s", buffer);
} else {
while (size > 0) {
data = convS->readUint32LE();
- if (debugFlag) printf("Unknown: %i\n", data); // TODO
+ if (debugFlag) debugCN(kDebugConversations, "Unknown: %i\n", data); // TODO
size -= 4;
}
}
@@ -607,7 +612,7 @@ void Converse::loadConversation(const char *convName) {
case CHUNK_CASN: // Conditional assign
case CHUNK_ASGN: // Assign
curAction = new EntryAction();
- if (debugFlag) printf("ASGN chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "ASGN chunk\n");
curAction->actionType = kAssignValue;
// Conditional part
@@ -650,32 +655,32 @@ void Converse::loadConversation(const char *convName) {
if (chunk == CHUNK_GOTO || chunk == CHUNK_CCGO) {
curAction->actionType = kGotoEntry;
- if (debugFlag) printf("GOTO chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "GOTO chunk\n");
} else if (chunk == CHUNK_HIDE || chunk == CHUNK_CHDE) {
curAction->actionType = kHideEntry;
- if (debugFlag) printf("HIDE chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "HIDE chunk\n");
} else if (chunk == CHUNK_UHID || chunk == CHUNK_CUHD) {
curAction->actionType = kUnhideEntry;
- if (debugFlag) printf("UHID chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "UHID chunk\n");
} else if (chunk == CHUNK_DSTR || chunk == CHUNK_CDST) {
curAction->actionType = kDestroyEntry;
- if (debugFlag) printf("DSTR chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "DSTR chunk\n");
} else if (chunk == CHUNK_EXIT || chunk == CHUNK_CEGO) {
curAction->actionType = kExitConv;
- if (debugFlag) printf("EXIT chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "EXIT chunk\n");
}
data = convS->readUint32LE();
- if (debugFlag) printf("Offset: %i\n", data);
+ if (debugFlag) debugCN(kDebugConversations, "Offset: %i\n", data);
curAction->targetOffset = data;
curEntry->actions.push_back(curAction);
break;
case CHUNK_FALL: // Fallthrough
- if (debugFlag) printf("FALL chunk\n");
+ if (debugFlag) debugCN(kDebugConversations, "FALL chunk\n");
size = convS->readUint32LE();
- if (debugFlag) printf("Minimum nodes: %i\n", size);
+ if (debugFlag) debugCN(kDebugConversations, "Minimum nodes: %i\n", size);
_convNodes[curNode]->fallthroughMinEntries = size;
data = convS->readUint32LE();
- if (debugFlag) printf("Offset: %i\n", data);
+ if (debugFlag) debugCN(kDebugConversations, "Offset: %i\n", data);
_convNodes[curNode]->fallthroughOffset = data;
break;
// ----------------------------------------------------------------------------
@@ -713,35 +718,35 @@ void Converse::loadConversationMads(const char *convName) {
// ------------------------------------------------------------
// Chunk 0
convS = convDataD.getItemStream(0);
- printf("Chunk 0\n");
- printf("Conv stream size: %i\n", convS->size());
+ debugCN(kDebugConversations, "Chunk 0\n");
+ debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
while (!convS->eos()) { // FIXME (eos changed)
- printf("%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
}
- printf("\n");
+ debugCN(kDebugConversations, "\n");
// ------------------------------------------------------------
// Chunk 1
convS = convDataD.getItemStream(1);
- printf("Chunk 1\n");
- printf("Conv stream size: %i\n", convS->size());
+ debugCN(kDebugConversations, "Chunk 1\n");
+ debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
while (!convS->eos()) { // FIXME (eos changed)
- printf("%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
}
- printf("\n");
+ debugCN(kDebugConversations, "\n");
// ------------------------------------------------------------
// Chunk 2
convS = convDataD.getItemStream(2);
- printf("Chunk 2\n");
- printf("Conv stream size: %i\n", convS->size());
+ debugCN(kDebugConversations, "Chunk 2\n");
+ debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
while (!convS->eos()) { // FIXME (eos changed)
- printf("%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
}
- printf("\n");
+ debugCN(kDebugConversations, "\n");
// ------------------------------------------------------------
// CNV file
@@ -764,46 +769,46 @@ void Converse::loadConversationMads(const char *convName) {
// TODO: finish this
// Chunk 0
convS = convData.getItemStream(0);
- printf("Chunk 0\n");
- printf("Conv stream size: %i\n", convS->size());
- printf("%i ", convS->readUint16LE());
- printf("%i ", convS->readUint16LE());
- printf("%i ", convS->readUint16LE());
- printf("%i ", convS->readUint16LE());
- printf("%i ", convS->readUint16LE());
- printf("%i ", convS->readUint16LE());
- printf("\n");
+ debugCN(kDebugConversations, "Chunk 0\n");
+ debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
+ debugCN(kDebugConversations, "%i ", convS->readUint16LE());
+ debugCN(kDebugConversations, "%i ", convS->readUint16LE());
+ debugCN(kDebugConversations, "%i ", convS->readUint16LE());
+ debugCN(kDebugConversations, "%i ", convS->readUint16LE());
+ debugCN(kDebugConversations, "%i ", convS->readUint16LE());
+ debugCN(kDebugConversations, "%i ", convS->readUint16LE());
+ debugCN(kDebugConversations, "\n");
count = convS->readUint16LE(); // conversation face count (usually 2)
- printf("Conversation faces: %i\n", count);
+ debugCN(kDebugConversations, "Conversation faces: %i\n", count);
for (i = 0; i < 5; i++) {
convS->read(buffer, 16);
- printf("Face %i: %s ", i + 1, buffer);
+ debugCN(kDebugConversations, "Face %i: %s ", i + 1, buffer);
}
- printf("\n");
+ debugCN(kDebugConversations, "\n");
// 5 face slots
// 1 = face slot has a face (with the filename specified above)
// 0 = face slot doesn't contain face data
for (i = 0; i < 5; i++) {
- printf("%i ", convS->readUint16LE());
+ debugCN(kDebugConversations, "%i ", convS->readUint16LE());
}
- printf("\n");
+ debugCN(kDebugConversations, "\n");
convS->read(buffer, 14); // speech file
- printf("Speech file: %s\n", buffer);
+ debugCN(kDebugConversations, "Speech file: %s\n", buffer);
while (!convS->eos()) { // FIXME: eos changed
- printf("%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
}
- printf("\n");
+ debugCN(kDebugConversations, "\n");
delete convS;
// ------------------------------------------------------------
// Chunk 1: Conversation nodes
convS = convData.getItemStream(1);
- printf("Chunk 1: conversation nodes\n");
- printf("Conv stream size: %i\n", convS->size());
+ debugCN(kDebugConversations, "Chunk 1: conversation nodes\n");
+ debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
while (true) {
uint16 id = convS->readUint16LE();
@@ -823,12 +828,12 @@ void Converse::loadConversationMads(const char *convName) {
unk = convS->readUint16LE();
assert (unk == 65535);
_convNodes.push_back(curEntry);
- printf("Node %i, ID %i, entries %i\n", _convNodes.size(), curEntry->id, curEntry->entryCount);
+ debugCN(kDebugConversations, "Node %i, ID %i, entries %i\n", _convNodes.size(), curEntry->id, curEntry->entryCount);
// flags = 0: node has more than 1 entry
// flags = 65535: node has 1 entry
}
- printf("Conversation has %i nodes\n", _convNodes.size());
- printf("\n");
+ debugCN(kDebugConversations, "Conversation has %i nodes\n", _convNodes.size());
+ debugCN(kDebugConversations, "\n");
delete convS;
@@ -839,14 +844,14 @@ void Converse::loadConversationMads(const char *convName) {
// ------------------------------------------------------------
// Chunk 5 contains the conversation strings
convS = convData.getItemStream(5);
- //printf("Chunk 5: conversation strings\n");
- //printf("Conv stream size: %i\n", convS->size());
+ //debugCN(kDebugConversations, "Chunk 5: conversation strings\n");
+ //debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
*buffer = 0;
while (true) {
//if (curPos == 0)
- // printf("%i: Offset %i: ", _convStrings.size(), convS->pos());
+ // debugCN(kDebugConversations, "%i: Offset %i: ", _convStrings.size(), convS->pos());
uint8 b = convS->readByte();
if (convS->eos()) break;
@@ -857,7 +862,7 @@ void Converse::loadConversationMads(const char *convName) {
}
if (buffer[curPos - 1] == '\0') {
// end of string
- //printf("%s\n", buffer);
+ //debugCN(kDebugConversations, "%s\n", buffer);
buf = new char[strlen(buffer) + 1];
strcpy(buf, buffer);
_convStrings.push_back(buf);
@@ -871,8 +876,8 @@ void Converse::loadConversationMads(const char *convName) {
// ------------------------------------------------------------
// Chunk 2: entry data
convS = convData.getItemStream(2);
- //printf("Chunk 2 - entry data\n");
- //printf("Conv stream size: %i\n", convS->size());
+ //debugCN(kDebugConversations, "Chunk 2 - entry data\n");
+ //debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
for (i = 0; i < _convNodes.size(); i++) {
for (j = 0; j < _convNodes[i]->entryCount; j++) {
@@ -887,7 +892,7 @@ void Converse::loadConversationMads(const char *convName) {
curEntry->size = convS->readUint16LE();
_convNodes[i]->entries.push_back(curEntry);
- //printf("Node %i, entry %i, id %i, offset %i, size %i, text: %s\n",
+ //debugCN(kDebugConversations, "Node %i, entry %i, id %i, offset %i, size %i, text: %s\n",
// i, j, curEntry->id, curEntry->offset, curEntry->size, curEntry->text);
}
}
@@ -897,8 +902,8 @@ void Converse::loadConversationMads(const char *convName) {
// ------------------------------------------------------------
// Chunk 3: message (MESG) chunks, created from the strings of chunk 5
convS = convData.getItemStream(3);
- //printf("Chunk 3 - MESG chunk data\n");
- //printf("Conv stream size: %i\n", convS->size());
+ //debugCN(kDebugConversations, "Chunk 3 - MESG chunk data\n");
+ //debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
while (true) {
uint16 index = convS->readUint16LE();
@@ -908,15 +913,15 @@ void Converse::loadConversationMads(const char *convName) {
stringIndex = index;
stringCount = convS->readUint16LE();
*buffer = 0;
- //printf("Message: %i\n", _madsMessageList.size());
+ //debugCN(kDebugConversations, "Message: %i\n", _madsMessageList.size());
for (i = stringIndex; i < stringIndex + stringCount; i++) {
- //printf("%i: %s\n", i, _convStrings[i]);
+ //debugCN(kDebugConversations, "%i: %s\n", i, _convStrings[i]);
curMessage->messageStrings.push_back(_convStrings[i]);
}
_madsMessageList.push_back(curMessage);
- //printf("----------\n");
+ //debugCN(kDebugConversations, "----------\n");
}
- //printf("\n");
+ //debugCN(kDebugConversations, "\n");
delete convS;
@@ -924,31 +929,31 @@ void Converse::loadConversationMads(const char *convName) {
// TODO: finish this
// Chunk 6: conversation script
convS = convData.getItemStream(6);
- printf("Chunk 6\n");
- printf("Conv stream size: %i\n", convS->size());
+ debugCN(kDebugConversations, "Chunk 6\n");
+ debugCN(kDebugConversations, "Conv stream size: %i\n", convS->size());
/*while (!convS->eos()) { // FIXME (eos changed)
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("%i ", convS->readByte());
- printf("\n");
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "%i ", convS->readByte());
+ debugCN(kDebugConversations, "\n");
}
return;*/
for (i = 0; i < _convNodes.size(); i++) {
for (j = 0; j < _convNodes[i]->entryCount; j++) {
- printf("*** Node %i entry %i data size %i\n", i, j, _convNodes[i]->entries[j]->size);
- printf("Entry ID %i, text %s\n", _convNodes[i]->entries[j]->id, _convNodes[i]->entries[j]->text);
+ debugCN(kDebugConversations, "*** Node %i entry %i data size %i\n", i, j, _convNodes[i]->entries[j]->size);
+ debugCN(kDebugConversations, "Entry ID %i, text %s\n", _convNodes[i]->entries[j]->id, _convNodes[i]->entries[j]->text);
Common::SubReadStream *entryStream = new Common::SubReadStream(convS, _convNodes[i]->entries[j]->size);
readConvEntryActions(entryStream, _convNodes[i]->entries[j]);
delete entryStream;
- printf("--------------------\n");
+ debugCN(kDebugConversations, "--------------------\n");
}
}
@@ -973,50 +978,50 @@ void Converse::readConvEntryActions(Common::SubReadStream *convS, ConvEntry *cur
switch (chunk) {
case 1:
- printf("TODO: chunk type %i\n", chunk);
+ debugCN(kDebugConversations, "TODO: chunk type %i\n", chunk);
break;
case 2:
- printf("HIDE\n");
+ debugCN(kDebugConversations, "HIDE\n");
convS->readByte();
count = convS->readByte();
- printf("%i entries: ", count);
+ debugCN(kDebugConversations, "%i entries: ", count);
for (int i = 0; i < count; i++)
- printf("%i %d", i, convS->readUint16LE());
- printf("\n");
+ debugCN(kDebugConversations, "%i %d", i, convS->readUint16LE());
+ debugCN(kDebugConversations, "\n");
break;
case 3:
- printf("UNHIDE\n");
+ debugCN(kDebugConversations, "UNHIDE\n");
convS->readByte();
count = convS->readByte();
- printf("%i entries: ", count);
+ debugCN(kDebugConversations, "%i entries: ", count);
for (int i = 0; i < count; i++)
- printf("%i %d", i, convS->readUint16LE());
- printf("\n");
+ debugCN(kDebugConversations, "%i %d", i, convS->readUint16LE());
+ debugCN(kDebugConversations, "\n");
break;
case 4: // MESSAGE
- printf("MESSAGE\n");
+ debugCN(kDebugConversations, "MESSAGE\n");
if (type == 255) {
- //printf("unconditional\n");
+ //debugCN(kDebugConversations, "unconditional\n");
} else if (type == 11) {
- //printf("conditional\n");
+ //debugCN(kDebugConversations, "conditional\n");
} else {
- printf("unknown type: %i\n", type);
+ debugCN(kDebugConversations, "unknown type: %i\n", type);
}
// Conditional part
if (type == 11) {
unk = convS->readUint16LE(); // 1
if (unk != 1)
- printf("Message: unk != 1 (it's %i)\n", unk);
+ debugCN(kDebugConversations, "Message: unk != 1 (it's %i)\n", unk);
var = convS->readUint16LE();
val = convS->readUint16LE();
- printf("Var %i == %i\n", var, val);
+ debugCN(kDebugConversations, "Var %i == %i\n", var, val);
}
unk = convS->readUint16LE(); // 256
if (unk != 256)
- printf("Message: unk != 256 (it's %i)\n", unk);
+ debugCN(kDebugConversations, "Message: unk != 256 (it's %i)\n", unk);
// it seems that the first text entry is set when the message
// chunk is supposed to be shown unconditionally, whereas the second text
@@ -1026,74 +1031,74 @@ void Converse::readConvEntryActions(Common::SubReadStream *convS, ConvEntry *cur
if (hasText1 == 1) {
messageIndex = convS->readUint16LE();
- printf("Message 1 index: %i, text:\n", messageIndex);
+ debugCN(kDebugConversations, "Message 1 index: %i, text:\n", messageIndex);
for (uint32 i = 0; i < _madsMessageList[messageIndex]->messageStrings.size(); i++) {
- printf("%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
+ debugCN(kDebugConversations, "%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
}
}
if (hasText2 == 1) {
messageIndex = convS->readUint16LE();
if (hasText1 == 0) {
- printf("Message 2 index: %i, text:\n", messageIndex);
+ debugCN(kDebugConversations, "Message 2 index: %i, text:\n", messageIndex);
for (uint32 i = 0; i < _madsMessageList[messageIndex]->messageStrings.size(); i++) {
- printf("%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
+ debugCN(kDebugConversations, "%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
}
}
}
break;
case 5: // AUTO
- printf("AUTO\n");
+ debugCN(kDebugConversations, "AUTO\n");
for (int k = 0; k < 4; k++)
convS->readByte();
messageIndex = convS->readUint16LE();
- printf("Message index: %i, text:\n", messageIndex);
+ debugCN(kDebugConversations, "Message index: %i, text:\n", messageIndex);
for (uint32 i = 0; i < _madsMessageList[messageIndex]->messageStrings.size(); i++) {
- printf("%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
+ debugCN(kDebugConversations, "%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
}
convS->readUint16LE();
break;
case 6:
- printf("TODO: chunk type %i\n", chunk);
+ debugCN(kDebugConversations, "TODO: chunk type %i\n", chunk);
break;
case 7: // GOTO
unk = convS->readUint32LE(); // 0
if (unk != 0 && unk != 1)
- printf("Goto: unk != 0 or 1 (it's %i)\n", unk);
+ debugCN(kDebugConversations, "Goto: unk != 0 or 1 (it's %i)\n", unk);
target = convS->readUint16LE();
convS->readUint16LE(); // 255
if (unk != 0)
- printf("Goto: unk != 0 (it's %i)\n", unk);
+ debugCN(kDebugConversations, "Goto: unk != 0 (it's %i)\n", unk);
if (target != 65535)
- printf("GOTO node %i\n", target);
+ debugCN(kDebugConversations, "GOTO node %i\n", target);
else
- printf("GOTO exit\n");
+ debugCN(kDebugConversations, "GOTO exit\n");
break;
case 8:
- printf("TODO: chunk type %i\n", chunk);
+ debugCN(kDebugConversations, "TODO: chunk type %i\n", chunk);
break;
case 9: // ASSIGN
- //printf("ASSIGN\n");
+ //debugCN(kDebugConversations, "ASSIGN\n");
unk = convS->readUint32LE(); // 0
if (unk != 0)
- printf("Assign: unk != 0 (it's %i)\n", unk);
+ debugCN(kDebugConversations, "Assign: unk != 0 (it's %i)\n", unk);
val = convS->readUint16LE();
var = convS->readUint16LE();
- //printf("Var %i = %i\n", var, val);
+ //debugCN(kDebugConversations, "Var %i = %i\n", var, val);
break;
default:
- printf ("Unknown chunk type! (%i)\n", chunk);
+ debugCN(kDebugConversations, "Unknown chunk type! (%i)\n", chunk);
break;
}
}
- printf("\n");
+ debugCN(kDebugConversations, "\n");
}
void Converse::setEntryInfo(int32 offset, EntryType type, int32 nodeIndex, int32 entryIndex) {
@@ -1104,7 +1109,7 @@ void Converse::setEntryInfo(int32 offset, EntryType type, int32 nodeIndex, int32
info.nodeIndex = nodeIndex;
info.entryIndex = entryIndex;
_offsetMap[hashOffset] = info;
- //printf("Set entry info: offset %i, type %i, node %i, entry %i\n", offset, type, nodeIndex, entryIndex);
+ //debugCN(kDebugConversations, "Set entry info: offset %i, type %i, node %i, entry %i\n", offset, type, nodeIndex, entryIndex);
}
const EntryInfo* Converse::getEntryInfo(int32 offset) {
@@ -1167,7 +1172,7 @@ bool Converse::performAction(EntryAction *action) {
}
if (action->actionType == kAssignValue) {
- //printf("Assigning variable at offset %i to value %i\n",
+ //debugCN(kDebugConversations, "Assigning variable at offset %i to value %i\n",
// action->targetOffset, action->value);
setValue(action->targetOffset, action->value);
return true; // nothing else to do in an assignment action
@@ -1185,24 +1190,24 @@ bool Converse::performAction(EntryAction *action) {
switch (action->actionType) {
case kGotoEntry:
- //printf("Goto entry at offset %i. Associated node is %i, entry %i\n",
+ //debugCN(kDebugConversations, "Goto entry at offset %i. Associated node is %i, entry %i\n",
// action->targetOffset, entryInfo->nodeIndex, entryInfo->entryIndex);
_vm->_conversationView->setNode(entryInfo->nodeIndex);
if (entryInfo->entryIndex >= 0)
_vm->_conversationView->selectEntry(entryInfo->entryIndex);
return false;
case kHideEntry:
- //printf("Hide entry at offset %i. Associated node is %i, entry %i\n",
+ //debugCN(kDebugConversations, "Hide entry at offset %i. Associated node is %i, entry %i\n",
// targetEntry->offset, entryInfo->nodeIndex, entryInfo->entryIndex);
targetEntry->visible = false;
return true;
case kUnhideEntry:
- //printf("Show entry at offset %i. Associated node is %i, entry %i\n",
+ //debugCN(kDebugConversations, "Show entry at offset %i. Associated node is %i, entry %i\n",
// targetEntry->offset, entryInfo->nodeIndex, entryInfo->entryIndex);
targetEntry->visible = true;
return true;
case kDestroyEntry:
- //printf("Destroy entry at offset %i. Associated node is %i, entry %i\n",
+ //debugCN(kDebugConversations, "Destroy entry at offset %i. Associated node is %i, entry %i\n",
// targetEntry->offset, entryInfo->nodeIndex, entryInfo->entryIndex);
if (entryInfo->entryIndex >= 0)
getNode(entryInfo->nodeIndex)->entries.remove_at(entryInfo->entryIndex);
@@ -1211,7 +1216,7 @@ bool Converse::performAction(EntryAction *action) {
targetEntry->visible = true;
return true;
case kExitConv:
- //printf("Exit conversation\n");
+ //debugCN(kDebugConversations, "Exit conversation\n");
endConversation();
return false;
default:
diff --git a/engines/m4/dialogs.cpp b/engines/m4/dialogs.cpp
index a7104537f5..101f21f48c 100644
--- a/engines/m4/dialogs.cpp
+++ b/engines/m4/dialogs.cpp
@@ -297,7 +297,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
char *lineP = &dialogLine[0];
char *cmdP = NULL;
- while (*(srcP - 1) != '\0') {
+ while (srcP && *(srcP - 1) != '\0') {
if ((*srcP == '\n') || (*srcP == '\0')) {
// Line completed
*lineP = '\0';
diff --git a/engines/m4/events.cpp b/engines/m4/events.cpp
index c66609844a..29b243aceb 100644
--- a/engines/m4/events.cpp
+++ b/engines/m4/events.cpp
@@ -235,7 +235,7 @@ bool Mouse::init(const char *seriesName, RGB8 *palette) {
cursorPalette = _cursorSprites->getPalette();
_vm->_palette->setPalette(cursorPalette, 0, colorCount);
- //printf("Cursor count: %d\n", _cursorSprites->getCount());
+ //debugCN(kDebugCore, "Cursor count: %d\n", _cursorSprites->getCount());
_vm->res()->toss(seriesName);
diff --git a/engines/m4/font.cpp b/engines/m4/font.cpp
index b5965732e5..cba32c2225 100644
--- a/engines/m4/font.cpp
+++ b/engines/m4/font.cpp
@@ -82,7 +82,7 @@ void Font::setFontM4(const char *filename) {
Common::SeekableReadStream *fontFile = _vm->res()->openFile(filename);
if (fontFile->readUint32LE() != MKID_BE('FONT')) {
- printf("Font::Font: FONT tag expected\n");
+ debugCN(kDebugGraphics, "Font::Font: FONT tag expected\n");
return;
}
@@ -90,10 +90,10 @@ void Font::setFontM4(const char *filename) {
_maxWidth = fontFile->readByte();
uint32 fontSize = fontFile->readUint32LE();
- //printf("Font::Font: _maxWidth = %d, _maxHeight = %d, fontSize = %d\n", _maxWidth, _maxHeight, fontSize);
+ //debugCN(kDebugGraphics, "Font::Font: _maxWidth = %d, _maxHeight = %d, fontSize = %d\n", _maxWidth, _maxHeight, fontSize);
if (fontFile->readUint32LE() != MKID_BE('WIDT')) {
- printf("Font::Font: WIDT tag expected\n");
+ debugCN(kDebugGraphics, "Font::Font: WIDT tag expected\n");
return;
}
@@ -101,7 +101,7 @@ void Font::setFontM4(const char *filename) {
fontFile->read(_charWidths, 256);
if (fontFile->readUint32LE() != MKID_BE('OFFS')) {
- printf("Font::Font: OFFS tag expected\n");
+ debugCN(kDebugGraphics, "Font::Font: OFFS tag expected\n");
return;
}
@@ -111,7 +111,7 @@ void Font::setFontM4(const char *filename) {
_charOffs[i] = fontFile->readUint16LE();
if (fontFile->readUint32LE() != MKID_BE('PIXS')) {
- printf("Font::Font: PIXS tag expected\n");
+ debugCN(kDebugGraphics, "Font::Font: PIXS tag expected\n");
return;
}
diff --git a/engines/m4/globals.cpp b/engines/m4/globals.cpp
index a96229a0b3..d982ecad0e 100644
--- a/engines/m4/globals.cpp
+++ b/engines/m4/globals.cpp
@@ -75,7 +75,7 @@ bool Kernel::sendTrigger(int32 triggerNum) {
bool Kernel::handleTrigger(int32 triggerNum) {
- printf("betweenRooms = %d; triggerNum = %08X\n", betweenRooms, (uint)triggerNum);
+ debugCN(kDebugScript, "betweenRooms = %d; triggerNum = %08X\n", betweenRooms, (uint)triggerNum);
if (betweenRooms)
return true;
@@ -89,10 +89,10 @@ bool Kernel::handleTrigger(int32 triggerNum) {
int room = (triggerNum >> 16) & 0xFFF;
- printf("room = %d; currentRoom = %d\n", room, currentRoom); fflush(stdout);
+ debugCN(kDebugScript, "room = %d; currentRoom = %d\n", room, currentRoom);
if (room != currentRoom) {
- printf("Kernel::handleTrigger() Trigger from another room\n");
+ debugCN(kDebugScript, "Kernel::handleTrigger() Trigger from another room\n");
return false;
}
@@ -123,8 +123,7 @@ bool Kernel::handleTrigger(int32 triggerNum) {
break;
case KT_DAEMON:
- printf("KT_DAEMON\n");
- fflush(stdout);
+ debugCN(kDebugScript, "KT_DAEMON\n");
triggerMode = KT_DAEMON;
daemonTriggerAvailable = false;
roomDaemon();
@@ -140,7 +139,7 @@ bool Kernel::handleTrigger(int32 triggerNum) {
break;
default:
- printf("Kernel::handleTrigger() Unknown trigger mode %d\n", mode);
+ debugCN(kDebugScript, "Kernel::handleTrigger() Unknown trigger mode %d\n", mode);
}
@@ -181,7 +180,7 @@ void Kernel::globalDaemon() {
if (_globalDaemonFn)
_vm->_script->runFunction(_globalDaemonFn);
else {
- printf("Kernel::globalDaemon() _globalDaemonFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::globalDaemon() _globalDaemonFn is NULL\n");
}
}
@@ -189,7 +188,7 @@ void Kernel::globalParser() {
if (_globalParserFn)
_vm->_script->runFunction(_globalParserFn);
else {
- printf("Kernel::globalParser() _globalParserFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::globalParser() _globalParserFn is NULL\n");
}
}
@@ -197,7 +196,7 @@ void Kernel::sectionInit() {
if (_sectionInitFn)
_vm->_script->runFunction(_sectionInitFn);
else {
- printf("Kernel::sectionInit() _sectionInitFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::sectionInit() _sectionInitFn is NULL\n");
}
}
@@ -205,7 +204,7 @@ void Kernel::sectionDaemon() {
if (_sectionDaemonFn)
_vm->_script->runFunction(_sectionDaemonFn);
else {
- printf("Kernel::sectionDaemon() _sectionDaemonFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::sectionDaemon() _sectionDaemonFn is NULL\n");
}
}
@@ -213,7 +212,7 @@ void Kernel::sectionParser() {
if (_sectionParserFn)
_vm->_script->runFunction(_sectionParserFn);
else {
- printf("Kernel::sectionParser() _sectionParserFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::sectionParser() _sectionParserFn is NULL\n");
}
}
@@ -221,7 +220,7 @@ void Kernel::roomInit() {
if (_roomInitFn)
_vm->_script->runFunction(_roomInitFn);
else {
- printf("Kernel::roomInit() _roomInitFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::roomInit() _roomInitFn is NULL\n");
}
}
@@ -229,7 +228,7 @@ void Kernel::roomDaemon() {
if (_roomDaemonFn)
_vm->_script->runFunction(_roomDaemonFn);
else {
- printf("Kernel::roomDaemon() _roomDaemonFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::roomDaemon() _roomDaemonFn is NULL\n");
}
}
@@ -237,7 +236,7 @@ void Kernel::roomPreParser() {
if (_roomPreParserFn)
_vm->_script->runFunction(_roomPreParserFn);
else {
- printf("Kernel::roomPreParser() _roomPreParserFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::roomPreParser() _roomPreParserFn is NULL\n");
}
}
@@ -245,7 +244,7 @@ void Kernel::roomParser() {
if (_roomParserFn)
_vm->_script->runFunction(_roomParserFn);
else {
- printf("Kernel::roomParser() _roomParserFn is NULL\n");
+ debugCN(kDebugScript, "Kernel::roomParser() _roomParserFn is NULL\n");
}
}
@@ -351,7 +350,7 @@ void MadsGlobals::loadMadsMessagesInfo() {
Common::SeekableReadStream *messageS = _vm->res()->get("messages.dat");
int16 count = messageS->readUint16LE();
- //printf("%i messages\n", count);
+ //debugCN(kDebugScript, "%i messages\n", count);
for (int i = 0; i < count; i++) {
MessageItem curMessage;
@@ -365,7 +364,7 @@ void MadsGlobals::loadMadsMessagesInfo() {
if (i == count - 1)
curMessage.compSize = messageS->size() - curMessage.offset;
- //printf("id: %i, offset: %i, uncomp size: %i\n", curMessage->id, curMessage->offset, curMessage->uncompSize);
+ //debugCN(kDebugScript, "id: %i, offset: %i, uncomp size: %i\n", curMessage->id, curMessage->offset, curMessage->uncompSize);
_madsMessages.push_back(curMessage);
}
diff --git a/engines/m4/globals.h b/engines/m4/globals.h
index 67dcfc2b94..117769ee8e 100644
--- a/engines/m4/globals.h
+++ b/engines/m4/globals.h
@@ -229,15 +229,18 @@ struct MadsConfigData {
#define SET_GLOBAL(x,y) _madsVm->globals()->_globals[x] = y
#define SET_GLOBAL32(x,y) { _madsVm->globals()->_globals[x] = (y) & 0xffff; _madsVm->globals()->_globals[(x) + 1] = (y) >> 16; }
+typedef int (*IntFunctionPtr)();
+
union DataMapEntry {
bool *boolValue;
uint16 *uint16Value;
int *intValue;
+ IntFunctionPtr fnPtr;
};
typedef Common::HashMap<uint16, uint16> DataMapHash;
-enum DataMapType {BOOL, UINT16, INT};
+enum DataMapType {BOOL, UINT16, INT, INT_FN};
class DataMapWrapper {
friend class DataMap;
@@ -249,16 +252,18 @@ public:
DataMapWrapper(uint16 *v) { _value.uint16Value = v; _type = UINT16; }
DataMapWrapper(int16 *v) { _value.uint16Value = (uint16 *)v; _type = UINT16; }
DataMapWrapper(int *v) { _value.intValue = v; _type = INT; }
+ DataMapWrapper(IntFunctionPtr v) { _value.fnPtr = v; _type = INT_FN; }
uint16 getIntValue() {
if (_type == BOOL) return *_value.boolValue ? 0xffff : 0;
else if (_type == UINT16) return *_value.uint16Value;
- else return *_value.intValue;
+ else if (_type == INT) return *_value.intValue;
+ else return _value.fnPtr();
}
void setIntValue(uint16 v) {
if (_type == BOOL) *_value.boolValue = v != 0;
else if (_type == UINT16) *_value.uint16Value = v;
- else *_value.intValue = v;
+ else if (_type == INT) *_value.intValue = v;
}
};
diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp
index 423dda5e7e..6d01db50bd 100644
--- a/engines/m4/graphics.cpp
+++ b/engines/m4/graphics.cpp
@@ -213,8 +213,8 @@ void M4Surface::drawSprite(int x, int y, SpriteInfo &info, const Common::Rect &c
int scaledHeight = scaleValue(info.height, info.scaleY, errY);
/*
- printf("M4Surface::drawSprite() info.width = %d; info.scaleX = %d; info.height = %d; info.scaleY = %d; scaledWidth = %d; scaledHeight = %d\n",
- info.width, info.scaleX, info.height, info.scaleY, scaledWidth, scaledHeight); fflush(stdout);
+ debugCN(kDebugGraphics, "M4Surface::drawSprite() info.width = %d; info.scaleX = %d; info.height = %d; info.scaleY = %d; scaledWidth = %d; scaledHeight = %d\n",
+ info.width, info.scaleX, info.height, info.scaleY, scaledWidth, scaledHeight);
*/
int clipX = 0, clipY = 0;
@@ -233,7 +233,7 @@ void M4Surface::drawSprite(int x, int y, SpriteInfo &info, const Common::Rect &c
scaledHeight = y + scaledHeight;
}
- //printf("M4Surface::drawSprite() width = %d; height = %d; scaledWidth = %d; scaledHeight = %d\n", info.width, info.height, scaledWidth, scaledHeight); fflush(stdout);
+ //debugCN(kDebugGraphics, "M4Surface::drawSprite() width = %d; height = %d; scaledWidth = %d; scaledHeight = %d\n", info.width, info.height, scaledWidth, scaledHeight);
// Check if sprite is inside the screen. If it's not, there's no need to draw it
if (scaledWidth + x <= 0 || scaledHeight + y <= 0) // check left and top (in case x,y are negative)
@@ -703,7 +703,7 @@ void M4Surface::madsLoadBackground(int roomNumber, RGBList **palData) {
else
compressedTileDataSize = tileDataUncomp->readUint32LE() - tileOfs;
- //printf("Tile: %i, compressed size: %i\n", i, compressedTileDataSize);
+ //debugCN(kDebugGraphics, "Tile: %i, compressed size: %i\n", i, compressedTileDataSize);
newTile->clear();
@@ -787,7 +787,7 @@ void M4Surface::m4LoadBackground(Common::SeekableReadStream *source) {
uint8 blackIndex = 0;
// Debug
- //printf("loadBackground(): %dx%d picture (%d bytes) - %dx%d tiles of size %dx%d\n",
+ //debugCN(kDebugGraphics, "loadBackground(): %dx%d picture (%d bytes) - %dx%d tiles of size %dx%d\n",
// widthVal, heightVal, size, tilesX, tilesY, tileWidth, tileHeight);
// BGR data, which is converted to RGB8
@@ -807,7 +807,7 @@ void M4Surface::m4LoadBackground(Common::SeekableReadStream *source) {
// note that the height of the scene in game scenes is smaller than 480, as the bottom part of the
// screen is the inventory
assert(width() == (int)widthVal);
- //printf("width(): %d, widthVal: %d, height(): %d, heightVal: %d\n", width(), widthVal, height(), heightVal);
+ //debugCN(kDebugGraphics, "width(): %d, widthVal: %d, height(): %d, heightVal: %d\n", width(), widthVal, height(), heightVal);
tileBuffer->create(tileWidth, tileHeight, 1);
diff --git a/engines/m4/hotspot.cpp b/engines/m4/hotspot.cpp
index 27180c5eb8..500464dc09 100644
--- a/engines/m4/hotspot.cpp
+++ b/engines/m4/hotspot.cpp
@@ -227,7 +227,7 @@ void HotSpotList::loadHotSpots(Common::SeekableReadStream* hotspotStream, int ho
// This looks to be some sort of bitmask. Perhaps it signifies
// the valid verbs for this hotspot
index = hotspotStream->readUint16LE(); // unknown
- //printf("%i ", index);
+ //debugC(kDebugCore, "%i ", index);
}
if (_vm->isM4())
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index a999a6bd5a..93490a0821 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -121,6 +121,8 @@ MadsM4Engine::MadsM4Engine(OSystem *syst, const M4GameDescription *gameDesc) :
DebugMan.addDebugChannel(kDebugScript, "script", "Script debug level");
DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics debug level");
DebugMan.addDebugChannel(kDebugConversations, "conversations", "Conversations debugging");
+ DebugMan.addDebugChannel(kDebugSound, "sound", "Sounds debug level");
+ DebugMan.addDebugChannel(kDebugCore, "core", "Core debug level");
_resourceManager = NULL;
_globals = NULL;
@@ -266,33 +268,39 @@ void MadsM4Engine::loadMenu(MenuType menuType, bool loadSaveFromHotkey, bool cal
_viewManager->moveToFront(view);
}
+#define DUMP_BUFFER_SIZE 1024
+
void MadsM4Engine::dumpFile(const char* filename, bool uncompress) {
+ Common::DumpFile f;
+ byte buffer[DUMP_BUFFER_SIZE];
Common::SeekableReadStream *fileS = res()->get(filename);
- byte buffer[256];
- FILE *destFile = fopen(filename, "wb");
+
+ if (!f.open(filename))
+ error("Could not open '%s' for writing", filename);
+
int bytesRead = 0;
- printf("Dumping %s, size: %i\n", filename, fileS->size());
+ warning("Dumping %s, size: %i\n", filename, fileS->size());
if (!uncompress) {
while (!fileS->eos()) {
- bytesRead = fileS->read(buffer, 256);
- fwrite(buffer, bytesRead, 1, destFile);
+ bytesRead = fileS->read(buffer, DUMP_BUFFER_SIZE);
+ f.write(buffer, bytesRead);
}
} else {
MadsPack packData(fileS);
Common::MemoryReadStream *sourceUnc;
for (int i = 0; i < packData.getCount(); i++) {
sourceUnc = packData.getItemStream(i);
- printf("Dumping compressed chunk %i of %i, size is %i\n", i + 1, packData.getCount(), sourceUnc->size());
+ debugCN(kDebugCore, "Dumping compressed chunk %i of %i, size is %i\n", i + 1, packData.getCount(), sourceUnc->size());
while (!sourceUnc->eos()) {
- bytesRead = sourceUnc->read(buffer, 256);
- fwrite(buffer, bytesRead, 1, destFile);
+ bytesRead = sourceUnc->read(buffer, DUMP_BUFFER_SIZE);
+ f.write(buffer, bytesRead);
}
delete sourceUnc;
}
}
- fclose(destFile);
+ f.close();
res()->toss(filename);
res()->purge();
}
@@ -338,8 +346,7 @@ Common::Error M4Engine::run() {
for (int i = 1; i < 58; i++) {
_vm->_kernel->trigger = i;
_script->runFunction(func);
- printf("=================================\n");
- fflush(stdout);
+ debugCN(kDebugCore, "=================================\n");
}
#endif
@@ -535,7 +542,7 @@ Common::Error MadsEngine::run() {
// Test code to dump all messages to the console
//for (int i = 0; i < _globals->getMessagesSize(); i++)
- //printf("%s\n----------\n", _globals->loadMessage(i));
+ //debugCN(kDebugCore, "%s\n----------\n", _globals->loadMessage(i));
if (getGameType() == GType_RexNebular) {
MadsGameLogic::initialiseGlobals();
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index b68f7248af..8069c960f1 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -70,7 +70,7 @@
* functionality has been implemented. No further work has been done on this for some time, so progress
* on this part of the engine can be considered frozen.
*
- * Games this engine will support:
+ * Games using this engine:
* MADS Games: Dragonsphere, Return of the Phantom, Rex Nebular and the Cosmic Gender Bender
* M4 Games: Orion Burger, The Riddle of Master Lu
*/
@@ -116,7 +116,9 @@ enum {
enum {
kDebugScript = 1 << 0,
kDebugConversations = 1 << 1,
- kDebugGraphics = 1 << 2
+ kDebugGraphics = 1 << 2,
+ kDebugSound = 1 << 3,
+ kDebugCore = 1 << 4
};
#define MESSAGE_BASIC 1
@@ -161,7 +163,6 @@ public:
const char *getGameFile(int fileType);
Common::EventManager *eventMan() { return _eventMan; }
- OSystem *system() { return _system; }
const M4GameDescription *_gameDescription;
diff --git a/engines/m4/m4_scene.cpp b/engines/m4/m4_scene.cpp
index 475fdba653..738f414add 100644
--- a/engines/m4/m4_scene.cpp
+++ b/engines/m4/m4_scene.cpp
@@ -61,7 +61,7 @@ void M4Scene::loadSceneSprites(int sceneNumber) {
_sceneSprites = new SpriteAsset(_vm, sceneS, sceneS->size(), filename);
_vm->res()->toss(filename);
- printf("Scene has %d sprites, each one having %d colors\n", _sceneSprites->getCount(), _sceneSprites->getColorCount());
+ debugCN(kDebugGraphics, "Scene has %d sprites, each one having %d colors\n", _sceneSprites->getCount(), _sceneSprites->getColorCount());
}
void M4Scene::loadSceneResources(int sceneNumber) {
@@ -136,7 +136,7 @@ void M4Scene::loadSceneSpriteCodes(int sceneNumber) {
// RGB8* spritePalette = _sceneSpriteCodes->getPalette();
//_vm->_palette->setPalette(spritePalette, 0, colorCount);
- printf("Scene has %d sprite codes, each one having %d colors\n", _sceneSpriteCodes->getCount(), colorCount);
+ debugCN(kDebugGraphics, "Scene has %d sprite codes, each one having %d colors\n", _sceneSpriteCodes->getCount(), colorCount);
// Note that toss() deletes the MemoryReadStream
_vm->res()->toss(filename);
@@ -252,7 +252,7 @@ void M4Scene::leftClick(int x, int y) {
*/
// Player said.... (for scene scripts)
- printf("Player said: %s %s\n", currentHotSpot->getVerb(), currentHotSpot->getVocab());
+ debugCN(kDebugGraphics, "Player said: %s %s\n", currentHotSpot->getVerb(), currentHotSpot->getVocab());
// FIXME: This should be moved somewhere else, and is incomplete
if (_m4Vm->scene()->getInterface()->_inventory.getSelectedIndex() == -1) {
@@ -268,7 +268,7 @@ void M4Scene::leftClick(int x, int y) {
strcpy(_vm->_player->object, "");
_vm->_player->commandReady = true;
- printf("## Player said: %s %s\n", _vm->_player->verb, _vm->_player->noun);
+ debugCN(kDebugGraphics, "## Player said: %s %s\n", _vm->_player->verb, _vm->_player->noun);
}
}
diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp
index ca53bdca75..1d15cbbaf7 100644
--- a/engines/m4/mads_anim.cpp
+++ b/engines/m4/mads_anim.cpp
@@ -721,21 +721,21 @@ void AnimviewView::processCommand() {
case 'O':
param = param + 2;
- //printf("O:%i ", atoi(param));
+ //warning(kDebugGraphics, "O:%i ", atoi(param));
_transition = atoi(param);
break;
case 'R':
param = param + 2;
- //printf("R:%s ", param);
+ //warning(kDebugGraphics, "R:%s ", param);
break;
case 'W':
- //printf("W ");
+ //warning(kDebugGraphics, "W ");
break;
case 'X':
- //printf("X ");
+ //warning(kDebugGraphics, "X ");
break;
default:
diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp
index cebe2215ca..878e86c573 100644
--- a/engines/m4/mads_logic.cpp
+++ b/engines/m4/mads_logic.cpp
@@ -182,7 +182,9 @@ void MadsSceneLogic::initialiseDataMap() {
MAP_DATA(&_madsVm->_player._playerPos.y);
MAP_DATA(&_madsVm->_player._direction);
MAP_DATA(&_madsVm->_player._visible);
- MAP_DATA(&_madsVm->scene()->_animActive);
+ MAP_DATA(&getActiveAnimationBool);
+ MAP_DATA(&getAnimationCurrentFrame);
+
}
DataMap &MadsSceneLogic::dataMap() {
@@ -658,12 +660,12 @@ void MadsSceneLogic::execute(uint32 subOffset) {
case OP_NOT: // logical nots top item on stack
param = stack.pop().get();
- stack.push(ScriptVar((uint32)!param & 0xffff));
+ stack.push(ScriptVar((uint32)(!param) & 0xffff));
break;
case OP_COMP: // complements top item on stack
param = stack.pop().get();
- stack.push(ScriptVar(~param & 0xffff));
+ stack.push(ScriptVar((~param) & 0xffff));
break;
case OP_NEG: // negates top item on stack
diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp
index 7e2e6f500b..91db7d343a 100644
--- a/engines/m4/mads_menus.cpp
+++ b/engines/m4/mads_menus.cpp
@@ -546,7 +546,7 @@ int DragonMainMenuView::getHighlightedItem(int x, int y) {
M4Sprite *spr = _menuItem->getFrame(0);
if ((x >= pt.x - 25) && (y >= pt.y - spr->height()) && (x < (pt.x - 25 + spr->width())) && (y < (pt.y))) {
- printf("x = %d, y = %d, index = %d\n", x, y, index);
+ debugCN(kDebugGraphics, "x = %d, y = %d, index = %d\n", x, y, index);
return index;
}
}
diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp
index 641ee756e3..e88a21eb4e 100644
--- a/engines/m4/mads_scene.cpp
+++ b/engines/m4/mads_scene.cpp
@@ -62,7 +62,6 @@ void SceneNode::load(Common::SeekableReadStream *stream) {
MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResources), MadsView(this) {
_vm = vm;
_activeAnimation = NULL;
- _animActive = false;
MadsView::_bgSurface = Scene::_backgroundSurface;
MadsView::_depthSurface = Scene::_walkSurface;
@@ -217,7 +216,6 @@ void MadsScene::leaveScene() {
if (_activeAnimation) {
delete _activeAnimation;
_activeAnimation = NULL;
- _animActive = false;
}
Scene::leaveScene();
@@ -386,7 +384,6 @@ void MadsScene::updateState() {
if (((MadsAnimation *) _activeAnimation)->freeFlag() || freeFlag) {
delete _activeAnimation;
_activeAnimation = NULL;
- _animActive = false;
}
}
@@ -458,7 +455,6 @@ void MadsScene::freeAnimation() {
delete _activeAnimation;
_activeAnimation = NULL;
- _animActive = false;
}
@@ -578,7 +574,6 @@ void MadsScene::loadAnimation(const Common::String &animName, int abortTimers) {
MadsAnimation *anim = new MadsAnimation(_vm, this);
anim->load(animName.c_str(), abortTimers);
_activeAnimation = anim;
- _animActive = true;
}
bool MadsScene::getDepthHighBit(const Common::Point &pt) {
@@ -1244,4 +1239,16 @@ void MadsInterfaceView::leaveScene() {
_madsVm->_viewManager->deleteView(view);
}
+//--------------------------------------------------------------------------
+
+int getActiveAnimationBool() {
+ return (_madsVm->scene()->activeAnimation()) ? 1 : 0;
+}
+
+int getAnimationCurrentFrame() {
+ Animation *anim = _madsVm->scene()->activeAnimation();
+ return anim ? anim->getCurrentFrame() : 0;
+}
+
+
} // End of namespace M4
diff --git a/engines/m4/mads_scene.h b/engines/m4/mads_scene.h
index a029c63a4b..743719d954 100644
--- a/engines/m4/mads_scene.h
+++ b/engines/m4/mads_scene.h
@@ -108,7 +108,6 @@ public:
Common::Point _destPos;
int _destFacing;
Common::Point _customDest;
- bool _animActive;
public:
MadsScene(MadsEngine *vm);
virtual ~MadsScene();
@@ -192,6 +191,9 @@ public:
bool onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents);
};
+extern int getActiveAnimationBool();
+extern int getAnimationCurrentFrame();
+
} // End of namespace M4
#endif
diff --git a/engines/m4/rails.cpp b/engines/m4/rails.cpp
index 11b9bcdbb9..ff18d645e7 100644
--- a/engines/m4/rails.cpp
+++ b/engines/m4/rails.cpp
@@ -233,7 +233,7 @@ void Rails::createEdge(int32 node1, int32 node2) {
valid = isLineWalkable(_nodes[node1]->x, _nodes[node1]->y,
_nodes[node2]->x, _nodes[node2]->y);
- printf("test code says: %d\n", valid);
+ debugCN(kDebugCore, "test code says: %d\n", valid);
// Check if the line passes through a forbidden rectangle
if (valid) {
@@ -255,7 +255,7 @@ void Rails::createEdge(int32 node1, int32 node2) {
_edges.insert_at(index, (int16*)(distance >> 16));
}
- printf("node1 = %d, node2 = %d, valid = %d\n", node1, node2, valid);
+ debugCN(kDebugCore, "node1 = %d, node2 = %d, valid = %d\n", node1, node2, valid);
}
diff --git a/engines/m4/resource.cpp b/engines/m4/resource.cpp
index eee1214e7f..fd54d439a6 100644
--- a/engines/m4/resource.cpp
+++ b/engines/m4/resource.cpp
@@ -43,12 +43,12 @@ FileSystem::FileSystem(const char *hashFilename) {
hashFile.open(hashFilename);
if (!hashFile.isOpen()) {
- printf("FileSystem::FileSystem: error opening hash %s\n", hashFilename);
+ debugCN(kDebugCore, "FileSystem::FileSystem: error opening hash %s\n", hashFilename);
}
hashSize = hashFile.readUint32LE();
- //printf("FileSystem::FileSystem: hashSize = %d\n", hashSize);
+ //debugCN(kDebugCore, "FileSystem::FileSystem: hashSize = %d\n", hashSize);
/* load file records and add them to the hash list */
for (uint i = 0; i < hashSize; i++) {
@@ -63,12 +63,12 @@ FileSystem::FileSystem(const char *hashFilename) {
if (entry.filename[0]) {
/*
- printf(" filename: %s\n", entry.filename);
- printf(" hagfile: %d\n", entry.hagfile);
- printf(" disks: %d\n", entry.disks);
- printf(" offset: %08X\n", entry.offset);
- printf(" size: %d\n", entry.size);
- printf(" next: %08X\n", entry.next);
+ debugCN(kDebugCore, " filename: %s\n", entry.filename);
+ debugCN(kDebugCore, " hagfile: %d\n", entry.hagfile);
+ debugCN(kDebugCore, " disks: %d\n", entry.disks);
+ debugCN(kDebugCore, " offset: %08X\n", entry.offset);
+ debugCN(kDebugCore, " size: %d\n", entry.size);
+ debugCN(kDebugCore, " next: %08X\n", entry.next);
*/
_fileEntries[entry.filename] = entry;
}
@@ -90,7 +90,7 @@ FileSystem::FileSystem(const char *hashFilename) {
_hagEntries[entry.fileIndex].hagFile->open(_hagEntries[entry.fileIndex].filename);
if (!_hagEntries[entry.fileIndex].hagFile->isOpen()) {
- printf("FileSystem::FileSystem: error opening hag %s\n", _hagEntries[entry.fileIndex].filename);
+ debugCN(kDebugCore, "FileSystem::FileSystem: error opening hag %s\n", _hagEntries[entry.fileIndex].filename);
}
}
@@ -113,7 +113,7 @@ Common::SeekableReadStream *FileSystem::loadFile(const char *resourceName, bool
Common::SeekableReadStream *result = NULL;
if (hfe) {
- //printf("FileSystem::loadFile() success opening %s\n", filename);
+ //debugCN(kDebugCore, "FileSystem::loadFile() success opening %s\n", filename);
HashHagEntry *hagEntry = &_hagEntries[hfe->hagfile];
if (preloadFlag) {
@@ -128,7 +128,7 @@ Common::SeekableReadStream *FileSystem::loadFile(const char *resourceName, bool
hfe->offset + hfe->size);
} else {
- printf("FileSystem::loadFile() error opening %s\n", resourceName);
+ debugCN(kDebugCore, "FileSystem::loadFile() error opening %s\n", resourceName);
}
return result;
@@ -207,7 +207,7 @@ void ResourceManager::toss(const char *resourceName) {
if (!strcmp(r->name, resourceName)) {
r->flags |= kResourcePurge;
- //printf("M4ResourceManager::toss: mark resource %s to be purged\n", resourceName);
+ //debugCN(kDebugCore, "M4ResourceManager::toss: mark resource %s to be purged\n", resourceName);
}
}
}
@@ -510,7 +510,7 @@ M4ResourceManager::~M4ResourceManager() {
}
Common::SeekableReadStream *M4ResourceManager::loadResource(const char *resourceName, bool preloadFlag) {
- //printf("M4ResourceManager::loadResource() loading resource %s\n", resourceName);
+ //debugCN(kDebugCore, "M4ResourceManager::loadResource() loading resource %s\n", resourceName);
Common::SeekableReadStream* result = NULL;
if (_hfs) {
// actually load the resource
diff --git a/engines/m4/script.cpp b/engines/m4/script.cpp
index 412707d95e..42d55c6dc7 100644
--- a/engines/m4/script.cpp
+++ b/engines/m4/script.cpp
@@ -121,7 +121,7 @@ SeriesStreamBreakList::~SeriesStreamBreakList() {
void SeriesStreamBreakList::load(Common::File *fd) {
uint32 count = fd->readUint32LE();
- printf("SeriesStreamBreakList::load() count = %d\n", count);
+ debugCN(kDebugScript, "SeriesStreamBreakList::load() count = %d\n", count);
for (uint32 i = 0; i < count; i++) {
SeriesStreamBreakItem *item = new SeriesStreamBreakItem();
item->frameNum = fd->readUint32LE();
@@ -135,7 +135,7 @@ void SeriesStreamBreakList::load(Common::File *fd) {
item->value = fd->readUint32LE();
_items.push_back(item);
- printf("%02d: frameNum = %d; digiName = %s; digiChannel = %d; digiVolume = %d; trigger = %d; flags = %d; variable = %d; value = %d\n",
+ debugCN(kDebugScript, "%02d: frameNum = %d; digiName = %s; digiChannel = %d; digiVolume = %d; trigger = %d; flags = %d; variable = %d; value = %d\n",
i, item->frameNum, item->digiName, item->digiChannel, item->digiVolume, item->trigger, item->flags, item->variable.value, item->value);
}
@@ -146,7 +146,7 @@ SaidArray::~SaidArray() {
void SaidArray::load(Common::File *fd) {
uint32 count = fd->readUint32LE();
- printf("SaidArray::load() count = %d\n", count);
+ debugCN(kDebugScript, "SaidArray::load() count = %d\n", count);
for (uint32 i = 0; i < count; i++) {
SaidArrayItem *item = new SaidArrayItem();
item->itemName = _inter->loadGlobalString(fd);
@@ -155,7 +155,7 @@ void SaidArray::load(Common::File *fd) {
item->digiNameGear = _inter->loadGlobalString(fd);
_items.push_back(item);
- printf("itemName = %s; digiNameLook = %s; digiNameTake = %s; digiNameGear = %s\n",
+ debugCN(kDebugScript, "itemName = %s; digiNameLook = %s; digiNameTake = %s; digiNameGear = %s\n",
item->itemName, item->digiNameLook, item->digiNameTake, item->digiNameGear);
}
@@ -166,7 +166,7 @@ ParserArray::~ParserArray() {
void ParserArray::load(Common::File *fd) {
uint32 count = fd->readUint32LE();
- printf("ParserArray::load() count = %d\n", count);
+ debugCN(kDebugScript, "ParserArray::load() count = %d\n", count);
for (uint32 i = 0; i < count; i++) {
ParserArrayItem *item = new ParserArrayItem();
item->w0 = _inter->loadGlobalString(fd);
@@ -180,7 +180,7 @@ void ParserArray::load(Common::File *fd) {
item->value = fd->readUint32LE();
_items.push_back(item);
- printf("w0 = %s; w1 = %s; trigger = %d; testVariable = %d; testValue = %d; variable = %d; value = %d\n",
+ debugCN(kDebugScript, "w0 = %s; w1 = %s; trigger = %d; testVariable = %d; testValue = %d; variable = %d; value = %d\n",
item->w0, item->w1, item->trigger, item->testVariable.value, item->testValue, item->variable.value, item->value);
}
@@ -194,9 +194,9 @@ ScriptFunction::~ScriptFunction() {
}
void ScriptFunction::load(Common::File *fd) {
- printf("ScriptFunction::load()\n");
+ debugCN(kDebugScript, "ScriptFunction::load()\n");
uint32 size = fd->readUint32LE();
- printf("ScriptFunction::load() size = %d\n", size);
+ debugCN(kDebugScript, "ScriptFunction::load() size = %d\n", size);
_code = fd->readStream(size);
}
@@ -243,16 +243,16 @@ void ScriptInterpreter::open(const char *filename) {
}
int functionCount = _scriptFile->readUint32LE();
- printf("functionCount = %d\n", functionCount);
+ debugCN(kDebugScript, "functionCount = %d\n", functionCount);
for (int i = 0; i < functionCount; i++) {
uint32 offset = _scriptFile->readUint32LE();
- printf("func(%d) offset = %08X\n", i, offset);
+ debugCN(kDebugScript, "func(%d) offset = %08X\n", i, offset);
uint32 len = _scriptFile->readUint32LE();
if (len > 0) {
char *funcName = new char[len + 1];
_scriptFile->read(funcName, len);
funcName[len] = '\0';
- printf("func(%d) name = %s\n", i, funcName);
+ debugCN(kDebugScript, "func(%d) name = %s\n", i, funcName);
_functionNames[Common::String(funcName)] = _functions.size();
// DEBUG
_scriptFunctionNames.push_back(Common::String(funcName));
@@ -262,16 +262,16 @@ void ScriptInterpreter::open(const char *filename) {
}
int dataCount = _scriptFile->readUint32LE();
- printf("dataCount = %d\n", dataCount);
+ debugCN(kDebugScript, "dataCount = %d\n", dataCount);
for (int i = 0; i < dataCount; i++) {
uint32 offset = _scriptFile->readUint32LE();
ScriptDataType type = (ScriptDataType)_scriptFile->readUint32LE();
- printf("data(%d) offset = %08X; type = %d\n", i, offset, type);
+ debugCN(kDebugScript, "data(%d) offset = %08X; type = %d\n", i, offset, type);
_data.push_back(new ScriptDataEntry(offset, type));
}
_globalVarCount = _scriptFile->readUint32LE();
- printf("_globalVarCount = %d\n", _globalVarCount);
+ debugCN(kDebugScript, "_globalVarCount = %d\n", _globalVarCount);
uint32 stringOfs = _scriptFile->readUint32LE();
_scriptFile->seek(stringOfs);
@@ -324,11 +324,11 @@ ScriptFunction *ScriptInterpreter::loadFunction(uint32 index) {
ScriptFunction *ScriptInterpreter::loadFunction(const Common::String &name) {
FunctionNameMap::iterator iter = _functionNames.find(name);
if (iter == _functionNames.end()) {
- printf("ScriptInterpreter::loadFunction() Function '%s' not found!\n", name.c_str());
+ debugCN(kDebugScript, "ScriptInterpreter::loadFunction() Function '%s' not found!\n", name.c_str());
return NULL;
}
uint32 funcIndex = (*iter)._value;
- printf("ScriptInterpreter::loadFunction() index('%s') = %d\n", name.c_str(), funcIndex);
+ debugCN(kDebugScript, "ScriptInterpreter::loadFunction() index('%s') = %d\n", name.c_str(), funcIndex);
return loadFunction(funcIndex);
}
@@ -354,7 +354,6 @@ int ScriptInterpreter::runFunction(ScriptFunction *scriptFunction) {
while (!done) {
byte opcode = _runningFunction->readByte();
done = !execOpcode(opcode);
- fflush(stdout);
}
_localStackPtr = oldLocalStackPtr;
@@ -376,24 +375,24 @@ void ScriptInterpreter::pop(ScriptValue &value) {
}
void ScriptInterpreter::dumpStack() {
- printf("ScriptInterpreter::dumpStack()\n");
+ debugCN(kDebugScript, "ScriptInterpreter::dumpStack()\n");
for (int i = 0; i < _stackPtr; i++) {
- printf("%03d. type = %02d; value = %d\n", i, _stack[i].type, _stack[i].value);
+ debugCN(kDebugScript, "%03d. type = %02d; value = %d\n", i, _stack[i].type, _stack[i].value);
}
}
void ScriptInterpreter::dumpRegisters() {
- printf("ScriptInterpreter::dumpRegisters()\n");
+ debugCN(kDebugScript, "ScriptInterpreter::dumpRegisters()\n");
for (int i = 0; i < ARRAYSIZE(_registers); i++) {
- printf("%03d. type = %02d; value = %d\n", i, _registers[i].type, _registers[i].value);
+ debugCN(kDebugScript, "%03d. type = %02d; value = %d\n", i, _registers[i].type, _registers[i].value);
}
}
void ScriptInterpreter::dumpGlobalVars() {
- printf("ScriptInterpreter::dumpGlobalVars()\n");
+ debugCN(kDebugScript, "ScriptInterpreter::dumpGlobalVars()\n");
for (int i = 0; i < ARRAYSIZE(_globalVars); i++) {
if (_globalVars[i].type != -1)
- printf("%03d. type = %02d; value = %d\n", i, _globalVars[i].type, _globalVars[i].value);
+ debugCN(kDebugScript, "%03d. type = %02d; value = %d\n", i, _globalVars[i].type, _globalVars[i].value);
}
}
@@ -405,7 +404,7 @@ int ScriptInterpreter::toInteger(const ScriptValue &value) {
return value.value;
default:
- printf("ScriptInterpreter::toInteger() Invalid type %d!\n", value.type);
+ debugCN(kDebugScript, "ScriptInterpreter::toInteger() Invalid type %d!\n", value.type);
return 0;
}
@@ -423,7 +422,7 @@ const char *ScriptInterpreter::toString(const ScriptValue &value) {
return _constStrings[value.value];
default:
- printf("ScriptInterpreter::toString() Invalid type %d!\n", value.type);
+ debugCN(kDebugScript, "ScriptInterpreter::toString() Invalid type %d!\n", value.type);
return NULL;
}
@@ -462,7 +461,7 @@ void ScriptInterpreter::loadValue(ScriptValue &value) {
break;
default:
- printf("ScriptInterpreter::loadValue() Invalid value type %d!\n", value.type);
+ debugCN(kDebugScript, "ScriptInterpreter::loadValue() Invalid value type %d!\n", value.type);
}
@@ -471,7 +470,7 @@ void ScriptInterpreter::loadValue(ScriptValue &value) {
void ScriptInterpreter::copyValue(ScriptValue &destValue, ScriptValue &sourceValue) {
if (sourceValue.type == -1) {
- printf("ScriptInterpreter::copyValue() Trying to read uninitialized value!\n");
+ debugCN(kDebugScript, "ScriptInterpreter::copyValue() Trying to read uninitialized value!\n");
}
switch (destValue.type) {
@@ -489,7 +488,7 @@ void ScriptInterpreter::copyValue(ScriptValue &destValue, ScriptValue &sourceVal
if (sourceValue.type == kInteger) {
_logicGlobals[destValue.value] = sourceValue.value;
} else {
- printf("ScriptInterpreter::copyValue() Invalid source value type %d!\n", sourceValue.type);
+ debugCN(kDebugScript, "ScriptInterpreter::copyValue() Invalid source value type %d!\n", sourceValue.type);
}
break;
@@ -498,7 +497,7 @@ void ScriptInterpreter::copyValue(ScriptValue &destValue, ScriptValue &sourceVal
break;
default:
- printf("ScriptInterpreter::copyValue() Invalid dest value type %d!\n", destValue.type);
+ debugCN(kDebugScript, "ScriptInterpreter::copyValue() Invalid dest value type %d!\n", destValue.type);
}
@@ -533,7 +532,7 @@ void ScriptInterpreter::derefValue(ScriptValue &value) {
break;
default:
- printf("ScriptInterpreter::derefValue() Invalid value type %d!\n", value.type);
+ debugCN(kDebugScript, "ScriptInterpreter::derefValue() Invalid value type %d!\n", value.type);
}
@@ -541,21 +540,21 @@ void ScriptInterpreter::derefValue(ScriptValue &value) {
void ScriptInterpreter::callKernelFunction(uint32 index) {
- printf("ScriptInterpreter::callKernelFunction() index = %d\n", index);
+ debugCN(kDebugScript, "ScriptInterpreter::callKernelFunction() index = %d\n", index);
if (index > _kernelFunctionsMax) {
- printf("ScriptInterpreter::callKernelFunction() Invalid kernel functionindex (%d)\n", index);
+ debugCN(kDebugScript, "ScriptInterpreter::callKernelFunction() Invalid kernel functionindex (%d)\n", index);
return;
}
- printf("ScriptInterpreter::callKernelFunction() name = %s\n", _kernelFunctions[index].desc);
+ debugCN(kDebugScript, "ScriptInterpreter::callKernelFunction() name = %s\n", _kernelFunctions[index].desc);
int args = (this->*(_kernelFunctions[index].proc))();
// Now remove values from the stack if the function used any
if (args > 4)
_stackPtr -= args - 4;
- printf("-------------\n");
+ debugCN(kDebugScript, "-------------\n");
}
@@ -569,30 +568,29 @@ ScriptValue ScriptInterpreter::getArg(uint32 index) {
}
void ScriptInterpreter::dumpArgs(uint32 count) {
- printf("ScriptInterpreter::dumpArgs() ");
+ debugCN(kDebugScript, "ScriptInterpreter::dumpArgs() ");
for (uint32 i = 0; i < count; i++) {
ScriptValue argValue = getArg(i);
if (argValue.type == kConstString) {
- printf("'%s'", toString(argValue));
+ debugCN(kDebugScript, "'%s'", toString(argValue));
} else {
- printf("%d", argValue.value);
+ debugCN(kDebugScript, "%d", argValue.value);
}
if (i + 1 < count)
- printf(", ");
+ debugCN(kDebugScript, ", ");
}
- printf("\n");
+ debugCN(kDebugScript, "\n");
}
void ScriptInterpreter::callFunction(uint32 index) {
// NOTE: This is a temporary hack for script functions not yet in the m4.dat
if (index == 0xFFFFFFFF)
return;
- printf("ScriptInterpreter::callFunction() index = %d [%s]\n", index, _scriptFunctionNames[index].c_str());
- fflush(stdout);
+ debugCN(kDebugScript, "ScriptInterpreter::callFunction() index = %d [%s]\n", index, _scriptFunctionNames[index].c_str());
ScriptFunction *subFunction = loadFunction(index);
if (!subFunction) {
// This *should* never happen since the linker checks this
- printf("ScriptInterpreter::callFunction() Function %d could not be loaded!\n", index);
+ debugCN(kDebugScript, "ScriptInterpreter::callFunction() Function %d could not be loaded!\n", index);
return;
}
runFunction(subFunction);
@@ -600,7 +598,7 @@ void ScriptInterpreter::callFunction(uint32 index) {
bool ScriptInterpreter::execOpcode(byte opcode) {
- printf("opcode = %d (%s)\n", opcode, opcodeNames[opcode]);
+ debugCN(kDebugScript, "opcode = %d (%s)\n", opcode, opcodeNames[opcode]);
ScriptValue value1, value2, value3;
uint32 temp;
@@ -649,14 +647,14 @@ bool ScriptInterpreter::execOpcode(byte opcode) {
case opJmp:
temp = _runningFunction->readUint32();
- printf("-> ofs = %08X\n", temp);
+ debugCN(kDebugScript, "-> ofs = %08X\n", temp);
_runningFunction->jumpAbsolute(temp);
return true;
case opJl:
temp = _runningFunction->readUint32();
if (_cmpFlags < 0) {
- printf("-> ofs = %08X\n", temp);
+ debugCN(kDebugScript, "-> ofs = %08X\n", temp);
_runningFunction->jumpAbsolute(temp);
}
return true;
@@ -664,7 +662,7 @@ bool ScriptInterpreter::execOpcode(byte opcode) {
case opJle:
temp = _runningFunction->readUint32();
if (_cmpFlags <= 0) {
- printf("-> ofs = %08X\n", temp);
+ debugCN(kDebugScript, "-> ofs = %08X\n", temp);
_runningFunction->jumpAbsolute(temp);
}
return true;
@@ -672,7 +670,7 @@ bool ScriptInterpreter::execOpcode(byte opcode) {
case opJg:
temp = _runningFunction->readUint32();
if (_cmpFlags > 0) {
- printf("-> ofs = %08X\n", temp);
+ debugCN(kDebugScript, "-> ofs = %08X\n", temp);
_runningFunction->jumpAbsolute(temp);
}
return true;
@@ -680,7 +678,7 @@ bool ScriptInterpreter::execOpcode(byte opcode) {
case opJge:
temp = _runningFunction->readUint32();
if (_cmpFlags >= 0) {
- printf("-> ofs = %08X\n", temp);
+ debugCN(kDebugScript, "-> ofs = %08X\n", temp);
_runningFunction->jumpAbsolute(temp);
}
return true;
@@ -688,7 +686,7 @@ bool ScriptInterpreter::execOpcode(byte opcode) {
case opJz:
temp = _runningFunction->readUint32();
if (_cmpFlags == 0) {
- printf("-> ofs = %08X\n", temp);
+ debugCN(kDebugScript, "-> ofs = %08X\n", temp);
_runningFunction->jumpAbsolute(temp);
}
return true;
@@ -696,17 +694,17 @@ bool ScriptInterpreter::execOpcode(byte opcode) {
case opJnz:
temp = _runningFunction->readUint32();
if (_cmpFlags != 0) {
- printf("-> ofs = %08X\n", temp);
+ debugCN(kDebugScript, "-> ofs = %08X\n", temp);
_runningFunction->jumpAbsolute(temp);
}
return true;
case opJmpByTable:
temp = _runningFunction->readUint32();
- printf("-> index = %d\n", _registers[0].value);
+ debugCN(kDebugScript, "-> index = %d\n", _registers[0].value);
_runningFunction->jumpRelative(_registers[0].value * 4);
temp = _runningFunction->readUint32();
- printf("-> ofs = %08X\n", temp);
+ debugCN(kDebugScript, "-> ofs = %08X\n", temp);
_runningFunction->jumpAbsolute(temp);
return true;
@@ -718,8 +716,8 @@ bool ScriptInterpreter::execOpcode(byte opcode) {
if (value1.type != kInteger || value2.type != kInteger)
warning("ScriptInterpreter::execOpcode() Trying to compare non-integer values (%d, %d, line %d)", value1.type, value2.type, _lineNum);
_cmpFlags = value1.value - value2.value;
- printf("-> cmp %d, %d\n", value1.value, value2.value);
- printf("-> _cmpFlags = %d\n", _cmpFlags);
+ debugCN(kDebugScript, "-> cmp %d, %d\n", value1.value, value2.value);
+ debugCN(kDebugScript, "-> _cmpFlags = %d\n", _cmpFlags);
return true;
case opCall:
@@ -773,7 +771,7 @@ bool ScriptInterpreter::execOpcode(byte opcode) {
return true;
default:
- printf("Invalid opcode %d!\n", opcode);
+ debugCN(kDebugScript, "Invalid opcode %d!\n", opcode);
return false;
}
@@ -922,14 +920,14 @@ int ScriptInterpreter::o1_wilburFinishedTalking() {
int ScriptInterpreter::o1_preloadSound() {
const char *name = STRING(0);
int room = INTEGER(1);
- printf("name = %s; room = %d\n", name, room);
+ debugCN(kDebugScript, "name = %s; room = %d\n", name, room);
return 2;
}
int ScriptInterpreter::o1_unloadSound() {
const char *name = STRING(0);
int room = INTEGER(1);
- printf("name = %s; room = %d\n", name, room);
+ debugCN(kDebugScript, "name = %s; room = %d\n", name, room);
return 2;
}
@@ -939,7 +937,7 @@ int ScriptInterpreter::o1_playSound() {
int volume = INTEGER(2);
int trigger = INTEGER(3);
int room = INTEGER(4);
- printf("name = %s; channel = %d; volume = %d; trigger = %d; room = %d\n",
+ debugCN(kDebugScript, "name = %s; channel = %d; volume = %d; trigger = %d; room = %d\n",
name, channel, volume, trigger, room);
Common::String soundName = Common::String(name) + ".raw";
@@ -957,7 +955,7 @@ int ScriptInterpreter::o1_playLoopingSound() {
int volume = INTEGER(2);
int trigger = INTEGER(3);
int room = INTEGER(4);
- printf("name = %s; channel = %d; volume = %d; trigger = %d; room = %d\n",
+ debugCN(kDebugScript, "name = %s; channel = %d; volume = %d; trigger = %d; room = %d\n",
name, channel, volume, trigger, room);
// HACK until fixed
@@ -968,14 +966,14 @@ int ScriptInterpreter::o1_playLoopingSound() {
int ScriptInterpreter::o1_stopSound() {
int channel = INTEGER(0);
- printf("channel = %d\n", channel);
+ debugCN(kDebugScript, "channel = %d\n", channel);
return 1;
}
int ScriptInterpreter::o1_fadeSetStart() {
// skip arg 0: palette ptr
int percent = INTEGER(1);
- printf("percent = %d\n", percent);
+ debugCN(kDebugScript, "percent = %d\n", percent);
return 2;
}
@@ -986,7 +984,7 @@ int ScriptInterpreter::o1_fadeInit() {
int percent = INTEGER(3);
int ticks = INTEGER(4);
int trigger = INTEGER(5);
- printf("first = %d; last = %d; percent = %d; ticks = %d; trigger = %d\n",
+ debugCN(kDebugScript, "first = %d; last = %d; percent = %d; ticks = %d; trigger = %d\n",
first, last, percent, ticks, trigger);
// HACK until palette fading is implemented
@@ -1005,7 +1003,7 @@ int ScriptInterpreter::o1_initPaletteCycle() {
int delay = INTEGER(2);
int ticks = INTEGER(3);
int trigger = INTEGER(4);
- printf("first = %d; last = %d; delay = %d; ticks = %d; trigger = %d\n",
+ debugCN(kDebugScript, "first = %d; last = %d; delay = %d; ticks = %d; trigger = %d\n",
first, last, delay, ticks, trigger);
// HACK until palette cycling is implemented
@@ -1022,12 +1020,11 @@ int ScriptInterpreter::o1_hasPlayerSaid() {
const char *words[3];
for (int i = 0; i < 3; i++)
words[i] = STRING(i);
- printf("'%s', '%s', '%s'\n", words[0], words[1], words[2]);
+ debugCN(kDebugScript, "'%s', '%s', '%s'\n", words[0], words[1], words[2]);
int result = _vm->_player->said(words[0], words[1], words[2]);
- printf(" -> '%d'\n", result);
- fflush(stdout);
+ debugCN(kDebugScript, " -> '%d'\n", result);
RETURN(result);
return 3;
@@ -1038,12 +1035,11 @@ int ScriptInterpreter::o1_hasPlayerSaidAny() {
for (int i = 0; i < 10; i++)
words[i] = STRING(i);
- printf("'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'\n",
+ debugCN(kDebugScript, "'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'\n",
words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
int result = _vm->_player->saidAny(words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
- printf(" -> '%d'\n", result);
- fflush(stdout);
+ debugCN(kDebugScript, " -> '%d'\n", result);
RETURN(result);
return 10;
@@ -1059,13 +1055,13 @@ int ScriptInterpreter::o1_playerHotspotWalkOverride() {
int y1 = INTEGER(1);
int x2 = INTEGER(2);
int y2 = INTEGER(3);
- printf("(%d, %d); (%d, %d)\n", x1, y1, x2, y2);
+ debugCN(kDebugScript, "(%d, %d); (%d, %d)\n", x1, y1, x2, y2);
return 4;
}
int ScriptInterpreter::o1_playerHasItem() {
const char *name = STRING(0);
- printf("item = '%s'\n", name);
+ debugCN(kDebugScript, "item = '%s'\n", name);
// TODO
RETURN(0);
return 1;
@@ -1075,14 +1071,14 @@ int ScriptInterpreter::o1_setWalkerLocation() {
// skip arg 0: walker
int x = INTEGER(1);
int y = INTEGER(2);
- printf("x = %d; y = %d\n", x, y);
+ debugCN(kDebugScript, "x = %d; y = %d\n", x, y);
return 3;
}
int ScriptInterpreter::o1_setWalkerFacing() {
// skip arg 0: walker
int facing = INTEGER(1);
- printf("facing = %d\n", facing);
+ debugCN(kDebugScript, "facing = %d\n", facing);
return 2;
}
@@ -1090,7 +1086,7 @@ int ScriptInterpreter::o1_setHotspot() {
// skip arg 0: hotspot list
const char *name = STRING(1);
int value = INTEGER(2);
- printf("name = '%s' -> %d\n", name, value);
+ debugCN(kDebugScript, "name = '%s' -> %d\n", name, value);
_vm->_scene->getSceneResources().hotspots->setActive(name, (value != 0));
@@ -1121,9 +1117,8 @@ int ScriptInterpreter::o1_playSeries() {
int firstFrame = INTEGER(9);
int lastFrame = INTEGER(10);
- printf("name = %s; layer = %04X; flags = %08X; trigger = %d; frameRate = %d; loopCount = %d; scale = %d; x = %d; y = %d: firstFrame = %d; lastFrame = %d\n",
+ debugCN(kDebugScript, "name = %s; layer = %04X; flags = %08X; trigger = %d; frameRate = %d; loopCount = %d; scale = %d; x = %d; y = %d: firstFrame = %d; lastFrame = %d\n",
name, layer, flags, trigger, frameRate, loopCount, scale, x, y, firstFrame, lastFrame);
- fflush(stdout);
// TODO: Return the machine to the script
_vm->_ws->playSeries(name, layer, flags, trigger, frameRate, loopCount, scale, x, y, firstFrame, lastFrame);
@@ -1142,9 +1137,8 @@ int ScriptInterpreter::o1_showSeries() {
int x = INTEGER(7);
int y = INTEGER(8);
- printf("name = %s; layer = %04X; flags = %08X; trigger = %d; duration = %d; frameIndex = %d; scale = %d; x = %d; y = %d\n",
+ debugCN(kDebugScript, "name = %s; layer = %04X; flags = %08X; trigger = %d; duration = %d; frameIndex = %d; scale = %d; x = %d; y = %d\n",
name, layer, flags, trigger, duration, frameIndex, scale, x, y);
- fflush(stdout);
// TODO: Return the machine to the script
_vm->_ws->showSeries(name, layer, flags, trigger, duration, frameIndex, scale, x, y);
@@ -1157,8 +1151,7 @@ int ScriptInterpreter::o1_loadSeries() {
int hash = INTEGER(1);
// skip arg 3: palette ptr
- printf("name = %s; hash = %d\n", name, hash);
- fflush(stdout);
+ debugCN(kDebugScript, "name = %s; hash = %d\n", name, hash);
int result = _vm->_ws->loadSeries(name, hash, NULL);
@@ -1189,7 +1182,7 @@ int ScriptInterpreter::o1_globalTriggerProc() {
int value1 = INTEGER(0);
int value2 = INTEGER(1);
int value3 = INTEGER(2);
- printf("%d; %d; %d\n", value1, value2, value3);
+ debugCN(kDebugScript, "%d; %d; %d\n", value1, value2, value3);
return 3;
}
@@ -1197,13 +1190,13 @@ int ScriptInterpreter::o1_triggerTimerProc() {
int value1 = INTEGER(0);
int value2 = INTEGER(1);
int value3 = INTEGER(2);
- printf("%d; %d; %d\n", value1, value2, value3);
+ debugCN(kDebugScript, "%d; %d; %d\n", value1, value2, value3);
return 3;
}
int ScriptInterpreter::o1_dispatchTrigger() {
int trigger = INTEGER(0);
- printf("trigger = %d\n", trigger);
+ debugCN(kDebugScript, "trigger = %d\n", trigger);
_vm->_kernel->sendTrigger(trigger);
//g_system->delayMillis(5000);
@@ -1229,7 +1222,7 @@ int ScriptInterpreter::o1_wilburSaid() {
SaidArrayItem *item = saidArray[i];
if (_vm->_player->said("LOOK AT", item->itemName) && item->digiNameLook) {
- printf(" -> LOOK AT: '%s'\n", item->digiNameLook);
+ debugCN(kDebugScript, " -> LOOK AT: '%s'\n", item->digiNameLook);
Common::String soundName = Common::String(item->digiNameLook) + ".raw";
_vm->_sound->playVoice(soundName.c_str(), 100);
result = 1;
@@ -1237,7 +1230,7 @@ int ScriptInterpreter::o1_wilburSaid() {
}
if (_vm->_player->said("TAKE", item->itemName) && item->digiNameTake) {
- printf(" -> TAKE: '%s'\n", item->digiNameTake);
+ debugCN(kDebugScript, " -> TAKE: '%s'\n", item->digiNameTake);
Common::String soundName = Common::String(item->digiNameTake) + ".raw";
_vm->_sound->playVoice(soundName.c_str(), 100);
result = 1;
@@ -1245,7 +1238,7 @@ int ScriptInterpreter::o1_wilburSaid() {
}
if (_vm->_player->said("GEAR", item->itemName) && item->digiNameGear) {
- printf(" -> GEAR: '%s'\n", item->digiNameGear);
+ debugCN(kDebugScript, " -> GEAR: '%s'\n", item->digiNameGear);
Common::String soundName = Common::String(item->digiNameGear) + ".raw";
_vm->_sound->playVoice(soundName.c_str(), 100);
result = 1;
@@ -1253,12 +1246,11 @@ int ScriptInterpreter::o1_wilburSaid() {
}
/*
- printf("##### itemName = '%s'; digiNameLook = %s; digiNameTake = %s; digiNameGear = %s\n",
+ debugCN(kDebugScript, "##### itemName = '%s'; digiNameLook = %s; digiNameTake = %s; digiNameGear = %s\n",
item->itemName, item->digiNameLook, item->digiNameTake, item->digiNameGear);
*/
}
- printf(" -> '%d'\n", result);
- fflush(stdout);
+ debugCN(kDebugScript, " -> '%d'\n", result);
RETURN(result);
return 1;
@@ -1278,8 +1270,7 @@ int ScriptInterpreter::o1_wilburSpeech() {
int volume = INTEGER(4);
int slot = INTEGER(5);
- printf("%s; %d; %d; %d; %d; %d\n", name, trigger, room, flag, volume, slot);
- fflush(stdout);
+ debugCN(kDebugScript, "%s; %d; %d; %d; %d; %d\n", name, trigger, room, flag, volume, slot);
//g_system->delayMillis(5000);
KernelTriggerType oldTriggerMode = _vm->_kernel->triggerMode;
@@ -1297,14 +1288,14 @@ int ScriptInterpreter::o1_wilburSpeech() {
void ScriptInterpreter::getKernelVar(int index, ScriptValue &value) {
- printf("ScriptInterpreter::getKernelVar() index = %d\n", index);
+ debugCN(kDebugScript, "ScriptInterpreter::getKernelVar() index = %d\n", index);
if (index > _kernelVarsMax) {
- printf("ScriptInterpreter::getKernelVar() Invalid kernel var index %d!\n", index);
+ debugCN(kDebugScript, "ScriptInterpreter::getKernelVar() Invalid kernel var index %d!\n", index);
return;
}
- printf("ScriptInterpreter::getKernelVar() name = %s\n", _kernelVars[index].desc);
+ debugCN(kDebugScript, "ScriptInterpreter::getKernelVar() name = %s\n", _kernelVars[index].desc);
ScriptKernelVariable var = _kernelVars[index].var;
@@ -1342,7 +1333,7 @@ void ScriptInterpreter::getKernelVar(int index, ScriptValue &value) {
break;
default:
- printf("ScriptInterpreter::getKernelVar() Invalid kernel var %d!\n", var);
+ debugCN(kDebugScript, "ScriptInterpreter::getKernelVar() Invalid kernel var %d!\n", var);
//g_system->delayMillis(2000);
}
@@ -1351,14 +1342,14 @@ void ScriptInterpreter::getKernelVar(int index, ScriptValue &value) {
void ScriptInterpreter::setKernelVar(int index, const ScriptValue &value) {
- printf("ScriptInterpreter::setKernelVar() index = %d\n", index);
+ debugCN(kDebugScript, "ScriptInterpreter::setKernelVar() index = %d\n", index);
if (index > _kernelVarsMax) {
- printf("ScriptInterpreter::setKernelVar() Invalid kernel var index %d!\n", index);
+ debugCN(kDebugScript, "ScriptInterpreter::setKernelVar() Invalid kernel var index %d!\n", index);
return;
}
- printf("ScriptInterpreter::setKernelVar() name = %s\n", _kernelVars[index].desc);
+ debugCN(kDebugScript, "ScriptInterpreter::setKernelVar() name = %s\n", _kernelVars[index].desc);
ScriptKernelVariable var = _kernelVars[index].var;
@@ -1366,31 +1357,31 @@ void ScriptInterpreter::setKernelVar(int index, const ScriptValue &value) {
case kKernelTrigger:
_vm->_kernel->trigger = toInteger(value);
- printf("kKernelTrigger -> %d\n", toInteger(value));
+ debugCN(kDebugScript, "kKernelTrigger -> %d\n", toInteger(value));
break;
case kKernelTriggerMode:
_vm->_kernel->triggerMode = (KernelTriggerType)toInteger(value);
- printf("kKernelTrigger -> %d\n", toInteger(value));
+ debugCN(kDebugScript, "kKernelTrigger -> %d\n", toInteger(value));
break;
case kKernelContinueHandlingTrigger:
_vm->_kernel->daemonTriggerAvailable = (toInteger(value) != 0);
- printf("kKernelContinueHandlingTrigger -> %d\n", toInteger(value));
+ debugCN(kDebugScript, "kKernelContinueHandlingTrigger -> %d\n", toInteger(value));
break;
case kGameNewRoom:
_vm->_kernel->newRoom = toInteger(value);
- printf("kGameNewRoom -> %d\n", toInteger(value));
+ debugCN(kDebugScript, "kGameNewRoom -> %d\n", toInteger(value));
break;
case kPlayerCommandReady:
// TODO
- printf("kPlayerCommandReady -> %d\n", toInteger(value));
+ debugCN(kDebugScript, "kPlayerCommandReady -> %d\n", toInteger(value));
break;
default:
- printf("ScriptInterpreter::setKernelVar() Invalid kernel var %d!\n", var);
+ debugCN(kDebugScript, "ScriptInterpreter::setKernelVar() Invalid kernel var %d!\n", var);
//g_system->delayMillis(2000);
}
diff --git a/engines/m4/script.h b/engines/m4/script.h
index 7382c05b67..2012926330 100644
--- a/engines/m4/script.h
+++ b/engines/m4/script.h
@@ -305,7 +305,7 @@ public:
// Is this ok?
template<class T>
const T& toData(const ScriptValue &value) {
- printf("ScriptInterpreter::toData() index = %d; type = %d; max = %d\n", value.value, _data[value.value]->type, _data.size());
+ debugCN(kDebugScript, "ScriptInterpreter::toData() index = %d; type = %d; max = %d\n", value.value, _data[value.value]->type, _data.size());
assert((uint32)value.value < _data.size());
T *result = 0;
_dataCache->load(_scriptFile, _data[value.value]->offset, result);
diff --git a/engines/m4/sound.cpp b/engines/m4/sound.cpp
index e0fbd2f7a9..76f0cded46 100644
--- a/engines/m4/sound.cpp
+++ b/engines/m4/sound.cpp
@@ -194,7 +194,7 @@ void Sound::loadDSRFile(const char *fileName) {
// Read header
_dsrFile.entryCount = fileStream->readUint16LE();
- //printf("DSR has %i entries\n", _dsrFile.entryCount);
+ //warning(kDebugSound, "DSR has %i entries\n", _dsrFile.entryCount);
for (int i = 0; i < _dsrFile.entryCount; i++) {
DSREntry newEntry;
@@ -206,13 +206,13 @@ void Sound::loadDSRFile(const char *fileName) {
_dsrFile.dsrEntries.push_back(newEntry);
/*
- printf("%i: ", i);
- printf("frequency: %i ", newEntry->frequency);
- printf("channels: %i ", newEntry->channels);
- printf("comp: %i ", newEntry.compSize);
- printf("uncomp: %i ", newEntry.uncompSize);
- printf("offset: %i ", newEntry->offset);
- printf("\n");
+ warning(kDebugSound, "%i: ", i);
+ warning(kDebugSound, "frequency: %i ", newEntry->frequency);
+ warning(kDebugSound, "channels: %i ", newEntry->channels);
+ warning(kDebugSound, "comp: %i ", newEntry.compSize);
+ warning(kDebugSound, "uncomp: %i ", newEntry.uncompSize);
+ warning(kDebugSound, "offset: %i ", newEntry->offset);
+ warning(kDebugSound, "\n");
*/
}
diff --git a/engines/m4/woodscript.cpp b/engines/m4/woodscript.cpp
index 3ce0fa0f2f..ccd3401d3c 100644
--- a/engines/m4/woodscript.cpp
+++ b/engines/m4/woodscript.cpp
@@ -46,7 +46,7 @@ Bytecode::~Bytecode() {
int Bytecode::loadInstruction(Instruction &instruction) {
- //printf("Bytecode::loadInstruction() ip = %08X\n", _code->pos());
+ //debugCN(kDebugScript, "Bytecode::loadInstruction() ip = %08X\n", _code->pos());
int32 format, data;
uint32 code, code2;
@@ -90,7 +90,7 @@ int Bytecode::loadInstruction(Instruction &instruction) {
void Bytecode::jumpAbsolute(int32 ofs) {
_code->seek(ofs * 4);
- //printf("Bytecode::jumpAbsolute() ofs = %08X\n", _code->pos());
+ //debugCN(kDebugScript, "Bytecode::jumpAbsolute() ofs = %08X\n", _code->pos());
}
void Bytecode::jumpRelative(int32 ofs) {
@@ -200,7 +200,7 @@ void WoodScript::runTimerSequenceRequests() {
Machine *WoodScript::createMachine(int32 machineHash, Sequence *parentSeq,
int32 dataHash, int32 dataRowIndex, int callbackHandler, const char *machineName) {
- //printf("WoodScript::createMachine(%d)\n", machineHash); fflush(stdout);
+ //debugCN(kDebugScript, "WoodScript::createMachine(%d)\n", machineHash);
Machine *machine = new Machine(this, machineHash, parentSeq, dataHash, dataRowIndex, callbackHandler, machineName, _machineId);
_machineId++;
@@ -228,7 +228,7 @@ Machine *WoodScript::playSeries(const char *seriesName, long layer, uint32 flags
int32 frameRate, int32 loopCount, int32 s, int32 x, int32 y,
int32 firstFrame, int32 lastFrame) {
- //printf("WoodScript::playSeries(%s)\n", seriesName);
+ //debugCN(kDebugScript, "WoodScript::playSeries(%s)\n", seriesName);
RGB8 *palette = NULL;
if (flags & SERIES_LOAD_PALETTE)
@@ -282,7 +282,7 @@ Machine *WoodScript::showSeries(const char *seriesName, long layer, uint32 flags
}
Machine *WoodScript::streamSeries(const char *seriesName, int32 frameRate, long layer, int32 triggerNum) {
- //printf("WoodScript::streamSeries(%s)\n", seriesName);
+ //debugCN(kDebugScript, "WoodScript::streamSeries(%s)\n", seriesName);
_globals[kGlobTemp1] = frameRate << 16;
/* FIXME: Single frames from a stream series will be decompressed on-the-fly, contrary to
"normal" sprite series, to save some memory, and since no random access to single
diff --git a/engines/m4/ws_machine.cpp b/engines/m4/ws_machine.cpp
index cb791026c9..3a25e3c622 100644
--- a/engines/m4/ws_machine.cpp
+++ b/engines/m4/ws_machine.cpp
@@ -147,7 +147,7 @@ void Machine::enterState() {
int32 Machine::execInstruction() {
- //printf("Machine::execInstruction()\n"); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::execInstruction()\n");
bool done = false;
Instruction instruction;
@@ -160,12 +160,16 @@ int32 Machine::execInstruction() {
if (machineConditionalsTable[instruction.instr - 64] != 0)
(this->*machineConditionalsTable[instruction.instr - 64])(instruction);
/* The next line is to yield on unimplemented opcodes */
- else { fflush(stdout); g_system->delayMillis(5000); }
+ else {
+ g_system->delayMillis(5000);
+ }
} else if (instruction.instr > 0) {
if (machineCommandsTable[instruction.instr] != 0)
done = !(this->*machineCommandsTable[instruction.instr])(instruction);
/* The next line is to yield on unimplemented opcodes */
- else { fflush(stdout); g_system->delayMillis(5000); }
+ else {
+ g_system->delayMillis(5000);
+ }
if (done) {
if (_id == machID) {
//TODO: Cancel all requests
@@ -199,7 +203,7 @@ void Machine::execBlock(int32 offset, int32 count) {
int32 instruction = -1;
- //printf("---------------------------------------\n"); fflush(stdout);
+ //debugCN(kDebugScript, "---------------------------------------\n");
while (instruction && instruction != 4 && _id == oldId && _recursionLevel == oldRecursionLevel &&
_code->pos() >= (uint32)startOffset && _code->pos() < (uint32)endOffset) {
@@ -208,7 +212,7 @@ void Machine::execBlock(int32 offset, int32 count) {
//g_system->delayMillis(500);
}
- //printf("---------------------------------------\n"); fflush(stdout);
+ //debugCN(kDebugScript, "---------------------------------------\n");
if (instruction == 3) {
execInstruction();
@@ -221,7 +225,7 @@ void Machine::execBlock(int32 offset, int32 count) {
}
bool Machine::m1_gotoState(Instruction &instruction) {
- //printf("Machine::m1_gotoState() state = %d\n", (int32)instruction.argv[0] >> 16);
+ //debugCN(kDebugScript, "Machine::m1_gotoState() state = %d\n", (int32)instruction.argv[0] >> 16);
_currentState = (int32)instruction.argv[0] >> 16;
_recursionLevel = 0;
@@ -229,14 +233,14 @@ bool Machine::m1_gotoState(Instruction &instruction) {
}
bool Machine::m1_jump(Instruction &instruction) {
- //printf("Machine::m1_jump() ofs = %08X\n", (int32)instruction.argv[0] >> 16);
+ //debugCN(kDebugScript, "Machine::m1_jump() ofs = %08X\n", (int32)instruction.argv[0] >> 16);
_code->jumpRelative((int32)instruction.argv[0] >> 16);
return true;
}
bool Machine::m1_terminate(Instruction &instruction) {
- //printf("Machine::m1_terminate()\n"); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_terminate()\n");
_currentState = -1;
_recursionLevel = 0;
@@ -244,15 +248,15 @@ bool Machine::m1_terminate(Instruction &instruction) {
}
bool Machine::m1_startSequence(Instruction &instruction) {
- //printf("Machine::m1_startSequence() sequence hash = %d\n", (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_startSequence() sequence hash = %d\n", (uint32)instruction.argv[0] >> 16);
int32 sequenceHash = instruction.argv[0] >> 16;
if (_sequence == NULL) {
- //printf("Machine::m1_startSequence() creating new sequence\n");
+ //debugCN(kDebugScript, "Machine::m1_startSequence() creating new sequence\n");
_sequence = _ws->createSequence(this, sequenceHash);
_code->setSequence(_sequence);
} else {
- //printf("Machine::m1_startSequence() using existing sequence\n");
+ //debugCN(kDebugScript, "Machine::m1_startSequence() using existing sequence\n");
_sequence->changeProgram(sequenceHash);
//_code->setSequence(_sequence);
}
@@ -260,28 +264,28 @@ bool Machine::m1_startSequence(Instruction &instruction) {
}
bool Machine::m1_pauseSequence(Instruction &instruction) {
- //printf("Machine::m1_pauseSequence()\n"); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_pauseSequence()\n");
_sequence->pause();
return true;
}
bool Machine::m1_resumeSequence(Instruction &instruction) {
- //printf("Machine::m1_resumeSequence()\n"); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_resumeSequence()\n");
_sequence->resume();
return true;
}
bool Machine::m1_storeValue(Instruction &instruction) {
- //printf("Machine::m1_storeValue() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]);
+ //debugCN(kDebugScript, "Machine::m1_storeValue() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]);
*instruction.argp[0] = instruction.getValue();
return true;
}
bool Machine::m1_sendMessage(Instruction &instruction) {
- //printf("Machine::m1_sendMessage() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]);
+ //debugCN(kDebugScript, "Machine::m1_sendMessage() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]);
#if 0
//TODO
@@ -300,7 +304,7 @@ bool Machine::m1_sendMessage(Instruction &instruction) {
}
bool Machine::m1_broadcastMessage(Instruction &instruction) {
- //printf("Machine::m1_broadcastMessage() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]);
+ //debugCN(kDebugScript, "Machine::m1_broadcastMessage() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]);
#if 0
//TODO
@@ -317,7 +321,7 @@ bool Machine::m1_broadcastMessage(Instruction &instruction) {
}
bool Machine::m1_replyMessage(Instruction &instruction) {
- //printf("Machine::m1_replyMessage() messageHash = %d; messageValue = %d\n", (uint32)instruction.argv[0], (uint32)instruction.argv[1]);
+ //debugCN(kDebugScript, "Machine::m1_replyMessage() messageHash = %d; messageValue = %d\n", (uint32)instruction.argv[0], (uint32)instruction.argv[1]);
#if 0
if (myArg2) {
msgValue = *myArg2;
@@ -331,28 +335,28 @@ bool Machine::m1_replyMessage(Instruction &instruction) {
}
bool Machine::m1_sendSystemMessage(Instruction &instruction) {
- //printf("Machine::m1_sendSystemMessage() messageValue = %d\n", (uint32)instruction.argv[0]);
+ //debugCN(kDebugScript, "Machine::m1_sendSystemMessage() messageValue = %d\n", (uint32)instruction.argv[0]);
#if 0
#endif
return true;
}
bool Machine::m1_createMachine(Instruction &instruction) {
- //printf("Machine::m1_createMachine()\n");
+ //debugCN(kDebugScript, "Machine::m1_createMachine()\n");
#if 0
#endif
return true;
}
bool Machine::m1_createMachineEx(Instruction &instruction) {
- //printf("Machine::m1_createMachineEx()\n");
+ //debugCN(kDebugScript, "Machine::m1_createMachineEx()\n");
#if 0
#endif
return true;
}
bool Machine::m1_clearVars(Instruction &instruction) {
- //printf("Machine::m1_clearVars()\n"); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_clearVars()\n");
_sequence->clearVars();
return true;
@@ -360,7 +364,7 @@ bool Machine::m1_clearVars(Instruction &instruction) {
void Machine::m1_onEndSequence(Instruction &instruction) {
- //printf("Machine::m1_onEndSequence() count = %08X\n", (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_onEndSequence() count = %08X\n", (uint32)instruction.argv[0] >> 16);
int32 count = instruction.argv[0] >> 16;
_sequence->issueEndOfSequenceRequest(_code->pos(), count);
@@ -368,7 +372,7 @@ void Machine::m1_onEndSequence(Instruction &instruction) {
}
void Machine::m1_onMessage(Instruction &instruction) {
- //printf("Machine::m1_onEndSequence() count = %08X\n", (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_onEndSequence() count = %08X\n", (uint32)instruction.argv[0] >> 16);
// TODO: Add message to list
@@ -378,42 +382,42 @@ void Machine::m1_onMessage(Instruction &instruction) {
}
void Machine::m1_switchLt(Instruction &instruction) {
- //printf("Machine::m1_switchLt() %d < %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_switchLt() %d < %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16);
if (instruction.argv[1] >= instruction.argv[2])
_code->jumpRelative(instruction.argv[0] >> 16);
}
void Machine::m1_switchLe(Instruction &instruction) {
- //printf("Machine::m1_switchLe() %d <= %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_switchLe() %d <= %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16);
if (instruction.argv[1] > instruction.argv[2])
_code->jumpRelative(instruction.argv[0] >> 16);
}
void Machine::m1_switchEq(Instruction &instruction) {
- //printf("Machine::m1_switchEq() %d == %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_switchEq() %d == %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16);
if (instruction.argv[1] != instruction.argv[2])
_code->jumpRelative(instruction.argv[0] >> 16);
}
void Machine::m1_switchNe(Instruction &instruction) {
- //printf("Machine::m1_switchNe() %d != %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_switchNe() %d != %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16);
if (instruction.argv[1] == instruction.argv[2])
_code->jumpRelative(instruction.argv[0] >> 16);
}
void Machine::m1_switchGe(Instruction &instruction) {
- //printf("Machine::m1_switchGe() %d >= %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_switchGe() %d >= %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16);
if (instruction.argv[1] < instruction.argv[2])
_code->jumpRelative(instruction.argv[0] >> 16);
}
void Machine::m1_switchGt(Instruction &instruction) {
- //printf("Machine::m1_switchGt() %d > %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "Machine::m1_switchGt() %d > %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16);
if (instruction.argv[1] <= instruction.argv[2])
_code->jumpRelative(instruction.argv[0] >> 16);
diff --git a/engines/m4/ws_sequence.cpp b/engines/m4/ws_sequence.cpp
index 79869a81d0..bb6230d041 100644
--- a/engines/m4/ws_sequence.cpp
+++ b/engines/m4/ws_sequence.cpp
@@ -201,7 +201,7 @@ void Sequence::resume() {
void Sequence::issueEndOfSequenceRequest(int32 codeOffset, int32 count) {
- //printf("Sequence::issueEndOfSequenceRequest(%04X, %04X)\n", codeOffset, count); fflush(stdout);
+ //debugCN(kDebugScript, "Sequence::issueEndOfSequenceRequest(%04X, %04X)\n", codeOffset, count);
//g_system->delayMillis(5000);
_endOfSequenceRequest.codeOffset = codeOffset;
@@ -216,7 +216,7 @@ bool Sequence::runProgram() {
bool done = true;
- //printf("_ws->getGlobal(kGlobTime) = %ld, _switchTime = %d\n", _ws->getGlobal(kGlobTime), _switchTime);
+ //debugCN(kDebugScript, "_ws->getGlobal(kGlobTime) = %ld, _switchTime = %d\n", _ws->getGlobal(kGlobTime), _switchTime);
if (_switchTime >= 0 && _ws->getGlobal(kGlobTime) >= _switchTime)
done = false;
@@ -228,7 +228,9 @@ bool Sequence::runProgram() {
_code->loadInstruction(instruction);
if (sequenceCommandsTable[instruction.instr] != 0)
done = !(this->*sequenceCommandsTable[instruction.instr])(instruction);
- else { fflush(stdout); /*g_system->delayMillis(1000);*/ }
+ else {
+ //g_system->delayMillis(1000);
+ }
}
return _terminated;
@@ -246,7 +248,7 @@ bool Sequence::changeProgram(int32 sequenceHash) {
SequenceAsset *sequenceAsset = _ws->assets()->getSequence(sequenceHash);
if (sequenceAsset->localVarCount() > _localVarCount) {
- //printf("Sequence::changeProgram(%d) sequenceAsset->localVarCount() > _localVarCount\n", sequenceHash);
+ //debugCN(kDebugScript, "Sequence::changeProgram(%d) sequenceAsset->localVarCount() > _localVarCount\n", sequenceHash);
return false;
}
@@ -301,14 +303,14 @@ void Sequence::draw(M4Surface *surface, const Common::Rect &clipRect, Common::Re
}
bool Sequence::s1_end(Instruction &instruction) {
- //printf("Sequence::s1_end()\n");
+ //debugCN(kDebugScript, "Sequence::s1_end()\n");
_terminated = true;
return false;
}
bool Sequence::s1_clearVars(Instruction &instruction) {
- //printf("Sequence::s1_clearVars()\n");
+ //debugCN(kDebugScript, "Sequence::s1_clearVars()\n");
clearVars();
_vars[kSeqVarMachineID] = _machine->getId();
@@ -316,14 +318,14 @@ bool Sequence::s1_clearVars(Instruction &instruction) {
}
bool Sequence::s1_set(Instruction &instruction) {
- //printf("Sequence::s1_set()\n");
+ //debugCN(kDebugScript, "Sequence::s1_set()\n");
*instruction.argp[0] = instruction.getValue();
return true;
}
bool Sequence::s1_compare(Instruction &instruction) {
- //printf("Sequence::s1_compare()\n");
+ //debugCN(kDebugScript, "Sequence::s1_compare()\n");
long value = instruction.getValue();
if (instruction.argv[0] < value)
@@ -336,28 +338,28 @@ bool Sequence::s1_compare(Instruction &instruction) {
}
bool Sequence::s1_add(Instruction &instruction) {
- //printf("Sequence::s1_add()\n");
+ //debugCN(kDebugScript, "Sequence::s1_add()\n");
*instruction.argp[0] += instruction.getValue();
return true;
}
bool Sequence::s1_sub(Instruction &instruction) {
- //printf("Sequence::s1_sub()\n");
+ //debugCN(kDebugScript, "Sequence::s1_sub()\n");
*instruction.argp[0] -= instruction.getValue();
return true;
}
bool Sequence::s1_mul(Instruction &instruction) {
- //printf("Sequence::s1_mul()\n");
+ //debugCN(kDebugScript, "Sequence::s1_mul()\n");
*instruction.argp[0] = FixedMul(instruction.argv[0], instruction.getValue());
return true;
}
bool Sequence::s1_div(Instruction &instruction) {
- //printf("Sequence::s1_div()\n");
+ //debugCN(kDebugScript, "Sequence::s1_div()\n");
// TODO: Catch divisor = 0 in FixedDiv
*instruction.argp[0] = FixedDiv(instruction.argv[0], instruction.getValue());
@@ -365,7 +367,7 @@ bool Sequence::s1_div(Instruction &instruction) {
}
bool Sequence::s1_and(Instruction &instruction) {
- //printf("Sequence::s1_and()\n");
+ //debugCN(kDebugScript, "Sequence::s1_and()\n");
*instruction.argp[0] = instruction.argv[0] & instruction.getValue();
if (*instruction.argp[0])
@@ -376,7 +378,7 @@ bool Sequence::s1_and(Instruction &instruction) {
}
bool Sequence::s1_or(Instruction &instruction) {
- //printf("Sequence::s1_or()\n");
+ //debugCN(kDebugScript, "Sequence::s1_or()\n");
*instruction.argp[0] = instruction.argv[0] | instruction.getValue();
if (*instruction.argp[0])
@@ -387,7 +389,7 @@ bool Sequence::s1_or(Instruction &instruction) {
}
bool Sequence::s1_not(Instruction &instruction) {
- //printf("Sequence::s1_not()\n");
+ //debugCN(kDebugScript, "Sequence::s1_not()\n");
if (instruction.argv[0] == 0) {
*instruction.argp[0] = 0x10000;
@@ -400,7 +402,7 @@ bool Sequence::s1_not(Instruction &instruction) {
}
bool Sequence::s1_sin(Instruction &instruction) {
- //printf("Sequence::s1_sin()\n");
+ //debugCN(kDebugScript, "Sequence::s1_sin()\n");
int32 tempAngle = *instruction.argp[1] >> 16;
if (tempAngle < 0)
@@ -417,7 +419,7 @@ bool Sequence::s1_sin(Instruction &instruction) {
}
bool Sequence::s1_cos(Instruction &instruction) {
- //printf("Sequence::s1_cos()\n");
+ //debugCN(kDebugScript, "Sequence::s1_cos()\n");
int32 tempAngle = *instruction.argp[1] >> 16;
if (tempAngle < 0)
@@ -434,42 +436,42 @@ bool Sequence::s1_cos(Instruction &instruction) {
}
bool Sequence::s1_abs(Instruction &instruction) {
- //printf("Sequence::s1_abs()\n");
+ //debugCN(kDebugScript, "Sequence::s1_abs()\n");
*instruction.argp[0] = ABS(instruction.argv[1]);
return true;
}
bool Sequence::s1_min(Instruction &instruction) {
- //printf("Sequence::s1_min()\n");
+ //debugCN(kDebugScript, "Sequence::s1_min()\n");
*instruction.argp[0] = MIN(instruction.argv[1], instruction.argv[2]);
return true;
}
bool Sequence::s1_max(Instruction &instruction) {
- //printf("Sequence::s1_max()\n");
+ //debugCN(kDebugScript, "Sequence::s1_max()\n");
*instruction.argp[0] = MAX(instruction.argv[1], instruction.argv[2]);
return true;
}
bool Sequence::s1_mod(Instruction &instruction) {
- //printf("Sequence::s1_mod()\n");
+ //debugCN(kDebugScript, "Sequence::s1_mod()\n");
*instruction.argp[0] = instruction.argv[0] % instruction.getValue();
return true;
}
bool Sequence::s1_floor(Instruction &instruction) {
- //printf("Sequence::s1_floor()\n");
+ //debugCN(kDebugScript, "Sequence::s1_floor()\n");
*instruction.argp[0] = instruction.getValue() & 0xffff0000;
return true;
}
bool Sequence::s1_round(Instruction &instruction) {
- //printf("Sequence::s1_round()\n");
+ //debugCN(kDebugScript, "Sequence::s1_round()\n");
if ((*instruction.argp[1] & 0xffff) >= 0x8000)
*instruction.argp[0] = (*instruction.argp[1] + 0x10000) & 0xffff0000;
@@ -479,7 +481,7 @@ bool Sequence::s1_round(Instruction &instruction) {
}
bool Sequence::s1_ceil(Instruction &instruction) {
- //printf("Sequence::s1_ceil()\n");
+ //debugCN(kDebugScript, "Sequence::s1_ceil()\n");
if ((*instruction.argp[1] & 0xffff) >= 0)
*instruction.argp[0] = (*instruction.argp[1] + 0x10000) & 0xffff0000;
@@ -489,19 +491,19 @@ bool Sequence::s1_ceil(Instruction &instruction) {
}
bool Sequence::s1_point(Instruction &instruction) {
- printf("Sequence::s1_point()\n");
+ debugCN(kDebugScript, "Sequence::s1_point()\n");
// TODO
return true;
}
bool Sequence::s1_dist2d(Instruction &instruction) {
- printf("Sequence::s1_dist2d()\n");
+ debugCN(kDebugScript, "Sequence::s1_dist2d()\n");
// TODO
return true;
}
bool Sequence::s1_crunch(Instruction &instruction) {
- //printf("Sequence::s1_crunch()\n");
+ //debugCN(kDebugScript, "Sequence::s1_crunch()\n");
long deltaTime;
@@ -515,12 +517,12 @@ bool Sequence::s1_crunch(Instruction &instruction) {
_startTime = _ws->getGlobal(kGlobTime);
- //printf("deltaTime = %ld\n", deltaTime >> 16); fflush(stdout);
+ //debugCN(kDebugScript, "deltaTime = %ld\n", deltaTime >> 16);
//g_system->delayMillis(5000);
if (deltaTime >= 0) {
_switchTime = _ws->getGlobal(kGlobTime) + (deltaTime >> 16);
- //printf("_ws->getGlobal(kGlobTime) = %ld\n", _ws->getGlobal(kGlobTime)); fflush(stdout);
+ //debugCN(kDebugScript, "_ws->getGlobal(kGlobTime) = %ld\n", _ws->getGlobal(kGlobTime));
//g_system->delayMillis(5000);
} else {
_switchTime = -1;
@@ -532,7 +534,7 @@ bool Sequence::s1_crunch(Instruction &instruction) {
}
bool Sequence::s1_branch(Instruction &instruction) {
- //printf("Sequence::s1_branch()\n");
+ //debugCN(kDebugScript, "Sequence::s1_branch()\n");
uint32 ofs = instruction.argv[1] >> 16;
switch (instruction.argv[0] >> 16) {
@@ -569,7 +571,7 @@ bool Sequence::s1_branch(Instruction &instruction) {
}
bool Sequence::s1_setFrame(Instruction &instruction) {
- //printf("Sequence::s1_setFrame()\n");
+ //debugCN(kDebugScript, "Sequence::s1_setFrame()\n");
int32 frameIndex;
if (instruction.argc == 3) {
@@ -580,8 +582,8 @@ bool Sequence::s1_setFrame(Instruction &instruction) {
frameIndex = (instruction.argv[0] & 0xFF0000) >> 16;
}
- //printf("Sequence::s1_setFrame() spriteHash = %d\n", (uint32)instruction.argv[0] >> 24);
- //printf("Sequence::s1_setFrame() frameIndex = %d\n", frameIndex);
+ //debugCN(kDebugScript, "Sequence::s1_setFrame() spriteHash = %d\n", (uint32)instruction.argv[0] >> 24);
+ //debugCN(kDebugScript, "Sequence::s1_setFrame() frameIndex = %d\n", frameIndex);
SpriteAsset *spriteAsset = _ws->assets()->getSprite((uint32)instruction.argv[0] >> 24);
_curFrame = spriteAsset->getFrame(frameIndex);
@@ -590,25 +592,25 @@ bool Sequence::s1_setFrame(Instruction &instruction) {
}
bool Sequence::s1_sendMessage(Instruction &instruction) {
- printf("Sequence::s1_sendMessage()\n");
+ debugCN(kDebugScript, "Sequence::s1_sendMessage()\n");
// TODO
return true;
}
bool Sequence::s1_push(Instruction &instruction) {
- printf("Sequence::s1_push()\n");
+ debugCN(kDebugScript, "Sequence::s1_push()\n");
// TODO
return true;
}
bool Sequence::s1_pop(Instruction &instruction) {
- printf("Sequence::s1_pop()\n");
+ debugCN(kDebugScript, "Sequence::s1_pop()\n");
// TODO
return true;
}
bool Sequence::s1_jumpSub(Instruction &instruction) {
- //printf("Sequence::s1_jumpSub()\n");
+ //debugCN(kDebugScript, "Sequence::s1_jumpSub()\n");
_returnHashes[_returnStackIndex] = _sequenceHash;
_returnOffsets[_returnStackIndex] = _code->pos();
@@ -628,7 +630,7 @@ bool Sequence::s1_jumpSub(Instruction &instruction) {
}
bool Sequence::s1_return(Instruction &instruction) {
- //printf("Sequence::s1_return()\n");
+ //debugCN(kDebugScript, "Sequence::s1_return()\n");
if (_returnStackIndex <= 0)
return s1_end(instruction);
@@ -652,7 +654,7 @@ bool Sequence::s1_return(Instruction &instruction) {
}
bool Sequence::s1_getFrameCount(Instruction &instruction) {
- //printf("Sequence::s1_getFrameCount()\n");
+ //debugCN(kDebugScript, "Sequence::s1_getFrameCount()\n");
SpriteAsset *spriteAsset = _ws->assets()->getSprite(instruction.argv[1] >> 24);
*instruction.argp[0] = spriteAsset->getCount() << 16;
@@ -660,7 +662,7 @@ bool Sequence::s1_getFrameCount(Instruction &instruction) {
}
bool Sequence::s1_getFrameRate(Instruction &instruction) {
- //printf("Sequence::s1_getFrameRate()\n");
+ //debugCN(kDebugScript, "Sequence::s1_getFrameRate()\n");
SpriteAsset *spriteAsset = _ws->assets()->getSprite(instruction.argv[1] >> 24);
*instruction.argp[0] = spriteAsset->getFrameRate();
@@ -668,37 +670,37 @@ bool Sequence::s1_getFrameRate(Instruction &instruction) {
}
bool Sequence::s1_getCelsPixSpeed(Instruction &instruction) {
- printf("Sequence::s1_getCelsPixSpeed()\n");
+ debugCN(kDebugScript, "Sequence::s1_getCelsPixSpeed()\n");
// TODO
return true;
}
bool Sequence::s1_setIndex(Instruction &instruction) {
- printf("Sequence::s1_setIndex()\n");
+ debugCN(kDebugScript, "Sequence::s1_setIndex()\n");
// TODO
return true;
}
bool Sequence::s1_setLayer(Instruction &instruction) {
- printf("Sequence::s1_setLayer()\n");
+ debugCN(kDebugScript, "Sequence::s1_setLayer()\n");
//TODO
return true;
}
bool Sequence::s1_setDepth(Instruction &instruction) {
- printf("Sequence::s1_setDepth()\n");
+ debugCN(kDebugScript, "Sequence::s1_setDepth()\n");
//TODO
return true;
}
bool Sequence::s1_setData(Instruction &instruction) {
- printf("Sequence::s1_setData()\n");
+ debugCN(kDebugScript, "Sequence::s1_setData()\n");
//TODO
return true;
}
bool Sequence::s1_openStream(Instruction &instruction) {
- //printf("Sequence::s1_openStream()\n");
+ //debugCN(kDebugScript, "Sequence::s1_openStream()\n");
_stream = _vm->res()->openFile(_machine->name().c_str());
streamOpen();
@@ -706,14 +708,14 @@ bool Sequence::s1_openStream(Instruction &instruction) {
}
bool Sequence::s1_streamNextFrame(Instruction &instruction) {
- //printf("Sequence::s1_streamNextFrame()\n");
+ //debugCN(kDebugScript, "Sequence::s1_streamNextFrame()\n");
streamNextFrame();
return true;
}
bool Sequence::s1_closeStream(Instruction &instruction) {
- printf("Sequence::s1_closeStream()\n");
+ debugCN(kDebugScript, "Sequence::s1_closeStream()\n");
//TODO
return true;
}
@@ -726,8 +728,7 @@ bool Sequence::streamOpen() {
_vars[kSeqVarSpriteFrameCount] = _streamSpriteAsset->getCount() << 16;
_vars[kSeqVarSpriteFrameRate] = _streamSpriteAsset->getFrameRate() << 16;
- //printf("Sequence::streamOpen() frames = %d; max = %d x %d\n", _streamSpriteAsset->getCount(), _streamSpriteAsset->getMaxFrameWidth(), _streamSpriteAsset->getMaxFrameHeight());
- //fflush(stdout);
+ //debugCN(kDebugScript, "Sequence::streamOpen() frames = %d; max = %d x %d\n", _streamSpriteAsset->getCount(), _streamSpriteAsset->getMaxFrameWidth(), _streamSpriteAsset->getMaxFrameHeight());
_curFrame = new M4Sprite(_vm, _streamSpriteAsset->getMaxFrameWidth(), _streamSpriteAsset->getMaxFrameHeight());
streamNextFrame();
diff --git a/engines/made/console.cpp b/engines/made/console.cpp
new file mode 100644
index 0000000000..ee85c465e8
--- /dev/null
+++ b/engines/made/console.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "made/console.h"
+#include "made/made.h"
+
+namespace Made {
+
+MadeConsole::MadeConsole(MadeEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
+
+MadeConsole::~MadeConsole() {
+}
+
+void MadeConsole::preEnter() {
+}
+
+void MadeConsole::postEnter() {
+}
+
+} // End of namespace Made
diff --git a/backends/platform/sdl/amigaos/amigaos.cpp b/engines/made/console.h
index d2924445a3..9f4632b986 100644
--- a/backends/platform/sdl/amigaos/amigaos.cpp
+++ b/engines/made/console.h
@@ -23,17 +23,28 @@
*
*/
-#ifdef __amigaos4__
+#ifndef MADE_CONSOLE_H
+#define MADE_CONSOLE_H
-#include "backends/platform/sdl/amigaos/amigaos.h"
-#include "backends/fs/amigaos4/amigaos4-fs-factory.h"
+#include "gui/debugger.h"
-void OSystem_AmigaOS::init() {
- // Initialze File System Factory
- _fsFactory = new AmigaOSFilesystemFactory();
+namespace Made {
- // Invoke parent implementation of this method
- OSystem_SDL::init();
-}
+class MadeEngine;
+
+class MadeConsole : public GUI::Debugger {
+public:
+ MadeConsole(MadeEngine *vm);
+ virtual ~MadeConsole(void);
+
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+private:
+ MadeEngine *_vm;
+};
+
+} // End of namespace Made
#endif
diff --git a/engines/made/made.cpp b/engines/made/made.cpp
index 4b59723772..4434f5e159 100644
--- a/engines/made/made.cpp
+++ b/engines/made/made.cpp
@@ -78,6 +78,8 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng
_rnd = new Common::RandomSource();
g_eventRec.registerRandomSource(*_rnd, "made");
+ _console = new MadeConsole(this);
+
int cd_num = ConfMan.getInt("cdrom");
if (cd_num >= 0)
_system->getAudioCDManager()->openCD(cd_num);
@@ -132,6 +134,7 @@ MadeEngine::~MadeEngine() {
_system->getAudioCDManager()->stop();
delete _rnd;
+ delete _console;
delete _pmvPlayer;
delete _res;
delete _screen;
@@ -233,6 +236,12 @@ void MadeEngine::handleEvents() {
if (_eventKey == Common::KEYCODE_BACKSPACE)
_eventKey = 9;
_eventNum = 5;
+
+ // Check for Debugger Activation
+ if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) {
+ this->getDebugger()->attach();
+ this->getDebugger()->onFrame();
+ }
break;
default:
diff --git a/engines/made/made.h b/engines/made/made.h
index 553476540a..302c8f5275 100644
--- a/engines/made/made.h
+++ b/engines/made/made.h
@@ -46,14 +46,18 @@
#include "engines/engine.h"
#include "made/sound.h"
+#include "made/console.h"
/**
* This is the namespace of the Made engine.
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Return to Zork
+ * - Leather Goddesses of Phobos 2
+ * - The Manhole
+ * - Rodney's Funscreen
*/
namespace Made {
@@ -97,6 +101,8 @@ public:
virtual bool hasFeature(EngineFeature f) const;
virtual void syncSoundSettings();
+ GUI::Debugger *getDebugger() { return _console; }
+
int getGameId() {
return _gameId;
}
@@ -109,6 +115,7 @@ public:
Common::Platform getPlatform() const;
private:
+ MadeConsole *_console;
public:
PmvPlayer *_pmvPlayer;
ResourceReader *_res;
diff --git a/engines/made/module.mk b/engines/made/module.mk
index 78c906b288..d8c0c9eeb5 100644
--- a/engines/made/module.mk
+++ b/engines/made/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/made
MODULE_OBJS := \
+ console.o \
database.o \
detection.o \
graphics.o \
diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp
index cdcb49f9f9..ecc2378f15 100644
--- a/engines/made/resource.cpp
+++ b/engines/made/resource.cpp
@@ -295,7 +295,6 @@ void MenuResource::load(byte *source, int size) {
_strings.push_back(string);
debug(2, "%02d: %s\n", i, string);
}
- fflush(stdout);
delete sourceS;
}
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index 81c18ef64b..773e3d17ed 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -204,7 +204,7 @@ void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, int16 f
for (int16 yc = 0; yc < clipHeight; yc++) {
linePtr = source + sourceAdd;
for (int16 xc = 0; xc < clipWidth; xc++) {
- if (*linePtr && (_vm->getGameID() == GID_RTZ || (mask == 0 || maskp[xc] == 0))) {
+ if (*linePtr && (_vm->getGameID() == GID_RTZ || (mask == 0 || (maskp && maskp[xc] == 0)))) {
if (*linePtr)
dest[xc] = *linePtr;
}
diff --git a/engines/metaengine.h b/engines/metaengine.h
index 7519feaaa4..7b69a3fe43 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -231,6 +231,7 @@ private:
friend class Common::Singleton<SingletonBaseType>;
public:
+ GameDescriptor findGameOnePluginAtATime(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
GameList detectGames(const Common::FSList &fslist) const;
const EnginePlugin::List &getPlugins() const;
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index 3eed08e3c1..bb64401f37 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -545,8 +545,14 @@ bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) {
// Get CARD/HSPT data and dump their scripts
if (!scumm_stricmp(argv[2], "CARD")) {
- printf ("\n\nDumping scripts for %s\'s card %d!\n", argv[1], (uint16)atoi(argv[3]));
- printf ("==================================\n\n");
+ // Use debugN to print these because the scripts can get very large and would
+ // really be useless if the the text console is not used. A DumpFile could also
+ // theoretically be used, but I (clone2727) typically use this dynamically and
+ // don't want countless files laying around without game context. If one would
+ // want a file of a script they could just redirect stdout to a file or use
+ // deriven.
+ debugN("\n\nDumping scripts for %s\'s card %d!\n", argv[1], (uint16)atoi(argv[3]));
+ debugN("==================================\n\n");
Common::SeekableReadStream *cardStream = _vm->getRawData(MKID_BE('CARD'), (uint16)atoi(argv[3]));
cardStream->seek(4);
RivenScriptList scriptList = _vm->_scriptMan->readScripts(cardStream, false);
@@ -556,15 +562,16 @@ bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) {
}
delete cardStream;
} else if (!scumm_stricmp(argv[2], "HSPT")) {
- printf ("\n\nDumping scripts for %s\'s card %d hotspots!\n", argv[1], (uint16)atoi(argv[3]));
- printf ("===========================================\n\n");
+ // See above for why this is printed via debugN
+ debugN("\n\nDumping scripts for %s\'s card %d hotspots!\n", argv[1], (uint16)atoi(argv[3]));
+ debugN("===========================================\n\n");
Common::SeekableReadStream *hsptStream = _vm->getRawData(MKID_BE('HSPT'), (uint16)atoi(argv[3]));
uint16 hotspotCount = hsptStream->readUint16BE();
for (uint16 i = 0; i < hotspotCount; i++) {
- printf ("Hotspot %d:\n", i);
+ debugN("Hotspot %d:\n", i);
hsptStream->seek(22, SEEK_CUR); // Skip non-script related stuff
RivenScriptList scriptList = _vm->_scriptMan->readScripts(hsptStream, false);
for (uint32 j = 0; j < scriptList.size(); j++) {
@@ -578,7 +585,8 @@ bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) {
DebugPrintf("%s doesn't have any scripts!\n", argv[2]);
}
- printf("\n\n");
+ // See above for why this is printed via debugN
+ debugN("\n\n");
_vm->changeToStack(oldStack);
diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h
index e4d26d16f7..7bd76193fc 100644
--- a/engines/mohawk/mohawk.h
+++ b/engines/mohawk/mohawk.h
@@ -37,6 +37,15 @@ namespace Common {
class SeekableReadStream;
}
+/**
+ * This is the namespace of the Mohawk engine.
+ *
+ * Status of this engine: ???
+ *
+ * Games using this engine:
+ * - Myst
+ * - Riven: The Sequel to Myst
+ */
namespace Mohawk {
enum MohawkGameType {
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index 6ed7a313a0..b351f611e3 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -1396,9 +1396,9 @@ MystResourceType10::MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableRe
// TODO: Not sure about order of Mouse Down, Mouse Drag and Mouse Up
// Or whether this is slightly different...
- printf("Type 10 _mouseDownOpcode: %d\n", _mouseDownOpcode);
- printf("Type 10 _mouseDragOpcode: %d\n", _mouseDragOpcode);
- printf("Type 10 _mouseUpOpcode: %d\n", _mouseUpOpcode);
+ debugCN(kDebugResource, "Type 10 _mouseDownOpcode: %d\n", _mouseDownOpcode);
+ debugCN(kDebugResource, "Type 10 _mouseDragOpcode: %d\n", _mouseDragOpcode);
+ debugCN(kDebugResource, "Type 10 _mouseUpOpcode: %d\n", _mouseUpOpcode);
for (byte i = 0; i < 4; i++) {
debugC(kDebugResource, "\tList %d:", i);
@@ -1452,9 +1452,9 @@ MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableRe
// TODO: Not sure about order of Mouse Down, Mouse Drag and Mouse Up
// Or whether this is slightly different...
- printf("Type 11 _mouseDownOpcode: %d\n", _mouseDownOpcode);
- printf("Type 11 _mouseDragOpcode: %d\n", _mouseDragOpcode);
- printf("Type 11 _mouseUpOpcode: %d\n", _mouseUpOpcode);
+ debugCN(kDebugResource, "Type 11 _mouseDownOpcode: %d\n", _mouseDownOpcode);
+ debugCN(kDebugResource, "Type 11 _mouseDragOpcode: %d\n", _mouseDragOpcode);
+ debugCN(kDebugResource, "Type 11 _mouseUpOpcode: %d\n", _mouseUpOpcode);
for (byte i = 0; i < 3; i++) {
debugC(kDebugResource, "\tList %d:", i);
@@ -1511,14 +1511,14 @@ MystResourceType12::MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableRe
// TODO: Think that u0 and u1 are animation frames to be
// drawn for var == 0 and var == 1
- printf("Type 12 _state0Frame: %d\n", _state0Frame);
- printf("Type 12 _state1Frame: %d\n", _state1Frame);
+ debugCN(kDebugResource, "Type 12 _state0Frame: %d\n", _state0Frame);
+ debugCN(kDebugResource, "Type 12 _state1Frame: %d\n", _state1Frame);
// TODO: Not sure about order of Mouse Down, Mouse Drag and Mouse Up
// Or whether this is slightly different...
- printf("Type 12 _mouseDownOpcode: %d\n", _mouseDownOpcode);
- printf("Type 12 _mouseDragOpcode: %d\n", _mouseDragOpcode);
- printf("Type 12 _mouseUpOpcode: %d\n", _mouseUpOpcode);
+ debugCN(kDebugResource, "Type 12 _mouseDownOpcode: %d\n", _mouseDownOpcode);
+ debugCN(kDebugResource, "Type 12 _mouseDragOpcode: %d\n", _mouseDragOpcode);
+ debugCN(kDebugResource, "Type 12 _mouseUpOpcode: %d\n", _mouseUpOpcode);
for (byte i = 0; i < 3; i++) {
debugC(kDebugResource, "\tList %d:", i);
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index a8cd643e2c..e397d30df3 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -294,17 +294,16 @@ void MystScriptParser::varUnusedCheck(uint16 op, uint16 var) {
}
void MystScriptParser::unknown(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- // NOTE: printf used here instead of debug, so unknown opcodes are always reported...
- printf("Unimplemented opcode 0x%02x (%d)\n", op, op);
- printf("\tUses var %d\n", var);
- printf("\tArg count = %d\n", argc);
- if (argc)
- printf("\tArgs: ");
- for (uint16 i = 0; i < argc; i++) {
- if (i == argc - 1)
- printf("%d\n", argv[i]);
- else
- printf("%d, ", argv[i]);
+ warning("Unimplemented opcode 0x%02x (%d)", op, op);
+ warning("\tUses var %d", var);
+ warning("\tArg count = %d", argc);
+ if (argc) {
+ Common::String str;
+ str += Common::String::format("%d", argv[0]);
+ for (uint16 i = 1; i < argc; i++) {
+ str += Common::String::format(", %d", argv[i]);
+ }
+ warning("\tArgs: %s\n", str.c_str());
}
}
@@ -1529,7 +1528,7 @@ void MystScriptParser::opcode_102(uint16 op, uint16 var, uint16 argc, uint16 *ar
debugC(kDebugScript, "\tstartTime: %d", startTime);
debugC(kDebugScript, "\tendTime: %d", endTime);
- printf("TODO: Opcode %d Movie Time Index %d to %d\n", op, startTime, endTime);
+ warning("TODO: Opcode %d Movie Time Index %d to %d", op, startTime, endTime);
// TODO: Need version of playMovie blocking which allows selection
// of start and finish points.
_vm->_video->playMovie(_vm->wrapMovieFilename("bkroom", kStoneshipStack), 159, 99);
@@ -2488,7 +2487,7 @@ void MystScriptParser::opcode_121(uint16 op, uint16 var, uint16 argc, uint16 *ar
uint16 startTime = argv[0];
uint16 endTime = argv[1];
- printf("TODO: Opcode %d Movie Time Index %d to %d\n", op, startTime, endTime);
+ warning("TODO: Opcode %d Movie Time Index %d to %d\n", op, startTime, endTime);
// TODO: Need version of playMovie blocking which allows selection
// of start and finish points.
_vm->_video->playMovie(_vm->wrapMovieFilename("ewindow", kMechanicalStack), 253, 0);
@@ -2550,7 +2549,7 @@ void MystScriptParser::opcode_123(uint16 op, uint16 var, uint16 argc, uint16 *ar
uint16 start_time = argv[0];
uint16 end_time = argv[1];
- printf("TODO: Opcode %d Movie Time Index %d to %d\n", op, start_time, end_time);
+ warning("TODO: Opcode %d Movie Time Index %d to %d\n", op, start_time, end_time);
// TODO: Need version of playMovie blocking which allows selection
// of start and finish points.
// TODO: Not 100% sure about movie position
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index 30d1d727eb..49ab260fb9 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -157,14 +157,14 @@ void RivenScript::setupOpcodes() {
static void printTabs(byte tabs) {
for (byte i = 0; i < tabs; i++)
- printf ("\t");
+ debugN("\t");
}
void RivenScript::dumpScript(Common::StringArray varNames, Common::StringArray xNames, byte tabs) {
if (_stream->pos() != 0)
_stream->seek(0);
- printTabs(tabs); printf ("Stream Type %d:\n", _scriptType);
+ printTabs(tabs); debugN("Stream Type %d:\n", _scriptType);
dumpCommands(varNames, xNames, tabs + 1);
}
@@ -178,50 +178,50 @@ void RivenScript::dumpCommands(Common::StringArray varNames, Common::StringArray
if (_stream->readUint16BE() != 2)
warning ("if-then-else unknown value is not 2");
uint16 var = _stream->readUint16BE();
- printTabs(tabs); printf("switch (%s) {\n", varNames[var].c_str());
+ printTabs(tabs); debugN("switch (%s) {\n", varNames[var].c_str());
uint16 logicBlockCount = _stream->readUint16BE();
for (uint16 j = 0; j < logicBlockCount; j++) {
uint16 varCheck = _stream->readUint16BE();
printTabs(tabs + 1);
if (varCheck == 0xFFFF)
- printf("default:\n");
+ debugN("default:\n");
else
- printf("case %d:\n", varCheck);
+ debugN("case %d:\n", varCheck);
dumpCommands(varNames, xNames, tabs + 2);
- printTabs(tabs + 2); printf("break;\n");
+ printTabs(tabs + 2); debugN("break;\n");
}
- printTabs(tabs); printf("}\n");
+ printTabs(tabs); debugN("}\n");
} else if (command == 7) { // Use the variable name
_stream->readUint16BE(); // Skip the opcode var count
printTabs(tabs);
uint16 var = _stream->readUint16BE();
- printf("%s = %d;\n", varNames[var].c_str(), _stream->readUint16BE());
+ debugN("%s = %d;\n", varNames[var].c_str(), _stream->readUint16BE());
} else if (command == 17) { // Use the external command name
_stream->readUint16BE(); // Skip the opcode var count
printTabs(tabs);
- printf("%s(", xNames[_stream->readUint16BE()].c_str());
+ debugN("%s(", xNames[_stream->readUint16BE()].c_str());
uint16 varCount = _stream->readUint16BE();
for (uint16 j = 0; j < varCount; j++) {
- printf("%d", _stream->readUint16BE());
+ debugN("%d", _stream->readUint16BE());
if (j != varCount - 1)
- printf(", ");
+ debugN(", ");
}
- printf (");\n");
+ debugN(");\n");
} else if (command == 24) { // Use the variable name
_stream->readUint16BE(); // Skip the opcode var count
printTabs(tabs);
uint16 var = _stream->readUint16BE();
- printf ("%s += %d;\n", varNames[var].c_str(), _stream->readUint16BE());
+ debugN("%s += %d;\n", varNames[var].c_str(), _stream->readUint16BE());
} else {
printTabs(tabs);
uint16 varCount = _stream->readUint16BE();
- printf("%s(", _opcodes[command].desc);
+ debugN("%s(", _opcodes[command].desc);
for (uint16 j = 0; j < varCount; j++) {
- printf("%d", _stream->readUint16BE());
+ debugN("%d", _stream->readUint16BE());
if (j != varCount - 1)
- printf(", ");
+ debugN(", ");
}
- printf(");\n");
+ debugN(");\n");
}
}
}
@@ -513,14 +513,14 @@ void RivenScript::fadeAmbientSounds(uint16 op, uint16 argc, uint16 *argv) {
// Command 38: Play a movie with extra parameters (movie id, delay high, delay low, record type, record id)
void RivenScript::complexPlayMovie(uint16 op, uint16 argc, uint16 *argv) {
warning("STUB: complexPlayMovie");
- printf ("\tMovie ID = %d\n", argv[0]);
- printf ("\tDelay = %d\n", (argv[1] << 16) + argv[2]);
+ debugN("\tMovie ID = %d\n", argv[0]);
+ debugN("\tDelay = %d\n", (argv[1] << 16) + argv[2]);
if (argv[3] == 0) {
- printf ("\tDraw PLST %d\n", argv[4]);
+ debugN("\tDraw PLST %d\n", argv[4]);
} else if (argv[3] == 40) {
- printf ("\tPlay SLST %d\n", argv[4]);
+ debugN("\tPlay SLST %d\n", argv[4]);
} else {
- error ("Unknown complexPlayMovie record type %d", argv[3]);
+ error("Unknown complexPlayMovie record type %d", argv[3]);
}
}
diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp
index e00a087923..f67a77aa21 100644
--- a/engines/parallaction/detection.cpp
+++ b/engines/parallaction/detection.cpp
@@ -325,7 +325,7 @@ int ParallactionMetaEngine::getMaximumSaveSlot() const { return 99; }
void ParallactionMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String filename = ConfMan.getDomain(target)->getVal("gameid");
- filename += Common::String::printf(".0%02d", slot);
+ filename += Common::String::format(".0%02d", slot);
g_system->getSavefileManager()->removeSavefile(filename);
}
diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp
index d1c67f1338..bf2bf6d419 100644
--- a/engines/parallaction/font.cpp
+++ b/engines/parallaction/font.cpp
@@ -574,7 +574,7 @@ void AmigaFont::blitData(byte c) {
}
uint16 AmigaFont::width(byte c) {
-// printf("kern(%i) = %i, space(%i) = %i\t", c, getKerning(c), c, getSpacing(c));
+// debug("kern(%i) = %i, space(%i) = %i\t", c, getKerning(c), c, getSpacing(c));
return getKerning(c) + getSpacing(c);
}
@@ -642,7 +642,7 @@ Font *AmigaDisk_ns::createFont(const char *name, Common::SeekableReadStream &str
}
Font *DosDisk_br::createFont(const char *name, Common::ReadStream &stream) {
-// printf("DosDisk_br::createFont(%s)\n", name);
+// debug("DosDisk_br::createFont(%s)", name);
Font *font;
if (_vm->getFeatures() & GF_DEMO) {
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index a1926fc197..6c39b2e696 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -322,7 +322,7 @@ void Gfx::bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *sur
uint line = 0, col = 0;
uint xAccum = 0, yAccum = 0;
- uint inc = width * (100 - scale);
+ uint inc = width * (100 - scale);
uint thr = width * 100;
for (uint16 i = 0; i < srcRect.height(); i++) {
diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp
index 9f50236360..51d3ba5799 100644
--- a/engines/parallaction/gui_ns.cpp
+++ b/engines/parallaction/gui_ns.cpp
@@ -118,6 +118,7 @@ public:
ChooseLanguageInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) {
_allowChoice = false;
_nextState = "selectgame";
+ _label = 0;
_dosLanguageSelectBlocks[0] = Common::Rect( 80, 110, 128, 180 ); // Italian
_dosLanguageSelectBlocks[1] = Common::Rect( 129, 85, 177, 155 ); // French
@@ -147,7 +148,6 @@ public:
_blocks = _dosLanguageSelectBlocks;
}
- _label = 0;
_language = -1;
_allowChoice = true;
}
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 7bbdf79f1c..ded1b3bda4 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -48,8 +48,9 @@
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Nippon Safes Inc. (complete)
+ * - The Big Red Adventure (work in progress)
*/
namespace Parallaction {
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 470c698a21..1cbd857ac9 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -154,7 +154,8 @@ Common::Error Parallaction_br::go() {
while (!shouldQuit()) {
if (getFeatures() & GF_DEMO) {
- scheduleLocationSwitch("camalb.1");
+ scheduleLocationSwitch("camalb");
+ _nextPart = 1;
_input->_inputMode = Input::kInputModeGame;
} else {
startGui(splash);
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index ff24a06ceb..994cfa46fb 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -23,7 +23,6 @@
*
*/
-
#include "parallaction/parallaction.h"
#include "parallaction/parser.h"
#include "parallaction/sound.h"
@@ -1284,7 +1283,7 @@ DECLARE_ZONE_PARSER(commands) {
DECLARE_ZONE_PARSER(label) {
debugC(7, kDebugParser, "ZONE_PARSER(label) ");
-// printf("label: %s", _tokens[1]);
+// debug("label: %s", _tokens[1]);
ctxt.z->_label = _vm->_gfx->renderFloatingLabel(_vm->_labelFont, _tokens[1]);
ctxt.z->_flags &= ~kFlagsNoName;
}
diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp
index fa1ac910e7..84db3af9a4 100644
--- a/engines/parallaction/staticres.cpp
+++ b/engines/parallaction/staticres.cpp
@@ -54,216 +54,215 @@ byte Input::_resMouseArrow_NS[256] = {
TODO: The cursor data should be adjusted by adding 0x10 to each byte, because the bitmap
must be drawn using the background palette.
*/
-byte Input::_resMouseArrow_BR_Amiga[512] =
-{
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x03, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
- 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+byte Input::_resMouseArrow_BR_Amiga[512] = {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
+ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/*
This palette snippet is used for animations in Big Red Adventure.
*/
byte _braAmigaFramesDefaultPalette[48] = {
- 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0xFF, 0xE0, 0xCF, 0x7F, 0x7F, 0x7F, 0xD9, 0x9C, 0x84, 0x00,
- 0x9E, 0xF0, 0x91, 0xCC, 0x36, 0xFF, 0x6A, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0x11, 0xB0, 0xEE,
- 0xF0, 0xFF, 0x17, 0x3D, 0x18, 0xAC, 0x3A, 0xB0, 0x00, 0x00, 0x7D, 0x00, 0x00, 0xFF, 0xA8, 0xFF,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0xFF, 0xE0, 0xCF, 0x7F, 0x7F, 0x7F, 0xD9, 0x9C, 0x84, 0x00,
+ 0x9E, 0xF0, 0x91, 0xCC, 0x36, 0xFF, 0x6A, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0x11, 0xB0, 0xEE,
+ 0xF0, 0xFF, 0x17, 0x3D, 0x18, 0xAC, 0x3A, 0xB0, 0x00, 0x00, 0x7D, 0x00, 0x00, 0xFF, 0xA8, 0xFF,
};
byte _amigaTopazFont[2600] = {
- 0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
- 0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
- 0x00, 0x1a, 0x0f, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x45, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, 0x08,
- 0x00, 0x40, 0x00, 0x08, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x00, 0x6e,
- 0x00, 0xbe, 0x00, 0x00, 0x06, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
- 0x6c, 0x6c, 0x18, 0x00, 0x38, 0x18, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x18,
- 0x3c, 0x3c, 0x1c, 0x7e, 0x1c, 0x7e, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7c, 0x3c,
- 0x7c, 0x1e, 0x78, 0x7e, 0x7e, 0x3c, 0x66, 0x3c, 0x06, 0xc6, 0x60, 0xc6, 0xc6, 0x3c, 0x7c, 0x78,
- 0x7c, 0x3c, 0x7e, 0x66, 0x66, 0xc6, 0xc3, 0xc3, 0xfe, 0x3c, 0xc0, 0x3c, 0x10, 0x00, 0x18, 0x00,
- 0x60, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x60, 0x18, 0x0c, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x70, 0x72, 0x0f, 0x00, 0x18,
- 0x00, 0x1c, 0x42, 0xc3, 0x18, 0x3c, 0x66, 0x7e, 0x1c, 0x00, 0x3e, 0x7e, 0x7e, 0x3c, 0x18, 0x78,
- 0x78, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x30, 0x38, 0x00, 0x40, 0x40, 0xc0, 0x18, 0x3c, 0x3c, 0x7e,
- 0x06, 0x66, 0x18, 0x7e, 0x7e, 0x36, 0x0c, 0x0c, 0x18, 0x3c, 0xc6, 0x3c, 0x60, 0x76, 0x18, 0x00,
- 0x0c, 0x7e, 0x71, 0x66, 0x00, 0x66, 0x60, 0x0e, 0x7e, 0x66, 0x18, 0x6e, 0x3c, 0x00, 0x18, 0x7e,
- 0x06, 0x66, 0x18, 0x00, 0x7e, 0x34, 0x0c, 0x0c, 0x18, 0x0c, 0x60, 0x00, 0x18, 0x3c, 0x0c, 0x00,
- 0x0c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x7e, 0x00, 0x18, 0x3c, 0x00, 0x18, 0x6c, 0x6c,
- 0x3e, 0x66, 0x6c, 0x18, 0x18, 0x18, 0x66, 0x18, 0x00, 0x00, 0x00, 0x06, 0x66, 0x38, 0x66, 0x66,
- 0x3c, 0x60, 0x30, 0x06, 0x66, 0x66, 0x18, 0x18, 0x06, 0x00, 0x60, 0x66, 0xc6, 0x66, 0x66, 0x30,
- 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x06, 0xcc, 0x60, 0xee, 0xe6, 0x66, 0x66, 0xcc, 0x66, 0x66,
- 0x18, 0x66, 0x66, 0xc6, 0x66, 0x66, 0x0c, 0x30, 0x60, 0x0c, 0x38, 0x00, 0x18, 0x00, 0x60, 0x00,
- 0x06, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x9c, 0x3c, 0x7e, 0x00, 0x0c, 0x36,
- 0x3c, 0x66, 0x18, 0x60, 0x66, 0x81, 0x24, 0x33, 0x06, 0x81, 0x00, 0x66, 0x18, 0x0c, 0x0c, 0x30,
- 0x00, 0x7a, 0x00, 0x00, 0x70, 0x44, 0xcc, 0xc6, 0xc6, 0x23, 0x00, 0x66, 0x18, 0x00, 0x1c, 0x00,
- 0x24, 0x60, 0x00, 0x1c, 0x18, 0x18, 0x00, 0x66, 0xcc, 0x00, 0x60, 0x3c, 0x30, 0xc6, 0x18, 0x00,
- 0x8e, 0x00, 0xc6, 0x66, 0x60, 0x38, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00,
- 0x24, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x7e,
- 0x8e, 0x66, 0x18, 0x00, 0x18, 0x18, 0x00, 0x66, 0x00, 0x18, 0x00, 0x18, 0x00, 0xfe, 0x60, 0xac,
- 0x68, 0x30, 0x30, 0x0c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x78, 0x06, 0x06, 0x6c, 0x7c,
- 0x60, 0x06, 0x66, 0x66, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x06, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60,
- 0x60, 0x60, 0x66, 0x18, 0x06, 0xd8, 0x60, 0xfe, 0xf6, 0x66, 0x66, 0xcc, 0x66, 0x70, 0x18, 0x66,
- 0x66, 0xc6, 0x3c, 0x3c, 0x18, 0x30, 0x30, 0x0c, 0x6c, 0x00, 0x0c, 0x3c, 0x7c, 0x3c, 0x3e, 0x3c,
- 0x7c, 0x3e, 0x7c, 0x18, 0x0c, 0x66, 0x18, 0xec, 0x7c, 0x3c, 0x7c, 0x3e, 0x7c, 0x3c, 0x7c, 0x66,
- 0x66, 0xc6, 0xc6, 0x66, 0x7e, 0x18, 0x18, 0x18, 0x00, 0xf0, 0x66, 0x18, 0x3e, 0x30, 0x66, 0x3c,
- 0x18, 0x3c, 0x00, 0x9d, 0x44, 0x66, 0x00, 0xb9, 0x00, 0x3c, 0x7e, 0x18, 0x18, 0x60, 0x66, 0x7a,
- 0x18, 0x00, 0x30, 0x44, 0x66, 0x4c, 0x4c, 0x66, 0x18, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x60,
- 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x60, 0xd8, 0x3c, 0x60, 0x66, 0xc6, 0xe6, 0x3c, 0x3c, 0x3c, 0x3c,
- 0x6c, 0x66, 0x6c, 0x66, 0x66, 0x66, 0x7e, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0x3c, 0x3c, 0x3c,
- 0x3c, 0x18, 0x3c, 0x7e, 0x3c, 0x3e, 0x6c, 0x00, 0x18, 0x3c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x66, 0x1e, 0x3c, 0x66, 0x00, 0x7e, 0x7e, 0x00, 0x18, 0x00, 0x6c, 0x3c, 0xd8, 0x76, 0x00,
- 0x30, 0x0c, 0xff, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x7e, 0x18, 0x0c, 0x1c, 0xcc, 0x06, 0x7c, 0x0c,
- 0x3c, 0x3e, 0x00, 0x00, 0x60, 0x00, 0x06, 0x0c, 0xd6, 0x7e, 0x7c, 0x60, 0x66, 0x78, 0x78, 0x6e,
- 0x7e, 0x18, 0x06, 0xf0, 0x60, 0xd6, 0xde, 0x66, 0x7c, 0xcc, 0x7c, 0x3c, 0x18, 0x66, 0x66, 0xd6,
- 0x18, 0x18, 0x30, 0x30, 0x18, 0x0c, 0xc6, 0x00, 0x00, 0x06, 0x66, 0x60, 0x66, 0x66, 0x30, 0x66,
- 0x66, 0x18, 0x0c, 0x6c, 0x18, 0xfe, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x30, 0x66, 0x66, 0xc6,
- 0x6c, 0x66, 0x0c, 0x70, 0x18, 0x0e, 0x00, 0xc3, 0x66, 0x18, 0x6c, 0x78, 0x3c, 0x18, 0x00, 0x66,
- 0x00, 0xb1, 0x3c, 0xcc, 0x00, 0xa5, 0x00, 0x00, 0x18, 0x30, 0x0c, 0x00, 0x66, 0x3a, 0x18, 0x00,
- 0x30, 0x38, 0x33, 0x58, 0x58, 0x2c, 0x30, 0x7e, 0x18, 0x66, 0x66, 0x66, 0x66, 0x78, 0x60, 0x66,
- 0x60, 0x4c, 0x60, 0x6e, 0xf0, 0x18, 0x60, 0x30, 0xe6, 0xf6, 0x66, 0x66, 0x66, 0x66, 0x38, 0x66,
- 0x70, 0x30, 0x66, 0x66, 0x4c, 0x4c, 0x6c, 0x06, 0x18, 0x06, 0x3c, 0x06, 0x06, 0x66, 0x66, 0x3c,
- 0x66, 0x0c, 0x66, 0x66, 0x78, 0x18, 0x18, 0x60, 0x7c, 0x66, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x66,
- 0x78, 0x60, 0x66, 0x66, 0x0c, 0x0c, 0x00, 0x18, 0x00, 0xfe, 0x06, 0x36, 0xdc, 0x00, 0x30, 0x0c,
- 0x3c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x76, 0x18, 0x18, 0x06, 0xfe, 0x06, 0x66, 0x18, 0x66, 0x06,
- 0x00, 0x00, 0x18, 0x7e, 0x18, 0x18, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60, 0x60, 0x66, 0x66, 0x18,
- 0x06, 0xd8, 0x60, 0xc6, 0xce, 0x66, 0x60, 0xcc, 0x6c, 0x0e, 0x18, 0x66, 0x3c, 0xfe, 0x3c, 0x18,
- 0x60, 0x30, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x60, 0x66, 0x7e, 0x30, 0x66, 0x66, 0x18,
- 0x0c, 0x78, 0x18, 0xd6, 0x66, 0x66, 0x66, 0x66, 0x60, 0x3c, 0x30, 0x66, 0x66, 0xd6, 0x38, 0x66,
- 0x18, 0x18, 0x18, 0x18, 0x00, 0x0f, 0x66, 0x18, 0x3e, 0x30, 0x42, 0x3c, 0x18, 0x3c, 0x00, 0x9d,
- 0x00, 0x66, 0x00, 0xb9, 0x00, 0x00, 0x18, 0x7c, 0x78, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x30, 0x00,
- 0x66, 0x32, 0x3e, 0xd9, 0x60, 0x66, 0x18, 0x7e, 0x40, 0x7e, 0x7e, 0x60, 0x78, 0x40, 0x78, 0x18,
- 0x78, 0x66, 0xd8, 0x18, 0x60, 0x0c, 0xf6, 0xde, 0x66, 0x66, 0x66, 0x66, 0x6c, 0x66, 0xe0, 0x0c,
- 0x66, 0x66, 0x18, 0x18, 0x66, 0x3e, 0x18, 0x3e, 0x60, 0x3e, 0x3e, 0x7e, 0x7e, 0x60, 0x7e, 0x18,
- 0x7e, 0x66, 0x6c, 0x18, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x18, 0x3c,
- 0x66, 0x66, 0x18, 0x18, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x6a, 0xce, 0x00, 0x18, 0x18, 0x66, 0x18,
- 0x18, 0x00, 0x18, 0x60, 0x66, 0x18, 0x30, 0x66, 0x0c, 0x66, 0x66, 0x18, 0x66, 0x0c, 0x18, 0x18,
- 0x06, 0x00, 0x60, 0x00, 0xc0, 0x66, 0x66, 0x30, 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x66, 0xcc,
- 0x60, 0xc6, 0xc6, 0x66, 0x60, 0xdc, 0x66, 0x66, 0x18, 0x66, 0x3c, 0xee, 0x66, 0x18, 0xc0, 0x30,
- 0x06, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x60, 0x66, 0x60, 0x30, 0x3e, 0x66, 0x18, 0x0c, 0x6c,
- 0x18, 0xc6, 0x66, 0x66, 0x7c, 0x3e, 0x60, 0x06, 0x30, 0x66, 0x3c, 0xfe, 0x6c, 0x3c, 0x30, 0x18,
- 0x18, 0x18, 0x00, 0x3c, 0x66, 0x18, 0x0c, 0x30, 0x00, 0x18, 0x18, 0x06, 0x00, 0x81, 0x7e, 0x33,
- 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x00, 0x7c, 0xcc, 0x66,
- 0x62, 0x33, 0x66, 0x66, 0x18, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x66, 0x60, 0x32, 0x60, 0x3e,
- 0xcc, 0x18, 0x7e, 0x66, 0xde, 0xce, 0x66, 0x66, 0x66, 0x66, 0xc6, 0x66, 0x60, 0x66, 0x66, 0x66,
- 0x32, 0x32, 0x66, 0x66, 0x18, 0x66, 0x60, 0x66, 0x66, 0x60, 0x60, 0x60, 0x60, 0x30, 0x60, 0x3e,
- 0x66, 0x18, 0x18, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x18, 0x66, 0x18, 0x06, 0x66, 0x66,
- 0x30, 0x30, 0x00, 0x18, 0x00, 0x6c, 0x18, 0xcc, 0x7b, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x00,
- 0x18, 0xc0, 0x3c, 0x18, 0x7e, 0x3c, 0x0c, 0x3c, 0x3c, 0x18, 0x3c, 0x38, 0x18, 0x18, 0x00, 0x00,
- 0x00, 0x18, 0x78, 0x66, 0x7c, 0x1e, 0x78, 0x7e, 0x60, 0x3e, 0x66, 0x3c, 0x3c, 0xc6, 0x7e, 0xc6,
- 0xc6, 0x3c, 0x60, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0xc6, 0xc3, 0x18, 0xfe, 0x3c, 0x03, 0x3c,
- 0x00, 0x00, 0x00, 0x3e, 0x7c, 0x3c, 0x3e, 0x3c, 0x30, 0x06, 0x66, 0x0c, 0x0c, 0x66, 0x0c, 0xc6,
- 0x66, 0x3c, 0x60, 0x06, 0x60, 0x7c, 0x1c, 0x3e, 0x18, 0x6c, 0xc6, 0x18, 0x7e, 0x0e, 0x18, 0x70,
- 0x00, 0xf0, 0x7e, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x81,
- 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0xcf, 0xc4, 0x67,
- 0x3c, 0x67, 0x3e, 0x66, 0x3c, 0x66, 0x66, 0x7f, 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x18, 0x30, 0x3c,
- 0x18, 0x3c, 0xce, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x7e, 0x3c, 0x3c, 0x3c, 0x7e, 0x7e,
- 0x6c, 0x3f, 0x1e, 0x3e, 0x3c, 0x3e, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x3c, 0x06, 0x18, 0x0c,
- 0x0c, 0x7c, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x0c, 0x7c, 0x3e, 0x3e, 0x7e, 0x7e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x00, 0x03,
- 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x00, 0x30, 0x00,
- 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03,
- 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x18, 0x00,
- 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x20,
- 0x00, 0x08, 0x00, 0x28, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x00, 0x40,
- 0x00, 0x08, 0x00, 0x48, 0x00, 0x08, 0x00, 0x50, 0x00, 0x08, 0x00, 0x58, 0x00, 0x08, 0x00, 0x60,
- 0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x00, 0x70, 0x00, 0x08, 0x00, 0x78, 0x00, 0x08, 0x00, 0x80,
- 0x00, 0x08, 0x00, 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0x98, 0x00, 0x08, 0x00, 0xa0,
- 0x00, 0x08, 0x00, 0xa8, 0x00, 0x08, 0x00, 0xb0, 0x00, 0x08, 0x00, 0xb8, 0x00, 0x08, 0x00, 0xc0,
- 0x00, 0x08, 0x00, 0xc8, 0x00, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x00, 0xd8, 0x00, 0x08, 0x00, 0xe0,
- 0x00, 0x08, 0x00, 0xe8, 0x00, 0x08, 0x00, 0xf0, 0x00, 0x08, 0x00, 0xf8, 0x00, 0x08, 0x01, 0x00,
- 0x00, 0x08, 0x01, 0x08, 0x00, 0x08, 0x01, 0x10, 0x00, 0x08, 0x01, 0x18, 0x00, 0x08, 0x01, 0x20,
- 0x00, 0x08, 0x01, 0x28, 0x00, 0x08, 0x01, 0x30, 0x00, 0x08, 0x01, 0x38, 0x00, 0x08, 0x01, 0x40,
- 0x00, 0x08, 0x01, 0x48, 0x00, 0x08, 0x01, 0x50, 0x00, 0x08, 0x01, 0x58, 0x00, 0x08, 0x01, 0x60,
- 0x00, 0x08, 0x01, 0x68, 0x00, 0x08, 0x01, 0x70, 0x00, 0x08, 0x01, 0x78, 0x00, 0x08, 0x01, 0x80,
- 0x00, 0x08, 0x01, 0x88, 0x00, 0x08, 0x01, 0x90, 0x00, 0x08, 0x01, 0x98, 0x00, 0x08, 0x01, 0xa0,
- 0x00, 0x08, 0x01, 0xa8, 0x00, 0x08, 0x01, 0xb0, 0x00, 0x08, 0x01, 0xb8, 0x00, 0x08, 0x01, 0xc0,
- 0x00, 0x08, 0x01, 0xc8, 0x00, 0x08, 0x01, 0xd0, 0x00, 0x08, 0x01, 0xd8, 0x00, 0x08, 0x01, 0xe0,
- 0x00, 0x08, 0x01, 0xe8, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xf8, 0x00, 0x08, 0x02, 0x00,
- 0x00, 0x08, 0x02, 0x08, 0x00, 0x08, 0x02, 0x10, 0x00, 0x08, 0x02, 0x18, 0x00, 0x08, 0x02, 0x20,
- 0x00, 0x08, 0x02, 0x28, 0x00, 0x08, 0x02, 0x30, 0x00, 0x08, 0x02, 0x38, 0x00, 0x08, 0x02, 0x40,
- 0x00, 0x08, 0x02, 0x48, 0x00, 0x08, 0x02, 0x50, 0x00, 0x08, 0x02, 0x58, 0x00, 0x08, 0x02, 0x60,
- 0x00, 0x08, 0x02, 0x68, 0x00, 0x08, 0x02, 0x70, 0x00, 0x08, 0x02, 0x78, 0x00, 0x08, 0x02, 0x80,
- 0x00, 0x08, 0x02, 0x88, 0x00, 0x08, 0x02, 0x90, 0x00, 0x08, 0x02, 0x98, 0x00, 0x08, 0x02, 0xa0,
- 0x00, 0x08, 0x02, 0xa8, 0x00, 0x08, 0x02, 0xb0, 0x00, 0x08, 0x02, 0xb8, 0x00, 0x08, 0x02, 0xc0,
- 0x00, 0x08, 0x02, 0xc8, 0x00, 0x08, 0x02, 0xd0, 0x00, 0x08, 0x02, 0xd8, 0x00, 0x08, 0x02, 0xe0,
- 0x00, 0x08, 0x02, 0xe8, 0x00, 0x08, 0x02, 0xf0, 0x00, 0x08, 0x02, 0xf8, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00,
- 0x00, 0x08, 0x03, 0x08, 0x00, 0x08, 0x03, 0x10, 0x00, 0x08, 0x03, 0x18, 0x00, 0x08, 0x03, 0x20,
- 0x00, 0x08, 0x03, 0x28, 0x00, 0x08, 0x03, 0x30, 0x00, 0x08, 0x03, 0x38, 0x00, 0x08, 0x03, 0x40,
- 0x00, 0x08, 0x03, 0x48, 0x00, 0x08, 0x03, 0x50, 0x00, 0x08, 0x03, 0x58, 0x00, 0x08, 0x03, 0x60,
- 0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x03, 0x68, 0x00, 0x08, 0x03, 0x70, 0x00, 0x08, 0x03, 0x78,
- 0x00, 0x08, 0x03, 0x80, 0x00, 0x08, 0x03, 0x88, 0x00, 0x08, 0x03, 0x90, 0x00, 0x08, 0x03, 0x98,
- 0x00, 0x08, 0x03, 0xa0, 0x00, 0x08, 0x03, 0xa8, 0x00, 0x08, 0x03, 0xb0, 0x00, 0x08, 0x03, 0xb8,
- 0x00, 0x08, 0x03, 0xc0, 0x00, 0x08, 0x03, 0xc8, 0x00, 0x08, 0x03, 0xd0, 0x00, 0x08, 0x03, 0xd8,
- 0x00, 0x08, 0x03, 0xe0, 0x00, 0x08, 0x03, 0xe8, 0x00, 0x08, 0x03, 0xf0, 0x00, 0x08, 0x03, 0xf8,
- 0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x08, 0x00, 0x08, 0x04, 0x10, 0x00, 0x08, 0x04, 0x18,
- 0x00, 0x08, 0x04, 0x20, 0x00, 0x08, 0x04, 0x28, 0x00, 0x08, 0x04, 0x30, 0x00, 0x08, 0x04, 0x38,
- 0x00, 0x08, 0x04, 0x40, 0x00, 0x08, 0x04, 0x48, 0x00, 0x08, 0x04, 0x50, 0x00, 0x08, 0x04, 0x58,
- 0x00, 0x08, 0x04, 0x60, 0x00, 0x08, 0x04, 0x68, 0x00, 0x08, 0x04, 0x70, 0x00, 0x08, 0x04, 0x78,
- 0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x88, 0x00, 0x08, 0x04, 0x90, 0x00, 0x08, 0x04, 0x98,
- 0x00, 0x08, 0x04, 0xa0, 0x00, 0x08, 0x04, 0xa8, 0x00, 0x08, 0x04, 0xb0, 0x00, 0x08, 0x04, 0xb8,
- 0x00, 0x08, 0x04, 0xc0, 0x00, 0x08, 0x04, 0xc8, 0x00, 0x08, 0x04, 0xd0, 0x00, 0x08, 0x04, 0xd8,
- 0x00, 0x08, 0x04, 0xe0, 0x00, 0x08, 0x04, 0xe8, 0x00, 0x08, 0x04, 0xf0, 0x00, 0x08, 0x04, 0xf8,
- 0x00, 0x08, 0x05, 0x00, 0x00, 0x08, 0x05, 0x08, 0x00, 0x08, 0x05, 0x10, 0x00, 0x08, 0x05, 0x18,
- 0x00, 0x08, 0x05, 0x20, 0x00, 0x08, 0x05, 0x28, 0x00, 0x08, 0x05, 0x30, 0x00, 0x08, 0x05, 0x38,
- 0x00, 0x08, 0x05, 0x40, 0x00, 0x08, 0x05, 0x48, 0x00, 0x08, 0x05, 0x50, 0x00, 0x08, 0x05, 0x58,
- 0x00, 0x08, 0x05, 0x60, 0x00, 0x08, 0x05, 0x68, 0x00, 0x08, 0x05, 0x70, 0x00, 0x08, 0x05, 0x78,
- 0x00, 0x08, 0x05, 0x80, 0x00, 0x08, 0x05, 0x88, 0x00, 0x08, 0x05, 0x90, 0x00, 0x08, 0x05, 0x98,
- 0x00, 0x08, 0x05, 0xa0, 0x00, 0x08, 0x05, 0xa8, 0x00, 0x08, 0x05, 0xb0, 0x00, 0x08, 0x05, 0xb8,
- 0x00, 0x08, 0x05, 0xc0, 0x00, 0x08, 0x05, 0xc8, 0x00, 0x08, 0x05, 0xd0, 0x00, 0x08, 0x05, 0xd8,
- 0x00, 0x08, 0x05, 0xe0, 0x00, 0x08, 0x05, 0xe8, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x03, 0x00,
- 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf2
+ 0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
+ 0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x1a, 0x0f, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x45, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, 0x08,
+ 0x00, 0x40, 0x00, 0x08, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x00, 0x6e,
+ 0x00, 0xbe, 0x00, 0x00, 0x06, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x6c, 0x6c, 0x18, 0x00, 0x38, 0x18, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x18,
+ 0x3c, 0x3c, 0x1c, 0x7e, 0x1c, 0x7e, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7c, 0x3c,
+ 0x7c, 0x1e, 0x78, 0x7e, 0x7e, 0x3c, 0x66, 0x3c, 0x06, 0xc6, 0x60, 0xc6, 0xc6, 0x3c, 0x7c, 0x78,
+ 0x7c, 0x3c, 0x7e, 0x66, 0x66, 0xc6, 0xc3, 0xc3, 0xfe, 0x3c, 0xc0, 0x3c, 0x10, 0x00, 0x18, 0x00,
+ 0x60, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x60, 0x18, 0x0c, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x70, 0x72, 0x0f, 0x00, 0x18,
+ 0x00, 0x1c, 0x42, 0xc3, 0x18, 0x3c, 0x66, 0x7e, 0x1c, 0x00, 0x3e, 0x7e, 0x7e, 0x3c, 0x18, 0x78,
+ 0x78, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x30, 0x38, 0x00, 0x40, 0x40, 0xc0, 0x18, 0x3c, 0x3c, 0x7e,
+ 0x06, 0x66, 0x18, 0x7e, 0x7e, 0x36, 0x0c, 0x0c, 0x18, 0x3c, 0xc6, 0x3c, 0x60, 0x76, 0x18, 0x00,
+ 0x0c, 0x7e, 0x71, 0x66, 0x00, 0x66, 0x60, 0x0e, 0x7e, 0x66, 0x18, 0x6e, 0x3c, 0x00, 0x18, 0x7e,
+ 0x06, 0x66, 0x18, 0x00, 0x7e, 0x34, 0x0c, 0x0c, 0x18, 0x0c, 0x60, 0x00, 0x18, 0x3c, 0x0c, 0x00,
+ 0x0c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x7e, 0x00, 0x18, 0x3c, 0x00, 0x18, 0x6c, 0x6c,
+ 0x3e, 0x66, 0x6c, 0x18, 0x18, 0x18, 0x66, 0x18, 0x00, 0x00, 0x00, 0x06, 0x66, 0x38, 0x66, 0x66,
+ 0x3c, 0x60, 0x30, 0x06, 0x66, 0x66, 0x18, 0x18, 0x06, 0x00, 0x60, 0x66, 0xc6, 0x66, 0x66, 0x30,
+ 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x06, 0xcc, 0x60, 0xee, 0xe6, 0x66, 0x66, 0xcc, 0x66, 0x66,
+ 0x18, 0x66, 0x66, 0xc6, 0x66, 0x66, 0x0c, 0x30, 0x60, 0x0c, 0x38, 0x00, 0x18, 0x00, 0x60, 0x00,
+ 0x06, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x9c, 0x3c, 0x7e, 0x00, 0x0c, 0x36,
+ 0x3c, 0x66, 0x18, 0x60, 0x66, 0x81, 0x24, 0x33, 0x06, 0x81, 0x00, 0x66, 0x18, 0x0c, 0x0c, 0x30,
+ 0x00, 0x7a, 0x00, 0x00, 0x70, 0x44, 0xcc, 0xc6, 0xc6, 0x23, 0x00, 0x66, 0x18, 0x00, 0x1c, 0x00,
+ 0x24, 0x60, 0x00, 0x1c, 0x18, 0x18, 0x00, 0x66, 0xcc, 0x00, 0x60, 0x3c, 0x30, 0xc6, 0x18, 0x00,
+ 0x8e, 0x00, 0xc6, 0x66, 0x60, 0x38, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00,
+ 0x24, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x7e,
+ 0x8e, 0x66, 0x18, 0x00, 0x18, 0x18, 0x00, 0x66, 0x00, 0x18, 0x00, 0x18, 0x00, 0xfe, 0x60, 0xac,
+ 0x68, 0x30, 0x30, 0x0c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x78, 0x06, 0x06, 0x6c, 0x7c,
+ 0x60, 0x06, 0x66, 0x66, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x06, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60,
+ 0x60, 0x60, 0x66, 0x18, 0x06, 0xd8, 0x60, 0xfe, 0xf6, 0x66, 0x66, 0xcc, 0x66, 0x70, 0x18, 0x66,
+ 0x66, 0xc6, 0x3c, 0x3c, 0x18, 0x30, 0x30, 0x0c, 0x6c, 0x00, 0x0c, 0x3c, 0x7c, 0x3c, 0x3e, 0x3c,
+ 0x7c, 0x3e, 0x7c, 0x18, 0x0c, 0x66, 0x18, 0xec, 0x7c, 0x3c, 0x7c, 0x3e, 0x7c, 0x3c, 0x7c, 0x66,
+ 0x66, 0xc6, 0xc6, 0x66, 0x7e, 0x18, 0x18, 0x18, 0x00, 0xf0, 0x66, 0x18, 0x3e, 0x30, 0x66, 0x3c,
+ 0x18, 0x3c, 0x00, 0x9d, 0x44, 0x66, 0x00, 0xb9, 0x00, 0x3c, 0x7e, 0x18, 0x18, 0x60, 0x66, 0x7a,
+ 0x18, 0x00, 0x30, 0x44, 0x66, 0x4c, 0x4c, 0x66, 0x18, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x60,
+ 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x60, 0xd8, 0x3c, 0x60, 0x66, 0xc6, 0xe6, 0x3c, 0x3c, 0x3c, 0x3c,
+ 0x6c, 0x66, 0x6c, 0x66, 0x66, 0x66, 0x7e, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0x3c, 0x3c, 0x3c,
+ 0x3c, 0x18, 0x3c, 0x7e, 0x3c, 0x3e, 0x6c, 0x00, 0x18, 0x3c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x1e, 0x3c, 0x66, 0x00, 0x7e, 0x7e, 0x00, 0x18, 0x00, 0x6c, 0x3c, 0xd8, 0x76, 0x00,
+ 0x30, 0x0c, 0xff, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x7e, 0x18, 0x0c, 0x1c, 0xcc, 0x06, 0x7c, 0x0c,
+ 0x3c, 0x3e, 0x00, 0x00, 0x60, 0x00, 0x06, 0x0c, 0xd6, 0x7e, 0x7c, 0x60, 0x66, 0x78, 0x78, 0x6e,
+ 0x7e, 0x18, 0x06, 0xf0, 0x60, 0xd6, 0xde, 0x66, 0x7c, 0xcc, 0x7c, 0x3c, 0x18, 0x66, 0x66, 0xd6,
+ 0x18, 0x18, 0x30, 0x30, 0x18, 0x0c, 0xc6, 0x00, 0x00, 0x06, 0x66, 0x60, 0x66, 0x66, 0x30, 0x66,
+ 0x66, 0x18, 0x0c, 0x6c, 0x18, 0xfe, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x30, 0x66, 0x66, 0xc6,
+ 0x6c, 0x66, 0x0c, 0x70, 0x18, 0x0e, 0x00, 0xc3, 0x66, 0x18, 0x6c, 0x78, 0x3c, 0x18, 0x00, 0x66,
+ 0x00, 0xb1, 0x3c, 0xcc, 0x00, 0xa5, 0x00, 0x00, 0x18, 0x30, 0x0c, 0x00, 0x66, 0x3a, 0x18, 0x00,
+ 0x30, 0x38, 0x33, 0x58, 0x58, 0x2c, 0x30, 0x7e, 0x18, 0x66, 0x66, 0x66, 0x66, 0x78, 0x60, 0x66,
+ 0x60, 0x4c, 0x60, 0x6e, 0xf0, 0x18, 0x60, 0x30, 0xe6, 0xf6, 0x66, 0x66, 0x66, 0x66, 0x38, 0x66,
+ 0x70, 0x30, 0x66, 0x66, 0x4c, 0x4c, 0x6c, 0x06, 0x18, 0x06, 0x3c, 0x06, 0x06, 0x66, 0x66, 0x3c,
+ 0x66, 0x0c, 0x66, 0x66, 0x78, 0x18, 0x18, 0x60, 0x7c, 0x66, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x66,
+ 0x78, 0x60, 0x66, 0x66, 0x0c, 0x0c, 0x00, 0x18, 0x00, 0xfe, 0x06, 0x36, 0xdc, 0x00, 0x30, 0x0c,
+ 0x3c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x76, 0x18, 0x18, 0x06, 0xfe, 0x06, 0x66, 0x18, 0x66, 0x06,
+ 0x00, 0x00, 0x18, 0x7e, 0x18, 0x18, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60, 0x60, 0x66, 0x66, 0x18,
+ 0x06, 0xd8, 0x60, 0xc6, 0xce, 0x66, 0x60, 0xcc, 0x6c, 0x0e, 0x18, 0x66, 0x3c, 0xfe, 0x3c, 0x18,
+ 0x60, 0x30, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x60, 0x66, 0x7e, 0x30, 0x66, 0x66, 0x18,
+ 0x0c, 0x78, 0x18, 0xd6, 0x66, 0x66, 0x66, 0x66, 0x60, 0x3c, 0x30, 0x66, 0x66, 0xd6, 0x38, 0x66,
+ 0x18, 0x18, 0x18, 0x18, 0x00, 0x0f, 0x66, 0x18, 0x3e, 0x30, 0x42, 0x3c, 0x18, 0x3c, 0x00, 0x9d,
+ 0x00, 0x66, 0x00, 0xb9, 0x00, 0x00, 0x18, 0x7c, 0x78, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x30, 0x00,
+ 0x66, 0x32, 0x3e, 0xd9, 0x60, 0x66, 0x18, 0x7e, 0x40, 0x7e, 0x7e, 0x60, 0x78, 0x40, 0x78, 0x18,
+ 0x78, 0x66, 0xd8, 0x18, 0x60, 0x0c, 0xf6, 0xde, 0x66, 0x66, 0x66, 0x66, 0x6c, 0x66, 0xe0, 0x0c,
+ 0x66, 0x66, 0x18, 0x18, 0x66, 0x3e, 0x18, 0x3e, 0x60, 0x3e, 0x3e, 0x7e, 0x7e, 0x60, 0x7e, 0x18,
+ 0x7e, 0x66, 0x6c, 0x18, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x18, 0x3c,
+ 0x66, 0x66, 0x18, 0x18, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x6a, 0xce, 0x00, 0x18, 0x18, 0x66, 0x18,
+ 0x18, 0x00, 0x18, 0x60, 0x66, 0x18, 0x30, 0x66, 0x0c, 0x66, 0x66, 0x18, 0x66, 0x0c, 0x18, 0x18,
+ 0x06, 0x00, 0x60, 0x00, 0xc0, 0x66, 0x66, 0x30, 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x66, 0xcc,
+ 0x60, 0xc6, 0xc6, 0x66, 0x60, 0xdc, 0x66, 0x66, 0x18, 0x66, 0x3c, 0xee, 0x66, 0x18, 0xc0, 0x30,
+ 0x06, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x60, 0x66, 0x60, 0x30, 0x3e, 0x66, 0x18, 0x0c, 0x6c,
+ 0x18, 0xc6, 0x66, 0x66, 0x7c, 0x3e, 0x60, 0x06, 0x30, 0x66, 0x3c, 0xfe, 0x6c, 0x3c, 0x30, 0x18,
+ 0x18, 0x18, 0x00, 0x3c, 0x66, 0x18, 0x0c, 0x30, 0x00, 0x18, 0x18, 0x06, 0x00, 0x81, 0x7e, 0x33,
+ 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x00, 0x7c, 0xcc, 0x66,
+ 0x62, 0x33, 0x66, 0x66, 0x18, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x66, 0x60, 0x32, 0x60, 0x3e,
+ 0xcc, 0x18, 0x7e, 0x66, 0xde, 0xce, 0x66, 0x66, 0x66, 0x66, 0xc6, 0x66, 0x60, 0x66, 0x66, 0x66,
+ 0x32, 0x32, 0x66, 0x66, 0x18, 0x66, 0x60, 0x66, 0x66, 0x60, 0x60, 0x60, 0x60, 0x30, 0x60, 0x3e,
+ 0x66, 0x18, 0x18, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x18, 0x66, 0x18, 0x06, 0x66, 0x66,
+ 0x30, 0x30, 0x00, 0x18, 0x00, 0x6c, 0x18, 0xcc, 0x7b, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x00,
+ 0x18, 0xc0, 0x3c, 0x18, 0x7e, 0x3c, 0x0c, 0x3c, 0x3c, 0x18, 0x3c, 0x38, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x18, 0x78, 0x66, 0x7c, 0x1e, 0x78, 0x7e, 0x60, 0x3e, 0x66, 0x3c, 0x3c, 0xc6, 0x7e, 0xc6,
+ 0xc6, 0x3c, 0x60, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0xc6, 0xc3, 0x18, 0xfe, 0x3c, 0x03, 0x3c,
+ 0x00, 0x00, 0x00, 0x3e, 0x7c, 0x3c, 0x3e, 0x3c, 0x30, 0x06, 0x66, 0x0c, 0x0c, 0x66, 0x0c, 0xc6,
+ 0x66, 0x3c, 0x60, 0x06, 0x60, 0x7c, 0x1c, 0x3e, 0x18, 0x6c, 0xc6, 0x18, 0x7e, 0x0e, 0x18, 0x70,
+ 0x00, 0xf0, 0x7e, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x81,
+ 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0xcf, 0xc4, 0x67,
+ 0x3c, 0x67, 0x3e, 0x66, 0x3c, 0x66, 0x66, 0x7f, 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x18, 0x30, 0x3c,
+ 0x18, 0x3c, 0xce, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x7e, 0x3c, 0x3c, 0x3c, 0x7e, 0x7e,
+ 0x6c, 0x3f, 0x1e, 0x3e, 0x3c, 0x3e, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x3c, 0x06, 0x18, 0x0c,
+ 0x0c, 0x7c, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x0c, 0x7c, 0x3e, 0x3e, 0x7e, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x00, 0x03,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x00, 0x30, 0x00,
+ 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x18, 0x00,
+ 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x20,
+ 0x00, 0x08, 0x00, 0x28, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x00, 0x40,
+ 0x00, 0x08, 0x00, 0x48, 0x00, 0x08, 0x00, 0x50, 0x00, 0x08, 0x00, 0x58, 0x00, 0x08, 0x00, 0x60,
+ 0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x00, 0x70, 0x00, 0x08, 0x00, 0x78, 0x00, 0x08, 0x00, 0x80,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0x98, 0x00, 0x08, 0x00, 0xa0,
+ 0x00, 0x08, 0x00, 0xa8, 0x00, 0x08, 0x00, 0xb0, 0x00, 0x08, 0x00, 0xb8, 0x00, 0x08, 0x00, 0xc0,
+ 0x00, 0x08, 0x00, 0xc8, 0x00, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x00, 0xd8, 0x00, 0x08, 0x00, 0xe0,
+ 0x00, 0x08, 0x00, 0xe8, 0x00, 0x08, 0x00, 0xf0, 0x00, 0x08, 0x00, 0xf8, 0x00, 0x08, 0x01, 0x00,
+ 0x00, 0x08, 0x01, 0x08, 0x00, 0x08, 0x01, 0x10, 0x00, 0x08, 0x01, 0x18, 0x00, 0x08, 0x01, 0x20,
+ 0x00, 0x08, 0x01, 0x28, 0x00, 0x08, 0x01, 0x30, 0x00, 0x08, 0x01, 0x38, 0x00, 0x08, 0x01, 0x40,
+ 0x00, 0x08, 0x01, 0x48, 0x00, 0x08, 0x01, 0x50, 0x00, 0x08, 0x01, 0x58, 0x00, 0x08, 0x01, 0x60,
+ 0x00, 0x08, 0x01, 0x68, 0x00, 0x08, 0x01, 0x70, 0x00, 0x08, 0x01, 0x78, 0x00, 0x08, 0x01, 0x80,
+ 0x00, 0x08, 0x01, 0x88, 0x00, 0x08, 0x01, 0x90, 0x00, 0x08, 0x01, 0x98, 0x00, 0x08, 0x01, 0xa0,
+ 0x00, 0x08, 0x01, 0xa8, 0x00, 0x08, 0x01, 0xb0, 0x00, 0x08, 0x01, 0xb8, 0x00, 0x08, 0x01, 0xc0,
+ 0x00, 0x08, 0x01, 0xc8, 0x00, 0x08, 0x01, 0xd0, 0x00, 0x08, 0x01, 0xd8, 0x00, 0x08, 0x01, 0xe0,
+ 0x00, 0x08, 0x01, 0xe8, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xf8, 0x00, 0x08, 0x02, 0x00,
+ 0x00, 0x08, 0x02, 0x08, 0x00, 0x08, 0x02, 0x10, 0x00, 0x08, 0x02, 0x18, 0x00, 0x08, 0x02, 0x20,
+ 0x00, 0x08, 0x02, 0x28, 0x00, 0x08, 0x02, 0x30, 0x00, 0x08, 0x02, 0x38, 0x00, 0x08, 0x02, 0x40,
+ 0x00, 0x08, 0x02, 0x48, 0x00, 0x08, 0x02, 0x50, 0x00, 0x08, 0x02, 0x58, 0x00, 0x08, 0x02, 0x60,
+ 0x00, 0x08, 0x02, 0x68, 0x00, 0x08, 0x02, 0x70, 0x00, 0x08, 0x02, 0x78, 0x00, 0x08, 0x02, 0x80,
+ 0x00, 0x08, 0x02, 0x88, 0x00, 0x08, 0x02, 0x90, 0x00, 0x08, 0x02, 0x98, 0x00, 0x08, 0x02, 0xa0,
+ 0x00, 0x08, 0x02, 0xa8, 0x00, 0x08, 0x02, 0xb0, 0x00, 0x08, 0x02, 0xb8, 0x00, 0x08, 0x02, 0xc0,
+ 0x00, 0x08, 0x02, 0xc8, 0x00, 0x08, 0x02, 0xd0, 0x00, 0x08, 0x02, 0xd8, 0x00, 0x08, 0x02, 0xe0,
+ 0x00, 0x08, 0x02, 0xe8, 0x00, 0x08, 0x02, 0xf0, 0x00, 0x08, 0x02, 0xf8, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x08, 0x03, 0x08, 0x00, 0x08, 0x03, 0x10, 0x00, 0x08, 0x03, 0x18, 0x00, 0x08, 0x03, 0x20,
+ 0x00, 0x08, 0x03, 0x28, 0x00, 0x08, 0x03, 0x30, 0x00, 0x08, 0x03, 0x38, 0x00, 0x08, 0x03, 0x40,
+ 0x00, 0x08, 0x03, 0x48, 0x00, 0x08, 0x03, 0x50, 0x00, 0x08, 0x03, 0x58, 0x00, 0x08, 0x03, 0x60,
+ 0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x03, 0x68, 0x00, 0x08, 0x03, 0x70, 0x00, 0x08, 0x03, 0x78,
+ 0x00, 0x08, 0x03, 0x80, 0x00, 0x08, 0x03, 0x88, 0x00, 0x08, 0x03, 0x90, 0x00, 0x08, 0x03, 0x98,
+ 0x00, 0x08, 0x03, 0xa0, 0x00, 0x08, 0x03, 0xa8, 0x00, 0x08, 0x03, 0xb0, 0x00, 0x08, 0x03, 0xb8,
+ 0x00, 0x08, 0x03, 0xc0, 0x00, 0x08, 0x03, 0xc8, 0x00, 0x08, 0x03, 0xd0, 0x00, 0x08, 0x03, 0xd8,
+ 0x00, 0x08, 0x03, 0xe0, 0x00, 0x08, 0x03, 0xe8, 0x00, 0x08, 0x03, 0xf0, 0x00, 0x08, 0x03, 0xf8,
+ 0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x08, 0x00, 0x08, 0x04, 0x10, 0x00, 0x08, 0x04, 0x18,
+ 0x00, 0x08, 0x04, 0x20, 0x00, 0x08, 0x04, 0x28, 0x00, 0x08, 0x04, 0x30, 0x00, 0x08, 0x04, 0x38,
+ 0x00, 0x08, 0x04, 0x40, 0x00, 0x08, 0x04, 0x48, 0x00, 0x08, 0x04, 0x50, 0x00, 0x08, 0x04, 0x58,
+ 0x00, 0x08, 0x04, 0x60, 0x00, 0x08, 0x04, 0x68, 0x00, 0x08, 0x04, 0x70, 0x00, 0x08, 0x04, 0x78,
+ 0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x88, 0x00, 0x08, 0x04, 0x90, 0x00, 0x08, 0x04, 0x98,
+ 0x00, 0x08, 0x04, 0xa0, 0x00, 0x08, 0x04, 0xa8, 0x00, 0x08, 0x04, 0xb0, 0x00, 0x08, 0x04, 0xb8,
+ 0x00, 0x08, 0x04, 0xc0, 0x00, 0x08, 0x04, 0xc8, 0x00, 0x08, 0x04, 0xd0, 0x00, 0x08, 0x04, 0xd8,
+ 0x00, 0x08, 0x04, 0xe0, 0x00, 0x08, 0x04, 0xe8, 0x00, 0x08, 0x04, 0xf0, 0x00, 0x08, 0x04, 0xf8,
+ 0x00, 0x08, 0x05, 0x00, 0x00, 0x08, 0x05, 0x08, 0x00, 0x08, 0x05, 0x10, 0x00, 0x08, 0x05, 0x18,
+ 0x00, 0x08, 0x05, 0x20, 0x00, 0x08, 0x05, 0x28, 0x00, 0x08, 0x05, 0x30, 0x00, 0x08, 0x05, 0x38,
+ 0x00, 0x08, 0x05, 0x40, 0x00, 0x08, 0x05, 0x48, 0x00, 0x08, 0x05, 0x50, 0x00, 0x08, 0x05, 0x58,
+ 0x00, 0x08, 0x05, 0x60, 0x00, 0x08, 0x05, 0x68, 0x00, 0x08, 0x05, 0x70, 0x00, 0x08, 0x05, 0x78,
+ 0x00, 0x08, 0x05, 0x80, 0x00, 0x08, 0x05, 0x88, 0x00, 0x08, 0x05, 0x90, 0x00, 0x08, 0x05, 0x98,
+ 0x00, 0x08, 0x05, 0xa0, 0x00, 0x08, 0x05, 0xa8, 0x00, 0x08, 0x05, 0xb0, 0x00, 0x08, 0x05, 0xb8,
+ 0x00, 0x08, 0x05, 0xc0, 0x00, 0x08, 0x05, 0xc8, 0x00, 0x08, 0x05, 0xd0, 0x00, 0x08, 0x05, 0xd8,
+ 0x00, 0x08, 0x05, 0xe0, 0x00, 0x08, 0x05, 0xe8, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x03, 0x00,
+ 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf2
};
diff --git a/engines/queen/debug.cpp b/engines/queen/debug.cpp
index 1abb2415d2..f4d7cf3b2e 100644
--- a/engines/queen/debug.cpp
+++ b/engines/queen/debug.cpp
@@ -149,12 +149,12 @@ bool Debugger::Cmd_Items(int argc, const char **argv) {
bool Debugger::Cmd_PrintBobs(int argc, const char**argv) {
int i;
BobSlot *bob = _vm->graphics()->bob(0);
- DebugPrintf("+--------------------------------+\n");
- DebugPrintf("|# | x| y|f|scl|frm|a|m| ex| ey|\n");
- DebugPrintf("+--+---+---+-+---+---+-+-+---+---+\n");
+ DebugPrintf("+------------------------------------+\n");
+ DebugPrintf("|# | x| y|f|scl|frm|a|m|spd| ex| ey|\n");
+ DebugPrintf("+--+---+---+-+---+---+-+-+---+---+---+\n");
for (i = 0; i < Graphics::MAX_BOBS_NUMBER; ++i, ++bob) {
if (bob->active) {
- DebugPrintf("|%2d|%3d|%3d|%1d|%3d|%3d|%1d|%1d|%3d|%3d|\n",
+ DebugPrintf("|%2d|%3d|%3d|%1d|%3d|%3d|%1d|%1d|%3d|%3d|%3d|\n",
i, bob->x, bob->y, bob->xflip, bob->scale, bob->frameNum,
bob->animating, bob->moving, bob->speed, bob->endx, bob->endy);
}
diff --git a/engines/queen/logic.cpp b/engines/queen/logic.cpp
index 053312c584..de254300b6 100644
--- a/engines/queen/logic.cpp
+++ b/engines/queen/logic.cpp
@@ -1550,7 +1550,7 @@ void Logic::asmEndGame() {
while (n--) {
_vm->update();
}
-// printf("Game completed.");
+// debug("Game completed.");
_vm->quitGame();
}
@@ -2004,7 +2004,7 @@ void Logic::asmPanLeftToBomb() {
}
void Logic::asmEndDemo() {
-// printf("Flight of the Amazon Queen, released January 95.");
+// debug("Flight of the Amazon Queen, released January 95.");
_vm->quitGame();
}
@@ -2049,7 +2049,7 @@ void Logic::asmInterviewIntro() {
}
void Logic::asmEndInterview() {
-// printf("Interactive Interview copyright (c) 1995, IBI.");
+// debug("Interactive Interview copyright (c) 1995, IBI.");
_vm->quitGame();
}
diff --git a/engines/queen/queen.h b/engines/queen/queen.h
index 5a8f1357f4..93d705b182 100644
--- a/engines/queen/queen.h
+++ b/engines/queen/queen.h
@@ -56,8 +56,8 @@ FORCEINLINE int16 READ_BE_INT16(const void *ptr) {
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Flight of the Amazon Queen
*/
namespace Queen {
diff --git a/engines/queen/talk.cpp b/engines/queen/talk.cpp
index 6bc79daa73..106b0d6123 100644
--- a/engines/queen/talk.cpp
+++ b/engines/queen/talk.cpp
@@ -777,7 +777,7 @@ void Talk::defaultAnimation(
}
// Make sure that Person closes their mouth
- if (!isJoe && parameters->ff > 0)
+ if (!isJoe && parameters && parameters->ff > 0)
_vm->bankMan()->overpack(parameters->ff, startFrame, bankNum);
}
diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp
index 8bc8025032..5111f1ae07 100644
--- a/engines/saga/actor.cpp
+++ b/engines/saga/actor.cpp
@@ -42,18 +42,42 @@
namespace Saga {
ActorData::ActorData() {
- memset(this, 0, sizeof(*this));
-}
+ _frames = NULL;
+ _frameListResourceId = 0;
+ _speechColor = 0;
+ _inScene = false;
+
+ _actorFlags = 0;
+ _currentAction = 0;
+ _facingDirection = 0;
+ _actionDirection = 0;
+ _actionCycle = 0;
+ _targetObject = 0;
+ _lastZone = NULL;
+
+ _cycleFrameSequence = 0;
+ _cycleDelay = 0;
+ _cycleTimeCount = 0;
+ _cycleFlags = 0;
+
+ _fallVelocity = 0;
+ _fallAcceleration = 0;
+ _fallPosition = 0;
-ActorData::~ActorData() {
- if (!_shareFrames)
- free(_frames);
- free(_tileDirections);
- free(_walkStepsPoints);
- freeSpriteList();
+ _dragonBaseFrame = 0;
+ _dragonStepCycle = 0;
+ _dragonMoveType = 0;
+
+ _frameNumber = 0;
+
+ _walkStepsCount = 0;
+ _walkStepIndex = 0;
+
+ _walkFrameSequence = 0;
}
+
void ActorData::saveState(Common::OutSaveFile *out) {
- int i = 0;
+ uint i = 0;
CommonObjectData::saveState(out);
out->writeUint16LE(_actorFlags);
out->writeSint32LE(_currentAction);
@@ -74,13 +98,13 @@ void ActorData::saveState(Common::OutSaveFile *out) {
out->writeByte(_dragonMoveType);
out->writeSint32LE(_frameNumber);
- out->writeSint32LE(_tileDirectionsAlloced);
- for (i = 0; i < _tileDirectionsAlloced; i++) {
+ out->writeSint32LE(_tileDirections.size());
+ for (i = 0; i < _tileDirections.size(); i++) {
out->writeByte(_tileDirections[i]);
}
- out->writeSint32LE(_walkStepsAlloced);
- for (i = 0; i < _walkStepsAlloced; i++) {
+ out->writeSint32LE(_walkStepsPoints.size());
+ for (i = 0; i < _walkStepsPoints.size(); i++) {
out->writeSint16LE(_walkStepsPoints[i].x);
out->writeSint16LE(_walkStepsPoints[i].y);
}
@@ -93,7 +117,7 @@ void ActorData::saveState(Common::OutSaveFile *out) {
}
void ActorData::loadState(uint32 version, Common::InSaveFile *in) {
- int i = 0;
+ uint i = 0;
CommonObjectData::loadState(in);
_actorFlags = in->readUint16LE();
_currentAction = in->readSint32LE();
@@ -125,13 +149,13 @@ void ActorData::loadState(uint32 version, Common::InSaveFile *in) {
_frameNumber = in->readSint32LE();
- setTileDirectionsSize(in->readSint32LE(), true);
- for (i = 0; i < _tileDirectionsAlloced; i++) {
+ _tileDirections.resize(in->readSint32LE());
+ for (i = 0; i < _tileDirections.size(); i++) {
_tileDirections[i] = in->readByte();
}
- setWalkStepsPointsSize(in->readSint32LE(), true);
- for (i = 0; i < _walkStepsAlloced; i++) {
+ _walkStepsPoints.resize(in->readSint32LE());
+ for (i = 0; i < _walkStepsPoints.size(); i++) {
_walkStepsPoints[i].x = in->readSint16LE();
_walkStepsPoints[i].y = in->readSint16LE();
}
@@ -143,38 +167,16 @@ void ActorData::loadState(uint32 version, Common::InSaveFile *in) {
_walkFrameSequence = in->readSint32LE();
}
-void ActorData::setTileDirectionsSize(int size, bool forceRealloc) {
- if ((size <= _tileDirectionsAlloced) && !forceRealloc) {
- return;
- }
- _tileDirectionsAlloced = size;
- _tileDirections = (byte*)realloc(_tileDirections, _tileDirectionsAlloced * sizeof(*_tileDirections));
-}
-
void ActorData::cycleWrap(int cycleLimit) {
if (_actionCycle >= cycleLimit)
_actionCycle = 0;
}
-void ActorData::setWalkStepsPointsSize(int size, bool forceRealloc) {
- if ((size <= _walkStepsAlloced) && !forceRealloc) {
- return;
- }
- _walkStepsAlloced = size;
- _walkStepsPoints = (Point*)realloc(_walkStepsPoints, _walkStepsAlloced * sizeof(*_walkStepsPoints));
-}
-
void ActorData::addWalkStepPoint(const Point &point) {
- setWalkStepsPointsSize(_walkStepsCount + 1, false);
+ _walkStepsPoints.resize(_walkStepsCount + 1);
_walkStepsPoints[_walkStepsCount++] = point;
}
-void ActorData::freeSpriteList() {
- _spriteList.freeMem();
-}
-
-
-
static int commonObjectCompare(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) {
int p1 = obj1->_location.y - obj1->_location.z;
int p2 = obj2->_location.y - obj2->_location.z;
@@ -212,26 +214,14 @@ static int tileCommonObjectCompare(const CommonObjectDataPointer& obj1, const Co
Actor::Actor(SagaEngine *vm) : _vm(vm) {
int i;
- byte *stringsPointer;
- size_t stringsLength;
- ActorData *actor;
- ObjectData *obj;
+ ByteArray stringsData;
debug(9, "Actor::Actor()");
_handleActionDiv = 15;
- _actors = NULL;
- _actorsCount = 0;
-
- _objs = NULL;
- _objsCount = 0;
-
#ifdef ACTOR_DEBUG
_debugPointsCount = 0;
#endif
- _protagStates = NULL;
- _protagStatesCount = 0;
-
_pathList.resize(600);
_pathListIndex = 0;
@@ -242,7 +232,7 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) {
_yCellCount = _vm->_scene->getHeight();
_xCellCount = _vm->getDisplayInfo().width;
- _pathCell = (int8 *)malloc(_yCellCount * _xCellCount * sizeof(*_pathCell));
+ _pathCell.resize(_yCellCount * _xCellCount);
_pathRect.left = 0;
_pathRect.right = _vm->getDisplayInfo().width;
@@ -260,19 +250,17 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) {
if (_vm->getGameId() == GID_ITE) {
- _vm->_resource->loadResource(_actorContext, _vm->getResourceDescription()->actorsStringsResourceId, stringsPointer, stringsLength);
+ _vm->_resource->loadResource(_actorContext, _vm->getResourceDescription()->actorsStringsResourceId, stringsData);
- _vm->loadStrings(_actorsStrings, stringsPointer, stringsLength);
- free(stringsPointer);
+ _vm->loadStrings(_actorsStrings, stringsData);
}
if (_vm->getGameId() == GID_ITE) {
- _actorsCount = ITE_ACTORCOUNT;
- _actors = (ActorData **)malloc(_actorsCount * sizeof(*_actors));
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i] = new ActorData();
- actor->_id = actorIndexToId(i);
+ _actors.resize(ITE_ACTORCOUNT);
+ i = 0;
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor, i++) {
actor->_index = i;
+ actor->_id = actorIndexToId(actor->_index);
debug(9, "init actor id=%d index=%d", actor->_id, actor->_index);
actor->_nameIndex = ITE_ActorTable[i].nameIndex;
actor->_scriptEntrypointNumber = ITE_ActorTable[i].scriptEntrypointNumber;
@@ -294,12 +282,11 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) {
warning("Disabling actor Id=%d index=%d", actor->_id, actor->_index);
}
}
- _objsCount = ITE_OBJECTCOUNT;
- _objs = (ObjectData **)malloc(_objsCount * sizeof(*_objs));
- for (i = 0; i < _objsCount; i++) {
- obj = _objs[i] = new ObjectData();
- obj->_id = objIndexToId(i);
+ _objs.resize(ITE_OBJECTCOUNT);
+ i = 0;
+ for (ObjectDataArray::iterator obj = _objs.begin(); obj != _objs.end(); ++obj, i++) {
obj->_index = i;
+ obj->_id = objIndexToId(obj->_index);
debug(9, "init obj id=%d index=%d", obj->_id, obj->_index);
obj->_nameIndex = ITE_ObjectTable[i].nameIndex;
obj->_scriptEntrypointNumber = ITE_ObjectTable[i].scriptEntrypointNumber;
@@ -318,69 +305,42 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) {
Actor::~Actor() {
debug(9, "Actor::~Actor()");
-
- free(_pathCell);
- _actorsStrings.freeMem();
- //release resources
- freeProtagStates();
- freeActorList();
- freeObjList();
-}
-
-void Actor::freeProtagStates() {
- int i;
- for (i = 0; i < _protagStatesCount; i++) {
- free(_protagStates[i]._frames);
- }
- free(_protagStates);
- _protagStates = NULL;
- _protagStatesCount = 0;
}
-void Actor::loadFrameList(int frameListResourceId, ActorFrameSequence *&framesPointer, int &framesCount) {
- byte *resourcePointer;
- size_t resourceLength;
+void Actor::loadFrameList(int frameListResourceId, ActorFrameSequences &frames) {
+ ByteArray resourceData;
debug(9, "Loading frame resource id %d", frameListResourceId);
- _vm->_resource->loadResource(_actorContext, frameListResourceId, resourcePointer, resourceLength);
-
- framesCount = resourceLength / 16;
- debug(9, "Frame resource contains %d frames (res length is %d)", framesCount, (int)resourceLength);
+ _vm->_resource->loadResource(_actorContext, frameListResourceId, resourceData);
- framesPointer = (ActorFrameSequence *)malloc(sizeof(ActorFrameSequence) * framesCount);
- if (framesPointer == NULL && framesCount != 0) {
- memoryError("Actor::loadFrameList");
- }
+ frames.resize(resourceData.size() / 16);
+ debug(9, "Frame resource contains %d frames (res length is %d)", frames.size(), (int)resourceData.size());
- MemoryReadStreamEndian readS(resourcePointer, resourceLength, _actorContext->isBigEndian());
+ ByteArrayReadStreamEndian readS(resourceData, _actorContext->isBigEndian());
- for (int i = 0; i < framesCount; i++) {
- debug(9, "frameType %d", i);
+ for (ActorFrameSequences::iterator frame = frames.begin(); frame != frames.end(); ++frame) {
for (int orient = 0; orient < ACTOR_DIRECTIONS_COUNT; orient++) {
// Load all four orientations
- framesPointer[i].directions[orient].frameIndex = readS.readUint16();
+ frame->directions[orient].frameIndex = readS.readUint16();
if (_vm->getGameId() == GID_ITE) {
- framesPointer[i].directions[orient].frameCount = readS.readSint16();
+ frame->directions[orient].frameCount = readS.readSint16();
} else {
- framesPointer[i].directions[orient].frameCount = readS.readByte();
+ frame->directions[orient].frameCount = readS.readByte();
readS.readByte();
}
- if (framesPointer[i].directions[orient].frameCount < 0)
- warning("frameCount < 0 (%d)", framesPointer[i].directions[orient].frameCount);
- debug(9, "frameIndex %d frameCount %d", framesPointer[i].directions[orient].frameIndex, framesPointer[i].directions[orient].frameCount);
+ if (frame->directions[orient].frameCount < 0)
+ warning("frameCount < 0 (%d)", frame->directions[orient].frameCount);
+ debug(9, "frameIndex %d frameCount %d", frame->directions[orient].frameIndex, frame->directions[orient].frameCount);
}
}
-
- free(resourcePointer);
}
bool Actor::loadActorResources(ActorData *actor) {
bool gotSomething = false;
if (actor->_frameListResourceId) {
- loadFrameList(actor->_frameListResourceId, actor->_frames, actor->_framesCount);
-
- actor->_shareFrames = false;
+ loadFrameList(actor->_frameListResourceId, actor->_framesContainer);
+ actor->_frames = &actor->_framesContainer;
gotSomething = true;
} else {
@@ -400,26 +360,18 @@ bool Actor::loadActorResources(ActorData *actor) {
return gotSomething;
}
-void Actor::freeActorList() {
- int i;
- ActorData *actor;
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
- delete actor;
- }
- free(_actors);
- _actors = NULL;
- _actorsCount = 0;
-}
-
void Actor::loadActorSpriteList(ActorData *actor) {
- int lastFrame = 0;
+ uint lastFrame = 0;
+ uint curFrameIndex;
int resourceId = actor->_spriteListResourceId;
-
- for (int i = 0; i < actor->_framesCount; i++) {
- for (int orient = 0; orient < ACTOR_DIRECTIONS_COUNT; orient++) {
- if (actor->_frames[i].directions[orient].frameIndex > lastFrame) {
- lastFrame = actor->_frames[i].directions[orient].frameIndex;
+
+ if (actor->_frames != NULL) {
+ for (ActorFrameSequences::const_iterator i = actor->_frames->begin(); i != actor->_frames->end(); ++i) {
+ for (int orient = 0; orient < ACTOR_DIRECTIONS_COUNT; orient++) {
+ curFrameIndex = i->directions[orient].frameIndex;
+ if (curFrameIndex > lastFrame) {
+ lastFrame = curFrameIndex;
+ }
}
}
}
@@ -430,7 +382,7 @@ void Actor::loadActorSpriteList(ActorData *actor) {
if (_vm->getGameId() == GID_ITE) {
if (actor->_flags & kExtended) {
- while ((lastFrame >= actor->_spriteList.spriteCount)) {
+ while ((lastFrame >= actor->_spriteList.size())) {
resourceId++;
debug(9, "Appending to actor sprite list %d", resourceId);
_vm->_sprite->loadList(resourceId, actor->_spriteList);
@@ -441,9 +393,7 @@ void Actor::loadActorSpriteList(ActorData *actor) {
void Actor::loadActorList(int protagonistIdx, int actorCount, int actorsResourceID, int protagStatesCount, int protagStatesResourceID) {
int i, j;
- ActorData *actor;
- byte* actorListData;
- size_t actorListLength;
+ ByteArray actorListData;
byte walk[128];
byte acv[6];
int movementSpeed;
@@ -451,24 +401,20 @@ void Actor::loadActorList(int protagonistIdx, int actorCount, int actorsResource
int walkStepCount;
int stateResourceId;
- freeActorList();
-
- _vm->_resource->loadResource(_actorContext, actorsResourceID, actorListData, actorListLength);
+ _vm->_resource->loadResource(_actorContext, actorsResourceID, actorListData);
- _actorsCount = actorCount;
-
- if (actorListLength != (uint)_actorsCount * ACTOR_INHM_SIZE) {
+ if (actorListData.size() != (uint)actorCount * ACTOR_INHM_SIZE) {
error("Actor::loadActorList wrong actorlist length");
}
- MemoryReadStream actorS(actorListData, actorListLength);
+ ByteArrayReadStreamEndian actorS(actorListData);
- _actors = (ActorData **)malloc(_actorsCount * sizeof(*_actors));
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i] = new ActorData();
- actor->_id = objectIndexToId(kGameObjectActor, i); //actorIndexToId(i);
+ _actors.resize(actorCount);
+ i = 0;
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor, i++) {
actor->_index = i;
- debug(4, "init actor id=0x%x index=%d", actor->_id, actor->_index);
+ actor->_id = objectIndexToId(kGameObjectActor, actor->_index); //actorIndexToId(i);
+ debug(4, "init actor id=0x%X index=%d", actor->_id, actor->_index);
actorS.readUint32LE(); //next displayed
actorS.readByte(); //type
actor->_flags = actorS.readByte();
@@ -531,86 +477,58 @@ void Actor::loadActorList(int protagonistIdx, int actorCount, int actorsResource
}
// actorS.seek(6, SEEK_CUR); //action vars
}
- free(actorListData);
- _actors[protagonistIdx]->_flags |= kProtagonist | kExtended;
+ _actors[protagonistIdx]._flags |= kProtagonist | kExtended;
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor) {
//if (actor->_flags & kProtagonist) {
loadActorResources(actor);
//break;
//}
}
- _centerActor = _protagonist = _actors[protagonistIdx];
+ _centerActor = _protagonist = &_actors[protagonistIdx];
_protagState = 0;
if (protagStatesResourceID) {
- if (!_protagonist->_shareFrames)
- free(_protagonist->_frames);
- freeProtagStates();
-
- _protagStates = (ProtagStateData *)malloc(sizeof(ProtagStateData) * protagStatesCount);
+ _protagStates.resize(protagStatesCount);
- byte *idsResourcePointer;
- size_t idsResourceLength;
+ ByteArray idsResourceData;
- _vm->_resource->loadResource(_actorContext, protagStatesResourceID,
- idsResourcePointer, idsResourceLength);
+ _vm->_resource->loadResource(_actorContext, protagStatesResourceID, idsResourceData);
- if (idsResourceLength < (size_t)protagStatesCount * 4) {
+ if (idsResourceData.size() < (size_t)protagStatesCount * 4) {
error("Wrong protagonist states resource");
}
- MemoryReadStream statesIds(idsResourcePointer, idsResourceLength);
+ ByteArrayReadStreamEndian statesIds(idsResourceData);
for (i = 0; i < protagStatesCount; i++) {
stateResourceId = statesIds.readUint32LE();
- loadFrameList(stateResourceId, _protagStates[i]._frames, _protagStates[i]._framesCount);
+ loadFrameList(stateResourceId, _protagStates[i]._frames);
}
- free(idsResourcePointer);
- _protagonist->_frames = _protagStates[_protagState]._frames;
- _protagonist->_framesCount = _protagStates[_protagState]._framesCount;
- _protagonist->_shareFrames = true;
+ _protagonist->_frames = &_protagStates[_protagState]._frames;
}
- _protagStatesCount = protagStatesCount;
-}
-
-void Actor::freeObjList() {
- int i;
- ObjectData *object;
- for (i = 0; i < _objsCount; i++) {
- object = _objs[i];
- delete object;
- }
- free(_objs);
- _objs = NULL;
- _objsCount = 0;
}
void Actor::loadObjList(int objectCount, int objectsResourceID) {
- int i;
+ uint i;
int frameListResourceId;
- ObjectData *object;
- byte* objectListData;
- size_t objectListLength;
- freeObjList();
+ ByteArray objectListData;
- _vm->_resource->loadResource(_actorContext, objectsResourceID, objectListData, objectListLength);
+ _vm->_resource->loadResource(_actorContext, objectsResourceID, objectListData);
- _objsCount = objectCount;
+ _objs.resize(objectCount);
- MemoryReadStream objectS(objectListData, objectListLength);
+ ByteArrayReadStreamEndian objectS(objectListData);
- _objs = (ObjectData **)malloc(_objsCount * sizeof(*_objs));
- for (i = 0; i < _objsCount; i++) {
- object = _objs[i] = new ObjectData();
- object->_id = objectIndexToId(kGameObjectObject, i);
+ i = 0;
+ for (ObjectDataArray::iterator object = _objs.begin(); object != _objs.end(); ++object, i++) {
object->_index = i;
+ object->_id = objectIndexToId(kGameObjectObject, object->_index);
debug(9, "init object id=%d index=%d", object->_id, object->_index);
objectS.readUint32LE(); //next displayed
objectS.readByte(); //type
@@ -635,7 +553,6 @@ void Actor::loadObjList(int objectCount, int objectsResourceID) {
objectS.readUint16LE(); //BOTTOM
object->_interactBits = objectS.readUint16LE();
}
- free(objectListData);
}
void Actor::takeExit(uint16 actorId, const HitZone *hitZone) {
@@ -683,7 +600,7 @@ void Actor::stepZoneAction(ActorData *actor, const HitZone *hitZone, bool exit,
event.param5 = ID_NOTHING; // With Object
event.param6 = ID_PROTAG; // Actor
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
}
@@ -693,7 +610,7 @@ ObjectData *Actor::getObj(uint16 objId) {
if (!validObjId(objId))
error("Actor::getObj Wrong objId 0x%X", objId);
- obj = _objs[objIdToIndex(objId)];
+ obj = &_objs[objIdToIndex(objId)];
if (obj->_disabled)
error("Actor::getObj disabled objId 0x%X", objId);
@@ -716,7 +633,7 @@ ActorData *Actor::getActor(uint16 actorId) {
return _protagonist;
}
- actor = _actors[actorIdToIndex(actorId)];
+ actor = &_actors[actorIdToIndex(actorId)];
if (actor->_disabled)
error("Actor::getActor disabled actorId 0x%X", actorId);
@@ -729,12 +646,8 @@ void Actor::setProtagState(int state) {
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
- if (!_protagonist->_shareFrames)
- free(_protagonist->_frames);
- _protagonist->_frames = _protagStates[state]._frames;
- _protagonist->_framesCount = _protagStates[state]._framesCount;
- _protagonist->_shareFrames = true;
+ _protagonist->_frames = &_protagStates[state]._frames;
}
#endif
@@ -797,15 +710,18 @@ ActorFrameRange *Actor::getActorFrameRange(uint16 actorId, int frameType) {
if ((actor->_facingDirection < kDirUp) || (actor->_facingDirection > kDirUpLeft))
error("Actor::getActorFrameRange Wrong direction 0x%X actorId 0x%X", actor->_facingDirection, actorId);
+ ActorFrameSequences *frames;
+ frames = actor->_frames;
+
if (_vm->getGameId() == GID_ITE) {
- if (frameType >= actor->_framesCount) {
- warning("Actor::getActorFrameRange Wrong frameType 0x%X (%d) actorId 0x%X", frameType, actor->_framesCount, actorId);
+ if (uint(frameType) >= frames->size()) {
+ warning("Actor::getActorFrameRange Wrong frameType 0x%X (%d) actorId 0x%X", frameType, frames->size(), actorId);
return &def;
}
fourDirection = actorDirectionsLUT[actor->_facingDirection];
- return &actor->_frames[frameType].directions[fourDirection];
+ return &(*frames)[frameType].directions[fourDirection];
}
#ifdef ENABLE_IHNM
@@ -816,12 +732,12 @@ ActorFrameRange *Actor::getActorFrameRange(uint16 actorId, int frameType) {
// Both of them are invisible and immovable
// There is no point to keep throwing warnings about this, the original checks for
// a valid framecount too
- if (actor->_framesCount == 0) {
+ if ((frames == NULL) || (frames->empty())) {
return &def;
}
- frameType = CLIP(frameType, 0, actor->_framesCount - 1);
+ frameType = CLIP(frameType, 0, int(frames->size() - 1));
fourDirection = actorDirectionsLUT[actor->_facingDirection];
- return &actor->_frames[frameType].directions[fourDirection];
+ return &(*frames)[frameType].directions[fourDirection];
}
#endif
@@ -1085,9 +1001,6 @@ void Actor::drawOrderListAdd(const CommonObjectDataPointer& element, CompareFunc
}
void Actor::createDrawOrderList() {
- int i;
- ActorData *actor;
- ObjectData *obj;
CompareFunction compareFunction = 0;
if (_vm->_scene->getFlags() & kSceneFlagISO) {
@@ -1102,8 +1015,7 @@ void Actor::createDrawOrderList() {
}
_drawOrderList.clear();
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor) {
if (!actor->_inScene)
continue;
@@ -1113,8 +1025,7 @@ void Actor::createDrawOrderList() {
}
}
- for (i = 0; i < _objsCount; i++) {
- obj = _objs[i];
+ for (ObjectDataArray::iterator obj = _objs.begin(); obj != _objs.end(); ++obj) {
if (obj->_disabled)
continue;
@@ -1146,19 +1057,20 @@ bool Actor::getSpriteParams(CommonObjectData *commonObjectData, int &frameNumber
ActorData *actor = (ActorData *)commonObjectData;
spriteList = &(actor->_spriteList);
frameNumber = actor->_frameNumber;
- if (spriteList->infoList == NULL)
+ if (spriteList->empty()) {
loadActorSpriteList(actor);
+ }
} else if (validObjId(commonObjectData->_id)) {
spriteList = &_vm->_sprite->_mainSprites;
frameNumber = commonObjectData->_spriteListResourceId;
}
- if (spriteList->spriteCount == 0) {
+ if (spriteList->empty()) {
return false;
}
- if ((frameNumber < 0) || (spriteList->spriteCount <= frameNumber)) {
+ if ((frameNumber < 0) || (spriteList->size() <= uint(frameNumber))) {
debug(1, "Actor::getSpriteParams frameNumber invalid for %s id 0x%X (%d)",
validObjId(commonObjectData->_id) ? "object" : "actor",
commonObjectData->_id, frameNumber);
@@ -1184,7 +1096,7 @@ void Actor::drawActors() {
return;
}
- if (_vm->_scene->_entryList.entryListCount == 0) {
+ if (_vm->_scene->_entryList.empty()) {
return;
}
@@ -1222,12 +1134,13 @@ void Actor::drawSpeech() {
ActorData *actor;
int width, height;
int stringLength = strlen(_activeSpeech.strings[0]);
- char *outputString = (char*)calloc(stringLength + 1, 1);
+ Common::Array<char> outputString;
+ outputString.resize(stringLength + 1);
if (_activeSpeech.speechFlags & kSpeakSlow)
- strncpy(outputString, _activeSpeech.strings[0], _activeSpeech.slowModeCharIndex + 1);
+ strncpy(&outputString.front(), _activeSpeech.strings[0], _activeSpeech.slowModeCharIndex + 1);
else
- strncpy(outputString, _activeSpeech.strings[0], stringLength);
+ strncpy(&outputString.front(), _activeSpeech.strings[0], stringLength);
if (_activeSpeech.actorsCount > 1) {
height = _vm->_font->getHeight(kKnownFontScript);
@@ -1244,15 +1157,13 @@ void Actor::drawSpeech() {
else if (_vm->getGameId() == GID_IHNM)
textPoint.y = 10; // CLIP(actor->_screenPosition.y - 160, 10, _vm->_scene->getHeight(true) - 10 - height);
- _vm->_font->textDraw(kKnownFontScript, outputString, textPoint,
+ _vm->_font->textDraw(kKnownFontScript, &outputString.front(), textPoint,
_activeSpeech.speechColor[i], _activeSpeech.outlineColor[i], _activeSpeech.getFontFlags(i));
}
} else {
- _vm->_font->textDrawRect(kKnownFontScript, outputString, _activeSpeech.drawRect, _activeSpeech.speechColor[0],
+ _vm->_font->textDrawRect(kKnownFontScript, &outputString.front(), _activeSpeech.drawRect, _activeSpeech.speechColor[0],
_activeSpeech.outlineColor[0], _activeSpeech.getFontFlags(0));
}
-
- free(outputString);
}
void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount, int sampleResourceId, int speechFlags) {
@@ -1302,9 +1213,9 @@ void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount,
// Check Script::sfDropObject for the other part of this hack
if (_vm->getGameId() == GID_IHNM && _vm->_scene->currentChapterNumber() == 3 &&
_vm->_scene->currentSceneNumber() == 59 && _activeSpeech.sampleResourceId == 286) {
- for (i = 0; i < _objsCount; i++) {
- if (_objs[i]->_id == 16385) { // the compact disk
- _objs[i]->_sceneNumber = 59;
+ for (ObjectDataArray::iterator obj = _objs.begin(); obj != _objs.end(); ++obj) {
+ if (obj->_id == 16385) { // the compact disk
+ obj->_sceneNumber = 59;
break;
}
}
@@ -1376,36 +1287,31 @@ void Actor::abortSpeech() {
}
void Actor::saveState(Common::OutSaveFile *out) {
- uint16 i;
out->writeSint16LE(getProtagState());
- for (i = 0; i < _actorsCount; i++) {
- ActorData *a = _actors[i];
- a->saveState(out);
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor) {
+ actor->saveState(out);
}
- for (i = 0; i < _objsCount; i++) {
- ObjectData *o = _objs[i];
- o->saveState(out);
+ for (ObjectDataArray::iterator obj = _objs.begin(); obj != _objs.end(); ++obj) {
+ obj->saveState(out);
}
}
void Actor::loadState(Common::InSaveFile *in) {
- int32 i;
int16 protagState = in->readSint16LE();
- if (protagState != 0 || _protagonist->_shareFrames)
+ if (protagState != 0 || (_protagonist->shareFrames())) {
setProtagState(protagState);
+ }
- for (i = 0; i < _actorsCount; i++) {
- ActorData *a = _actors[i];
- a->loadState(_vm->getCurrentLoadVersion(), in);
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor) {
+ actor->loadState(_vm->getCurrentLoadVersion(), in);
}
- for (i = 0; i < _objsCount; i++) {
- ObjectData *o = _objs[i];
- o->loadState(in);
+ for (ObjectDataArray::iterator obj = _objs.begin(); obj != _objs.end(); ++obj) {
+ obj->loadState(in);
}
}
diff --git a/engines/saga/actor.h b/engines/saga/actor.h
index 2f8fdea8ec..2b6b5c2a3b 100644
--- a/engines/saga/actor.h
+++ b/engines/saga/actor.h
@@ -196,6 +196,8 @@ struct ActorFrameSequence {
ActorFrameRange directions[ACTOR_DIRECTIONS_COUNT];
};
+typedef Common::Array<ActorFrameSequence> ActorFrameSequences;
+
uint pathLine(PointList &pointList, uint idx, const Point &point1, const Point &point2);
struct Location {
@@ -323,6 +325,21 @@ public:
_screenDepth = in->readSint32LE();
_screenScale = in->readSint32LE();
}
+
+ CommonObjectData() {
+ _disabled = false;
+ _index = 0;
+ _id = 0;
+ _scriptEntrypointNumber = 0;
+
+ _flags = 0;
+ _nameIndex = 0;
+ _sceneNumber = 0;
+ _spriteListResourceId = 0;
+
+ _screenDepth = 0;
+ _screenScale = 0;
+ }
};
typedef CommonObjectData *CommonObjectDataPointer;
@@ -333,19 +350,21 @@ class ObjectData: public CommonObjectData {
public:
//constant
uint16 _interactBits;
+
ObjectData() {
- memset(this, 0, sizeof(*this));
+ _interactBits = 0;
}
};
+typedef Common::Array<ObjectData> ObjectDataArray;
+
class ActorData: public CommonObjectData {
public:
//constant
SpriteList _spriteList; // sprite list data
- bool _shareFrames;
- ActorFrameSequence *_frames; // Actor's frames
- int _framesCount; // Actor's frames count
+ ActorFrameSequences *_frames; // Actor's frames
+ ActorFrameSequences _framesContainer; // Actor's frames
int _frameListResourceId; // Actor's frame list resource id
byte _speechColor; // Actor dialogue color
@@ -376,11 +395,9 @@ public:
int32 _frameNumber; // current frame number
- int32 _tileDirectionsAlloced;
- byte *_tileDirections;
+ ByteArray _tileDirections;
- int32 _walkStepsAlloced;
- Point *_walkStepsPoints;
+ Common::Array<Point> _walkStepsPoints;
int32 _walkStepsCount;
int32 _walkStepIndex;
@@ -391,21 +408,21 @@ public:
public:
ActorData();
- ~ActorData();
void saveState(Common::OutSaveFile *out);
void loadState(uint32 version, Common::InSaveFile *in);
- void setTileDirectionsSize(int size, bool forceRealloc);
void cycleWrap(int cycleLimit);
- void setWalkStepsPointsSize(int size, bool forceRealloc);
void addWalkStepPoint(const Point &point);
- void freeSpriteList();
+ bool shareFrames() {
+ return ((_frames != NULL) && (_frames != &_framesContainer));
+ }
};
+typedef Common::Array<ActorData> ActorDataArray;
+
struct ProtagStateData {
- ActorFrameSequence *_frames; // Actor's frames
- int _framesCount; // Actor's frames count
+ ActorFrameSequences _frames; // Actor's frames
};
@@ -450,15 +467,17 @@ public:
void cmdActorWalkTo(int argc, const char **argv);
- bool validActorId(uint16 id) { return (id == ID_PROTAG) || ((id >= objectIndexToId(kGameObjectActor, 0)) && (id < objectIndexToId(kGameObjectActor, _actorsCount))); }
+ bool validActorId(uint16 id) {
+ return (id == ID_PROTAG) || ((id >= objectIndexToId(kGameObjectActor, 0)) && (id < objectIndexToId(kGameObjectActor, _actors.size())));
+ }
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[0]; }
+ ActorData *getFirstActor() { return &_actors.front(); }
// clarification: Obj - means game object, such Hat, Spoon etc, Object - means Actor,Obj,HitZone,StepZone
- bool validObjId(uint16 id) { return (id >= objectIndexToId(kGameObjectObject, 0)) && (id < objectIndexToId(kGameObjectObject, _objsCount)); }
+ bool validObjId(uint16 id) { return (id >= objectIndexToId(kGameObjectObject, 0)) && (id < objectIndexToId(kGameObjectObject, _objs.size())); }
int objIdToIndex(uint16 id) { return objectIdToIndex(id); }
uint16 objIndexToId(int index) { return objectIndexToId(kGameObjectObject, index); }
ObjectData *getObj(uint16 objId);
@@ -525,18 +544,14 @@ public:
void setProtagState(int state);
int getProtagState() { return _protagState; }
- void freeProtagStates();
-
- void freeActorList();
void loadActorList(int protagonistIdx, int actorCount, int actorsResourceID,
int protagStatesCount, int protagStatesResourceID);
- void freeObjList();
void loadObjList(int objectCount, int objectsResourceID);
protected:
friend class Script;
bool loadActorResources(ActorData *actor);
- void loadFrameList(int frameListResourceId, ActorFrameSequence *&framesPointer, int &framesCount);
+ void loadFrameList(int frameListResourceId, ActorFrameSequences &frames);
private:
void stepZoneAction(ActorData *actor, const HitZone *hitZone, bool exit, bool stopped);
void loadActorSpriteList(ActorData *actor);
@@ -584,11 +599,9 @@ private:
protected:
//constants
- int _actorsCount;
- ActorData **_actors;
+ ActorDataArray _actors;
- int _objsCount;
- ObjectData **_objs;
+ ObjectDataArray _objs;
SagaEngine *_vm;
ResourceContext *_actorContext;
@@ -613,8 +626,7 @@ protected:
bool _dragonHunt;
private:
- ProtagStateData *_protagStates;
- int _protagStatesCount;
+ Common::Array<ProtagStateData> _protagStates;
//path stuff
struct PathNode {
@@ -629,7 +641,7 @@ private:
Rect _barrierList[ACTOR_BARRIERS_MAX];
int _barrierCount;
- int8 *_pathCell;
+ Common::Array<int8> _pathCell;
int _xCellCount;
int _yCellCount;
diff --git a/engines/saga/actor_walk.cpp b/engines/saga/actor_walk.cpp
index 21643ac1de..5a8ea0c856 100644
--- a/engines/saga/actor_walk.cpp
+++ b/engines/saga/actor_walk.cpp
@@ -179,9 +179,8 @@ void Actor::actorFaceTowardsPoint(uint16 actorId, const Location &toLocation) {
}
void Actor::updateActorsScene(int actorsEntrance) {
- int i, j;
+ int j;
int followerDirection;
- ActorData *actor;
Location tempLocation;
Location possibleLocation;
Point delta;
@@ -196,14 +195,13 @@ void Actor::updateActorsScene(int actorsEntrance) {
_activeSpeech.playing = false;
_protagonist = NULL;
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor) {
actor->_inScene = false;
- actor->_spriteList.freeMem();
+ actor->_spriteList.clear();
if (actor->_disabled) {
continue;
}
- if ((actor->_flags & (kProtagonist | kFollower)) || (i == 0)) {
+ if ((actor->_flags & (kProtagonist | kFollower)) || (actor->_index == 0)) {
if (actor->_flags & kProtagonist) {
actor->_finalTarget = actor->_location;
_centerActor = _protagonist = actor;
@@ -227,12 +225,12 @@ void Actor::updateActorsScene(int actorsEntrance) {
if (_protagonist == NULL)
return;
- if ((actorsEntrance >= 0) && (_vm->_scene->_entryList.entryListCount > 0)) {
- if (_vm->_scene->_entryList.entryListCount <= actorsEntrance) {
+ if ((actorsEntrance >= 0) && (!_vm->_scene->_entryList.empty())) {
+ if (_vm->_scene->_entryList.size() <= uint(actorsEntrance)) {
actorsEntrance = 0; //OCEAN bug
}
- sceneEntry = _vm->_scene->_entryList.getEntry(actorsEntrance);
+ sceneEntry = &_vm->_scene->_entryList[actorsEntrance];
if (_vm->_scene->getFlags() & kSceneFlagISO) {
_protagonist->_location = sceneEntry->location;
} else {
@@ -266,8 +264,7 @@ void Actor::updateActorsScene(int actorsEntrance) {
followerDirection = _protagonist->_facingDirection + 3;
calcScreenPosition(_protagonist);
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor) {
if (actor->_flags & (kFollower)) {
actor->_facingDirection = actor->_actionDirection = _protagonist->_facingDirection;
actor->_currentAction = kActionWait;
@@ -323,8 +320,6 @@ void Actor::updateActorsScene(int actorsEntrance) {
}
void Actor::handleActions(int msec, bool setup) {
- int i;
- ActorData *actor;
ActorFrameRange *frameRange;
int state;
int speed;
@@ -336,12 +331,11 @@ void Actor::handleActions(int msec, bool setup) {
Point hitPoint;
Location pickLocation;
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
+ for (ActorDataArray::iterator actor = _actors.begin(); actor != _actors.end(); ++actor) {
if (!actor->_inScene)
continue;
- if ((_vm->getGameId() == GID_ITE) && (i == ACTOR_DRAGON_INDEX)) {
+ if ((_vm->getGameId() == GID_ITE) && (actor->_index == ACTOR_DRAGON_INDEX)) {
moveDragon(actor);
continue;
}
@@ -722,7 +716,7 @@ void Actor::handleActions(int msec, bool setup) {
void Actor::direct(int msec) {
- if (_vm->_scene->_entryList.entryListCount == 0) {
+ if (_vm->_scene->_entryList.empty()) {
return;
}
@@ -866,8 +860,6 @@ bool Actor::followProtagonist(ActorData *actor) {
bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) {
ActorData *actor;
- ActorData *anotherActor;
- int i;
Rect testBox;
Rect testBox2;
@@ -943,7 +935,7 @@ bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) {
int max = _vm->getGameId() == GID_ITE ? 8 : 4;
- for (i = 1; i < max; i++) {
+ for (int i = 1; i < max; i++) {
pointAdd = pointFrom;
pointAdd.y += i;
if (_vm->_scene->canWalk(pointAdd)) {
@@ -978,9 +970,7 @@ bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) {
collision.x = ACTOR_COLLISION_WIDTH * actor->_screenScale / (256 * 2);
collision.y = ACTOR_COLLISION_HEIGHT * actor->_screenScale / (256 * 2);
-
- for (i = 0; (i < _actorsCount) && (_barrierCount < ACTOR_BARRIERS_MAX); i++) {
- anotherActor = _actors[i];
+ for (ActorDataArray::iterator anotherActor = _actors.begin(); (anotherActor != _actors.end()) && (_barrierCount < ACTOR_BARRIERS_MAX); ++anotherActor) {
if (!anotherActor->_inScene)
continue;
if (anotherActor == actor)
@@ -1067,8 +1057,8 @@ bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) {
return false;
} else {
if (actor->_flags & kProtagonist) {
- _actors[1]->_actorFlags &= ~kActorNoFollow; // TODO: mark all actors with kFollower flag, not only 1 and 2
- _actors[2]->_actorFlags &= ~kActorNoFollow;
+ _actors[1]._actorFlags &= ~kActorNoFollow; // TODO: mark all actors with kFollower flag, not only 1 and 2
+ _actors[2]._actorFlags &= ~kActorNoFollow;
}
actor->_currentAction = (actor->_walkStepsCount >= ACTOR_MAX_STEPS_COUNT) ? kActionWalkToLink : kActionWalkToPoint;
actor->_walkFrameSequence = getFrameType(kFrameWalk);
@@ -1153,7 +1143,7 @@ void Actor::moveDragon(ActorData *actor) {
event.param4 = -1; // Object
event.param5 = -1; // With Object
event.param6 = -1; // Actor
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
_dragonHunt = false;
}
diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp
index 0d65d2f191..aca29ed82e 100644
--- a/engines/saga/animation.cpp
+++ b/engines/saga/animation.cpp
@@ -42,8 +42,6 @@ namespace Saga {
Anim::Anim(SagaEngine *vm) : _vm(vm) {
uint16 i;
- _cutawayList = NULL;
- _cutawayListLength = 0;
_cutawayActive = false;
for (i = 0; i < MAX_ANIMATIONS; i++)
@@ -55,21 +53,16 @@ Anim::Anim(SagaEngine *vm) : _vm(vm) {
Anim::~Anim() {
reset();
-#ifdef ENABLE_IHNM
- freeCutawayList();
-#endif
}
#ifdef ENABLE_IHNM
-void Anim::loadCutawayList(const byte *resourcePointer, size_t resourceLength) {
- free(_cutawayList);
- _cutawayListLength = resourceLength / 8;
- _cutawayList = (Cutaway *)malloc(_cutawayListLength * sizeof(Cutaway));
+void Anim::loadCutawayList(const ByteArray &resourceData) {
+ _cutawayList.resize(resourceData.size() / 8);
- MemoryReadStream cutawayS(resourcePointer, resourceLength);
+ ByteArrayReadStreamEndian cutawayS(resourceData);
- for (int i = 0; i < _cutawayListLength; i++) {
+ for (uint i = 0; i < _cutawayList.size(); i++) {
_cutawayList[i].backgroundResourceId = cutawayS.readUint16LE();
_cutawayList[i].animResourceId = cutawayS.readUint16LE();
_cutawayList[i].cycles = cutawayS.readSint16LE();
@@ -77,20 +70,16 @@ void Anim::loadCutawayList(const byte *resourcePointer, size_t resourceLength) {
}
}
-void Anim::freeCutawayList() {
- free(_cutawayList);
- _cutawayList = NULL;
- _cutawayListLength = 0;
+void Anim::clearCutawayList() {
+ _cutawayList.clear();
}
int Anim::playCutaway(int cut, bool fade) {
debug(0, "playCutaway(%d, %d)", cut, fade);
Event event;
- Event *q_event = NULL;
+ EventColumns *eventColumns = NULL;
bool startImmediately = false;
- byte *resourceData;
- size_t resourceDataLength;
ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE);
_cutAwayFade = fade;
@@ -111,7 +100,7 @@ int Anim::playCutaway(int cut, bool fade) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// set fade mode
event.type = kEvTImmediate;
@@ -120,7 +109,7 @@ int Anim::playCutaway(int cut, bool fade) {
event.param = kNoFade;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
// Prepare cutaway
@@ -148,7 +137,7 @@ int Anim::playCutaway(int cut, bool fade) {
event.time = 0;
event.duration = 0;
event.param = _cutawayList[cut].backgroundResourceId;
- q_event = _vm->_events->chain(q_event, &event);
+ eventColumns = _vm->_events->chain(eventColumns, event);
} else {
showCutawayBg(_cutawayList[cut].backgroundResourceId);
}
@@ -180,9 +169,10 @@ int Anim::playCutaway(int cut, bool fade) {
// for the second from the left monitor in Ellen's chapter etc
// Therefore, skip the animation bit if animResourceId is 0 and only show the background
if (_cutawayList[cut].animResourceId != 0) {
- _vm->_resource->loadResource(context, _cutawayList[cut].animResourceId, resourceData, resourceDataLength);
- load(MAX_ANIMATIONS + cutawaySlot, resourceData, resourceDataLength);
- free(resourceData);
+ ByteArray resourceData;
+ _vm->_resource->loadResource(context, _cutawayList[cut].animResourceId, resourceData);
+ load(MAX_ANIMATIONS + cutawaySlot, resourceData);
+
setCycles(MAX_ANIMATIONS + cutawaySlot, _cutawayList[cut].cycles);
setFrameTime(MAX_ANIMATIONS + cutawaySlot, 1000 / _cutawayList[cut].frameRate);
@@ -198,9 +188,9 @@ int Anim::playCutaway(int cut, bool fade) {
event.time = (40 / 3) * 1000 / _cutawayList[cut].frameRate;
if (fade)
- q_event = _vm->_events->chain(q_event, &event);
+ eventColumns = _vm->_events->chain(eventColumns, event);
else
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
return MAX_ANIMATIONS + cutawaySlot;
@@ -222,7 +212,7 @@ void Anim::returnFromCutaway() {
if (_cutawayActive) {
Event event;
- Event *q_event = NULL;
+ EventColumns *eventColumns = NULL;
if (_cutAwayFade) {
static PalEntry cur_pal[PAL_ENTRIES];
@@ -237,7 +227,7 @@ void Anim::returnFromCutaway() {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// set fade mode
event.type = kEvTImmediate;
@@ -246,7 +236,7 @@ void Anim::returnFromCutaway() {
event.param = kNoFade;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
// Clear the cutaway. Note that this sets _cutawayActive to false
@@ -257,9 +247,9 @@ void Anim::returnFromCutaway() {
event.duration = 0;
if (_cutAwayFade)
- q_event = _vm->_events->chain(q_event, &event); // chain with the other events
+ eventColumns = _vm->_events->chain(eventColumns, event); // chain with the other events
else
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
_vm->_scene->restoreScene();
@@ -279,7 +269,7 @@ void Anim::returnFromCutaway() {
event.op = kEventResumeAll;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event); // chain with the other events
+ _vm->_events->chain(eventColumns, event); // chain with the other events
// Draw the scene
event.type = kEvTImmediate;
@@ -287,7 +277,7 @@ void Anim::returnFromCutaway() {
event.op = kEventDraw;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event); // chain with the other events
+ _vm->_events->chain(eventColumns, event); // chain with the other events
// Handle fade up, if we previously faded down
if (_cutAwayFade) {
@@ -297,14 +287,14 @@ void Anim::returnFromCutaway() {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = saved_pal;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
event.type = kEvTOneshot;
event.code = kScriptEvent;
event.op = kEventThreadWake;
event.param = kWaitTypeWakeUp;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
}
@@ -338,22 +328,20 @@ void Anim::clearCutaway() {
void Anim::showCutawayBg(int bg) {
ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE);
- byte *resourceData;
- size_t resourceDataLength;
- byte *buf;
- size_t buflen;
+ ByteArray resourceData;
+ ByteArray image;
int width;
int height;
Event event;
static PalEntry pal[PAL_ENTRIES];
- _vm->_resource->loadResource(context, bg, resourceData, resourceDataLength);
- _vm->decodeBGImage(resourceData, resourceDataLength, &buf, &buflen, &width, &height);
+ _vm->_resource->loadResource(context, bg, resourceData);
+ _vm->decodeBGImage(resourceData, image, &width, &height);
- const byte *palPointer = _vm->getImagePal(resourceData, resourceDataLength);
+ const byte *palPointer = _vm->getImagePal(resourceData);
memcpy(pal, palPointer, sizeof(pal));
const Rect rect(width, height);
- _vm->_render->getBackGroundSurface()->blit(rect, buf);
+ _vm->_render->getBackGroundSurface()->blit(rect, image.getBuffer());
_vm->_render->setFullRefresh(true);
_vm->_frameCount++;
@@ -365,13 +353,10 @@ void Anim::showCutawayBg(int bg) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = pal;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
} else {
_vm->_gfx->setPalette(pal);
}
-
- free(buf);
- free(resourceData);
}
void Anim::startVideo(int vid, bool fade) {
@@ -397,18 +382,18 @@ void Anim::returnFromVideo() {
#endif
-void Anim::load(uint16 animId, const byte *animResourceData, size_t animResourceLength) {
+void Anim::load(uint16 animId, const ByteArray &resourceData) {
AnimationData *anim;
uint16 temp;
if (animId >= MAX_ANIMATIONS) {
if (animId >= MAX_ANIMATIONS + ARRAYSIZE(_cutawayAnimations))
error("Anim::load could not find unused animation slot");
- anim = _cutawayAnimations[animId - MAX_ANIMATIONS] = new AnimationData(animResourceData, animResourceLength);
+ anim = _cutawayAnimations[animId - MAX_ANIMATIONS] = new AnimationData();
} else
- anim = _animations[animId] = new AnimationData(animResourceData, animResourceLength);
+ anim = _animations[animId] = new AnimationData();
- MemoryReadStreamEndian headerReadS(anim->resourceData, anim->resourceLength, _vm->isBigEndian());
+ ByteArrayReadStreamEndian headerReadS(resourceData, _vm->isBigEndian());
anim->magic = headerReadS.readUint16LE(); // cause ALWAYS LE
anim->screenWidth = headerReadS.readUint16();
anim->screenHeight = headerReadS.readUint16();
@@ -418,23 +403,30 @@ void Anim::load(uint16 animId, const byte *animResourceData, size_t animResource
anim->maxFrame = headerReadS.readByte() - 1;
anim->loopFrame = headerReadS.readByte() - 1;
temp = headerReadS.readUint16BE();
- anim->start = headerReadS.pos();
+ size_t start;
+
+ start = headerReadS.pos();
if (temp == (uint16)(-1)) {
temp = 0;
}
- anim->start += temp;
+ start += temp;
+ size_t dataOffset = headerReadS.pos();
+ if (dataOffset != start) {
+ warning("Anim::load animId=%d start != dataOffset 0x%X 0x%X", animId, uint(start), uint(dataOffset));
+ }
+
+ anim->resourceData.resize(resourceData.size() - dataOffset);
+
+ memcpy(anim->resourceData.getBuffer(), resourceData.getBuffer() + dataOffset, anim->resourceData.size());
// Cache frame offsets
// WORKAROUND: Cutaway with background resource ID 37 (loaded as cutaway #4) is ending credits.
// For some reason it has wrong number of frames specified in its header. So we calculate it here:
- if (animId > MAX_ANIMATIONS && _cutawayListLength > 4 && _cutawayList[4].backgroundResourceId == 37 && anim->maxFrame == 143)
+ if (animId > MAX_ANIMATIONS && _cutawayList.size() > 4 && _cutawayList[4].backgroundResourceId == 37 && anim->maxFrame == 143)
anim->maxFrame = fillFrameOffsets(anim, false);
- anim->frameOffsets = (size_t *)malloc((anim->maxFrame + 1) * sizeof(*anim->frameOffsets));
- if (anim->frameOffsets == NULL) {
- memoryError("Anim::load");
- }
+ anim->frameOffsets.resize(anim->maxFrame + 1);
fillFrameOffsets(anim);
@@ -504,7 +496,7 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
event.op = kEventFrame;
event.param = animId;
event.time = 10;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
// Nothing to render here (apart from the background, which is already rendered),
// so return
@@ -534,7 +526,7 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
event.op = kEventFrame;
event.param = animId;
event.time = 0;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
return;
}
@@ -575,7 +567,7 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = anim->frameTime + vectorTime;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
return;
} else {
@@ -601,7 +593,7 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
event.op = kEventFrame;
event.param = animId;
event.time = frameTime;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
void Anim::stop(uint16 animId) {
@@ -688,7 +680,7 @@ void Anim::decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_
error("decodeFrame() Buffer size inadequate");
}
- MemoryReadStream readS(anim->resourceData + frameOffset, anim->resourceLength - frameOffset);
+ MemoryReadStream readS(&anim->resourceData[frameOffset], anim->resourceData.size() - frameOffset);
// FIXME: This is thrown when the first video of the IHNM end sequence is shown (the "turn off screen"
// video), however the video is played correctly and the rest of the end sequence continues normally
@@ -825,9 +817,7 @@ int Anim::fillFrameOffsets(AnimationData *anim, bool reallyFill) {
int i;
bool longData = isLongData();
- MemoryReadStreamEndian readS(anim->resourceData, anim->resourceLength, !_vm->isBigEndian()); // RLE has inversion BE<>LE
-
- readS.seek(12);
+ MemoryReadStreamEndian readS(&anim->resourceData.front(), anim->resourceData.size(), !_vm->isBigEndian()); // RLE has inversion BE<>LE
while (readS.pos() != readS.size()) {
if (reallyFill) {
@@ -843,7 +833,7 @@ int Anim::fillFrameOffsets(AnimationData *anim, bool reallyFill) {
// including the frame header, is in big endian format
do {
markByte = readS.readByte();
-// debug(7, "_pos=%x currentFrame=%i markByte=%x", readS.pos(), currentFrame, markByte);
+// debug(7, "_pos=%X currentFrame=%i markByte=%X", readS.pos(), currentFrame, markByte);
switch (markByte) {
case SAGA_FRAME_START: // Start of frame
@@ -942,9 +932,9 @@ void Anim::animInfo() {
void Anim::cutawayInfo() {
uint16 i;
- _vm->_console->DebugPrintf("There are %d cutaways loaded:\n", _cutawayListLength);
+ _vm->_console->DebugPrintf("There are %d cutaways loaded:\n", _cutawayList.size());
- for (i = 0; i < _cutawayListLength; i++) {
+ for (i = 0; i < _cutawayList.size(); i++) {
_vm->_console->DebugPrintf("%02d: Bg res: %u Anim res: %u Cycles: %u Framerate: %u\n", i,
_cutawayList[i].backgroundResourceId, _cutawayList[i].animResourceId,
_cutawayList[i].cycles, _cutawayList[i].frameRate);
diff --git a/engines/saga/animation.h b/engines/saga/animation.h
index 72b145089c..c27909115e 100644
--- a/engines/saga/animation.h
+++ b/engines/saga/animation.h
@@ -66,8 +66,7 @@ struct Cutaway {
// Animation info array member
struct AnimationData {
- byte *resourceData;
- size_t resourceLength;
+ ByteArray resourceData;
uint16 magic;
@@ -80,10 +79,8 @@ struct AnimationData {
int16 maxFrame;
int16 loopFrame;
- int16 start;
-
int16 currentFrame;
- size_t *frameOffsets;
+ Common::Array<size_t> frameOffsets;
uint16 completed;
uint16 cycles;
@@ -93,17 +90,6 @@ struct AnimationData {
AnimationState state;
int16 linkId;
uint16 flags;
-
- AnimationData(const byte *animResourceData, size_t animResourceLength) {
- memset(this, 0, sizeof(*this));
- resourceLength = animResourceLength;
- resourceData = (byte*)malloc(animResourceLength);
- memcpy(resourceData, animResourceData, animResourceLength);
- }
- ~AnimationData() {
- free(frameOffsets);
- free(resourceData);
- }
};
class Anim {
@@ -111,8 +97,8 @@ public:
Anim(SagaEngine *vm);
~Anim();
- void loadCutawayList(const byte *resourcePointer, size_t resourceLength);
- void freeCutawayList();
+ void loadCutawayList(const ByteArray &resourceData);
+ void clearCutawayList();
int playCutaway(int cut, bool fade);
void endCutaway();
void returnFromCutaway();
@@ -123,7 +109,7 @@ public:
void endVideo();
void returnFromVideo();
- void load(uint16 animId, const byte *animResourceData, size_t animResourceLength);
+ void load(uint16 animId, const ByteArray &resourceData);
void freeId(uint16 animId);
void play(uint16 animId, int vectorTime, bool playing = true);
void link(int16 animId1, int16 animId2);
@@ -154,9 +140,9 @@ public:
bool hasCutaway() { return _cutawayActive; }
void setCutAwayMode(int mode) { _cutAwayMode = mode; }
- int cutawayListLength() { return _cutawayListLength; }
- int cutawayBgResourceID(int cutaway) { return _cutawayList[cutaway].backgroundResourceId; }
- int cutawayAnimResourceID(int cutaway) { return _cutawayList[cutaway].animResourceId; }
+// int cutawayListLength() { return _cutawayListLength; }
+// int cutawayBgResourceID(int cutaway) { return _cutawayList[cutaway].backgroundResourceId; }
+// int cutawayAnimResourceID(int cutaway) { return _cutawayList[cutaway].animResourceId; }
private:
void decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_t bufLength);
@@ -205,9 +191,8 @@ private:
SagaEngine *_vm;
AnimationData *_animations[MAX_ANIMATIONS];
AnimationData *_cutawayAnimations[2];
- Cutaway *_cutawayList;
+ Common::Array<Cutaway> _cutawayList;
PalEntry saved_pal[PAL_ENTRIES];
- int _cutawayListLength;
bool _cutawayActive;
int _cutAwayMode;
bool _cutAwayFade;
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index 7913291527..e43f1ee5c7 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -56,9 +56,9 @@ struct SAGAGameDescription {
bool SagaEngine::isBigEndian() const { return isMacResources() && getGameId() == GID_ITE; }
bool SagaEngine::isMacResources() const { return (getPlatform() == Common::kPlatformMacintosh); }
-const GameResourceDescription *SagaEngine::getResourceDescription() { return _gameDescription->resourceDescription; }
+const GameResourceDescription *SagaEngine::getResourceDescription() const { return _gameDescription->resourceDescription; }
-const GameFontDescription *SagaEngine::getFontDescription(int index) {
+const GameFontDescription *SagaEngine::getFontDescription(int index) const {
assert(index < _gameDescription->fontsCount);
return &_gameDescription->fontDescriptions[index];
}
@@ -259,7 +259,7 @@ SaveStateDescriptor SagaMetaEngine::querySaveMetaInfos(const char *target, int s
version = SWAP_BYTES_32(version);
}
- debug(2, "Save version: %x", version);
+ debug(2, "Save version: 0x%X", version);
if (version < 4)
warning("This savegame is not endian-safe. There may be problems");
diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp
index 1f4091d07c..cf27ad7559 100644
--- a/engines/saga/events.cpp
+++ b/engines/saga/events.cpp
@@ -49,13 +49,12 @@ Events::Events(SagaEngine *vm) : _vm(vm) {
Events::~Events() {
debug(8, "Shutting down event subsystem...");
- freeList();
}
// Function to process event list once per frame.
// First advances event times, then processes each event with the appropriate
// handler depending on the type of event.
-int Events::handleEvents(long msec) {
+void Events::handleEvents(long msec) {
long delta_time;
int result;
@@ -64,7 +63,7 @@ int Events::handleEvents(long msec) {
// Process each event in list
for (EventList::iterator eventi = _eventList.begin(); eventi != _eventList.end(); ++eventi) {
- Event *event_p = &*eventi;
+ Event *event_p = &eventi->front();
// Call the appropriate event handler for the specific event type
switch (event_p->type) {
@@ -95,17 +94,15 @@ int Events::handleEvents(long msec) {
// handler
if ((result == kEvStDelete) || (result == kEvStInvalidCode)) {
// If there is no event chain, delete the base event.
- if (event_p->chain == NULL) {
+ if (eventi->size() < 2) {
eventi = _eventList.reverse_erase(eventi);
} else {
// If there is an event chain present, move the next event
// in the chain up, adjust it by the previous delta time,
// and reprocess the event
delta_time = event_p->time;
- Event *from_chain = event_p->chain;
- memcpy(event_p, from_chain, sizeof(*event_p));
- free(from_chain);
-
+ eventi->pop_front();
+ event_p = &eventi->front();
event_p->time += delta_time;
--eventi;
}
@@ -113,8 +110,6 @@ int Events::handleEvents(long msec) {
break;
}
}
-
- return SUCCESS;
}
int Events::handleContinuous(Event *event) {
@@ -177,9 +172,8 @@ int Events::handleContinuous(Event *event) {
// set flag of Dissolve to 1. It is a hack to simulate zero masking.
int w, h;
byte *maskBuffer;
- size_t len;
- _vm->_scene->getBGMaskInfo(w, h, maskBuffer, len);
+ _vm->_scene->getBGMaskInfo(w, h, maskBuffer);
rect.left = (_vm->getDisplayInfo().width - w) / 2;
rect.top = (_vm->getDisplayInfo().height - h) / 2;
rect.setWidth(w);
@@ -362,31 +356,26 @@ int Events::handleOneShot(Event *event) {
{
ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE);
- byte *resourceData;
- size_t resourceDataLength;
+ ByteArray resourceData;
- _vm->_resource->loadResource(context, _vm->getResourceDescription()->psychicProfileResourceId, resourceData, resourceDataLength);
+ _vm->_resource->loadResource(context, _vm->getResourceDescription()->psychicProfileResourceId, resourceData);
- byte *buf;
- size_t buflen;
+ ByteArray image;
int width;
int height;
- _vm->decodeBGImage(resourceData, resourceDataLength, &buf, &buflen, &width, &height);
+ _vm->decodeBGImage(resourceData, image, &width, &height);
- const PalEntry *palette = (const PalEntry *)_vm->getImagePal(resourceData, resourceDataLength);
+ const PalEntry *palette = (const PalEntry *)_vm->getImagePal(resourceData);
const Rect profileRect(width, height);
- _vm->_render->getBackGroundSurface()->blit(profileRect, buf);
+ _vm->_render->getBackGroundSurface()->blit(profileRect, image.getBuffer());
_vm->_render->addDirtyRect(profileRect);
_vm->_frameCount++;
_vm->_gfx->setPalette(palette);
- free(buf);
- free(resourceData);
-
// Draw the scene. It won't be drawn by Render::drawScene(), as a placard is up
_vm->_scene->draw();
}
@@ -570,122 +559,74 @@ int Events::handleInterval(Event *event) {
return kEvStDelete;
}
-// Schedules an event in the event list; returns a pointer to the scheduled
-// event suitable for chaining if desired.
-Event *Events::queue(Event *event) {
- Event *queuedEvent;
-
- _eventList.push_back(*event);
- queuedEvent = &*--_eventList.end();
- initializeEvent(queuedEvent);
-
- return queuedEvent;
-}
-
-// Places a 'add_event' on the end of an event chain given by 'head_event'
-// (head_event may be in any position in the event chain)
-Event *Events::chain(Event *headEvent, Event *addEvent) {
- if (headEvent == NULL) {
- return queue(addEvent);
- }
+EventColumns *Events::chain(EventColumns *eventColumns, const Event &event) {
+
+ if (eventColumns == NULL) {
+ EventColumns tmp;
- Event *walkEvent;
- for (walkEvent = headEvent; walkEvent->chain != NULL; walkEvent = walkEvent->chain) {
- continue;
+ _eventList.push_back(tmp);
+ eventColumns = &_eventList.back();
}
- walkEvent->chain = (Event *)malloc(sizeof(*walkEvent->chain));
- *walkEvent->chain = *addEvent;
- initializeEvent(walkEvent->chain);
+ eventColumns->push_back(event);
+ initializeEvent(eventColumns->back());
- return walkEvent->chain;
+ return eventColumns;
}
-int Events::initializeEvent(Event *event) {
- event->chain = NULL;
- switch (event->type) {
+void Events::initializeEvent(Event &event) {
+ switch (event.type) {
case kEvTOneshot:
break;
case kEvTContinuous:
case kEvTImmediate:
- event->time += event->duration;
+ event.time += event.duration;
break;
case kEvTInterval:
break;
- default:
- return FAILURE;
}
-
- return SUCCESS;
}
-int Events::clearList(bool playQueuedMusic) {
- Event *chain_walk;
- Event *next_chain;
-
+void Events::clearList(bool playQueuedMusic) {
// Walk down event list
for (EventList::iterator eventi = _eventList.begin(); eventi != _eventList.end(); ++eventi) {
// Only remove events not marked kEvFNoDestory (engine events)
- if (!(eventi->code & kEvFNoDestory)) {
+ if (!(eventi->front().code & kEvFNoDestory)) {
// Handle queued music change events before deleting them
// This can happen in IHNM by music events set by sfQueueMusic()
// Fixes bug #2057987 - "IHNM: Music stops in Ellen's chapter"
- if (playQueuedMusic && ((eventi->code & EVENT_MASK) == kMusicEvent)) {
+ if (playQueuedMusic && ((eventi->front().code & EVENT_MASK) == kMusicEvent)) {
_vm->_music->stop();
- if (eventi->op == kEventPlay)
- _vm->_music->play(eventi->param, (MusicFlags)eventi->param2);
+ if (eventi->front().op == kEventPlay)
+ _vm->_music->play(eventi->front().param, (MusicFlags)eventi->front().param2);
}
- // Remove any events chained off this one
- for (chain_walk = eventi->chain; chain_walk != NULL; chain_walk = next_chain) {
- next_chain = chain_walk->chain;
- free(chain_walk);
- }
eventi = _eventList.reverse_erase(eventi);
}
}
-
- return SUCCESS;
}
// Removes all events from the list (even kEvFNoDestory)
-int Events::freeList() {
- Event *chain_walk;
- Event *next_chain;
-
- // Walk down event list
- EventList::iterator eventi = _eventList.begin();
- while (eventi != _eventList.end()) {
-
- // Remove any events chained off this one */
- for (chain_walk = eventi->chain; chain_walk != NULL; chain_walk = next_chain) {
- next_chain = chain_walk->chain;
- free(chain_walk);
- }
- eventi = _eventList.erase(eventi);
- }
-
- return SUCCESS;
+void Events::freeList() {
+ _eventList.clear();
}
// Walks down the event list, updating event times by 'msec'.
-int Events::processEventTime(long msec) {
+void Events::processEventTime(long msec) {
uint16 event_count = 0;
for (EventList::iterator eventi = _eventList.begin(); eventi != _eventList.end(); ++eventi) {
- eventi->time -= msec;
+ eventi->front().time -= msec;
event_count++;
- if (eventi->type == kEvTImmediate)
+ if (eventi->front().type == kEvTImmediate)
break;
if (event_count > EVENT_WARNINGCOUNT) {
warning("Event list exceeds %u", EVENT_WARNINGCOUNT);
}
}
-
- return SUCCESS;
}
} // End of namespace Saga
diff --git a/engines/saga/events.h b/engines/saga/events.h
index d1530787c2..135c0beb55 100644
--- a/engines/saga/events.h
+++ b/engines/saga/events.h
@@ -142,13 +142,14 @@ struct Event {
long duration; // Duration of event
long d_reserved;
- Event *chain; // Event chain (For consecutive events)
Event() {
memset(this, 0, sizeof(*this));
}
};
-typedef Common::List<Event> EventList;
+typedef Common::List<Event> EventColumns;
+
+typedef Common::List<EventColumns> EventList;
#define EVENT_WARNINGCOUNT 1000
#define EVENT_MASK 0x00FF
@@ -164,19 +165,26 @@ class Events {
public:
Events(SagaEngine *vm);
~Events();
- int handleEvents(long msec);
- int clearList(bool playQueuedMusic = true);
- int freeList();
- Event *queue(Event *event);
- Event *chain(Event *headEvent, Event *addEvent);
+ void handleEvents(long msec);
+ void clearList(bool playQueuedMusic = true);
+ void freeList();
+
+ // Schedules an event in the event list; returns a pointer to the scheduled
+ // event columns suitable for chaining if desired.
+ EventColumns *queue(const Event &event) {
+ return chain(NULL, event);
+ }
+
+ // Places a 'event' on the end of an event columns given by 'eventColumns'
+ EventColumns *chain(EventColumns *eventColumns, const Event &event);
private:
int handleContinuous(Event *event);
int handleOneShot(Event *event);
int handleInterval(Event *event);
int handleImmediate(Event *event);
- int processEventTime(long msec);
- int initializeEvent(Event *event);
+ void processEventTime(long msec);
+ void initializeEvent(Event &event);
private:
SagaEngine *_vm;
diff --git a/engines/saga/font.cpp b/engines/saga/font.cpp
index 47f1a122c0..01e74d2984 100644
--- a/engines/saga/font.cpp
+++ b/engines/saga/font.cpp
@@ -41,11 +41,9 @@ Font::Font(SagaEngine *vm) : _vm(vm) {
assert(_vm->getFontsCount() > 0);
- _fonts = (FontData **)calloc(_vm->getFontsCount(), sizeof(*_fonts));
- _loadedFonts = 0;
-
+ _fonts.resize(_vm->getFontsCount());
for (i = 0; i < _vm->getFontsCount(); i++) {
- loadFont(_vm->getFontDescription(i)->fontResourceId);
+ loadFont(&_fonts[i], _vm->getFontDescription(i)->fontResourceId);
}
_fontMapping = 0;
@@ -53,25 +51,11 @@ Font::Font(SagaEngine *vm) : _vm(vm) {
Font::~Font() {
debug(8, "Font::~Font(): Freeing fonts.");
- int i;
-
- for (i = 0 ; i < _loadedFonts ; i++) {
- if (_fonts[i] != NULL) {
- free(_fonts[i]->normal.font);
- free(_fonts[i]->outline.font);
- }
-
- free(_fonts[i]);
- }
-
- free(_fonts);
}
-void Font::loadFont(uint32 fontResourceId) {
- FontData *font;
- byte *fontResourcePointer;
- size_t fontResourceLength;
+void Font::loadFont(FontData *font, uint32 fontResourceId) {
+ ByteArray fontResourceData;
int numBits;
int c;
ResourceContext *fontContext;
@@ -84,16 +68,13 @@ void Font::loadFont(uint32 fontResourceId) {
}
// Load font resource
- _vm->_resource->loadResource(fontContext, fontResourceId, fontResourcePointer, fontResourceLength);
+ _vm->_resource->loadResource(fontContext, fontResourceId, fontResourceData);
- if (fontResourceLength < FONT_DESCSIZE) {
- error("Font::loadFont() Invalid font length (%i < %i)", (int)fontResourceLength, FONT_DESCSIZE);
+ if (fontResourceData.size() < FONT_DESCSIZE) {
+ error("Font::loadFont() Invalid font length (%i < %i)", (int)fontResourceData.size(), FONT_DESCSIZE);
}
- MemoryReadStreamEndian readS(fontResourcePointer, fontResourceLength, fontContext->isBigEndian());
-
- // Create new font structure
- font = (FontData *)malloc(sizeof(*font));
+ ByteArrayReadStreamEndian readS(fontResourceData, fontContext->isBigEndian());
// Read font header
font->normal.header.charHeight = readS.readUint16();
@@ -126,17 +107,12 @@ void Font::loadFont(uint32 fontResourceId) {
error("Invalid font resource size");
}
- font->normal.font = (byte*)malloc(fontResourceLength - FONT_DESCSIZE);
- memcpy(font->normal.font, fontResourcePointer + FONT_DESCSIZE, fontResourceLength - FONT_DESCSIZE);
-
- free(fontResourcePointer);
+ font->normal.font.resize(fontResourceData.size() - FONT_DESCSIZE);
+ memcpy(font->normal.font.getBuffer(), fontResourceData.getBuffer() + FONT_DESCSIZE, fontResourceData.size() - FONT_DESCSIZE);
// Create outline font style
createOutline(font);
-
- // Set font data
- _fonts[_loadedFonts++] = font;
}
void Font::createOutline(FontData *font) {
@@ -145,12 +121,12 @@ void Font::createOutline(FontData *font) {
int newByteWidth;
int newRowLength = 0;
int currentByte;
- unsigned char *basePointer;
- unsigned char *srcPointer;
- unsigned char *destPointer1;
- unsigned char *destPointer2;
- unsigned char *destPointer3;
- unsigned char charRep;
+ byte *basePointer;
+ byte *srcPointer;
+ byte *destPointer1;
+ byte *destPointer2;
+ byte *destPointer3;
+ byte charRep;
// Populate new font style character data
for (i = 0; i < FONT_CHARCOUNT; i++) {
@@ -177,20 +153,20 @@ void Font::createOutline(FontData *font) {
font->outline.header.rowLength = newRowLength;
// Allocate new font representation storage
- font->outline.font = (unsigned char *)calloc(newRowLength, font->outline.header.charHeight);
+ font->outline.font.resize(newRowLength * font->outline.header.charHeight);
// Generate outline font representation
for (i = 0; i < FONT_CHARCOUNT; i++) {
for (row = 0; row < font->normal.header.charHeight; row++) {
for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) {
- basePointer = font->outline.font + font->outline.fontCharEntry[i].index + currentByte;
+ basePointer = &font->outline.font[font->outline.fontCharEntry[i].index + currentByte];
destPointer1 = basePointer + newRowLength * row;
destPointer2 = basePointer + newRowLength * (row + 1);
destPointer3 = basePointer + newRowLength * (row + 2);
if (currentByte > 0) {
// Get last two columns from previous byte
- srcPointer = font->normal.font + font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1);
+ srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1)];
charRep = *srcPointer;
*destPointer1 |= ((charRep << 6) | (charRep << 7));
*destPointer2 |= ((charRep << 6) | (charRep << 7));
@@ -198,7 +174,7 @@ void Font::createOutline(FontData *font) {
}
if (currentByte < font->normal.fontCharEntry[i].byteWidth) {
- srcPointer = font->normal.font + font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte;
+ srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte];
charRep = *srcPointer;
*destPointer1 |= charRep | (charRep >> 1) | (charRep >> 2);
*destPointer2 |= charRep | (charRep >> 1) | (charRep >> 2);
@@ -210,15 +186,15 @@ void Font::createOutline(FontData *font) {
// "Hollow out" character to prevent overdraw
for (row = 0; row < font->normal.header.charHeight; row++) {
for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) {
- destPointer2 = font->outline.font + font->outline.header.rowLength * (row + 1) + font->outline.fontCharEntry[i].index + currentByte;
+ destPointer2 = &font->outline.font[font->outline.header.rowLength * (row + 1) + font->outline.fontCharEntry[i].index + currentByte];
if (currentByte > 0) {
// Get last two columns from previous byte
- srcPointer = font->normal.font + font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1);
+ srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1)];
*destPointer2 &= ((*srcPointer << 7) ^ 0xFFU);
}
if (currentByte < font->normal.fontCharEntry[i].byteWidth) {
- srcPointer = font->normal.font + font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte;
+ srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte];
*destPointer2 &= ((*srcPointer >> 1) ^ 0xFFU);
}
}
@@ -289,7 +265,7 @@ void Font::draw(FontId fontId, const char *text, size_t count, const Common::Poi
void Font::outFont(const FontStyle &drawFont, const char *text, size_t count, const Common::Point &point, int color, FontEffectFlags flags) {
const byte *textPointer;
- byte *c_dataPointer;
+ const byte *c_dataPointer;
int c_code;
int charRow = 0;
Point textPoint(point);
@@ -384,7 +360,7 @@ void Font::outFont(const FontStyle &drawFont, const char *text, size_t count, co
break;
}
- c_dataPointer = drawFont.font + charRow * drawFont.header.rowLength + drawFont.fontCharEntry[c_code].index;
+ c_dataPointer = &drawFont.font[charRow * drawFont.header.rowLength + drawFont.fontCharEntry[c_code].index];
for (c_byte = 0; c_byte < c_byte_len; c_byte++, c_dataPointer++) {
// Check each bit, draw pixel if bit is set
diff --git a/engines/saga/font.h b/engines/saga/font.h
index 1b9f290a1b..6f66545756 100644
--- a/engines/saga/font.h
+++ b/engines/saga/font.h
@@ -120,7 +120,7 @@ struct FontCharEntry {
struct FontStyle {
FontHeader header;
FontCharEntry fontCharEntry[256];
- byte *font;
+ ByteArray font;
};
struct FontData {
@@ -170,14 +170,14 @@ class Font {
void textDrawRect(FontId fontId, const char *text, const Common::Rect &rect, int color, int effectColor, FontEffectFlags flags);
void textDraw(FontId fontId, const char *string, const Common::Point &point, int color, int effectColor, FontEffectFlags flags);
- void loadFont(uint32 fontResourceId);
+ void loadFont(FontData *font, uint32 fontResourceId);
void createOutline(FontData *font);
void draw(FontId fontId, const char *text, size_t count, const Common::Point &point, int color, int effectColor, FontEffectFlags flags);
void outFont(const FontStyle &drawFont, const char *text, size_t count, const Common::Point &point, int color, FontEffectFlags flags);
FontData *getFont(FontId fontId) {
validate(fontId);
- return _fonts[fontId];
+ return &_fonts[fontId];
}
int getHeight(FontId fontId) {
@@ -190,7 +190,7 @@ class Font {
}
}
bool valid(FontId fontId) {
- return (fontId < _loadedFonts);
+ return (uint(fontId) < _fonts.size());
}
int getByteLen(int numBits) const {
int byteLength = numBits / 8;
@@ -207,8 +207,7 @@ class Font {
int _fontMapping;
- int _loadedFonts;
- FontData **_fonts;
+ Common::Array<FontData> _fonts;
};
} // End of namespace Saga
diff --git a/engines/saga/gfx.cpp b/engines/saga/gfx.cpp
index 40a633ac5d..77842acc7b 100644
--- a/engines/saga/gfx.cpp
+++ b/engines/saga/gfx.cpp
@@ -173,13 +173,11 @@ void Gfx::initPalette() {
error("Resource::loadGlobalResources() resource context not found");
}
- byte *resourcePointer;
- size_t resourceLength;
+ ByteArray resourceData;
- _vm->_resource->loadResource(resourceContext, RID_IHNM_DEFAULT_PALETTE,
- resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, RID_IHNM_DEFAULT_PALETTE, resourceData);
- MemoryReadStream metaS(resourcePointer, resourceLength);
+ ByteArrayReadStreamEndian metaS(resourceData);
for (int i = 0; i < 256; i++) {
_globalPalette[i].red = metaS.readByte();
@@ -187,8 +185,6 @@ void Gfx::initPalette() {
_globalPalette[i].blue = metaS.readByte();
}
- free(resourcePointer);
-
setPalette(_globalPalette, true);
}
@@ -504,22 +500,19 @@ void Gfx::setCursor(CursorType cursorType) {
break;
}
- byte *resource;
- size_t resourceLength;
- byte *image;
- size_t imageLength;
+ ByteArray resourceData;
+ ByteArray image;
int width, height;
if (resourceId != (uint32)-1) {
ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE);
- _vm->_resource->loadResource(context, resourceId, resource, resourceLength);
+ _vm->_resource->loadResource(context, resourceId, resourceData);
- _vm->decodeBGImage(resource, resourceLength, &image, &imageLength, &width, &height);
+ _vm->decodeBGImage(resourceData, image, &width, &height);
} else {
- resource = NULL;
width = height = 31;
- image = (byte *)calloc(width, height);
+ image.resize(width * height);
for (int i = 0; i < 14; i++) {
image[15 * 31 + i] = 1;
@@ -530,10 +523,7 @@ void Gfx::setCursor(CursorType cursorType) {
}
// Note: Hard-coded hotspot
- CursorMan.replaceCursor(image, width, height, 15, 15, 0);
-
- free(image);
- free(resource);
+ CursorMan.replaceCursor(image.getBuffer(), width, height, 15, 15, 0);
}
}
@@ -564,8 +554,9 @@ bool hitTestPoly(const Point *points, unsigned int npoints, const Point& test_po
// This method adds a dirty rectangle automatically
void Gfx::drawFrame(const Common::Point &p1, const Common::Point &p2, int color) {
- _backBuffer.drawFrame(p1, p2, color);
- _vm->_render->addDirtyRect(Common::Rect(p1.x, p1.y, p2.x + 1, p2.y + 1));
+ Common::Rect rect(MIN(p1.x, p2.x), MIN(p1.y, p2.y), MAX(p1.x, p2.x) + 1, MAX(p1.y, p2.y) + 1);
+ _backBuffer.frameRect(rect, color);
+ _vm->_render->addDirtyRect(rect);
}
// This method adds a dirty rectangle automatically
diff --git a/engines/saga/gfx.h b/engines/saga/gfx.h
index f3ccad469f..18d88503ce 100644
--- a/engines/saga/gfx.h
+++ b/engines/saga/gfx.h
@@ -108,10 +108,7 @@ struct Surface : Graphics::Surface {
rect.right = w;
rect.bottom = h;
}
- void drawFrame(const Common::Point &p1, const Common::Point &p2, int color) {
- Common::Rect rect(MIN(p1.x, p2.x), MIN(p1.y, p2.y), MAX(p1.x, p2.x) + 1, MAX(p1.y, p2.y) + 1);
- frameRect(rect, color);
- }
+
void drawRect(const Common::Rect &destRect, int color) {
Common::Rect rect(w , h);
rect.clip(destRect);
@@ -198,7 +195,7 @@ public:
// WARNING: This method does not add a dirty rectangle automatically.
// Whenever it gets called, the corresponding caller must take care
// to add the corresponding dirty rectangle itself
- void drawPolyLine(Common::Point *points, int count, int color) {
+ void drawPolyLine(const Common::Point *points, int count, int color) {
_backBuffer.drawPolyLine(points, count, color);
}
diff --git a/engines/saga/image.cpp b/engines/saga/image.cpp
index 7d8eb83550..87d9e514c8 100644
--- a/engines/saga/image.cpp
+++ b/engines/saga/image.cpp
@@ -47,22 +47,18 @@ static int granulate(int value, int granularity) {
}
}
-int SagaEngine::decodeBGImage(const byte *image_data, size_t image_size,
- byte **output_buf, size_t *output_buf_len, int *w, int *h, bool flip) {
+bool SagaEngine::decodeBGImage(const ByteArray &imageData, ByteArray &outputBuffer, int *w, int *h, bool flip) {
ImageHeader hdr;
int modex_height;
const byte *RLE_data_ptr;
size_t RLE_data_len;
- byte *decode_buf;
- size_t decode_buf_len;
- byte *out_buf;
- size_t out_buf_len;
+ ByteArray decodeBuffer;
- if (image_size <= SAGA_IMAGE_DATA_OFFSET) {
- error("decodeBGImage() Image size is way too small (%d)", (int)image_size);
+ if (imageData.size() <= SAGA_IMAGE_DATA_OFFSET) {
+ error("decodeBGImage() Image size is way too small (%d)", (int)imageData.size());
}
- MemoryReadStreamEndian readS(image_data, image_size, isBigEndian());
+ ByteArrayReadStreamEndian readS(imageData, isBigEndian());
hdr.width = readS.readUint16();
hdr.height = readS.readUint16();
@@ -70,45 +66,36 @@ int SagaEngine::decodeBGImage(const byte *image_data, size_t image_size,
readS.readUint16();
readS.readUint16();
- RLE_data_ptr = image_data + SAGA_IMAGE_DATA_OFFSET;
- RLE_data_len = image_size - SAGA_IMAGE_DATA_OFFSET;
+ RLE_data_ptr = &imageData.front() + SAGA_IMAGE_DATA_OFFSET;
+ RLE_data_len = imageData.size() - SAGA_IMAGE_DATA_OFFSET;
modex_height = granulate(hdr.height, 4);
- decode_buf_len = hdr.width * modex_height;
- decode_buf = (byte *)malloc(decode_buf_len);
+ decodeBuffer.resize(hdr.width * modex_height);
- out_buf_len = hdr.width * hdr.height;
- out_buf = (byte *)malloc(out_buf_len);
+ outputBuffer.resize(hdr.width * hdr.height);
- if (decodeBGImageRLE(RLE_data_ptr,
- RLE_data_len, decode_buf, decode_buf_len) != SUCCESS) {
- free(decode_buf);
- free(out_buf);
- return FAILURE;
+ if (!decodeBGImageRLE(RLE_data_ptr, RLE_data_len, decodeBuffer)) {
+ return false;
}
- unbankBGImage(out_buf, decode_buf, hdr.width, hdr.height);
+ unbankBGImage(outputBuffer.getBuffer(), decodeBuffer.getBuffer(), hdr.width, hdr.height);
// For some reason bg images in IHNM are upside down
if (getGameId() == GID_IHNM && !flip) {
- flipImage(out_buf, hdr.width, hdr.height);
+ flipImage(outputBuffer.getBuffer(), hdr.width, hdr.height);
}
- free(decode_buf);
-
- *output_buf_len = out_buf_len;
- *output_buf = out_buf;
-
*w = hdr.width;
*h = hdr.height;
- return SUCCESS;
+ return true;
}
-int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outbuf, size_t outbuf_len) {
+bool SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, ByteArray &outbuf) {
const byte *inbuf_ptr;
byte *outbuf_ptr;
+ byte *outbuf_start;
uint32 inbuf_remain;
const byte *inbuf_end;
@@ -134,18 +121,18 @@ int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outb
inbuf_ptr = inbuf;
inbuf_remain = inbuf_len;
- outbuf_ptr = outbuf;
- outbuf_remain = outbuf_len;
+ outbuf_start = outbuf_ptr = outbuf.getBuffer();
+ outbuf_remain = outbuf.size();
+ outbuf_end = (outbuf_start + outbuf_remain) - 1;
+ memset(outbuf_start, 0, outbuf_remain);
inbuf_end = (inbuf + inbuf_len) - 1;
- outbuf_end = (outbuf + outbuf_len) - 1;
- memset(outbuf, 0, outbuf_len);
while ((inbuf_remain > 1) && (outbuf_remain > 0) && !decode_err) {
if ((inbuf_ptr > inbuf_end) || (outbuf_ptr > outbuf_end)) {
- return FAILURE;
+ return false;
}
mark_byte = *inbuf_ptr++;
@@ -158,7 +145,7 @@ int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outb
// Uncompressed run follows: Max runlength 63
runcount = mark_byte & 0x3f;
if ((inbuf_remain < runcount) || (outbuf_remain < runcount)) {
- return FAILURE;
+ return false;
}
for (c = 0; c < runcount; c++) {
@@ -173,7 +160,7 @@ int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outb
// Compressed run follows: Max runlength 63
runcount = (mark_byte & 0x3f) + 3;
if (!inbuf_remain || (outbuf_remain < runcount)) {
- return FAILURE;
+ return false;
}
for (c = 0; c < runcount; c++) {
@@ -194,8 +181,8 @@ int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outb
runcount = ((mark_byte >> 3) & 0x07U) + 3;
backtrack_amount = *inbuf_ptr;
- if (!inbuf_remain || (backtrack_amount > (outbuf_ptr - outbuf)) || (runcount > outbuf_remain)) {
- return FAILURE;
+ if (!inbuf_remain || (backtrack_amount > (outbuf_ptr - outbuf_start)) || (runcount > outbuf_remain)) {
+ return false;
}
inbuf_ptr++;
@@ -224,7 +211,7 @@ int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outb
runcount = (mark_byte & 0x0F) + 1;
if ((inbuf_remain < (runcount + 2)) || (outbuf_remain < (runcount * 8))) {
- return FAILURE;
+ return false;
}
bitfield_byte1 = *inbuf_ptr++;
@@ -252,7 +239,7 @@ int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outb
// Uncompressed run follows
runcount = ((mark_byte & 0x0F) << 8) + *inbuf_ptr;
if ((inbuf_remain < (runcount + 1)) || (outbuf_remain < runcount)) {
- return FAILURE;
+ return false;
}
inbuf_ptr++;
@@ -271,14 +258,14 @@ int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outb
// Repeat decoded sequence from output stream
backtrack_amount = ((mark_byte & 0x0F) << 8) + *inbuf_ptr;
if (inbuf_remain < 2) {
- return FAILURE;
+ return false;
}
inbuf_ptr++;
runcount = *inbuf_ptr++;
- if ((backtrack_amount > (outbuf_ptr - outbuf)) || (outbuf_remain < runcount)) {
- return FAILURE;
+ if ((backtrack_amount > (outbuf_ptr - outbuf_start)) || (outbuf_remain < runcount)) {
+ return false;
}
backtrack_ptr = outbuf_ptr - backtrack_amount;
@@ -292,44 +279,42 @@ int SagaEngine::decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outb
continue;
break;
default:
- return FAILURE;
+ return false;
}
}
- return SUCCESS;
+ return true;
}
-int SagaEngine::flipImage(byte *img_buf, int columns, int scanlines) {
+void SagaEngine::flipImage(byte *imageBuffer, int columns, int scanlines) {
int line;
- byte *tmp_scan;
+ ByteArray tmp_scan;
byte *flip_p1;
byte *flip_p2;
+ byte *flip_tmp;
int flipcount = scanlines / 2;
- tmp_scan = (byte *)malloc(columns);
- if (tmp_scan == NULL) {
- return FAILURE;
+ tmp_scan.resize(columns);
+ flip_tmp = tmp_scan.getBuffer();
+ if (flip_tmp == NULL) {
+ return;
}
- flip_p1 = img_buf;
- flip_p2 = img_buf + (columns * (scanlines - 1));
+ flip_p1 = imageBuffer;
+ flip_p2 = imageBuffer + (columns * (scanlines - 1));
for (line = 0; line < flipcount; line++) {
- memcpy(tmp_scan, flip_p1, columns);
+ memcpy(flip_tmp, flip_p1, columns);
memcpy(flip_p1, flip_p2, columns);
- memcpy(flip_p2, tmp_scan, columns);
+ memcpy(flip_p2, flip_tmp, columns);
flip_p1 += columns;
flip_p2 -= columns;
}
-
- free(tmp_scan);
-
- return SUCCESS;
}
-int SagaEngine::unbankBGImage(byte *dst_buf, const byte *src_buf, int columns, int scanlines) {
+void SagaEngine::unbankBGImage(byte *dst_buf, const byte *src_buf, int columns, int scanlines) {
int x, y;
int temp;
int quadruple_rows;
@@ -424,15 +409,6 @@ int SagaEngine::unbankBGImage(byte *dst_buf, const byte *src_buf, int columns, i
default:
break;
}
- return SUCCESS;
-}
-
-const byte *SagaEngine::getImagePal(const byte *image_data, size_t image_size) {
- if (image_size <= SAGA_IMAGE_HEADER_LEN) {
- return NULL;
- }
-
- return image_data + SAGA_IMAGE_HEADER_LEN;
}
} // End of namespace Saga
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index a77ec1c140..5b15fc9803 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -124,8 +124,7 @@ static const int IHNMTextStringIdsLUT[56] = {
#define buttonRes1 0x42544E01
Interface::Interface(SagaEngine *vm) : _vm(vm) {
- byte *resource;
- size_t resourceLength;
+ ByteArray resourceData;
int i;
#if 0
@@ -170,34 +169,27 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
}
}
- _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->mainPanelResourceId, resource, resourceLength);
- _vm->decodeBGImage(resource, resourceLength, &_mainPanel.image,
- &_mainPanel.imageLength, &_mainPanel.imageWidth, &_mainPanel.imageHeight);
-
- free(resource);
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->mainPanelResourceId, resourceData);
+ _vm->decodeBGImage(resourceData, _mainPanel.image, &_mainPanel.imageWidth, &_mainPanel.imageHeight);
// Converse panel
_conversePanel.buttons = _vm->getDisplayInfo().conversePanelButtons;
_conversePanel.buttonsCount = _vm->getDisplayInfo().conversePanelButtonsCount;
- _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->conversePanelResourceId, resource, resourceLength);
- _vm->decodeBGImage(resource, resourceLength, &_conversePanel.image,
- &_conversePanel.imageLength, &_conversePanel.imageWidth, &_conversePanel.imageHeight);
- free(resource);
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->conversePanelResourceId, resourceData);
+ _vm->decodeBGImage(resourceData, _conversePanel.image, &_conversePanel.imageWidth, &_conversePanel.imageHeight);
// Option panel
if (!_vm->_script->isNonInteractiveDemo()) {
_optionPanel.buttons = _vm->getDisplayInfo().optionPanelButtons;
_optionPanel.buttonsCount = _vm->getDisplayInfo().optionPanelButtonsCount;
- _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->optionPanelResourceId, resource, resourceLength);
- _vm->decodeBGImage(resource, resourceLength, &_optionPanel.image,
- &_optionPanel.imageLength, &_optionPanel.imageWidth, &_optionPanel.imageHeight);
- free(resource);
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->optionPanelResourceId, resourceData);
+ _vm->decodeBGImage(resourceData, _optionPanel.image, &_optionPanel.imageWidth, &_optionPanel.imageHeight);
} else {
_optionPanel.buttons = NULL;
_optionPanel.buttonsCount = 0;
- _optionPanel.sprites.spriteCount = 0;
+ _optionPanel.sprites.clear();
}
#ifdef ENABLE_IHNM
@@ -206,10 +198,8 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
_quitPanel.buttons = _vm->getDisplayInfo().quitPanelButtons;
_quitPanel.buttonsCount = _vm->getDisplayInfo().quitPanelButtonsCount;
- _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
- _vm->decodeBGImage(resource, resourceLength, &_quitPanel.image,
- &_quitPanel.imageLength, &_quitPanel.imageWidth, &_quitPanel.imageHeight);
- free(resource);
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resourceData);
+ _vm->decodeBGImage(resourceData, _quitPanel.image, &_quitPanel.imageWidth, &_quitPanel.imageHeight);
}
// Save panel
@@ -217,10 +207,8 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
_savePanel.buttons = _vm->getDisplayInfo().savePanelButtons;
_savePanel.buttonsCount = _vm->getDisplayInfo().savePanelButtonsCount;
- _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
- _vm->decodeBGImage(resource, resourceLength, &_savePanel.image,
- &_savePanel.imageLength, &_savePanel.imageWidth, &_savePanel.imageHeight);
- free(resource);
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resourceData);
+ _vm->decodeBGImage(resourceData, _savePanel.image, &_savePanel.imageWidth, &_savePanel.imageHeight);
}
// Load panel
@@ -228,10 +216,8 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
_loadPanel.buttons = _vm->getDisplayInfo().loadPanelButtons;
_loadPanel.buttonsCount = _vm->getDisplayInfo().loadPanelButtonsCount;
- _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
- _vm->decodeBGImage(resource, resourceLength, &_loadPanel.image,
- &_loadPanel.imageLength, &_loadPanel.imageWidth, &_loadPanel.imageHeight);
- free(resource);
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resourceData);
+ _vm->decodeBGImage(resourceData, _loadPanel.image, &_loadPanel.imageWidth, &_loadPanel.imageHeight);
}
#endif
@@ -323,16 +309,12 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
_inventoryStart = 0;
_inventoryEnd = 0;
_inventoryBox = 0;
- _inventorySize = ITE_INVENTORY_SIZE;
_saveReminderState = 0;
_optionSaveFileTop = 0;
_optionSaveFileTitleNumber = 0;
- _inventory = (uint16 *)calloc(_inventorySize, sizeof(uint16));
- if (_inventory == NULL) {
- error("Interface::Interface(): not enough memory");
- }
+ _inventory.resize(ITE_INVENTORY_SIZE);
_textInput = false;
_statusTextInput = false;
@@ -345,25 +327,6 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
}
Interface::~Interface() {
- free(_inventory);
-
- free(_mainPanel.image);
- free(_conversePanel.image);
- free(_optionPanel.image);
- free(_quitPanel.image);
- free(_loadPanel.image);
- free(_savePanel.image);
-
- _mainPanel.sprites.freeMem();
- _conversePanel.sprites.freeMem();
- _optionPanel.sprites.freeMem();
- _quitPanel.sprites.freeMem();
- _loadPanel.sprites.freeMem();
- _savePanel.sprites.freeMem();
- _protectPanel.sprites.freeMem();
-
- _defPortraits.freeMem();
- _scenePortraits.freeMem();
}
void Interface::saveReminderCallback(void *refCon) {
@@ -768,7 +731,7 @@ void Interface::setStatusText(const char *text, int statusColor) {
}
void Interface::loadScenePortraits(int resourceId) {
- _scenePortraits.freeMem();
+ _scenePortraits.clear();
_vm->_sprite->loadList(resourceId, _scenePortraits);
}
@@ -817,7 +780,7 @@ void Interface::draw() {
if (_panelMode == kPanelMain || _panelMode == kPanelMap ||
(_panelMode == kPanelNull && _vm->isIHNMDemo())) {
_mainPanel.getRect(rect);
- _vm->_gfx->drawRegion(rect, _mainPanel.image);
+ _vm->_gfx->drawRegion(rect, _mainPanel.image.getBuffer());
for (int i = 0; i < kVerbTypeIdsMax; i++) {
if (_verbTypeToPanelButton[i] != NULL) {
@@ -826,7 +789,7 @@ void Interface::draw() {
}
} else if (_panelMode == kPanelConverse) {
_conversePanel.getRect(rect);
- _vm->_gfx->drawRegion(rect, _conversePanel.image);
+ _vm->_gfx->drawRegion(rect, _conversePanel.image.getBuffer());
converseDisplayTextLines();
}
@@ -847,7 +810,7 @@ void Interface::draw() {
// can tell this is what the original engine does. And it keeps
// ITE from crashing when entering the Elk King's court.
- if (_rightPortrait >= _scenePortraits.spriteCount)
+ if (_rightPortrait >= (int)_scenePortraits.size())
_rightPortrait = 0;
_vm->_sprite->draw(_scenePortraits, _rightPortrait, rightPortraitPoint, 256);
@@ -960,7 +923,7 @@ void Interface::drawOption() {
int spritenum = 0;
_optionPanel.getRect(rect);
- _vm->_gfx->drawRegion(rect, _optionPanel.image);
+ _vm->_gfx->drawRegion(rect, _optionPanel.image.getBuffer());
for (int i = 0; i < _optionPanel.buttonsCount; i++) {
panelButton = &_optionPanel.buttons[i];
@@ -1037,7 +1000,7 @@ void Interface::drawQuit() {
if (_vm->getGameId() == GID_ITE)
drawButtonBox(rect, kButton, false);
else
- _vm->_gfx->drawRegion(rect, _quitPanel.image);
+ _vm->_gfx->drawRegion(rect, _quitPanel.image.getBuffer());
for (i = 0; i < _quitPanel.buttonsCount; i++) {
panelButton = &_quitPanel.buttons[i];
@@ -1103,7 +1066,7 @@ void Interface::drawLoad() {
if (_vm->getGameId() == GID_ITE)
drawButtonBox(rect, kButton, false);
else
- _vm->_gfx->drawRegion(rect, _loadPanel.image);
+ _vm->_gfx->drawRegion(rect, _loadPanel.image.getBuffer());
for (i = 0; i < _loadPanel.buttonsCount; i++) {
panelButton = &_loadPanel.buttons[i];
@@ -1323,7 +1286,7 @@ void Interface::drawSave() {
if (_vm->getGameId() == GID_ITE)
drawButtonBox(rect, kButton, false);
else
- _vm->_gfx->drawRegion(rect, _savePanel.image);
+ _vm->_gfx->drawRegion(rect, _savePanel.image.getBuffer());
for (i = 0; i < _savePanel.buttonsCount; i++) {
panelButton = &_savePanel.buttons[i];
@@ -1587,7 +1550,7 @@ void Interface::handleChapterSelectionClick(const Point& mousePoint) {
event.param4 = obj; // Object
event.param5 = 0; // With Object
event.param6 = obj; // Actor
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
}
}
@@ -2064,7 +2027,7 @@ void Interface::updateInventory(int pos) {
}
void Interface::addToInventory(int objectId) {
- if (_inventoryCount >= _inventorySize) {
+ if (uint(_inventoryCount) >= _inventory.size()) {
return;
}
@@ -2281,14 +2244,22 @@ void Interface::drawPanelButtonText(InterfacePanel *panel, PanelButton *panelBut
}
break;
case kTextMusic:
- if (_vm->_musicVolume)
+ if (_vm->_musicVolume) {
textId = kText10Percent + _vm->_musicVolume / 25 - 1;
+ if (textId > kTextMax) {
+ textId = kTextMax;
+ }
+ }
else
textId = kTextOff;
break;
case kTextSound:
- if (_vm->_soundVolume)
+ if (_vm->_soundVolume) {
textId = kText10Percent + _vm->_soundVolume / 25 - 1;
+ if (textId > kTextMax) {
+ textId = kTextMax;
+ }
+ }
else
textId = kTextOff;
break;
@@ -2423,18 +2394,9 @@ void Interface::drawVerbPanelText(PanelButton *panelButton, KnownColor textKnown
// Converse stuff
-void Interface::converseInit() {
- for (int i = 0; i < CONVERSE_MAX_TEXTS; i++)
- _converseText[i].text = NULL;
- converseClear();
-}
-
void Interface::converseClear() {
for (int i = 0; i < CONVERSE_MAX_TEXTS; i++) {
- if (_converseText[i].text != NULL) {
- free(_converseText[i].text);
- _converseText[i].text = NULL;
- }
+ _converseText[i].text.clear();
_converseText[i].stringNum = -1;
_converseText[i].replyId = 0;
_converseText[i].replyFlags = 0;
@@ -2480,8 +2442,8 @@ bool Interface::converseAddText(const char *text, int strId, int replyId, byte r
return true;
}
- _converseText[_converseTextCount].text = (char *)malloc(i + 1);
- strncpy(_converseText[_converseTextCount].text, _converseWorkString, i);
+ _converseText[_converseTextCount].text.resize(i + 1);
+ strncpy(&_converseText[_converseTextCount].text.front(), _converseWorkString, i);
_converseText[_converseTextCount].strId = strId;
_converseText[_converseTextCount].text[i] = 0;
@@ -2591,7 +2553,7 @@ void Interface::converseDisplayTextLines() {
rect.left += 8;
_vm->_gfx->drawRect(rect, backgnd);
- str = _converseText[relPos].text;
+ str = &_converseText[relPos].text.front();
if (_converseText[relPos].textNum == 0) { // first entry
textPoint.x = rect.left - 6;
@@ -2725,10 +2687,9 @@ void Interface::loadState(Common::InSaveFile *in) {
void Interface::mapPanelShow() {
int i;
- byte *resource;
- size_t resourceLength, imageLength;
+ ByteArray resourceData;
Rect rect;
- byte *image;
+ ByteArray image;
int imageWidth, imageHeight;
const byte *pal;
PalEntry cPal[PAL_ENTRIES];
@@ -2737,9 +2698,8 @@ void Interface::mapPanelShow() {
rect.left = rect.top = 0;
- _vm->_resource->loadResource(_interfaceContext,
- _vm->_resource->convertResourceId(RID_ITE_TYCHO_MAP), resource, resourceLength);
- if (resourceLength == 0) {
+ _vm->_resource->loadResource(_interfaceContext, _vm->_resource->convertResourceId(RID_ITE_TYCHO_MAP), resourceData);
+ if (resourceData.empty()) {
error("Interface::mapPanelShow() unable to load Tycho map resource");
}
@@ -2753,8 +2713,8 @@ void Interface::mapPanelShow() {
_vm->_render->setFlag(RF_MAP);
- _vm->decodeBGImage(resource, resourceLength, &image, &imageLength, &imageWidth, &imageHeight);
- pal = _vm->getImagePal(resource, resourceLength);
+ _vm->decodeBGImage(resourceData, image, &imageWidth, &imageHeight);
+ pal = _vm->getImagePal(resourceData);
for (i = 0; i < PAL_ENTRIES; i++) {
cPal[i].red = *pal++;
@@ -2765,7 +2725,7 @@ void Interface::mapPanelShow() {
rect.setWidth(imageWidth);
rect.setHeight(imageHeight);
- _vm->_gfx->drawRegion(rect, image);
+ _vm->_gfx->drawRegion(rect, image.getBuffer());
// Evil Evil
for (i = 0; i < 6 ; i++) {
@@ -2774,8 +2734,6 @@ void Interface::mapPanelShow() {
_vm->_system->delayMillis(5);
}
- free(resource);
- free(image);
setSaveReminderState(false);
@@ -2832,10 +2790,9 @@ void Interface::keyBoss() {
_vm->_music->pause();
int i;
- byte *resource;
- size_t resourceLength, imageLength;
+ ByteArray resourceData;
Rect rect;
- byte *image;
+ ByteArray image;
int imageWidth, imageHeight;
const byte *pal;
PalEntry cPal[PAL_ENTRIES];
@@ -2844,20 +2801,20 @@ void Interface::keyBoss() {
rect.left = rect.top = 0;
- _vm->_resource->loadResource(_interfaceContext, RID_IHNM_BOSS_SCREEN, resource, resourceLength);
- if (resourceLength == 0) {
+ _vm->_resource->loadResource(_interfaceContext, RID_IHNM_BOSS_SCREEN, resourceData);
+ if (resourceData.empty()) {
error("Interface::bossKey() unable to load Boss image resource");
}
_bossMode = _panelMode;
setMode(kPanelBoss);
- _vm->decodeBGImage(resource, resourceLength, &image, &imageLength, &imageWidth, &imageHeight);
+ _vm->decodeBGImage(resourceData, image, &imageWidth, &imageHeight);
rect.setWidth(imageWidth);
rect.setHeight(imageHeight);
_vm->_gfx->getCurrentPal(_mapSavedPal);
- pal = _vm->getImagePal(resource, resourceLength);
+ pal = _vm->getImagePal(resourceData);
cPal[0].red = 0;
cPal[0].green = 0;
@@ -2869,12 +2826,9 @@ void Interface::keyBoss() {
cPal[i].blue = 128;
}
- _vm->_gfx->drawRegion(rect, image);
+ _vm->_gfx->drawRegion(rect, image.getBuffer());
_vm->_gfx->setPalette(cPal);
-
- free(resource);
- free(image);
}
diff --git a/engines/saga/interface.h b/engines/saga/interface.h
index 0fbe5bef20..b9a96653a7 100644
--- a/engines/saga/interface.h
+++ b/engines/saga/interface.h
@@ -94,8 +94,7 @@ enum FadeModes {
struct InterfacePanel {
int x;
int y;
- byte *image;
- size_t imageLength;
+ ByteArray image;
int imageWidth;
int imageHeight;
@@ -106,8 +105,6 @@ struct InterfacePanel {
InterfacePanel() {
x = y = 0;
- image = NULL;
- imageLength = 0;
imageWidth = imageHeight = 0;
currentButton = NULL;
buttonsCount = 0;
@@ -164,7 +161,7 @@ struct InterfacePanel {
};
struct Converse {
- char *text;
+ Common::Array<char> text;
int strId;
int stringNum;
int textNum;
@@ -356,7 +353,6 @@ private:
void processStatusTextInput(Common::KeyState keystate);
public:
- void converseInit();
void converseClear();
bool converseAddText(const char *text, int strId, int replyId, byte replyFlags, int replyBit);
void converseDisplayText();
@@ -431,8 +427,7 @@ private:
Point _lastMousePoint;
- uint16 *_inventory;
- int _inventorySize;
+ Common::Array<uint16> _inventory;
int _inventoryStart;
int _inventoryEnd;
int _inventoryPos;
diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp
index e149753dfd..2053c7158f 100644
--- a/engines/saga/introproc_ihnm.cpp
+++ b/engines/saga/introproc_ihnm.cpp
@@ -83,19 +83,18 @@ int Scene::IHNMStartProc() {
}
_vm->_music->setVolume(0, 1000);
- _vm->_anim->freeCutawayList();
+ _vm->_anim->clearCutawayList();
// Queue first scene
firstScene.loadFlag = kLoadBySceneNumber;
firstScene.sceneDescriptor = -1;
- firstScene.sceneDescription = NULL;
firstScene.sceneSkipTarget = false;
firstScene.sceneProc = NULL;
firstScene.transitionType = kTransitionFade;
firstScene.actorsEntrance = 0;
firstScene.chapter = -1;
- _vm->_scene->queueScene(&firstScene);
+ _vm->_scene->queueScene(firstScene);
return SUCCESS;
}
@@ -114,7 +113,7 @@ int Scene::IHNMCreditsProc() {
}
_vm->_music->setVolume(0, 1000);
- _vm->_anim->freeCutawayList();
+ _vm->_anim->clearCutawayList();
return SUCCESS;
}
@@ -122,8 +121,7 @@ int Scene::IHNMCreditsProc() {
void Scene::IHNMLoadCutaways() {
ResourceContext *resourceContext;
//ResourceContext *soundContext;
- byte *resourcePointer;
- size_t resourceLength;
+ ByteArray resourceData;
resourceContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
if (resourceContext == NULL) {
@@ -131,18 +129,16 @@ void Scene::IHNMLoadCutaways() {
}
if (!_vm->isIHNMDemo())
- _vm->_resource->loadResource(resourceContext, RID_IHNM_INTRO_CUTAWAYS, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, RID_IHNM_INTRO_CUTAWAYS, resourceData);
else
- _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_INTRO_CUTAWAYS, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_INTRO_CUTAWAYS, resourceData);
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("Scene::IHNMStartProc() Can't load cutaway list");
}
// Load the cutaways for the title screens
- _vm->_anim->loadCutawayList(resourcePointer, resourceLength);
-
- free(resourcePointer);
+ _vm->_anim->loadCutawayList(resourceData);
}
bool Scene::checkKey() {
diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp
index 83fdadf59e..ae7dedefa5 100644
--- a/engines/saga/introproc_ite.cpp
+++ b/engines/saga/introproc_ite.cpp
@@ -61,15 +61,15 @@ using Common::IT_ITA;
#define MUSIC_2 10
LoadSceneParams ITE_IntroList[] = {
- {RID_ITE_INTRO_ANIM_SCENE, kLoadByResourceId, NULL, Scene::SC_ITEIntroAnimProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {RID_ITE_CAVE_SCENE_1, kLoadByResourceId, NULL, Scene::SC_ITEIntroCave1Proc, false, kTransitionFade, 0, NO_CHAPTER_CHANGE},
- {RID_ITE_CAVE_SCENE_2, kLoadByResourceId, NULL, Scene::SC_ITEIntroCave2Proc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {RID_ITE_CAVE_SCENE_3, kLoadByResourceId, NULL, Scene::SC_ITEIntroCave3Proc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {RID_ITE_CAVE_SCENE_4, kLoadByResourceId, NULL, Scene::SC_ITEIntroCave4Proc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {RID_ITE_VALLEY_SCENE, kLoadByResourceId, NULL, Scene::SC_ITEIntroValleyProc, false, kTransitionFade, 0, NO_CHAPTER_CHANGE},
- {RID_ITE_TREEHOUSE_SCENE, kLoadByResourceId, NULL, Scene::SC_ITEIntroTreeHouseProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {RID_ITE_FAIREPATH_SCENE, kLoadByResourceId, NULL, Scene::SC_ITEIntroFairePathProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {RID_ITE_FAIRETENT_SCENE, kLoadByResourceId, NULL, Scene::SC_ITEIntroFaireTentProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}
+ {RID_ITE_INTRO_ANIM_SCENE, kLoadByResourceId, Scene::SC_ITEIntroAnimProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_CAVE_SCENE_1, kLoadByResourceId, Scene::SC_ITEIntroCave1Proc, false, kTransitionFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_CAVE_SCENE_2, kLoadByResourceId, Scene::SC_ITEIntroCave2Proc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_CAVE_SCENE_3, kLoadByResourceId, Scene::SC_ITEIntroCave3Proc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_CAVE_SCENE_4, kLoadByResourceId, Scene::SC_ITEIntroCave4Proc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_VALLEY_SCENE, kLoadByResourceId, Scene::SC_ITEIntroValleyProc, false, kTransitionFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_TREEHOUSE_SCENE, kLoadByResourceId, Scene::SC_ITEIntroTreeHouseProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_FAIREPATH_SCENE, kLoadByResourceId, Scene::SC_ITEIntroFairePathProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_FAIRETENT_SCENE, kLoadByResourceId, Scene::SC_ITEIntroFaireTentProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}
};
int Scene::ITEStartProc() {
@@ -84,25 +84,24 @@ int Scene::ITEStartProc() {
for (i = 0; i < scenesCount; i++) {
tempScene = ITE_IntroList[i];
tempScene.sceneDescriptor = _vm->_resource->convertResourceId(tempScene.sceneDescriptor);
- _vm->_scene->queueScene(&tempScene);
+ _vm->_scene->queueScene(tempScene);
}
firstScene.loadFlag = kLoadBySceneNumber;
firstScene.sceneDescriptor = _vm->getStartSceneNumber();
- firstScene.sceneDescription = NULL;
firstScene.sceneSkipTarget = true;
firstScene.sceneProc = NULL;
firstScene.transitionType = kTransitionFade;
firstScene.actorsEntrance = 0;
firstScene.chapter = -1;
- _vm->_scene->queueScene(&firstScene);
+ _vm->_scene->queueScene(firstScene);
return SUCCESS;
}
-Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialogue dialogue[]) {
+EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]) {
TextListEntry textEntry;
TextListEntry *entry;
Event event;
@@ -136,7 +135,7 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo
event.op = kEventDisplay;
event.data = entry;
event.time = (i == 0) ? 0 : VOICE_PAD;
- q_event = _vm->_events->chain(q_event, &event);
+ eventColumns = _vm->_events->chain(eventColumns, event);
// Play voice
event.type = kEvTOneshot;
@@ -144,7 +143,7 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo
event.op = kEventPlay;
event.param = dialogue[i].i_voice_rn;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
voice_len = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn);
if (voice_len < 0) {
@@ -157,10 +156,10 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo
event.op = kEventRemove;
event.data = entry;
event.time = voice_len;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
- return q_event;
+ return eventColumns;
}
enum {
@@ -180,7 +179,7 @@ enum {
// Queue a page of credits text. The original interpreter did word-wrapping
// automatically. We currently don't.
-Event *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]) {
+EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]) {
int game;
Common::Language lang;
@@ -241,7 +240,7 @@ Event *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const
TextListEntry textEntry;
TextListEntry *entry;
Event event;
- Event *q_event = NULL;
+ EventColumns *eventColumns = NULL;
textEntry.knownColor = kKnownColorSubtitleTextColor;
textEntry.effectKnownColor = kKnownColorTransparent;
@@ -283,7 +282,7 @@ Event *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const
event.op = kEventDisplay;
event.data = entry;
event.time = delta_time;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// Remove text
event.type = kEvTOneshot;
@@ -291,12 +290,12 @@ Event *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const
event.op = kEventRemove;
event.data = entry;
event.time = duration;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
y += (_vm->_font->getHeight(font) + line_spacing);
}
- return q_event;
+ return eventColumns;
}
int Scene::SC_ITEIntroAnimProc(int param, void *refCon) {
@@ -306,7 +305,7 @@ int Scene::SC_ITEIntroAnimProc(int param, void *refCon) {
// Handles the introductory Dreamer's Guild / NWC logo animation scene.
int Scene::ITEIntroAnimProc(int param) {
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
switch (param) {
case SCENE_BEGIN:{
@@ -317,7 +316,7 @@ int Scene::ITEIntroAnimProc(int param) {
event.op = kEventDisplay;
event.param = kEvPSetPalette;
event.time = 0;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
debug(3, "Intro animation procedure started.");
debug(3, "Linking animation resources...");
@@ -355,7 +354,7 @@ int Scene::ITEIntroAnimProc(int param) {
event.op = kEventPlay;
event.param = 0;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Queue intro music playback
event.type = kEvTOneshot;
@@ -364,7 +363,7 @@ int Scene::ITEIntroAnimProc(int param) {
event.param2 = MUSIC_LOOP;
event.op = kEventPlay;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
break;
case SCENE_END:
@@ -384,7 +383,7 @@ int Scene::SC_ITEIntroCave1Proc(int param, void *refCon) {
// Handles first introductory cave painting scene
int Scene::ITEIntroCave1Proc(int param) {
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
int lang = 0;
if (_vm->getLanguage() == Common::DE_DEU)
@@ -468,24 +467,24 @@ int Scene::ITEIntroCave1Proc(int param) {
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// Queue narrator dialogue list
- q_event = ITEQueueDialogue(q_event, n_dialogues, dialogue[lang]);
+ ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]);
// End scene after last dialogue over
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = VOICE_PAD;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
break;
default:
- warning("Illegal scene procedure paramater");
+ warning("Illegal scene procedure parameter");
break;
}
@@ -499,7 +498,7 @@ int Scene::SC_ITEIntroCave2Proc(int param, void *refCon) {
// Handles second introductory cave painting scene
int Scene::ITEIntroCave2Proc(int param) {
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
int lang = 0;
if (_vm->getLanguage() == Common::DE_DEU)
@@ -566,30 +565,30 @@ int Scene::ITEIntroCave2Proc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// Begin palette cycling animation for candles
event.type = kEvTOneshot;
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Queue narrator dialogue list
- q_event = ITEQueueDialogue(q_event, n_dialogues, dialogue[lang]);
+ ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]);
// End scene after last dialogue over
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = VOICE_PAD;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
break;
default:
- warning("Illegal scene procedure paramater");
+ warning("Illegal scene procedure parameter");
break;
}
@@ -603,7 +602,7 @@ int Scene::SC_ITEIntroCave3Proc(int param, void *refCon) {
// Handles third introductory cave painting scene
int Scene::ITEIntroCave3Proc(int param) {
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
int lang = 0;
if (_vm->getLanguage() == Common::DE_DEU)
@@ -671,30 +670,30 @@ int Scene::ITEIntroCave3Proc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// Begin palette cycling animation for candles
event.type = kEvTOneshot;
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Queue narrator dialogue list
- q_event = ITEQueueDialogue(q_event, n_dialogues, dialogue[lang]);
+ ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]);
// End scene after last dialogue over
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = VOICE_PAD;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
break;
default:
- warning("Illegal scene procedure paramater");
+ warning("Illegal scene procedure parameter");
break;
}
@@ -708,7 +707,7 @@ int Scene::SC_ITEIntroCave4Proc(int param, void *refCon) {
// Handles fourth introductory cave painting scene
int Scene::ITEIntroCave4Proc(int param) {
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
int lang = 0;
if (_vm->getLanguage() == Common::DE_DEU)
@@ -789,30 +788,30 @@ int Scene::ITEIntroCave4Proc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// Begin palette cycling animation for candles
event.type = kEvTOneshot;
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Queue narrator dialogue list
- q_event = ITEQueueDialogue(q_event, n_dialogues, dialogue[lang]);
+ ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]);
// End scene after last dialogue over
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = VOICE_PAD;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
break;
default:
- warning("Illegal scene procedure paramater");
+ warning("Illegal scene procedure parameter");
break;
}
@@ -826,7 +825,7 @@ int Scene::SC_ITEIntroValleyProc(int param, void *refCon) {
// Handles intro title scene (valley overlook)
int Scene::ITEIntroValleyProc(int param) {
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
static const IntroCredit credits[] = {
{EN_ANY, kITEAny, kCHeader, "Producer"},
@@ -856,7 +855,7 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventPlay;
event.param = 0;
event.time = 0;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// Begin ITE title theme music
_vm->_music->stop();
@@ -867,7 +866,7 @@ int Scene::ITEIntroValleyProc(int param) {
event.param2 = MUSIC_NORMAL;
event.op = kEventPlay;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Pause animation before logo
event.type = kEvTOneshot;
@@ -875,7 +874,7 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventStop;
event.param = 0;
event.time = 3000;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Display logo
event.type = kEvTContinuous;
@@ -883,7 +882,7 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventDissolveBGMask;
event.time = 0;
event.duration = LOGO_DISSOLVE_DURATION;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Remove logo
event.type = kEvTContinuous;
@@ -891,7 +890,7 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventDissolve;
event.time = 3000;
event.duration = LOGO_DISSOLVE_DURATION;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Unpause animation before logo
event.type = kEvTOneshot;
@@ -899,17 +898,17 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventPlay;
event.time = 0;
event.param = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Queue game credits list
- q_event = ITEQueueCredits(9000, CREDIT_DURATION1, n_credits, credits);
+ eventColumns = ITEQueueCredits(9000, CREDIT_DURATION1, n_credits, credits);
// End scene after credit display
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = 1000;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
@@ -929,7 +928,7 @@ int Scene::SC_ITEIntroTreeHouseProc(int param, void *refCon) {
// Handles second intro credit screen (treehouse view)
int Scene::ITEIntroTreeHouseProc(int param) {
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
static const IntroCredit credits1[] = {
{EN_ANY, kITEAny, kCHeader, "Game Design"},
@@ -981,7 +980,7 @@ int Scene::ITEIntroTreeHouseProc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
if (_vm->_anim->hasAnimation(0)) {
// Begin title screen background animation
@@ -992,19 +991,19 @@ int Scene::ITEIntroTreeHouseProc(int param) {
event.op = kEventPlay;
event.param = 0;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
// Queue game credits list
- q_event = ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1);
- q_event = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2);
+ eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1);
+ eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2);
// End scene after credit display
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = 1000;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
@@ -1024,7 +1023,7 @@ int Scene::SC_ITEIntroFairePathProc(int param, void *refCon) {
// Handles third intro credit screen (path to puzzle tent)
int Scene::ITEIntroFairePathProc(int param) {
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
static const IntroCredit credits1[] = {
{EN_ANY, kITEAny, kCHeader, "Programming"},
@@ -1063,7 +1062,7 @@ int Scene::ITEIntroFairePathProc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// Begin title screen background animation
_vm->_anim->setCycles(0, -1);
@@ -1073,18 +1072,18 @@ int Scene::ITEIntroFairePathProc(int param) {
event.op = kEventPlay;
event.param = 0;
event.time = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Queue game credits list
- q_event = ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1);
- q_event = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2);
+ eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1);
+ eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2);
// End scene after credit display
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = 1000;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
@@ -1104,8 +1103,7 @@ int Scene::SC_ITEIntroFaireTentProc(int param, void *refCon) {
// Handles fourth intro credit screen (treehouse view)
int Scene::ITEIntroFaireTentProc(int param) {
Event event;
- Event *q_event;
- Event *q_event_start;
+ EventColumns *eventColumns;
switch (param) {
case SCENE_BEGIN:
@@ -1116,14 +1114,14 @@ int Scene::ITEIntroFaireTentProc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
- q_event_start = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// End scene after momentary pause
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = 5000;
- q_event = _vm->_events->chain(q_event_start, &event);
+ _vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
diff --git a/engines/saga/isomap.cpp b/engines/saga/isomap.cpp
index f0ad9bbd5e..6450af268a 100644
--- a/engines/saga/isomap.cpp
+++ b/engines/saga/isomap.cpp
@@ -85,34 +85,40 @@ static const IsoMap::TilePoint hardDirTable[8] = {
{ 0, 1, 0, SAGA_STRAIGHT_HARD_COST},
};
-IsoMap::IsoMap(SagaEngine *vm) : _vm(vm) {
- _tileData = NULL;
- _tileDataLength = 0;
+static const int16 directions[8][2] = {
+ { 16, 16},
+ { 16, 0},
+ { 16, -16},
+ { 0, -16},
+ { -16, -16},
+ { -16, 0},
+ { -16, 16},
+ { 0, 16}
+};
- _multiTableData = NULL;
- _multiDataCount = 0;
+IsoMap::IsoMap(SagaEngine *vm) : _vm(vm) {
_viewScroll.x = (128 - 8) * 16;
_viewScroll.x = (128 - 8) * 16 - 64;
_viewDiff = 1;
-
}
-void IsoMap::loadImages(const byte *resourcePointer, size_t resourceLength) {
+void IsoMap::loadImages(const ByteArray &resourceData) {
IsoTileData *tileData;
uint16 i;
size_t offsetDiff;
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("IsoMap::loadImages wrong resourceLength");
}
- MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian());
+ ByteArrayReadStreamEndian readS(resourceData, _vm->isBigEndian());
readS.readUint16(); // skip
i = readS.readUint16();
i = i / SAGA_ISOTILEDATA_LEN;
_tilesTable.resize(i);
-
+ Common::Array<size_t> tempOffsets;
+ tempOffsets.resize(_tilesTable.size());
readS.seek(0);
@@ -120,7 +126,7 @@ void IsoMap::loadImages(const byte *resourcePointer, size_t resourceLength) {
tileData = &_tilesTable[i];
tileData->height = readS.readByte();
tileData->attributes = readS.readSByte();
- tileData->offset = readS.readUint16();
+ tempOffsets[i] = readS.readUint16();
tileData->terrainMask = readS.readUint16();
tileData->FGDBGDAttr = readS.readByte();
readS.readByte(); //skip
@@ -128,26 +134,25 @@ void IsoMap::loadImages(const byte *resourcePointer, size_t resourceLength) {
offsetDiff = readS.pos();
- _tileDataLength = resourceLength - offsetDiff;
- _tileData = (byte*)malloc(_tileDataLength);
- memcpy(_tileData, resourcePointer + offsetDiff, _tileDataLength);
+ _tileData.resize(resourceData.size() - offsetDiff);
+ memcpy(_tileData.getBuffer(), resourceData.getBuffer() + offsetDiff, _tileData.size());
for (i = 0; i < _tilesTable.size(); i++) {
- _tilesTable[i].offset -= offsetDiff;
+ _tilesTable[i].tilePointer = _tileData.getBuffer() + tempOffsets[i] - offsetDiff;
}
}
-void IsoMap::loadPlatforms(const byte * resourcePointer, size_t resourceLength) {
+void IsoMap::loadPlatforms(const ByteArray &resourceData) {
TilePlatformData *tilePlatformData;
uint16 i, x, y;
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("IsoMap::loadPlatforms wrong resourceLength");
}
- MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian());
+ ByteArrayReadStreamEndian readS(resourceData, _vm->isBigEndian());
- i = resourceLength / SAGA_TILEPLATFORMDATA_LEN;
+ i = resourceData.size() / SAGA_TILEPLATFORMDATA_LEN;
_tilePlatformList.resize(i);
for (i = 0; i < _tilePlatformList.size(); i++) {
@@ -166,14 +171,14 @@ void IsoMap::loadPlatforms(const byte * resourcePointer, size_t resourceLength)
}
-void IsoMap::loadMap(const byte * resourcePointer, size_t resourceLength) {
+void IsoMap::loadMap(const ByteArray &resourceData) {
uint16 x, y;
- if (resourceLength != SAGA_TILEMAP_LEN) {
- error("IsoMap::loadMap wrong resourceLength");
+ if (resourceData.size() != SAGA_TILEMAP_LEN) {
+ error("IsoMap::loadMap wrong resource length %d", resourceData.size());
}
- MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian());
+ ByteArrayReadStreamEndian readS(resourceData, _vm->isBigEndian());
_tileMap.edgeType = readS.readByte();
readS.readByte(); //skip
@@ -185,16 +190,16 @@ void IsoMap::loadMap(const byte * resourcePointer, size_t resourceLength) {
}
-void IsoMap::loadMetaTiles(const byte * resourcePointer, size_t resourceLength) {
+void IsoMap::loadMetaTiles(const ByteArray &resourceData) {
MetaTileData *metaTileData;
uint16 i, j;
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("IsoMap::loadMetaTiles wrong resourceLength");
}
- MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian());
- i = resourceLength / SAGA_METATILEDATA_LEN;
+ ByteArrayReadStreamEndian readS(resourceData, _vm->isBigEndian());
+ i = resourceData.size() / SAGA_METATILEDATA_LEN;
_metaTileList.resize(i);
for (i = 0; i < _metaTileList.size(); i++) {
@@ -207,16 +212,16 @@ void IsoMap::loadMetaTiles(const byte * resourcePointer, size_t resourceLength)
}
}
-void IsoMap::loadMulti(const byte * resourcePointer, size_t resourceLength) {
+void IsoMap::loadMulti(const ByteArray &resourceData) {
MultiTileEntryData *multiTileEntryData;
uint16 i;
int16 offsetDiff;
- if (resourceLength < 2) {
+ if (resourceData.size() < 2) {
error("IsoMap::loadMetaTiles wrong resourceLength");
}
- MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian());
+ ByteArrayReadStreamEndian readS(resourceData, _vm->isBigEndian());
i = readS.readUint16();
_multiTable.resize(i);
@@ -240,26 +245,21 @@ void IsoMap::loadMulti(const byte * resourcePointer, size_t resourceLength) {
_multiTable[i].offset -= offsetDiff;
}
- _multiDataCount = (readS.size() - readS.pos()) / 2;
+ uint16 multiDataCount = (readS.size() - readS.pos()) / 2;
- _multiTableData = (int16 *)malloc(_multiDataCount * sizeof(*_multiTableData));
- for (i = 0; i < _multiDataCount; i++) {
+ _multiTableData.resize(multiDataCount);
+ for (i = 0; i < _multiTableData.size(); i++) {
_multiTableData[i] = readS.readSint16();
}
}
-void IsoMap::freeMem() {
+void IsoMap::clear() {
_tilesTable.clear();
_tilePlatformList.clear();
_metaTileList.clear();
_multiTable.clear();
-
- free(_tileData);
- _tileData = NULL;
-
- free(_multiTableData);
- _multiTableData = NULL;
- _multiDataCount = 0;
+ _tileData.clear();
+ _multiTableData.clear();
}
void IsoMap::adjustScroll(bool jump) {
@@ -344,12 +344,12 @@ int16 IsoMap::findMulti(int16 tileIndex, int16 absU, int16 absV, int16 absH) {
state = multiTileEntryData->currentState;
offset = (ru + state * multiTileEntryData->uSize) * multiTileEntryData->vSize + rv;
- offset *= sizeof(*_multiTableData);
+ offset *= sizeof(int16);
offset += multiTileEntryData->offset;
- if (offset + sizeof(*_multiTableData) - 1 >= _multiDataCount * sizeof(*_multiTableData)) {
+ if (offset + sizeof(int16) > _multiTableData.size() * sizeof(int16)) {
error("wrong multiTileEntryData->offset");
}
- tiles = (int16*)((byte*)_multiTableData + offset);
+ tiles = (int16*)((byte*)&_multiTableData.front() + offset);
tileIndex = *tiles;
if (tileIndex >= 256) {
warning("something terrible happened");
@@ -707,7 +707,7 @@ void IsoMap::drawTile(uint16 tileIndex, const Point &point, const Location *loca
return;
}
- tilePointer = _tileData + _tilesTable[tileIndex].offset;
+ tilePointer = _tilesTable[tileIndex].tilePointer;
height = _tilesTable[tileIndex].height;
if ((height <= 8) || (height > 64)) {
@@ -831,18 +831,30 @@ void IsoMap::drawTile(uint16 tileIndex, const Point &point, const Location *loca
widthCount += fgRunCount;
count = 0;
- while ((col < _tileClip.left) && (count < fgRunCount)) {
- count++;
- col++;
+ int colDiff = _tileClip.left - col;
+ if (colDiff > 0) {
+ if (colDiff > fgRunCount) {
+ colDiff = fgRunCount;
+ }
+ count = colDiff;
+ col += colDiff;
}
- while ((col < _tileClip.right) && (count < fgRunCount)) {
- assert(_vm->_gfx->getBackBufferPixels() <= (byte *)(drawPointer + count));
- assert((_vm->_gfx->getBackBufferPixels() + (_vm->getDisplayInfo().width *
- _vm->getDisplayInfo().height)) > (byte *)(drawPointer + count));
- drawPointer[count] = readPointer[count];
- count++;
- col++;
+
+ colDiff = _tileClip.right - col;
+ if (colDiff > 0) {
+ int countDiff = fgRunCount - count;
+ if (colDiff > countDiff) {
+ colDiff = countDiff;
+ }
+ if (colDiff > 0) {
+ byte *dst = (byte *)(drawPointer + count);
+ assert(_vm->_gfx->getBackBufferPixels() <= dst);
+ assert((_vm->_gfx->getBackBufferPixels() + (_vm->getDisplayInfo().width * _vm->getDisplayInfo().height)) >= (byte *)(dst + colDiff));
+ memcpy(dst, (readPointer + count), colDiff);
+ col += colDiff;
+ }
}
+
readPointer += fgRunCount;
drawPointer += fgRunCount;
}
@@ -1149,8 +1161,6 @@ void IsoMap::placeOnTileMap(const Location &start, Location &result, int16 dista
int16 vBase;
int16 u;
int16 v;
- int i;
- ActorData *actor;
TilePoint tilePoint;
uint16 dir;
int16 dist;
@@ -1171,8 +1181,7 @@ void IsoMap::placeOnTileMap(const Location &start, Location &result, int16 dista
memset( &_searchArray, 0, sizeof(_searchArray));
- for (i = 0; i < _vm->_actor->_actorsCount; i++) {
- actor = _vm->_actor->_actors[i];
+ for (ActorDataArray::const_iterator actor = _vm->_actor->_actors.begin(); actor != _vm->_actor->_actors.end(); ++actor) {
if (!actor->_inScene) continue;
u = (actor->_location.u() >> 4) - uBase;
@@ -1452,14 +1461,13 @@ void IsoMap::findDragonTilePath(ActorData* actor,const Location &start, const Lo
actor->_walkStepsCount = i;
if (i) {
- actor->setTileDirectionsSize(i, false);
- memcpy(actor->_tileDirections, res, i);
+ actor->_tileDirections.resize(i);
+ memcpy(&actor->_tileDirections.front(), res, i);
}
}
void IsoMap::findTilePath(ActorData* actor, const Location &start, const Location &end) {
- ActorData *other;
int i;
int16 u;
int16 v;
@@ -1499,10 +1507,9 @@ void IsoMap::findTilePath(ActorData* actor, const Location &start, const Locatio
if (!(actor->_actorFlags & kActorNoCollide) &&
(_vm->_scene->currentSceneResourceId() != ITE_SCENE_OVERMAP)) {
- for (i = 0; i < _vm->_actor->_actorsCount; i++) {
- other = _vm->_actor->_actors[i];
+ for (ActorDataArray::const_iterator other = _vm->_actor->_actors.begin(); other != _vm->_actor->_actors.end(); ++other) {
if (!other->_inScene) continue;
- if (other == actor) continue;
+ if (other->_id == actor->_id) continue;
u = (other->_location.u() >> 4) - uBase;
v = (other->_location.v() >> 4) - vBase;
@@ -1585,8 +1592,8 @@ void IsoMap::findTilePath(ActorData* actor, const Location &start, const Locatio
actor->_walkStepsCount = i;
if (i) {
- actor->setTileDirectionsSize(i, false);
- memcpy(actor->_tileDirections, res, i);
+ actor->_tileDirections.resize(i);
+ memcpy(&actor->_tileDirections.front(), res, i);
}
}
@@ -1601,19 +1608,6 @@ void IsoMap::setTileDoorState(int doorNumber, int doorState) {
multiTileEntryData->currentState = doorState;
}
-static const int16 directions[8][2] = {
- { 16, 16},
- { 16, 0},
- { 16, -16},
- { 0, -16},
- { -16, -16},
- { -16, 0},
- { -16, 16},
- { 0, 16}
-};
-
-
-
bool IsoMap::nextTileTarget(ActorData* actor) {
uint16 dir;
diff --git a/engines/saga/isomap.h b/engines/saga/isomap.h
index 46173e2b13..7dc7dff8cd 100644
--- a/engines/saga/isomap.h
+++ b/engines/saga/isomap.h
@@ -95,7 +95,7 @@ enum TileMapEdgeType {
struct IsoTileData {
byte height;
int8 attributes;
- size_t offset;
+ byte *tilePointer;
uint16 terrainMask;
byte FGDBGDAttr;
int8 GetMaskRule() const {
@@ -154,14 +154,13 @@ class IsoMap {
public:
IsoMap(SagaEngine *vm);
~IsoMap() {
- freeMem();
}
- void loadImages(const byte * resourcePointer, size_t resourceLength);
- void loadMap(const byte * resourcePointer, size_t resourceLength);
- void loadPlatforms(const byte * resourcePointer, size_t resourceLength);
- void loadMetaTiles(const byte * resourcePointer, size_t resourceLength);
- void loadMulti(const byte * resourcePointer, size_t resourceLength);
- void freeMem();
+ void loadImages(const ByteArray &resourceData);
+ void loadMap(const ByteArray &resourceData);
+ void loadPlatforms(const ByteArray &resourceData);
+ void loadMetaTiles(const ByteArray &resourceData);
+ void loadMulti(const ByteArray &resourceData);
+ void clear();
void draw();
void drawSprite(SpriteList &spriteList, int spriteNumber, const Location &location, const Point &screenPosition, int scale);
void adjustScroll(bool jump);
@@ -213,16 +212,14 @@ private:
IsoTileData *getTile(int16 u, int16 v, int16 z);
- byte *_tileData;
- size_t _tileDataLength;
+ ByteArray _tileData;
Common::Array<IsoTileData> _tilesTable;
Common::Array<TilePlatformData> _tilePlatformList;
Common::Array<MetaTileData> _metaTileList;
Common::Array<MultiTileEntryData> _multiTable;
- uint16 _multiDataCount;
- int16 *_multiTableData;
+ Common::Array<int16> _multiTableData;
TileMapData _tileMap;
diff --git a/engines/saga/itedata.cpp b/engines/saga/itedata.cpp
index 7503818319..ab0aa12d18 100644
--- a/engines/saga/itedata.cpp
+++ b/engines/saga/itedata.cpp
@@ -269,7 +269,7 @@ ObjectTableData ITE_ObjectTable[ITE_OBJECTCOUNT] = {
{ 54, 281, 620, 352, 0, 80, 46, 0 } // Orb of Storms in Dam Lab
};
-FxTable ITE_SfxTable[ITE_SFXCOUNT] = {
+IteFxTable ITE_SfxTable[ITE_SFXCOUNT] = {
{ 14, 127 }, // Door open
{ 15, 127 }, // Door close
{ 16, 63 }, // Rush water (floppy volume: 127)
diff --git a/engines/saga/itedata.h b/engines/saga/itedata.h
index 71041902bc..f0f626a51a 100644
--- a/engines/saga/itedata.h
+++ b/engines/saga/itedata.h
@@ -77,16 +77,16 @@ struct ObjectTableData {
uint16 interactBits;
};
-struct FxTable {
- int res;
- int vol;
+struct IteFxTable {
+ byte res;
+ byte vol;
};
#define ITE_OBJECTCOUNT 39
#define ITE_SFXCOUNT 63
extern ObjectTableData ITE_ObjectTable[ITE_OBJECTCOUNT];
-extern FxTable ITE_SfxTable[ITE_SFXCOUNT];
+extern IteFxTable ITE_SfxTable[ITE_SFXCOUNT];
extern const char *ITEinterfaceTextStrings[][53];
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index 199b0dfd8a..f1cdcbce46 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -117,6 +117,7 @@ void MusicDriver::send(uint32 b) {
Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
_currentVolume = 0;
+ _currentMusicBuffer = NULL;
_driver = new MusicDriver();
_digitalMusicContext = _vm->_resource->getContext(GAME_DIGITALMUSICFILE);
@@ -162,11 +163,13 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
// Just set an XMIDI parser for Mac IHNM for now
_parser = MidiParser::createParser_XMIDI();
} else {
- byte *resourceData;
- size_t resourceSize;
+ ByteArray resourceData;
int resourceId = (_vm->getGameId() == GID_ITE ? 9 : 0);
- _vm->_resource->loadResource(_musicContext, resourceId, resourceData, resourceSize);
- if (!memcmp(resourceData, "FORM", 4)) {
+ _vm->_resource->loadResource(_musicContext, resourceId, resourceData);
+ if (resourceData.size() < 4) {
+ error("Music::Music Unable to load midi resource data");
+ }
+ if (!memcmp(resourceData.getBuffer(), "FORM", 4)) {
_parser = MidiParser::createParser_XMIDI();
// ITE had MT32 mapped instruments
_driver->setGM(_vm->getGameId() != GID_ITE);
@@ -175,17 +178,12 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
// ITE with standalone MIDI files is General MIDI
_driver->setGM(_vm->getGameId() == GID_ITE);
}
- free(resourceData);
}
-
+
_parser->setMidiDriver(_driver);
_parser->setTimerRate(_driver->getBaseTempo());
_parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
- _songTableLen = 0;
- _songTable = 0;
-
- _midiMusicData = NULL;
_digitalMusic = false;
}
@@ -196,9 +194,6 @@ Music::~Music() {
delete _driver;
_parser->setMidiDriver(NULL);
delete _parser;
-
- free(_songTable);
- free(_midiMusicData);
}
void Music::musicVolumeGaugeCallback(void *refCon) {
@@ -258,9 +253,7 @@ bool Music::isPlaying() {
void Music::play(uint32 resourceId, MusicFlags flags) {
Audio::SeekableAudioStream *audioStream = NULL;
- byte *resourceData;
- size_t resourceSize;
- uint32 loopStart;
+ uint32 loopStart = 0;
debug(2, "Music::play %d, %d", resourceId, flags);
@@ -392,14 +385,19 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
#endif
return;
} else {
- _vm->_resource->loadResource(_musicContext, resourceId, resourceData, resourceSize);
+ if (_currentMusicBuffer == &_musicBuffer[1]) {
+ _currentMusicBuffer = &_musicBuffer[0];
+ } else {
+ _currentMusicBuffer = &_musicBuffer[1];
+ }
+ _vm->_resource->loadResource(_musicContext, resourceId, *_currentMusicBuffer);
}
- if (resourceSize < 4) {
+ if (_currentMusicBuffer->size() < 4) {
error("Music::play() wrong music resource size");
}
- if (!_parser->loadMusic(resourceData, resourceSize))
+ if (!_parser->loadMusic(_currentMusicBuffer->getBuffer(), _currentMusicBuffer->size()))
error("Music::play() wrong music resource");
_parser->setTrack(0);
@@ -409,9 +407,6 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
// Handle music looping
_parser->property(MidiParser::mpAutoLoop, (flags & MUSIC_LOOP) ? 1 : 0);
-
- free(_midiMusicData);
- _midiMusicData = resourceData;
}
void Music::pause() {
diff --git a/engines/saga/music.h b/engines/saga/music.h
index 470b6e18b3..c7fef7225b 100644
--- a/engines/saga/music.h
+++ b/engines/saga/music.h
@@ -28,9 +28,9 @@
#ifndef SAGA_MUSIC_H
#define SAGA_MUSIC_H
-#include "sound/mixer.h"
#include "sound/mididrv.h"
#include "sound/midiparser.h"
+#include "sound/mixer.h"
#include "sound/decoders/mp3.h"
#include "sound/decoders/vorbis.h"
#include "sound/decoders/flac.h"
@@ -106,8 +106,7 @@ public:
void setVolume(int volume, int time = 1);
int getVolume() { return _currentVolume; }
- int32 *_songTable;
- int _songTableLen;
+ Common::Array<int32> _songTable;
private:
SagaEngine *_vm;
@@ -126,11 +125,12 @@ private:
ResourceContext *_digitalMusicContext;
MidiParser *_parser;
- byte *_midiMusicData;
static void musicVolumeGaugeCallback(void *refCon);
static void onTimer(void *refCon);
void musicVolumeGauge();
+ ByteArray *_currentMusicBuffer;
+ ByteArray _musicBuffer[2];
};
} // End of namespace Saga
diff --git a/engines/saga/objectmap.cpp b/engines/saga/objectmap.cpp
index 02179d1d49..61d90cda69 100644
--- a/engines/saga/objectmap.cpp
+++ b/engines/saga/objectmap.cpp
@@ -45,84 +45,58 @@
namespace Saga {
-HitZone::HitZone(MemoryReadStreamEndian *readStream, int index, int sceneNumber): _index(index) {
- int i, j;
- HitZone::ClickArea *clickArea;
- Point *point;
-
+void HitZone::load(SagaEngine *vm, MemoryReadStreamEndian *readStream, int index, int sceneNumber) {
+ _index = index;
_flags = readStream->readByte();
- _clickAreasCount = readStream->readByte();
+ _clickAreas.resize(readStream->readByte());
_rightButtonVerb = readStream->readByte();
readStream->readByte(); // pad
_nameIndex = readStream->readUint16();
_scriptNumber = readStream->readUint16();
- _clickAreas = (HitZone::ClickArea *)malloc(_clickAreasCount * sizeof(*_clickAreas));
-
- if (_clickAreas == NULL) {
- memoryError("HitZone::HitZone");
- }
-
- for (i = 0; i < _clickAreasCount; i++) {
- clickArea = &_clickAreas[i];
- clickArea->pointsCount = readStream->readUint16LE();
+ for (ClickAreas::iterator i = _clickAreas.begin(); i != _clickAreas.end(); ++i) {
+ i->resize(readStream->readUint16LE());
- assert(clickArea->pointsCount);
+ assert(!i->empty());
- clickArea->points = (Point *)malloc(clickArea->pointsCount * sizeof(*(clickArea->points)));
- if (clickArea->points == NULL) {
- memoryError("HitZone::HitZone");
- }
-
- for (j = 0; j < clickArea->pointsCount; j++) {
- point = &clickArea->points[j];
- point->x = readStream->readSint16();
- point->y = readStream->readSint16();
+ for (ClickArea::iterator j = i->begin(); j != i->end(); ++j) {
+ j->x = readStream->readSint16();
+ j->y = readStream->readSint16();
// WORKAROUND: bug #1259608: "ITE: Riff ignores command in Ferret merchant center"
// Apparently ITE Mac version has bug in game data. Both ObjectMap and ActionMap
// for exit area are little taller (y = 123) and thus Riff goes to exit
// when clicked on barrel of nails.
- if (sceneNumber == 18 && index == 0 && i == 0 && j == 0 && point->y == 123)
- point->y = 129;
+ if (vm->getGameId() == GID_ITE) {
+ if (sceneNumber == 18 && index == 0 && (i == _clickAreas.begin()) && (j == i->begin()) && j->y == 123) {
+ j->y = 129;
+ }
+ }
}
}
}
-HitZone::~HitZone() {
- for (int i = 0; i < _clickAreasCount; i++) {
- free(_clickAreas[i].points);
- }
- free(_clickAreas);
-}
-
bool HitZone::getSpecialPoint(Point &specialPoint) const {
- int i, pointsCount;
- HitZone::ClickArea *clickArea;
- Point *points;
-
- for (i = 0; i < _clickAreasCount; i++) {
- clickArea = &_clickAreas[i];
- pointsCount = clickArea->pointsCount;
- points = clickArea->points;
- if (pointsCount == 1) {
- specialPoint = points[0];
+ for (ClickAreas::const_iterator i = _clickAreas.begin(); i != _clickAreas.end(); ++i) {
+ if (i->size() == 1) {
+ specialPoint = (*i)[0];
return true;
}
}
return false;
}
+
bool HitZone::hitTest(const Point &testPoint) {
- int i, pointsCount;
- HitZone::ClickArea *clickArea;
- Point *points;
+ const Point *points;
+ uint pointsCount;
if (_flags & kHitZoneEnabled) {
- for (i = 0; i < _clickAreasCount; i++) {
- clickArea = &_clickAreas[i];
- pointsCount = clickArea->pointsCount;
- points = clickArea->points;
-
+ for (ClickAreas::const_iterator i = _clickAreas.begin(); i != _clickAreas.end(); ++i) {
+ pointsCount = i->size();
+ if (pointsCount < 2) {
+ continue;
+ }
+ points = &i->front();
if (pointsCount == 2) {
// Hit-test a box region
if ((testPoint.x >= points[0].x) &&
@@ -132,11 +106,9 @@ bool HitZone::hitTest(const Point &testPoint) {
return true;
}
} else {
- if (pointsCount > 2) {
- // Hit-test a polygon
- if (hitTestPoly(points, pointsCount, testPoint)) {
- return true;
- }
+ // Hit-test a polygon
+ if (hitTestPoly(points, pointsCount, testPoint)) {
+ return true;
}
}
}
@@ -146,26 +118,25 @@ bool HitZone::hitTest(const Point &testPoint) {
#ifdef SAGA_DEBUG
void HitZone::draw(SagaEngine *vm, int color) {
- int i, pointsCount, j;
+ int pointsCount, j;
Location location;
- HitZone::ClickArea *clickArea;
- Point *points;
+ HitZone::ClickArea tmpPoints;
+ const Point *points;
Point specialPoint1;
Point specialPoint2;
- for (i = 0; i < _clickAreasCount; i++) {
- clickArea = &_clickAreas[i];
- pointsCount = clickArea->pointsCount;
+ for (ClickAreas::const_iterator i = _clickAreas.begin(); i != _clickAreas.end(); ++i) {
+ pointsCount = i->size();
+ points = &i->front();
if (vm->_scene->getFlags() & kSceneFlagISO) {
- points = (Point*)malloc(sizeof(Point) * pointsCount);
+ tmpPoints.resize(pointsCount);
for (j = 0; j < pointsCount; j++) {
- location.u() = clickArea->points[j].x;
- location.v() = clickArea->points[j].y;
+ location.u() = points[j].x;
+ location.v() = points[j].y;
location.z = 0;
- vm->_isoMap->tileCoordsToScreenPoint(location, points[j]);
+ vm->_isoMap->tileCoordsToScreenPoint(location, tmpPoints[j]);
}
- } else {
- points = clickArea->points;
+ points = &tmpPoints.front();
}
if (pointsCount == 2) {
@@ -179,10 +150,6 @@ void HitZone::draw(SagaEngine *vm, int color) {
vm->_gfx->drawPolyLine(points, pointsCount, color);
}
}
- if (vm->_scene->getFlags() & kSceneFlagISO) {
- free(points);
- }
-
}
if (getSpecialPoint(specialPoint1)) {
specialPoint2 = specialPoint1;
@@ -196,55 +163,36 @@ void HitZone::draw(SagaEngine *vm, int color) {
#endif
// Loads an object map resource ( objects ( clickareas ( points ) ) )
-void ObjectMap::load(const byte *resourcePointer, size_t resourceLength) {
- int i;
+void ObjectMap::load(const ByteArray &resourceData) {
- if (resourceLength == 0) {
- return;
+ if (!_hitZoneList.empty()) {
+ error("ObjectMap::load _hitZoneList not empty");
}
- if (resourceLength < 4) {
- error("ObjectMap::load wrong resourceLength");
+ if (resourceData.empty()) {
+ return;
}
- MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian());
-
- _hitZoneListCount = readS.readSint16();
- if (_hitZoneListCount < 0) {
- error("ObjectMap::load _hitZoneListCount < 0");
+ if (resourceData.size() < 4) {
+ error("ObjectMap::load wrong resourceLength");
}
- if (_hitZoneList)
- error("ObjectMap::load _hitZoneList != NULL");
+ ByteArrayReadStreamEndian readS(resourceData, _vm->isBigEndian());
- _hitZoneList = (HitZone **) malloc(_hitZoneListCount * sizeof(HitZone *));
- if (_hitZoneList == NULL) {
- memoryError("ObjectMap::load");
- }
+ _hitZoneList.resize(readS.readUint16());
- for (i = 0; i < _hitZoneListCount; i++) {
- _hitZoneList[i] = new HitZone(&readS, i, _vm->_scene->currentSceneNumber());
+ int idx = 0;
+ for (HitZoneArray::iterator i = _hitZoneList.begin(); i != _hitZoneList.end(); ++i) {
+ i->load(_vm, &readS, idx++, _vm->_scene->currentSceneNumber());
}
}
-void ObjectMap::freeMem() {
- int i;
-
- if (_hitZoneList) {
- for (i = 0; i < _hitZoneListCount; i++) {
- delete _hitZoneList[i];
- }
-
- free(_hitZoneList);
- _hitZoneList = NULL;
- }
- _hitZoneListCount = 0;
+void ObjectMap::clear() {
+ _hitZoneList.clear();
}
-
#ifdef SAGA_DEBUG
void ObjectMap::draw(const Point& testPoint, int color, int color2) {
- int i;
int hitZoneIndex;
char txtBuf[32];
Point pickPoint;
@@ -260,8 +208,8 @@ void ObjectMap::draw(const Point& testPoint, int color, int color2) {
hitZoneIndex = hitTest(pickPoint);
- for (i = 0; i < _hitZoneListCount; i++) {
- _hitZoneList[i]->draw(_vm, (hitZoneIndex == i) ? color2 : color);
+ for (HitZoneArray::iterator i = _hitZoneList.begin(); i != _hitZoneList.end(); ++i) {
+ i->draw(_vm, (hitZoneIndex == i->getIndex()) ? color2 : color);
}
if (hitZoneIndex != -1) {
@@ -274,12 +222,11 @@ void ObjectMap::draw(const Point& testPoint, int color, int color2) {
#endif
int ObjectMap::hitTest(const Point& testPoint) {
- int i;
// Loop through all scene objects
- for (i = 0; i < _hitZoneListCount; i++) {
- if (_hitZoneList[i]->hitTest(testPoint)) {
- return i;
+ for (HitZoneArray::iterator i = _hitZoneList.begin(); i != _hitZoneList.end(); ++i) {
+ if (i->hitTest(testPoint)) {
+ return i->getIndex();
}
}
@@ -287,7 +234,7 @@ int ObjectMap::hitTest(const Point& testPoint) {
}
void ObjectMap::cmdInfo() {
- _vm->_console->DebugPrintf("%d zone(s) loaded.\n\n", _hitZoneListCount);
+ _vm->_console->DebugPrintf("%d zone(s) loaded.\n\n", _hitZoneList.size());
}
} // End of namespace Saga
diff --git a/engines/saga/objectmap.h b/engines/saga/objectmap.h
index df0dcffe57..446afd478e 100644
--- a/engines/saga/objectmap.h
+++ b/engines/saga/objectmap.h
@@ -33,15 +33,14 @@ namespace Saga {
class HitZone {
private:
- struct ClickArea {
- int pointsCount;
- Point *points;
- };
-
+ typedef Common::Array<Point> ClickArea;
+ typedef Common::Array<ClickArea> ClickAreas;
public:
- HitZone(MemoryReadStreamEndian *readStream, int index, int sceneNumber);
- ~HitZone();
+ void load(SagaEngine *vm, MemoryReadStreamEndian *readStream, int index, int sceneNumber);
+ int getIndex() const {
+ return _index;
+ }
int getNameIndex() const {
return _nameIndex;
}
@@ -76,40 +75,38 @@ public:
return objectIndexToId(kGameObjectStepZone, _index);
}
bool getSpecialPoint(Point &specialPoint) const;
+#ifdef SAGA_DEBUG
void draw(SagaEngine *vm, int color); // for debugging
+#endif
bool hitTest(const Point &testPoint);
private:
int _flags; // Saga::HitZoneFlags
- int _clickAreasCount;
int _rightButtonVerb;
int _nameIndex;
int _scriptNumber;
int _index;
- ClickArea *_clickAreas;
+ ClickAreas _clickAreas;
};
+typedef Common::Array<HitZone> HitZoneArray;
class ObjectMap {
public:
ObjectMap(SagaEngine *vm) : _vm(vm) {
- _hitZoneList = NULL;
- _hitZoneListCount = 0;
-
- }
- ~ObjectMap() {
- freeMem();
}
- void load(const byte *resourcePointer, size_t resourceLength);
- void freeMem();
+ void load(const ByteArray &resourceData);
+ void clear();
+#ifdef SAGA_DEBUG
void draw(const Point& testPoint, int color, int color2); // for debugging
+#endif
int hitTest(const Point& testPoint);
HitZone *getHitZone(int16 index) {
- if ((index < 0) || (index >= _hitZoneListCount)) {
+ if (uint(index) >= _hitZoneList.size()) {
return NULL;
}
- return _hitZoneList[index];
+ return &_hitZoneList[index];
}
void cmdInfo();
@@ -117,8 +114,7 @@ public:
private:
SagaEngine *_vm;
- int _hitZoneListCount;
- HitZone **_hitZoneList;
+ HitZoneArray _hitZoneList;
};
} // End of namespace Saga
diff --git a/engines/saga/palanim.cpp b/engines/saga/palanim.cpp
index dc892b845a..b0b76fc947 100644
--- a/engines/saga/palanim.cpp
+++ b/engines/saga/palanim.cpp
@@ -35,126 +35,95 @@
namespace Saga {
PalAnim::PalAnim(SagaEngine *vm) : _vm(vm) {
- _loaded = false;
- _entryCount = 0;
- _entries = NULL;
}
-PalAnim::~PalAnim() {
-}
-
-int PalAnim::loadPalAnim(const byte *resdata, size_t resdata_len) {
- void *test_p;
+void PalAnim::loadPalAnim(const ByteArray &resourceData) {
- uint16 i;
+ clear();
- if (_loaded) {
- freePalAnim();
+ if (resourceData.empty()) {
+ return;
}
- if (resdata == NULL) {
- return FAILURE;
- }
-
- MemoryReadStreamEndian readS(resdata, resdata_len, _vm->isBigEndian());
+ ByteArrayReadStreamEndian readS(resourceData, _vm->isBigEndian());
if (_vm->getGameId() == GID_IHNM) {
- return SUCCESS;
+ return;
}
- _entryCount = readS.readUint16();
-
- debug(3, "PalAnim::loadPalAnim(): Loading %d PALANIM entries.", _entryCount);
+ _entries.resize(readS.readUint16());
- test_p = malloc(_entryCount * sizeof(PalanimEntry));
- _entries = (PalanimEntry *)test_p;
+ debug(3, "PalAnim::loadPalAnim(): Loading %d PALANIM entries.", _entries.size());
- for (i = 0; i < _entryCount; i++) {
- int color_count;
- int pal_count;
- int p, c;
+ for (Common::Array<PalanimEntry>::iterator i = _entries.begin(); i != _entries.end(); ++i) {
+
+ i->cycle = 0;
- _entries[i].cycle = 0;
+ i->colors.resize(readS.readUint16());
+ debug(2, "PalAnim::loadPalAnim(): Loading %d SAGA_COLOR structures.", i->colors.size());
- color_count = readS.readUint16();
- pal_count = readS.readUint16();
+ i->palIndex.resize(readS.readUint16());
+ debug(2, "PalAnim::loadPalAnim(): Loading %d palette indices.\n", i->palIndex.size());
- _entries[i].pal_count = pal_count;
- _entries[i].color_count = color_count;
- debug(2, "PalAnim::loadPalAnim(): Entry %d: Loading %d palette indices.\n", i, pal_count);
-
- test_p = malloc(sizeof(char) * pal_count);
- _entries[i].pal_index = (byte *)test_p;
-
- debug(2, "PalAnim::loadPalAnim(): Entry %d: Loading %d SAGA_COLOR structures.", i, color_count);
-
- test_p = malloc(sizeof(Color) * color_count);
- _entries[i].colors = (Color *)test_p;
-
- for (p = 0; p < pal_count; p++) {
- _entries[i].pal_index[p] = readS.readByte();
+ for (uint j = 0; j < i->palIndex.size(); j++) {
+ i->palIndex[j] = readS.readByte();
}
- for (c = 0; c < color_count; c++) {
- _entries[i].colors[c].red = readS.readByte();
- _entries[i].colors[c].green = readS.readByte();
- _entries[i].colors[c].blue = readS.readByte();
+ for (Common::Array<Color>::iterator j = i->colors.begin(); j != i->colors.end(); ++j) {
+ j->red = readS.readByte();
+ j->green = readS.readByte();
+ j->blue = readS.readByte();
}
}
-
- _loaded = true;
- return SUCCESS;
}
-int PalAnim::cycleStart() {
+void PalAnim::cycleStart() {
Event event;
- if (!_loaded) {
- return FAILURE;
+ if (_entries.empty()) {
+ return;
}
event.type = kEvTOneshot;
event.code = kPalAnimEvent;
event.op = kEventCycleStep;
event.time = PALANIM_CYCLETIME;
- _vm->_events->queue(&event);
-
- return SUCCESS;
+ _vm->_events->queue(event);
}
-int PalAnim::cycleStep(int vectortime) {
+void PalAnim::cycleStep(int vectortime) {
static PalEntry pal[256];
- uint16 pal_index;
- uint16 col_index;
+ uint16 palIndex;
+ uint16 colIndex;
- uint16 i, j;
+ uint16 j;
uint16 cycle;
- uint16 cycle_limit;
+ uint16 cycleLimit;
Event event;
- if (!_loaded) {
- return FAILURE;
+ if (_entries.empty()) {
+ return;
}
_vm->_gfx->getCurrentPal(pal);
- for (i = 0; i < _entryCount; i++) {
- cycle = _entries[i].cycle;
- cycle_limit = _entries[i].color_count;
- for (j = 0; j < _entries[i].pal_count; j++) {
- pal_index = (unsigned char)_entries[i].pal_index[j];
- col_index = (cycle + j) % cycle_limit;
- pal[pal_index].red = (byte) _entries[i].colors[col_index].red;
- pal[pal_index].green = (byte) _entries[i].colors[col_index].green;
- pal[pal_index].blue = (byte) _entries[i].colors[col_index].blue;
+ for (Common::Array<PalanimEntry>::iterator i = _entries.begin(); i != _entries.end(); ++i) {
+ cycle = i->cycle;
+ cycleLimit = i->colors.size();
+ for (j = 0; j < i->palIndex.size(); j++) {
+ palIndex = i->palIndex[j];
+ colIndex = (cycle + j) % cycleLimit;
+ pal[palIndex].red = (byte) i->colors[colIndex].red;
+ pal[palIndex].green = (byte) i->colors[colIndex].green;
+ pal[palIndex].blue = (byte) i->colors[colIndex].blue;
}
- _entries[i].cycle++;
+ i->cycle++;
- if (_entries[i].cycle == cycle_limit) {
- _entries[i].cycle = 0;
+ if (i->cycle == cycleLimit) {
+ i->cycle = 0;
}
}
@@ -167,32 +136,14 @@ int PalAnim::cycleStep(int vectortime) {
event.code = kPalAnimEvent;
event.op = kEventCycleStep;
event.time = vectortime + PALANIM_CYCLETIME;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
- return SUCCESS;
}
-int PalAnim::freePalAnim() {
- uint16 i;
-
- if (!_loaded) {
- return FAILURE;
- }
-
- for (i = 0; i < _entryCount; i++) {
- debug(2, "PalAnim::freePalAnim(): Entry %d: Freeing colors.", i);
- free(_entries[i].colors);
- debug(2, "PalAnim::freePalAnim(): Entry %d: Freeing indices.", i);
- free(_entries[i].pal_index);
- }
-
- debug(3, "PalAnim::freePalAnim(): Freeing entries.");
-
- free(_entries);
-
- _loaded = false;
-
- return SUCCESS;
+void PalAnim::clear() {
+ debug(3, "PalAnim::clear()");
+
+ _entries.clear();
}
} // End of namespace Saga
diff --git a/engines/saga/palanim.h b/engines/saga/palanim.h
index 52002e01c3..2d2c3f1399 100644
--- a/engines/saga/palanim.h
+++ b/engines/saga/palanim.h
@@ -33,29 +33,24 @@ namespace Saga {
#define PALANIM_CYCLETIME 100
struct PalanimEntry {
- uint16 pal_count;
- uint16 color_count;
uint16 cycle;
- byte *pal_index;
- Color *colors;
+ ByteArray palIndex;
+ Common::Array<Color> colors;
};
class PalAnim {
public:
PalAnim(SagaEngine *vm);
- ~PalAnim();
- int loadPalAnim(const byte *, size_t);
- int cycleStart();
- int cycleStep(int vectortime);
- int freePalAnim();
+ void loadPalAnim(const ByteArray &resourceData);
+ void cycleStart();
+ void cycleStep(int vectortime);
+ void clear();
private:
SagaEngine *_vm;
- bool _loaded;
- uint16 _entryCount;
- PalanimEntry *_entries;
+ Common::Array<PalanimEntry> _entries;
};
} // End of namespace Saga
diff --git a/engines/saga/puzzle.cpp b/engines/saga/puzzle.cpp
index 73839eb6ea..af81c3c670 100644
--- a/engines/saga/puzzle.cpp
+++ b/engines/saga/puzzle.cpp
@@ -172,7 +172,7 @@ void Puzzle::initPieces() {
_vm->_actor->getSpriteParams(puzzle, frameNumber, spriteList);
for (int i = 0; i < PUZZLE_PIECES; i++) {
- spI = &(spriteList->infoList[i]);
+ spI = &((*spriteList)[i]);
_pieceInfo[i].offX = (byte)(spI->width >> 1);
_pieceInfo[i].offY = (byte)(spI->height >> 1);
@@ -347,7 +347,7 @@ void Puzzle::dropPiece(Point mousePt) {
if (newy < boxy)
newy = PUZZLE_Y_OFFSET;
- spI = &(spriteList->infoList[_puzzlePiece]);
+ spI = &((*spriteList)[_puzzlePiece]);
if (newx + spI->width > boxw)
newx = boxw - spI->width ;
diff --git a/engines/saga/resource.cpp b/engines/saga/resource.cpp
index 7d82aa4bda..0fb7327f0d 100644
--- a/engines/saga/resource.cpp
+++ b/engines/saga/resource.cpp
@@ -43,8 +43,7 @@ bool ResourceContext::loadResV1(uint32 contextOffset, uint32 contextSize) {
size_t i;
bool result;
byte tableInfo[RSC_TABLEINFO_SIZE];
- byte *tableBuffer;
- size_t tableSize;
+ ByteArray tableBuffer;
uint32 count;
uint32 resourceTableOffset;
ResourceData *resourceData;
@@ -70,17 +69,15 @@ bool ResourceContext::loadResV1(uint32 contextOffset, uint32 contextSize) {
}
// Load resource table
- tableSize = RSC_TABLEENTRY_SIZE * count;
-
- tableBuffer = (byte *)malloc(tableSize);
+ tableBuffer.resize(RSC_TABLEENTRY_SIZE * count);
_file.seek(resourceTableOffset + contextOffset, SEEK_SET);
- result = (_file.read(tableBuffer, tableSize) == tableSize);
+ result = (_file.read(tableBuffer.getBuffer(), tableBuffer.size()) == tableBuffer.size());
if (result) {
_table.resize(count);
- MemoryReadStreamEndian readS1(tableBuffer, tableSize, _isBigEndian);
+ MemoryReadStreamEndian readS1(tableBuffer.getBuffer(), tableBuffer.size(), _isBigEndian);
for (i = 0; i < count; i++) {
resourceData = &_table[i];
@@ -94,7 +91,6 @@ bool ResourceContext::loadResV1(uint32 contextOffset, uint32 contextSize) {
}
}
- free(tableBuffer);
return result;
}
@@ -107,8 +103,6 @@ bool ResourceContext::load(SagaEngine *vm, Resource *resource) {
uint32 subjectResourceId;
uint32 patchResourceId;
ResourceData *subjectResourceData;
- byte *tableBuffer;
- size_t tableSize;
bool isMacBinary;
if (_fileName == NULL) { // IHNM special case
@@ -145,10 +139,12 @@ bool ResourceContext::load(SagaEngine *vm, Resource *resource) {
if (subjectContext == NULL) {
error("ResourceContext::load() Subject context not found");
}
- resource->loadResource(this, _table.size() - 1, tableBuffer, tableSize);
+ ByteArray tableBuffer;
+
+ resource->loadResource(this, _table.size() - 1, tableBuffer);
- MemoryReadStreamEndian readS2(tableBuffer, tableSize, _isBigEndian);
- for (i = 0; i < tableSize / 8; i++) {
+ ByteArrayReadStreamEndian readS2(tableBuffer, _isBigEndian);
+ for (i = 0; i < tableBuffer.size() / 8; i++) {
subjectResourceId = readS2.readUint32();
patchResourceId = readS2.readUint32();
subjectResourceData = subjectContext->getResourceData(subjectResourceId);
@@ -157,7 +153,6 @@ bool ResourceContext::load(SagaEngine *vm, Resource *resource) {
subjectResourceData->offset = resourceData->offset;
subjectResourceData->size = resourceData->size;
}
- free(tableBuffer);
}
//process external patch files
@@ -370,25 +365,25 @@ void Resource::clearContexts() {
}
}
-void Resource::loadResource(ResourceContext *context, uint32 resourceId, byte*&resourceBuffer, size_t &resourceSize) {
+void Resource::loadResource(ResourceContext *context, uint32 resourceId, ByteArray &resourceBuffer) {
Common::File *file;
uint32 resourceOffset;
ResourceData *resourceData;
- debug(8, "loadResource %d", resourceId);
resourceData = context->getResourceData(resourceId);
file = context->getFile(resourceData);
resourceOffset = resourceData->offset;
- resourceSize = resourceData->size;
- resourceBuffer = (byte*)malloc(resourceSize);
+ debug(8, "loadResource %d 0x%X:0x%X", resourceId, resourceOffset, uint(resourceData->size));
+ resourceBuffer.resize(resourceData->size);
+
file->seek((long)resourceOffset, SEEK_SET);
- if (file->read(resourceBuffer, resourceSize) != resourceSize) {
+ if (file->read(resourceBuffer.getBuffer(), resourceBuffer.size()) != resourceBuffer.size()) {
error("Resource::loadResource() failed to read");
}
diff --git a/engines/saga/resource.h b/engines/saga/resource.h
index e32d16c469..5009c862f4 100644
--- a/engines/saga/resource.h
+++ b/engines/saga/resource.h
@@ -206,7 +206,7 @@ public:
virtual ~Resource();
bool createContexts();
void clearContexts();
- void loadResource(ResourceContext *context, uint32 resourceId, byte*&resourceBuffer, size_t &resourceSize);
+ void loadResource(ResourceContext *context, uint32 resourceId, ByteArray &resourceBuffer);
virtual uint32 convertResourceId(uint32 resourceId) = 0;
virtual void loadGlobalResources(int chapter, int actorsEntrance) = 0;
diff --git a/engines/saga/resource_res.cpp b/engines/saga/resource_res.cpp
index 8546030241..646de8667b 100644
--- a/engines/saga/resource_res.cpp
+++ b/engines/saga/resource_res.cpp
@@ -48,13 +48,13 @@ void Resource_RES::loadGlobalResources(int chapter, int actorsEntrance) {
if (chapter < 0)
chapter = !_vm->isIHNMDemo() ? 8 : 7;
- _vm->_script->_globalVoiceLUT.freeMem();
+ _vm->_script->_globalVoiceLUT.clear();
// TODO: close chapter context, or rather reassign it in our case
ResourceContext *resourceContext;
ResourceContext *soundContext;
- int i;
+ uint i;
resourceContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
if (resourceContext == NULL) {
@@ -66,41 +66,38 @@ void Resource_RES::loadGlobalResources(int chapter, int actorsEntrance) {
error("Resource::loadGlobalResources() sound context not found");
}
- byte *resourcePointer;
- size_t resourceLength;
+ ByteArray resourceData;
if (!_vm->isIHNMDemo()) {
- _vm->_resource->loadResource(resourceContext, metaResourceTable[chapter],
- resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, metaResourceTable[chapter], resourceData);
} else {
- _vm->_resource->loadResource(resourceContext, metaResourceTableDemo[chapter],
- resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, metaResourceTableDemo[chapter], resourceData);
}
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("Resource::loadGlobalResources wrong metaResource");
}
- MemoryReadStream metaS(resourcePointer, resourceLength);
-
- _metaResource.sceneIndex = metaS.readSint16LE();
- _metaResource.objectCount = metaS.readSint16LE();
- _metaResource.objectsStringsResourceID = metaS.readSint32LE();
- _metaResource.inventorySpritesID = metaS.readSint32LE();
- _metaResource.mainSpritesID = metaS.readSint32LE();
- _metaResource.objectsResourceID = metaS.readSint32LE();
- _metaResource.actorCount = metaS.readSint16LE();
- _metaResource.actorsStringsResourceID = metaS.readSint32LE();
- _metaResource.actorsResourceID = metaS.readSint32LE();
- _metaResource.protagFaceSpritesID = metaS.readSint32LE();
- _metaResource.field_22 = metaS.readSint32LE();
- _metaResource.field_26 = metaS.readSint16LE();
- _metaResource.protagStatesCount = metaS.readSint16LE();
- _metaResource.protagStatesResourceID = metaS.readSint32LE();
- _metaResource.cutawayListResourceID = metaS.readSint32LE();
- _metaResource.songTableID = metaS.readSint32LE();
-
- free(resourcePointer);
+ {
+ ByteArrayReadStreamEndian metaS(resourceData);
+
+ _metaResource.sceneIndex = metaS.readSint16LE();
+ _metaResource.objectCount = metaS.readSint16LE();
+ _metaResource.objectsStringsResourceID = metaS.readSint32LE();
+ _metaResource.inventorySpritesID = metaS.readSint32LE();
+ _metaResource.mainSpritesID = metaS.readSint32LE();
+ _metaResource.objectsResourceID = metaS.readSint32LE();
+ _metaResource.actorCount = metaS.readSint16LE();
+ _metaResource.actorsStringsResourceID = metaS.readSint32LE();
+ _metaResource.actorsResourceID = metaS.readSint32LE();
+ _metaResource.protagFaceSpritesID = metaS.readSint32LE();
+ _metaResource.field_22 = metaS.readSint32LE();
+ _metaResource.field_26 = metaS.readSint16LE();
+ _metaResource.protagStatesCount = metaS.readSint16LE();
+ _metaResource.protagStatesResourceID = metaS.readSint32LE();
+ _metaResource.cutawayListResourceID = metaS.readSint32LE();
+ _metaResource.songTableID = metaS.readSint32LE();
+ }
_vm->_actor->loadActorList(actorsEntrance, _metaResource.actorCount,
_metaResource.actorsResourceID, _metaResource.protagStatesCount,
@@ -108,90 +105,83 @@ void Resource_RES::loadGlobalResources(int chapter, int actorsEntrance) {
_vm->_actor->_protagonist->_sceneNumber = _metaResource.sceneIndex;
- _vm->_actor->_objectsStrings.freeMem();
+ _vm->_actor->_objectsStrings.clear();
- _vm->_resource->loadResource(resourceContext, _metaResource.objectsStringsResourceID, resourcePointer, resourceLength);
- _vm->loadStrings(_vm->_actor->_objectsStrings, resourcePointer, resourceLength);
- free(resourcePointer);
+ _vm->_resource->loadResource(resourceContext, _metaResource.objectsStringsResourceID, resourceData);
+ _vm->loadStrings(_vm->_actor->_objectsStrings, resourceData);
- if (chapter >= _vm->_sndRes->_fxTableIDsLen) {
+ if (uint(chapter) >= _vm->_sndRes->_fxTableIDs.size()) {
error("Chapter ID exceeds fxTableIDs length");
}
debug(0, "Going to read %d of %d", chapter, _vm->_sndRes->_fxTableIDs[chapter]);
_vm->_resource->loadResource(soundContext, _vm->_sndRes->_fxTableIDs[chapter],
- resourcePointer, resourceLength);
+ resourceData);
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("Resource::loadGlobalResources Can't load sound effects for current track");
}
- free(_vm->_sndRes->_fxTable);
-
- _vm->_sndRes->_fxTableLen = resourceLength / 4;
- _vm->_sndRes->_fxTable = (FxTable *)malloc(sizeof(FxTable) * _vm->_sndRes->_fxTableLen);
+ _vm->_sndRes->_fxTable.resize(resourceData.size() / 4);
- MemoryReadStream fxS(resourcePointer, resourceLength);
+ {
+ ByteArrayReadStreamEndian fxS(resourceData);
- for (i = 0; i < _vm->_sndRes->_fxTableLen; i++) {
- _vm->_sndRes->_fxTable[i].res = fxS.readSint16LE();
- _vm->_sndRes->_fxTable[i].vol = fxS.readSint16LE();
+ for (i = 0; i < _vm->_sndRes->_fxTable.size(); i++) {
+ _vm->_sndRes->_fxTable[i].res = fxS.readSint16LE();
+ _vm->_sndRes->_fxTable[i].vol = fxS.readSint16LE();
+ }
}
- free(resourcePointer);
- _vm->_interface->_defPortraits.freeMem();
+ _vm->_interface->_defPortraits.clear();
_vm->_sprite->loadList(_metaResource.protagFaceSpritesID, _vm->_interface->_defPortraits);
- _vm->_actor->_actorsStrings.freeMem();
+ _vm->_actor->_actorsStrings.clear();
- _vm->_resource->loadResource(resourceContext, _metaResource.actorsStringsResourceID, resourcePointer, resourceLength);
- _vm->loadStrings(_vm->_actor->_actorsStrings, resourcePointer, resourceLength);
- free(resourcePointer);
+ _vm->_resource->loadResource(resourceContext, _metaResource.actorsStringsResourceID, resourceData);
+ _vm->loadStrings(_vm->_actor->_actorsStrings, resourceData);
- _vm->_sprite->_inventorySprites.freeMem();
+ _vm->_sprite->_inventorySprites.clear();
_vm->_sprite->loadList(_metaResource.inventorySpritesID, _vm->_sprite->_inventorySprites);
- _vm->_sprite->_mainSprites.freeMem();
+ _vm->_sprite->_mainSprites.clear();
_vm->_sprite->loadList(_metaResource.mainSpritesID, _vm->_sprite->_mainSprites);
_vm->_actor->loadObjList(_metaResource.objectCount, _metaResource.objectsResourceID);
- _vm->_resource->loadResource(resourceContext, _metaResource.cutawayListResourceID, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, _metaResource.cutawayListResourceID, resourceData);
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("Resource::loadGlobalResources Can't load cutaway list");
}
- _vm->_anim->loadCutawayList(resourcePointer, resourceLength);
+ _vm->_anim->loadCutawayList(resourceData);
if (_metaResource.songTableID > 0) {
- _vm->_resource->loadResource(resourceContext, _metaResource.songTableID, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, _metaResource.songTableID, resourceData);
if (chapter == 6) {
- int32 id = READ_LE_UINT32(&resourcePointer[actorsEntrance * 4]);
- free(resourcePointer);
- _vm->_resource->loadResource(resourceContext, id, resourcePointer, resourceLength);
+ if (resourceData.size() < (uint(actorsEntrance) * 4 + 4)) {
+ error("Resource::loadGlobalResources chapter 6 has wrong resource");
+ }
+ int32 id = READ_LE_UINT32(&resourceData[actorsEntrance * 4]);
+ _vm->_resource->loadResource(resourceContext, id, resourceData);
}
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("Resource::loadGlobalResources Can't load songs list for current track");
}
- free(_vm->_music->_songTable);
-
- _vm->_music->_songTableLen = resourceLength / 4;
- _vm->_music->_songTable = (int32 *)malloc(sizeof(int32) * _vm->_music->_songTableLen);
+ _vm->_music->_songTable.resize(resourceData.size() / 4);
- MemoryReadStream songS(resourcePointer, resourceLength);
+ ByteArrayReadStreamEndian songS(resourceData);
- for (i = 0; i < _vm->_music->_songTableLen; i++)
+ for (i = 0; i < _vm->_music->_songTable.size(); i++)
_vm->_music->_songTable[i] = songS.readSint32LE();
- free(resourcePointer);
} else {
// The IHNM demo has a fixed music track and doesn't load a song table
_vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(3, MUSIC_LOOP);
- free(resourcePointer);
}
int voiceLUTResourceID = 0;
@@ -207,9 +197,8 @@ void Resource_RES::loadGlobalResources(int chapter, int actorsEntrance) {
}
if (voiceLUTResourceID) {
- _vm->_resource->loadResource(resourceContext, voiceLUTResourceID, resourcePointer, resourceLength);
- _vm->_script->loadVoiceLUT(_vm->_script->_globalVoiceLUT, resourcePointer, resourceLength);
- free(resourcePointer);
+ _vm->_resource->loadResource(resourceContext, voiceLUTResourceID, resourceData);
+ _vm->_script->loadVoiceLUT(_vm->_script->_globalVoiceLUT, resourceData);
}
_vm->_spiritualBarometer = 0;
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index 1b7fa97f8d..abd681ce87 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -291,7 +291,7 @@ Common::Error SagaEngine::run() {
_sound = new Sound(this, _mixer);
if (!isSaga2()) {
- _interface->converseInit();
+ _interface->converseClear();
_script->setVerb(_script->getVerbType(kVerbWalkTo));
}
@@ -393,28 +393,26 @@ Common::Error SagaEngine::run() {
return Common::kNoError;
}
-void SagaEngine::loadStrings(StringsTable &stringsTable, const byte *stringsPointer, size_t stringsLength) {
+void SagaEngine::loadStrings(StringsTable &stringsTable, const ByteArray &stringsData) {
uint16 stringsCount;
size_t offset;
size_t prevOffset = 0;
- int i;
+ Common::Array<size_t> tempOffsets;
+ uint ui;
- if (stringsLength == 0) {
+ if (stringsData.empty()) {
error("SagaEngine::loadStrings() Error loading strings list resource");
}
- stringsTable.stringsPointer = (byte*)malloc(stringsLength);
- memcpy(stringsTable.stringsPointer, stringsPointer, stringsLength);
-
- MemoryReadStreamEndian scriptS(stringsTable.stringsPointer, stringsLength, isBigEndian()); //TODO: get endianess from context
+ ByteArrayReadStreamEndian scriptS(stringsData, isBigEndian()); //TODO: get endianess from context
offset = scriptS.readUint16();
stringsCount = offset / 2;
- stringsTable.strings = (const char **)malloc(stringsCount * sizeof(*stringsTable.strings));
- i = 0;
+ ui = 0;
scriptS.seek(0);
- while (i < stringsCount) {
+ tempOffsets.resize(stringsCount);
+ while (ui < stringsCount) {
offset = scriptS.readUint16();
// In some rooms in IHNM, string offsets can be greater than the maximum value than a 16-bit integer can hold
// We detect this by checking the previous offset, and if it was bigger than the current one, an overflow
@@ -423,27 +421,47 @@ void SagaEngine::loadStrings(StringsTable &stringsTable, const byte *stringsPoin
if (prevOffset > offset)
offset += 65536;
prevOffset = offset;
- if (offset == stringsLength) {
- stringsCount = i;
- stringsTable.strings = (const char **)realloc(stringsTable.strings, stringsCount * sizeof(*stringsTable.strings));
+ if (offset == stringsData.size()) {
+ stringsCount = ui;
+ tempOffsets.resize(stringsCount);
break;
}
- if (offset > stringsLength) {
+ if (offset > stringsData.size()) {
// This case should never occur, but apparently it does in the Italian fan
// translation of IHNM
warning("SagaEngine::loadStrings wrong strings table");
- stringsCount = i;
- stringsTable.strings = (const char **)realloc(stringsTable.strings, stringsCount * sizeof(*stringsTable.strings));
+ stringsCount = ui;
+ tempOffsets.resize(stringsCount);
break;
}
- stringsTable.strings[i] = (const char *)stringsTable.stringsPointer + offset;
- debug(9, "string[%i]=%s", i, stringsTable.strings[i]);
- i++;
+ tempOffsets[ui] = offset;
+ ui++;
+ }
+
+ prevOffset = scriptS.pos();
+ int32 left = scriptS.size() - prevOffset;
+ if (left < 0) {
+ error("SagaEngine::loadStrings() Error loading strings buffer");
+ }
+
+ stringsTable.buffer.resize(left);
+ if (left > 0) {
+ scriptS.read(&stringsTable.buffer.front(), left);
+ }
+
+ stringsTable.strings.resize(tempOffsets.size());
+ for (ui = 0; ui < tempOffsets.size(); ui++) {
+ offset = tempOffsets[ui] - prevOffset;
+ if (offset >= stringsTable.buffer.size()) {
+ error("SagaEngine::loadStrings() Wrong offset");
+ }
+ stringsTable.strings[ui] = &stringsTable.buffer[offset];
+
+ debug(9, "string[%i]=%s", ui, stringsTable.strings[ui]);
}
- stringsTable.stringsCount = stringsCount;
}
-const char *SagaEngine::getObjectName(uint16 objectId) {
+const char *SagaEngine::getObjectName(uint16 objectId) const {
ActorData *actor;
ObjectData *obj;
const HitZone *hitZone;
@@ -598,7 +616,7 @@ void SagaEngine::setTalkspeed(int talkspeed) {
ConfMan.setInt("talkspeed", (talkspeed * 255 + 3 / 2) / 3);
}
-int SagaEngine::getTalkspeed() {
+int SagaEngine::getTalkspeed() const {
return (ConfMan.getInt("talkspeed") * 3 + 255 / 2) / 255;
}
diff --git a/engines/saga/saga.h b/engines/saga/saga.h
index 102d1e5c82..8eb4833278 100644
--- a/engines/saga/saga.h
+++ b/engines/saga/saga.h
@@ -49,7 +49,7 @@ struct ADGameFileDescription;
* SAGA2 status: in early stages of development, no recent activity. Contact sev
* if you want to work on it, since we have some original source codes.
*
- * Supported games:
+ * Games using this engine:
*
* SAGA:
* - Inherit the Earth
@@ -86,7 +86,7 @@ class ResourceContext;
using Common::MemoryReadStream;
using Common::MemoryReadStreamEndian;
-//#define SAGA_DEBUG 1 // define for test functions
+// #define SAGA_DEBUG 1 // define for test functions
#define SAGA_IMAGE_DATA_OFFSET 776
#define SAGA_IMAGE_HEADER_LEN 8
@@ -155,40 +155,40 @@ enum GameFeatures {
};
enum VerbTypeIds {
- kVerbITENone = 0,
- kVerbITEPickUp = 1,
- kVerbITELookAt = 2,
- kVerbITEWalkTo = 3,
- kVerbITETalkTo = 4,
- kVerbITEOpen = 5,
- kVerbITEClose = 6,
- kVerbITEGive = 7,
- kVerbITEUse = 8,
- kVerbITEOptions = 9,
- kVerbITEEnter = 10,
- kVerbITELeave = 11,
- kVerbITEBegin = 12,
- kVerbITEWalkOnly = 13,
- kVerbITELookOnly = 14,
-
-
- kVerbIHNMNone = 0,
- kVerbIHNMWalk = 1,
- kVerbIHNMLookAt = 2,
- kVerbIHNMTake = 3,
- kVerbIHNMUse = 4,
- kVerbIHNMTalkTo = 5,
- kVerbIHNMSwallow = 6,
- kVerbIHNMGive = 7,
- kVerbIHNMPush = 8,
- kVerbIHNMOptions = 9,
- kVerbIHNMEnter = 10,
- kVerbIHNMLeave = 11,
- kVerbIHNMBegin = 12,
- kVerbIHNMWalkOnly = 13,
- kVerbIHNMLookOnly = 14,
-
- kVerbTypeIdsMax = kVerbITELookOnly + 1
+ kVerbITENone = 0,
+ kVerbITEPickUp = 1,
+ kVerbITELookAt = 2,
+ kVerbITEWalkTo = 3,
+ kVerbITETalkTo = 4,
+ kVerbITEOpen = 5,
+ kVerbITEClose = 6,
+ kVerbITEGive = 7,
+ kVerbITEUse = 8,
+ kVerbITEOptions = 9,
+ kVerbITEEnter = 10,
+ kVerbITELeave = 11,
+ kVerbITEBegin = 12,
+ kVerbITEWalkOnly = 13,
+ kVerbITELookOnly = 14,
+
+
+ kVerbIHNMNone = 0,
+ kVerbIHNMWalk = 1,
+ kVerbIHNMLookAt = 2,
+ kVerbIHNMTake = 3,
+ kVerbIHNMUse = 4,
+ kVerbIHNMTalkTo = 5,
+ kVerbIHNMSwallow = 6,
+ kVerbIHNMGive = 7,
+ kVerbIHNMPush = 8,
+ kVerbIHNMOptions = 9,
+ kVerbIHNMEnter = 10,
+ kVerbIHNMLeave = 11,
+ kVerbIHNMBegin = 12,
+ kVerbIHNMWalkOnly = 13,
+ kVerbIHNMLookOnly = 14,
+
+ kVerbTypeIdsMax = kVerbITELookOnly + 1
};
enum PanelButtonType {
@@ -381,30 +381,21 @@ struct ImageHeader {
};
struct StringsTable {
- byte *stringsPointer;
- int stringsCount;
- const char **strings;
+ Common::Array<char> buffer;
+ Common::Array<char *> strings;
- const char *getString(int index) const {
- if ((stringsCount <= index) || (index < 0)) {
+ const char *getString(uint index) const {
+ if (strings.size() <= index) {
// This occurs at the end of Ted's chapter, right after the ending cutscene
- warning("StringsTable::getString wrong index 0x%X (%d)", index, stringsCount);
+ warning("StringsTable::getString wrong index 0x%X (%d)", index, strings.size());
return "";
}
return strings[index];
}
- void freeMem() {
- free(strings);
- free(stringsPointer);
- memset(this, 0, sizeof(*this));
- }
-
- StringsTable() {
- memset(this, 0, sizeof(*this));
- }
- ~StringsTable() {
- freeMem();
+ void clear() {
+ strings.clear();
+ buffer.clear();
}
};
@@ -467,6 +458,34 @@ inline uint16 objectIndexToId(int type, int index) {
return (type << OBJECT_TYPE_SHIFT) | (OBJECT_TYPE_MASK & index);
}
+class ByteArray : public Common::Array<byte> {
+public:
+ /**
+ * Return a pointer to the start of the buffer underlying this byte array,
+ * or NULL if the buffer is empty.
+ */
+ byte *getBuffer() {
+ return empty() ? NULL : &front();
+ }
+
+ const byte *getBuffer() const {
+ return empty() ? NULL : &front();
+ }
+
+ void assign(const ByteArray &src) {
+ resize(src.size());
+ if (!empty()) {
+ memcpy(&front(), &src.front(), size());
+ }
+ }
+};
+
+class ByteArrayReadStreamEndian : public MemoryReadStreamEndian {
+public:
+ ByteArrayReadStreamEndian(const ByteArray & byteArray, bool bigEndian = false) : MemoryReadStreamEndian(byteArray.getBuffer(), byteArray.size(), bigEndian) {
+ }
+};
+
class SagaEngine : public Engine {
friend class Scene;
@@ -484,15 +503,14 @@ public:
void save(const char *fileName, const char *saveName);
void load(const char *fileName);
- uint32 getCurrentLoadVersion() {
+ uint32 getCurrentLoadVersion() const {
return _saveHeader.version;
}
void fillSaveList();
char *calcSaveFileName(uint slotNumber);
SaveFileData *getSaveFile(uint idx);
- uint getSaveSlotNumber(uint idx);
- uint getNewSaveSlotNumber();
+ uint getNewSaveSlotNumber() const;
bool locateSaveFile(char *saveName, uint &titleNumber);
bool isSaveListFull() const {
return _saveFilesCount == MAX_SAVES;
@@ -501,7 +519,7 @@ public:
return isSaveListFull() ? _saveFilesCount : _saveFilesCount + 1;
}
- bool isIHNMDemo() { return _isIHNMDemo; }
+ bool isIHNMDemo() const { return _isIHNMDemo; }
int16 _framesEsc;
@@ -546,23 +564,28 @@ public:
Common::RandomSource _rnd;
private:
- int decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, byte *outbuf, size_t outbuf_len);
- int flipImage(byte *img_buf, int columns, int scanlines);
- int unbankBGImage(byte *dest_buf, const byte *src_buf, int columns, int scanlines);
+ bool decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, ByteArray &outbuf);
+ void flipImage(byte *imageBuffer, int columns, int scanlines);
+ void unbankBGImage(byte *dest_buf, const byte *src_buf, int columns, int scanlines);
uint32 _previousTicks;
public:
- int decodeBGImage(const byte *image_data, size_t image_size,
- byte **output_buf, size_t *output_buf_len, int *w, int *h, bool flip = false);
- const byte *getImagePal(const byte *image_data, size_t image_size);
- void loadStrings(StringsTable &stringsTable, const byte *stringsPointer, size_t stringsLength);
+ bool decodeBGImage(const ByteArray &imageData, ByteArray &outputBuffer, int *w, int *h, bool flip = false);
+ const byte *getImagePal(const ByteArray &imageData) {
+ if (imageData.size() <= SAGA_IMAGE_HEADER_LEN) {
+ return NULL;
+ }
+
+ return &imageData.front() + SAGA_IMAGE_HEADER_LEN;
+ }
+ void loadStrings(StringsTable &stringsTable, const ByteArray &stringsData);
- const char *getObjectName(uint16 objectId);
+ const char *getObjectName(uint16 objectId) const;
public:
int processInput();
Point mousePos() const;
- int getMouseClickCount() {
+ int getMouseClickCount() const {
return _mouseClickCount;
}
@@ -586,7 +609,7 @@ public:
return _leftMouseButtonPressed || _rightMouseButtonPressed;
}
- inline int ticksToMSec(int tick) {
+ inline int ticksToMSec(int tick) const {
if (getGameId() == GID_ITE)
return tick * 1000 / kScriptTimeTicksPerSecond;
else
@@ -617,9 +640,9 @@ public:
bool isBigEndian() const;
bool isMacResources() const;
bool isSaga2() const { return getGameId() == GID_DINO || getGameId() == GID_FTA2; }
- const GameResourceDescription *getResourceDescription();
+ const GameResourceDescription *getResourceDescription() const;
- const GameFontDescription *getFontDescription(int index);
+ const GameFontDescription *getFontDescription(int index) const;
int getFontsCount() const;
int getGameId() const;
@@ -648,7 +671,7 @@ private:
public:
ColorId KnownColor2ColorId(KnownColor knownColor);
void setTalkspeed(int talkspeed);
- int getTalkspeed();
+ int getTalkspeed() const;
};
} // End of namespace Saga
diff --git a/engines/saga/saveload.cpp b/engines/saga/saveload.cpp
index 2740462dab..c5388d6878 100644
--- a/engines/saga/saveload.cpp
+++ b/engines/saga/saveload.cpp
@@ -82,7 +82,7 @@ bool SagaEngine::locateSaveFile(char *saveName, uint &titleNumber) {
return false;
}
-uint SagaEngine::getNewSaveSlotNumber() {
+uint SagaEngine::getNewSaveSlotNumber() const {
uint i, j;
bool found;
for (i = 0; i < MAX_SAVES; i++) {
@@ -240,9 +240,9 @@ void SagaEngine::save(const char *fileName, const char *saveName) {
_actor->saveState(out);
- out->writeSint16LE(_script->_commonBufferSize);
+ out->writeSint16LE(_script->_commonBuffer.size());
- out->write(_script->_commonBuffer, _script->_commonBufferSize);
+ out->write(_script->_commonBuffer.getBuffer(), _script->_commonBuffer.size());
// ISO map x, y coordinates for ITE
if (getGameId() == GID_ITE) {
@@ -282,7 +282,7 @@ void SagaEngine::load(const char *fileName) {
_saveHeader.version = SWAP_BYTES_32(_saveHeader.version);
}
- debug(2, "Save version: %x", _saveHeader.version);
+ debug(2, "Save version: 0x%X", _saveHeader.version);
if (_saveHeader.version < 4)
warning("This savegame is not endian-safe. There may be problems");
@@ -351,7 +351,8 @@ void SagaEngine::load(const char *fileName) {
_actor->loadState(in);
commonBufferSize = in->readSint16LE();
- in->read(_script->_commonBuffer, commonBufferSize);
+ _script->_commonBuffer.resize(commonBufferSize);
+ in->read(_script->_commonBuffer.getBuffer(), commonBufferSize);
if (getGameId() == GID_ITE) {
mapx = in->readSint16LE();
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index 2887d79693..8e9e4463ba 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -137,10 +137,9 @@ const char *SAGAResourceTypesString[] = {
};
Scene::Scene(SagaEngine *vm) : _vm(vm) {
- byte *sceneLUTPointer;
- size_t sceneLUTLength;
+ ByteArray sceneLUTData;
uint32 resourceId;
- int i;
+ uint i;
// Do nothing for SAGA2 games for now
if (_vm->isSaga2()) {
@@ -158,74 +157,62 @@ Scene::Scene(SagaEngine *vm) : _vm(vm) {
// Load scene lookup table
resourceId = _vm->_resource->convertResourceId(_vm->getResourceDescription()->sceneLUTResourceId);
debug(3, "Loading scene LUT from resource %i", resourceId);
- _vm->_resource->loadResource(_sceneContext, resourceId, sceneLUTPointer, sceneLUTLength);
- if (sceneLUTLength == 0) {
- error("Scene::Scene() sceneLUTLength == 0");
- }
- _sceneCount = sceneLUTLength / 2;
- _sceneLUT = (int *)malloc(_sceneCount * sizeof(*_sceneLUT));
- if (_sceneLUT == NULL) {
- memoryError("Scene::Scene()");
+ _vm->_resource->loadResource(_sceneContext, resourceId, sceneLUTData);
+ if (sceneLUTData.empty()) {
+ error("Scene::Scene() sceneLUT is empty");
}
+ _sceneLUT.resize(sceneLUTData.size() / 2);
- MemoryReadStreamEndian readS(sceneLUTPointer, sceneLUTLength, _sceneContext->isBigEndian());
+ ByteArrayReadStreamEndian readS(sceneLUTData, _sceneContext->isBigEndian());
- for (i = 0; i < _sceneCount; i++) {
+ for (i = 0; i < _sceneLUT.size(); i++) {
_sceneLUT[i] = readS.readUint16();
debug(8, "sceneNumber %i has resourceId %i", i, _sceneLUT[i]);
}
- free(sceneLUTPointer);
-
#ifdef SAGA_DEBUG
#define DUMP_SCENES_LEVEL 10
if (DUMP_SCENES_LEVEL <= gDebugLevel) {
- uint j;
int backUpDebugLevel = gDebugLevel;
SAGAResourceTypes *types;
int typesCount;
SAGAResourceTypes resType;
+ SceneResourceDataArray resourceList;
getResourceTypes(types, typesCount);
- for (i = 0; i < _sceneCount; i++) {
+ for (i = 0; i < _sceneLUT.size(); i++) {
gDebugLevel = -1;
loadSceneDescriptor(_sceneLUT[i]);
- loadSceneResourceList(_sceneDescription.resourceListResourceId);
+ loadSceneResourceList(_sceneDescription.resourceListResourceId, resourceList);
gDebugLevel = backUpDebugLevel;
debug(DUMP_SCENES_LEVEL, "Dump Scene: number %i, descriptor resourceId %i, resourceList resourceId %i", i, _sceneLUT[i], _sceneDescription.resourceListResourceId);
- debug(DUMP_SCENES_LEVEL, "\tresourceListCount %i", (int)_resourceListCount);
- for (j = 0; j < _resourceListCount; j++) {
- if (_resourceList[j].resourceType >= typesCount) {
- error("wrong resource type %i", _resourceList[j].resourceType);
+ debug(DUMP_SCENES_LEVEL, "\tresourceListCount %i", (int)resourceList.size());
+ for (SceneResourceDataArray::iterator j = resourceList.begin(); j != resourceList.end(); ++j) {
+ if (j->resourceType >= typesCount) {
+ error("wrong resource type %i", j->resourceType);
}
- resType = types[_resourceList[j].resourceType];
+ resType = types[j->resourceType];
- debug(DUMP_SCENES_LEVEL, "\t%s resourceId %i", SAGAResourceTypesString[resType], _resourceList[j].resourceId);
+ debug(DUMP_SCENES_LEVEL, "\t%s resourceId %i", SAGAResourceTypesString[resType], j->resourceId);
}
- free(_resourceList);
}
}
#endif
- debug(3, "LUT has %d entries.", _sceneCount);
+ debug(3, "LUT has %d entries.", _sceneLUT.size());
_sceneLoaded = false;
_sceneNumber = 0;
_chapterNumber = 0;
_sceneResourceId = 0;
_inGame = false;
- _loadDescription = false;
- memset(&_sceneDescription, 0, sizeof(_sceneDescription));
- _resourceListCount = 0;
- _resourceList = NULL;
+ _sceneDescription.reset();
_sceneProc = NULL;
_objectMap = new ObjectMap(_vm);
_actionMap = new ObjectMap(_vm);
- memset(&_bg, 0, sizeof(_bg));
- memset(&_bgMask, 0, sizeof(_bgMask));
}
Scene::~Scene() {
@@ -236,7 +223,6 @@ Scene::~Scene() {
delete _actionMap;
delete _objectMap;
- free(_sceneLUT);
}
void Scene::getResourceTypes(SAGAResourceTypes *&types, int &typesCount) {
@@ -281,7 +267,7 @@ void Scene::startScene() {
event.type = kEvTOneshot;
event.code = kCursorEvent;
event.op = kEventHide;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
switch (_vm->getGameId()) {
case GID_ITE:
@@ -528,8 +514,7 @@ void Scene::getSlopes(int &beginSlope, int &endSlope) {
}
void Scene::getBGInfo(BGInfo &bgInfo) {
- bgInfo.buffer = _bg.buf;
- bgInfo.bufferLength = _bg.buf_len;
+ bgInfo.buffer = _bg.buffer.getBuffer();
bgInfo.bounds.left = 0;
bgInfo.bounds.top = 0;
@@ -581,15 +566,14 @@ bool Scene::offscreenPath(Point &testPoint) {
}
-void Scene::getBGMaskInfo(int &width, int &height, byte *&buffer, size_t &bufferLength) {
+void Scene::getBGMaskInfo(int &width, int &height, byte *&buffer) {
if (!_bgMask.loaded) {
error("Scene::getBGMaskInfo _bgMask not loaded");
}
width = _bgMask.w;
height = _bgMask.h;
- buffer = _bgMask.buf;
- bufferLength = _bgMask.buf_len;
+ buffer = _bgMask.buffer.getBuffer();
}
void Scene::initDoorsState() {
@@ -597,9 +581,8 @@ void Scene::initDoorsState() {
}
void Scene::loadScene(LoadSceneParams &loadSceneParams) {
- size_t i;
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
static PalEntry current_pal[PAL_ENTRIES];
if (loadSceneParams.transitionType == kTransitionFade)
@@ -610,7 +593,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.code = kCursorEvent;
event.op = kEventSetBusyCursor;
event.time = 0;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
_chapterPointsChanged = false;
@@ -623,8 +606,8 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
if (loadSceneParams.chapter == 6 || loadSceneParams.chapter == 8)
_vm->_interface->setLeftPortrait(0);
- _vm->_anim->freeCutawayList();
- _vm->_script->freeModules();
+ _vm->_anim->clearCutawayList();
+ _vm->_script->clearModules();
// deleteAllScenes();
@@ -659,8 +642,6 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
error("Scene::loadScene(): Error, a scene is already loaded");
}
- _loadDescription = true;
-
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
if (loadSceneParams.loadFlag == kLoadBySceneNumber) // When will we get rid of it?
@@ -678,16 +659,6 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
_sceneNumber = loadSceneParams.sceneDescriptor;
_sceneResourceId = getSceneResourceId(_sceneNumber);
break;
- case kLoadByDescription:
- _sceneNumber = -1;
- _sceneResourceId = -1;
- assert(loadSceneParams.sceneDescription != NULL);
- assert(loadSceneParams.sceneDescription->resourceList != NULL);
- _loadDescription = false;
- _sceneDescription = *loadSceneParams.sceneDescription;
- _resourceList = loadSceneParams.sceneDescription->resourceList;
- _resourceListCount = loadSceneParams.sceneDescription->resourceListCount;
- break;
}
debug(3, "Loading scene number %d:", _sceneNumber);
@@ -702,34 +673,15 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
}
// Load scene descriptor and resource list resources
- if (_loadDescription) {
- debug(3, "Loading scene resource %i", _sceneResourceId);
-
- loadSceneDescriptor(_sceneResourceId);
-
- loadSceneResourceList(_sceneDescription.resourceListResourceId);
- } else {
- debug(3, "Loading memory scene resource");
- }
+ debug(3, "Loading scene resource %i", _sceneResourceId);
- // Load resources from scene resource list
- for (i = 0; i < _resourceListCount; i++) {
- if (!_resourceList[i].invalid) {
- _vm->_resource->loadResource(_sceneContext, _resourceList[i].resourceId,
- _resourceList[i].buffer, _resourceList[i].size);
+ loadSceneDescriptor(_sceneResourceId);
-
- if (_resourceList[i].size >= 6) {
- if (!memcmp(_resourceList[i].buffer, "DUMMY!", 6)) {
- _resourceList[i].invalid = true;
- warning("DUMMY resource %i", _resourceList[i].resourceId);
- }
- }
- }
- }
+ SceneResourceDataArray resourceList;
+ loadSceneResourceList(_sceneDescription.resourceListResourceId, resourceList);
// Process resources from scene resource list
- processSceneResources();
+ processSceneResources(resourceList);
if (_sceneDescription.flags & kSceneFlagISO) {
_outsetSceneNumber = _sceneNumber;
@@ -748,7 +700,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
_sceneLoaded = true;
- q_event = NULL;
+ eventColumns = NULL;
if (loadSceneParams.transitionType == kTransitionFade) {
@@ -762,7 +714,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = current_pal;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// set fade mode
event.type = kEvTImmediate;
@@ -771,7 +723,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.param = kNoFade;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Display scene background, but stay with black palette
event.type = kEvTImmediate;
@@ -780,7 +732,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.param = kEvPNoSetPalette;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
@@ -796,7 +748,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.param4 = _sceneNumber; // Object
event.param5 = loadSceneParams.actorsEntrance; // With Object
event.param6 = 0; // Actor
- q_event = _vm->_events->chain(q_event, &event);
+ eventColumns = _vm->_events->chain(eventColumns, event);
}
if (loadSceneParams.transitionType == kTransitionFade) {
@@ -808,7 +760,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.param = kFadeIn;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ eventColumns = _vm->_events->chain(eventColumns, event);
// Fade in from black to the scene background palette
event.type = kEvTImmediate;
@@ -817,7 +769,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = _bg.pal;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// set fade mode
event.type = kEvTImmediate;
@@ -826,7 +778,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.param = kNoFade;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
if (loadSceneParams.sceneProc == NULL) {
@@ -845,13 +797,13 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.param2 = MUSIC_DEFAULT;
event.op = kEventPlay;
event.time = 0;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
} else {
event.type = kEvTOneshot;
event.code = kMusicEvent;
event.op = kEventStop;
event.time = 0;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
}
@@ -861,14 +813,14 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.op = kEventDisplay;
event.param = kEvPSetPalette;
event.time = 0;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
// Begin palette cycle animation if present
event.type = kEvTOneshot;
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
- q_event = _vm->_events->queue(&event);
+ _vm->_events->queue(event);
// Start the scene main script
if (_sceneDescription.sceneScriptEntrypointNumber > 0) {
@@ -882,7 +834,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.param4 = _sceneNumber; // Object
event.param5 = loadSceneParams.actorsEntrance; // With Object
event.param6 = 0; // Actor
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
debug(3, "Scene started");
@@ -905,7 +857,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.code = kInterfaceEvent;
event.op = kEventActivate;
event.time = 0;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
// Change the cursor back to a crosshair in IHNM
@@ -913,23 +865,22 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
event.code = kCursorEvent;
event.op = kEventSetNormalCursor;
event.time = 0;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
void Scene::loadSceneDescriptor(uint32 resourceId) {
- byte *sceneDescriptorData;
- size_t sceneDescriptorDataLength;
+ ByteArray sceneDescriptorData;
- memset(&_sceneDescription, 0, sizeof(_sceneDescription));
+ _sceneDescription.reset();
if (resourceId == 0) {
return;
}
- _vm->_resource->loadResource(_sceneContext, resourceId, sceneDescriptorData, sceneDescriptorDataLength);
+ _vm->_resource->loadResource(_sceneContext, resourceId, sceneDescriptorData);
- if (sceneDescriptorDataLength == 16) {
- MemoryReadStreamEndian readS(sceneDescriptorData, sceneDescriptorDataLength, _sceneContext->isBigEndian());
+ if (sceneDescriptorData.size() == 16) {
+ ByteArrayReadStreamEndian readS(sceneDescriptorData, _sceneContext->isBigEndian());
_sceneDescription.flags = readS.readSint16();
_sceneDescription.resourceListResourceId = readS.readSint16();
@@ -940,53 +891,44 @@ void Scene::loadSceneDescriptor(uint32 resourceId) {
_sceneDescription.startScriptEntrypointNumber = readS.readUint16();
_sceneDescription.musicResourceId = readS.readSint16();
}
-
- free(sceneDescriptorData);
}
-void Scene::loadSceneResourceList(uint32 resourceId) {
- byte *resourceListData;
- size_t resourceListDataLength;
- size_t i;
+void Scene::loadSceneResourceList(uint32 resourceId, SceneResourceDataArray &resourceList) {
+ ByteArray resourceListData;
- _resourceListCount = 0;
- _resourceList = NULL;
+ resourceList.clear();
if (resourceId == 0) {
return;
}
// Load the scene resource table
- _vm->_resource->loadResource(_sceneContext, resourceId, resourceListData, resourceListDataLength);
+ _vm->_resource->loadResource(_sceneContext, resourceId, resourceListData);
- if ((resourceListDataLength % SAGA_RESLIST_ENTRY_LEN) == 0) {
- MemoryReadStreamEndian readS(resourceListData, resourceListDataLength, _sceneContext->isBigEndian());
+ if ((resourceListData.size() % SAGA_RESLIST_ENTRY_LEN) == 0) {
+ ByteArrayReadStreamEndian readS(resourceListData, _sceneContext->isBigEndian());
// Allocate memory for scene resource list
- _resourceListCount = resourceListDataLength / SAGA_RESLIST_ENTRY_LEN;
- debug(3, "Scene resource list contains %i entries", (int)_resourceListCount);
- _resourceList = (SceneResourceData *)calloc(_resourceListCount, sizeof(*_resourceList));
+ resourceList.resize(resourceListData.size() / SAGA_RESLIST_ENTRY_LEN);
+ debug(3, "Scene resource list contains %i entries", (int)resourceList.size());
// Load scene resource list from raw scene
// resource table
debug(3, "Loading scene resource list");
- for (i = 0; i < _resourceListCount; i++) {
- _resourceList[i].resourceId = readS.readUint16();
- _resourceList[i].resourceType = readS.readUint16();
+ for (SceneResourceDataArray::iterator resource = resourceList.begin(); resource != resourceList.end(); ++resource) {
+ resource->resourceId = readS.readUint16();
+ resource->resourceType = readS.readUint16();
// demo version may contain invalid resourceId
- _resourceList[i].invalid = !_sceneContext->validResourceId(_resourceList[i].resourceId);
+ resource->invalid = !_sceneContext->validResourceId(resource->resourceId);
}
}
- free(resourceListData);
}
-void Scene::processSceneResources() {
- byte *resourceData;
- size_t resourceDataLength;
+void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
+ ByteArray resourceData;
const byte *palPointer;
- size_t i;
SAGAResourceTypes *types = 0;
int typesCount = 0;
SAGAResourceTypes resType;
@@ -994,22 +936,33 @@ void Scene::processSceneResources() {
getResourceTypes(types, typesCount);
// Process the scene resource list
- for (i = 0; i < _resourceListCount; i++) {
- if (_resourceList[i].invalid) {
+ for (SceneResourceDataArray::iterator resource = resourceList.begin(); resource != resourceList.end(); ++resource) {
+ if (resource->invalid) {
+ continue;
+ }
+ _vm->_resource->loadResource(_sceneContext, resource->resourceId, resourceData);
+
+
+ if (resourceData.size() >= 6) {
+ if (!memcmp(resourceData.getBuffer(), "DUMMY!", 6)) {
+ resource->invalid = true;
+ warning("DUMMY resource %i", resource->resourceId);
+ }
+ }
+
+ if (resource->invalid) {
continue;
}
- resourceData = _resourceList[i].buffer;
- resourceDataLength = _resourceList[i].size;
- if (_resourceList[i].resourceType >= typesCount) {
- error("Scene::processSceneResources() wrong resource type %i", _resourceList[i].resourceType);
+ if (resource->resourceType >= typesCount) {
+ error("Scene::processSceneResources() wrong resource type %i", resource->resourceType);
}
- resType = types[_resourceList[i].resourceType];
+ resType = types[resource->resourceType];
switch (resType) {
case SAGA_UNKNOWN:
- warning("UNKNOWN resourceType %i", _resourceList[i].resourceType);
+ warning("UNKNOWN resourceType %i", resource->resourceType);
break;
case SAGA_ACTOR:
//for (a = actorsInScene; a; a = a->nextInScene)
@@ -1027,20 +980,16 @@ void Scene::processSceneResources() {
}
debug(3, "Loading background resource.");
- _bg.res_buf = resourceData;
- _bg.res_len = resourceDataLength;
- _bg.loaded = 1;
-
- if (_vm->decodeBGImage(_bg.res_buf,
- _bg.res_len,
- &_bg.buf,
- &_bg.buf_len,
+
+ if (!_vm->decodeBGImage(resourceData,
+ _bg.buffer,
&_bg.w,
- &_bg.h) != SUCCESS) {
- error("Scene::processSceneResources() Error loading background resource %i", _resourceList[i].resourceId);
+ &_bg.h)) {
+ error("Scene::processSceneResources() Error loading background resource %i", resource->resourceId);
}
+ _bg.loaded = true;
- palPointer = _vm->getImagePal(_bg.res_buf, _bg.res_len);
+ palPointer = _vm->getImagePal(resourceData);
memcpy(_bg.pal, palPointer, sizeof(_bg.pal));
break;
case SAGA_BG_MASK: // Scene background mask resource
@@ -1048,30 +997,27 @@ void Scene::processSceneResources() {
error("Scene::ProcessSceneResources(): Duplicate background mask resource encountered");
}
debug(3, "Loading BACKGROUND MASK resource.");
- _bgMask.res_buf = resourceData;
- _bgMask.res_len = resourceDataLength;
- _bgMask.loaded = 1;
- _vm->decodeBGImage(_bgMask.res_buf, _bgMask.res_len, &_bgMask.buf,
- &_bgMask.buf_len, &_bgMask.w, &_bgMask.h, true);
+ _vm->decodeBGImage(resourceData, _bgMask.buffer, &_bgMask.w, &_bgMask.h, true);
+ _bgMask.loaded = true;
// At least in ITE the mask needs to be clipped.
_bgMask.w = MIN(_bgMask.w, _vm->getDisplayInfo().width);
_bgMask.h = MIN(_bgMask.h, getHeight());
- debug(4, "BACKGROUND MASK width=%d height=%d length=%d", _bgMask.w, _bgMask.h, (int)_bgMask.buf_len);
+ debug(4, "BACKGROUND MASK width=%d height=%d length=%d", _bgMask.w, _bgMask.h, _bgMask.buffer.size());
break;
case SAGA_STRINGS:
debug(3, "Loading scene strings resource...");
- _vm->loadStrings(_sceneStrings, resourceData, resourceDataLength);
+ _vm->loadStrings(_sceneStrings, resourceData);
break;
case SAGA_OBJECT_MAP:
debug(3, "Loading object map resource...");
- _objectMap->load(resourceData, resourceDataLength);
+ _objectMap->load(resourceData);
break;
case SAGA_ACTION_MAP:
debug(3, "Loading action map resource...");
- _actionMap->load(resourceData, resourceDataLength);
+ _actionMap->load(resourceData);
break;
case SAGA_ISO_IMAGES:
if (!(_sceneDescription.flags & kSceneFlagISO)) {
@@ -1080,7 +1026,7 @@ void Scene::processSceneResources() {
debug(3, "Loading isometric images resource.");
- _vm->_isoMap->loadImages(resourceData, resourceDataLength);
+ _vm->_isoMap->loadImages(resourceData);
break;
case SAGA_ISO_MAP:
if (!(_sceneDescription.flags & kSceneFlagISO)) {
@@ -1089,7 +1035,7 @@ void Scene::processSceneResources() {
debug(3, "Loading isometric map resource.");
- _vm->_isoMap->loadMap(resourceData, resourceDataLength);
+ _vm->_isoMap->loadMap(resourceData);
break;
case SAGA_ISO_PLATFORMS:
if (!(_sceneDescription.flags & kSceneFlagISO)) {
@@ -1098,7 +1044,7 @@ void Scene::processSceneResources() {
debug(3, "Loading isometric platforms resource.");
- _vm->_isoMap->loadPlatforms(resourceData, resourceDataLength);
+ _vm->_isoMap->loadPlatforms(resourceData);
break;
case SAGA_ISO_METATILES:
if (!(_sceneDescription.flags & kSceneFlagISO)) {
@@ -1107,20 +1053,20 @@ void Scene::processSceneResources() {
debug(3, "Loading isometric metatiles resource.");
- _vm->_isoMap->loadMetaTiles(resourceData, resourceDataLength);
+ _vm->_isoMap->loadMetaTiles(resourceData);
break;
case SAGA_ANIM:
{
- uint16 animId = _resourceList[i].resourceType - 14;
+ uint16 animId = resource->resourceType - 14;
debug(3, "Loading animation resource animId=%i", animId);
- _vm->_anim->load(animId, resourceData, resourceDataLength);
+ _vm->_anim->load(animId, resourceData);
}
break;
case SAGA_ENTRY:
debug(3, "Loading entry list resource...");
- loadSceneEntryList(resourceData, resourceDataLength);
+ loadSceneEntryList(resourceData);
break;
case SAGA_ISO_MULTI:
if (!(_sceneDescription.flags & kSceneFlagISO)) {
@@ -1129,23 +1075,23 @@ void Scene::processSceneResources() {
debug(3, "Loading isometric multi resource.");
- _vm->_isoMap->loadMulti(resourceData, resourceDataLength);
+ _vm->_isoMap->loadMulti(resourceData);
break;
case SAGA_PAL_ANIM:
debug(3, "Loading palette animation resource.");
- _vm->_palanim->loadPalAnim(resourceData, resourceDataLength);
+ _vm->_palanim->loadPalAnim(resourceData);
break;
case SAGA_FACES:
if (_vm->getGameId() == GID_ITE)
- _vm->_interface->loadScenePortraits(_resourceList[i].resourceId);
+ _vm->_interface->loadScenePortraits(resource->resourceId);
break;
case SAGA_PALETTE:
{
PalEntry pal[PAL_ENTRIES];
- byte *palPtr = resourceData;
+ byte *palPtr = resourceData.getBuffer();
- if (resourceDataLength < 3 * PAL_ENTRIES)
- error("Too small scene palette %i", (int)resourceDataLength);
+ if (resourceData.size() < 3 * PAL_ENTRIES)
+ error("Too small scene palette %i", (int)resourceData.size());
for (uint16 c = 0; c < PAL_ENTRIES; c++) {
pal[c].red = *palPtr++;
@@ -1156,7 +1102,7 @@ void Scene::processSceneResources() {
}
break;
default:
- error("Scene::ProcessSceneResources() Encountered unknown resource type %i", _resourceList[i].resourceType);
+ error("Scene::ProcessSceneResources() Encountered unknown resource type %i", resource->resourceType);
break;
}
}
@@ -1184,7 +1130,6 @@ void Scene::draw() {
void Scene::endScene() {
Rect rect;
- size_t i;
if (!_sceneLoaded)
return;
@@ -1222,37 +1167,28 @@ void Scene::endScene() {
// Free scene background
if (_bg.loaded) {
- free(_bg.buf);
- _bg.loaded = 0;
+ _bg.buffer.clear();
+ _bg.loaded = false;
}
// Free scene background mask
if (_bgMask.loaded) {
- free(_bgMask.buf);
- _bgMask.loaded = 0;
- }
-
- // Free scene resource list
- for (i = 0; i < _resourceListCount; i++) {
- free(_resourceList[i].buffer);
- }
-
- if (_loadDescription) {
- free(_resourceList);
+ _bgMask.buffer.clear();
+ _bgMask.loaded = false;
}
// Free animation info list
_vm->_anim->reset();
- _vm->_palanim->freePalAnim();
+ _vm->_palanim->clear();
- _objectMap->freeMem();
- _actionMap->freeMem();
- _entryList.freeMem();
- _sceneStrings.freeMem();
+ _objectMap->clear();
+ _actionMap->clear();
+ _entryList.clear();
+ _sceneStrings.clear();
if (_vm->getGameId() == GID_ITE)
- _vm->_isoMap->freeMem();
+ _vm->_isoMap->clear();
_vm->_events->clearList();
_textList.clear();
@@ -1275,7 +1211,7 @@ void Scene::restoreScene() {
event.param = kEvPNoSetPalette;
event.time = 0;
event.duration = 0;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
_vm->_gfx->showCursor(true);
}
@@ -1285,7 +1221,7 @@ void Scene::cmdSceneChange(int argc, const char **argv) {
scene_num = atoi(argv[1]);
- if ((scene_num < 1) || (scene_num >= _sceneCount)) {
+ if ((scene_num < 1) || (uint(scene_num) >= _sceneLUT.size())) {
_vm->_console->DebugPrintf("Invalid scene number.\n");
return;
}
@@ -1303,34 +1239,29 @@ void Scene::cmdObjectMapInfo() {
_objectMap->cmdInfo();
}
-void Scene::loadSceneEntryList(const byte* resourcePointer, size_t resourceLength) {
- int i;
-
- _entryList.entryListCount = resourceLength / 8;
-
- MemoryReadStreamEndian readS(resourcePointer, resourceLength, _sceneContext->isBigEndian());
+void Scene::loadSceneEntryList(const ByteArray &resourceData) {
+ uint i;
+ if (!_entryList.empty()) {
+ error("Scene::loadSceneEntryList entryList not empty");
+ }
- if (_entryList.entryList)
- error("Scene::loadSceneEntryList entryList != NULL");
+ _entryList.resize(resourceData.size() / 8);
- _entryList.entryList = (SceneEntry *) malloc(_entryList.entryListCount * sizeof(*_entryList.entryList));
- if (_entryList.entryList == NULL) {
- memoryError("Scene::loadSceneEntryList");
- }
+ ByteArrayReadStreamEndian readS(resourceData, _sceneContext->isBigEndian());
- for (i = 0; i < _entryList.entryListCount; i++) {
- _entryList.entryList[i].location.x = readS.readSint16();
- _entryList.entryList[i].location.y = readS.readSint16();
- _entryList.entryList[i].location.z = readS.readSint16();
- _entryList.entryList[i].facing = readS.readUint16();
+ for (i = 0; i < _entryList.size(); i++) {
+ _entryList[i].location.x = readS.readSint16();
+ _entryList[i].location.y = readS.readSint16();
+ _entryList[i].location.z = readS.readSint16();
+ _entryList[i].facing = readS.readUint16();
}
}
void Scene::clearPlacard() {
static PalEntry cur_pal[PAL_ENTRIES];
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
_vm->_interface->setFadeMode(kFadeOut);
@@ -1342,7 +1273,7 @@ void Scene::clearPlacard() {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
// set fade mode
event.type = kEvTImmediate;
@@ -1351,14 +1282,14 @@ void Scene::clearPlacard() {
event.param = kNoFade;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
if (_vm->getGameId() == GID_ITE) {
event.type = kEvTOneshot;
event.code = kTextEvent;
event.op = kEventRemove;
event.data = _vm->_script->getPlacardTextEntry();
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
} else {
_vm->_scene->_textList.clear();
}
@@ -1368,7 +1299,7 @@ void Scene::clearPlacard() {
event.op = kEventRestoreMode;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
@@ -1379,7 +1310,7 @@ void Scene::clearPlacard() {
event.param = kPanelMain;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
#endif
@@ -1390,7 +1321,7 @@ void Scene::clearPlacard() {
event.param = kEvPNoSetPalette;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// set fade mode
event.type = kEvTImmediate;
@@ -1399,7 +1330,7 @@ void Scene::clearPlacard() {
event.param = kFadeIn;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Fade in from black to the scene background palette
event.type = kEvTImmediate;
@@ -1408,7 +1339,7 @@ void Scene::clearPlacard() {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = _bg.pal;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// set fade mode
event.type = kEvTImmediate;
@@ -1417,18 +1348,18 @@ void Scene::clearPlacard() {
event.param = kNoFade;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
event.type = kEvTOneshot;
event.code = kCursorEvent;
event.op = kEventShow;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
event.type = kEvTOneshot;
event.code = kScriptEvent;
event.op = kEventThreadWake;
event.param = kWaitTypePlacard;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
#ifdef ENABLE_IHNM
@@ -1439,7 +1370,7 @@ void Scene::showPsychicProfile(const char *text) {
PalEntry *pal;
TextListEntry textEntry;
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
if (_vm->_interface->getMode() == kPanelPlacard)
return;
@@ -1453,7 +1384,7 @@ void Scene::showPsychicProfile(const char *text) {
event.type = kEvTOneshot;
event.code = kCursorEvent;
event.op = kEventHide;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
_vm->_interface->setFadeMode(kFadeOut);
@@ -1465,7 +1396,7 @@ void Scene::showPsychicProfile(const char *text) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// set fade mode
event.type = kEvTImmediate;
@@ -1474,17 +1405,17 @@ void Scene::showPsychicProfile(const char *text) {
event.param = kNoFade;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
event.type = kEvTOneshot;
event.code = kInterfaceEvent;
event.op = kEventClearStatus;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Set the background and palette for the psychic profile
event.type = kEvTOneshot;
event.code = kPsychicProfileBgEvent;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
_vm->_scene->_textList.clear();
@@ -1507,7 +1438,7 @@ void Scene::showPsychicProfile(const char *text) {
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = _psychicProfileTextEntry;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
_vm->_scene->getBGPal(pal);
@@ -1518,13 +1449,13 @@ void Scene::showPsychicProfile(const char *text) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = pal;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
event.type = kEvTOneshot;
event.code = kScriptEvent;
event.op = kEventThreadWake;
event.param = kWaitTypePlacard;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
void Scene::clearPsychicProfile() {
diff --git a/engines/saga/scene.h b/engines/saga/scene.h
index 0131e01abb..8d48e71445 100644
--- a/engines/saga/scene.h
+++ b/engines/saga/scene.h
@@ -32,6 +32,7 @@
#include "saga/actor.h"
#include "saga/interface.h"
#include "saga/puzzle.h"
+#include "saga/events.h"
namespace Saga {
@@ -55,8 +56,6 @@ namespace Saga {
class ObjectMap;
-struct Event;
-
enum SceneFlags {
kSceneFlagISO = 1,
kSceneFlagShowCursor = 2
@@ -74,7 +73,6 @@ enum FTA2Endings {
struct BGInfo {
Rect bounds;
byte *buffer;
- size_t bufferLength;
};
typedef int (SceneProc) (int, void *);
@@ -112,11 +110,14 @@ enum SAGAResourceTypes {
struct SceneResourceData {
uint32 resourceId;
int resourceType;
- byte *buffer;
- size_t size;
bool invalid;
+
+ SceneResourceData() : resourceId(0), resourceType(0), invalid(false) {
+ }
};
+typedef Common::Array<SceneResourceData> SceneResourceDataArray;
+
#define SAGA_SCENE_DESC_LEN 16
struct SceneDescription {
@@ -128,47 +129,31 @@ struct SceneDescription {
uint16 sceneScriptEntrypointNumber;
uint16 startScriptEntrypointNumber;
int16 musicResourceId;
- SceneResourceData *resourceList;
- size_t resourceListCount;
+
+ void reset() {
+ flags = resourceListResourceId = endSlope = beginSlope = scriptModuleNumber = sceneScriptEntrypointNumber = startScriptEntrypointNumber = musicResourceId = 0;
+ }
};
struct SceneEntry {
Location location;
- int facing;
+ uint16 facing;
};
-struct SceneEntryList {
- SceneEntry *entryList;
- int entryListCount;
-
- const SceneEntry * getEntry(int index) {
- if ((index < 0) || (index >= entryListCount)) {
- error("SceneEntryList::getEntry wrong index (%d)", index);
- }
- return &entryList[index];
- }
- void freeMem() {
- free(entryList);
- memset(this, 0, sizeof(*this));
- }
- SceneEntryList() {
- memset(this, 0, sizeof(*this));
- }
- ~SceneEntryList() {
- freeMem();
- }
+class SceneEntryList : public Common::Array<SceneEntry> {
};
struct SceneImage {
- int loaded;
+ bool loaded;
int w;
int h;
int p;
- byte *buf;
- size_t buf_len;
- byte *res_buf;
- size_t res_len;
+ ByteArray buffer;
PalEntry pal[256];
+
+ SceneImage() : loaded(false), w(0), h(0), p(0) {
+ memset(pal, 0, sizeof(pal));
+ }
};
@@ -179,14 +164,12 @@ enum SceneTransitionType {
enum SceneLoadFlags {
kLoadByResourceId,
- kLoadBySceneNumber,
- kLoadByDescription
+ kLoadBySceneNumber
};
struct LoadSceneParams {
int32 sceneDescriptor;
SceneLoadFlags loadFlag;
- SceneDescription* sceneDescription;
SceneProc *sceneProc;
bool sceneSkipTarget;
SceneTransitionType transitionType;
@@ -248,8 +231,8 @@ class Scene {
void skipScene();
void endScene();
void restoreScene();
- void queueScene(LoadSceneParams *sceneQueue) {
- _sceneQueue.push_back(*sceneQueue);
+ void queueScene(const LoadSceneParams &sceneQueue) {
+ _sceneQueue.push_back(sceneQueue);
}
void draw();
@@ -258,7 +241,7 @@ class Scene {
bool isInIntro() { return !_inGame; }
const Rect& getSceneClip() const { return _sceneClip; }
- void getBGMaskInfo(int &width, int &height, byte *&buffer, size_t &bufferLength);
+ void getBGMaskInfo(int &width, int &height, byte *&buffer);
int isBGMaskPresent() { return _bgMask.loaded; }
int getBGMaskType(const Point &testPoint) {
@@ -274,7 +257,7 @@ class Scene {
}
#endif
- return (_bgMask.buf[offset] >> 4) & 0x0f;
+ return (_bgMask.buffer[offset] >> 4) & 0x0f;
}
bool validBGMaskPoint(const Point &testPoint) {
@@ -325,7 +308,7 @@ class Scene {
bool isSceneLoaded() const { return _sceneLoaded; }
- int getSceneResourceId(int sceneNumber) {
+ uint16 getSceneResourceId(int sceneNumber) {
#ifdef SCENE_DEBUG
if ((sceneNumber < 0) || (sceneNumber >= _sceneCount)) {
error("getSceneResourceId: wrong sceneNumber %i", sceneNumber);
@@ -376,17 +359,16 @@ class Scene {
private:
void loadScene(LoadSceneParams &loadSceneParams);
void loadSceneDescriptor(uint32 resourceId);
- void loadSceneResourceList(uint32 resourceId);
- void loadSceneEntryList(const byte* resourcePointer, size_t resourceLength);
- void processSceneResources();
+ void loadSceneResourceList(uint32 resourceId, SceneResourceDataArray &resourceList);
+ void loadSceneEntryList(const ByteArray &resourceData);
+ void processSceneResources(SceneResourceDataArray &resourceList);
void getResourceTypes(SAGAResourceTypes *&types, int &typesCount);
SagaEngine *_vm;
ResourceContext *_sceneContext;
- int *_sceneLUT;
- int _sceneCount;
+ Common::Array<uint16> _sceneLUT;
SceneQueueList _sceneQueue;
bool _sceneLoaded;
int _currentProtag;
@@ -398,10 +380,7 @@ class Scene {
int _currentMusicRepeat;
bool _chapterPointsChanged;
bool _inGame;
- bool _loadDescription;
SceneDescription _sceneDescription;
- size_t _resourceListCount;
- SceneResourceData *_resourceList;
SceneProc *_sceneProc;
SceneImage _bg;
SceneImage _bgMask;
@@ -456,8 +435,8 @@ class Scene {
static int SC_ITEIntroFaireTentProc(int param, void *refCon);
private:
- Event *ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialogue dialogue[]);
- Event *ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]);
+ EventColumns *ITEQueueDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]);
+ EventColumns *ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]);
int ITEIntroAnimProc(int param);
int ITEIntroCave1Proc(int param);
int ITEIntroCave2Proc(int param);
diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp
index b0e20da48c..3ae2f19e1b 100644
--- a/engines/saga/script.cpp
+++ b/engines/saga/script.cpp
@@ -46,12 +46,11 @@ namespace Saga {
SAGA1Script::SAGA1Script(SagaEngine *vm) : Script(vm) {
ResourceContext *resourceContext;
- byte *resourcePointer;
- size_t resourceLength;
+ ByteArray resourceData;
int prevTell;
- int i, j;
- byte *stringsPointer;
- size_t stringsLength;
+ uint ui;
+ int j;
+ ByteArray stringsData;
//initialize member variables
_abortEnabled = true;
@@ -67,9 +66,7 @@ SAGA1Script::SAGA1Script(SagaEngine *vm) : Script(vm) {
_pointerObject = ID_NOTHING;
_staticSize = 0;
- _commonBufferSize = COMMON_BUFFER_SIZE;
- _commonBuffer = (byte*)malloc(_commonBufferSize);
- memset(_commonBuffer, 0, _commonBufferSize);
+ _commonBuffer.resize(COMMON_BUFFER_SIZE);
debug(8, "Initializing scripting subsystem");
// Load script resource file context
@@ -86,47 +83,41 @@ SAGA1Script::SAGA1Script(SagaEngine *vm) : Script(vm) {
uint32 scriptResourceId = 0;
scriptResourceId = _vm->getResourceDescription()->moduleLUTResourceId;
debug(3, "Loading module LUT from resource %i", scriptResourceId);
- _vm->_resource->loadResource(resourceContext, scriptResourceId, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, scriptResourceId, resourceData);
// Create logical script LUT from resource
- if (resourceLength % 22 == 0) { // ITE CD
+ if (resourceData.size() % 22 == 0) { // ITE CD
_modulesLUTEntryLen = 22;
- } else if (resourceLength % 16 == 0) { // ITE disk, IHNM
+ } else if (resourceData.size() % 16 == 0) { // ITE disk, IHNM
_modulesLUTEntryLen = 16;
} else {
- error("Script::Script() Invalid script lookup table length (%i)", (int)resourceLength);
+ error("Script::Script() Invalid script lookup table length (%i)", (int)resourceData.size());
}
// Calculate number of entries
- _modulesCount = resourceLength / _modulesLUTEntryLen;
+ int modulesCount = resourceData.size() / _modulesLUTEntryLen;
- debug(3, "LUT has %i entries", _modulesCount);
+ debug(3, "LUT has %i entries", modulesCount);
// Allocate space for logical LUT
- _modules = (ModuleData *)malloc(_modulesCount * sizeof(*_modules));
- if (_modules == NULL) {
- memoryError("Script::Script()");
- }
+ _modules.resize(modulesCount);
// Convert LUT resource to logical LUT
- MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, resourceContext->isBigEndian());
- for (i = 0; i < _modulesCount; i++) {
- memset(&_modules[i], 0, sizeof(ModuleData));
+ ByteArrayReadStreamEndian scriptS(resourceData, resourceContext->isBigEndian());
+ for (ui = 0; ui < _modules.size(); ui++) {
prevTell = scriptS.pos();
- _modules[i].scriptResourceId = scriptS.readUint16();
- _modules[i].stringsResourceId = scriptS.readUint16();
- _modules[i].voicesResourceId = scriptS.readUint16();
+ _modules[ui].scriptResourceId = scriptS.readUint16();
+ _modules[ui].stringsResourceId = scriptS.readUint16();
+ _modules[ui].voicesResourceId = scriptS.readUint16();
// Skip the unused portion of the structure
for (j = scriptS.pos(); j < prevTell + _modulesLUTEntryLen; j++) {
if (scriptS.readByte() != 0)
- warning("Unused scriptLUT part isn't really unused for LUT %d (pos: %d)", i, j);
+ warning("Unused scriptLUT part isn't really unused for LUT %d (pos: %d)", ui, j);
}
}
- free(resourcePointer);
-
// TODO
//
// In ITE, the "main strings" resource contains both the verb strings
@@ -135,10 +126,9 @@ SAGA1Script::SAGA1Script(SagaEngine *vm) : Script(vm) {
// In IHNM, the "main strings" contains the verb strings, but not the
// object names. At least, I think that's the case.
- _vm->_resource->loadResource(resourceContext, _vm->getResourceDescription()->mainStringsResourceId, stringsPointer, stringsLength);
+ _vm->_resource->loadResource(resourceContext, _vm->getResourceDescription()->mainStringsResourceId, stringsData);
- _vm->loadStrings(_mainStrings, stringsPointer, stringsLength);
- free(stringsPointer);
+ _vm->loadStrings(_mainStrings, stringsData);
setupScriptOpcodeList();
@@ -157,19 +147,10 @@ SAGA1Script::SAGA1Script(SagaEngine *vm) : Script(vm) {
SAGA1Script::~SAGA1Script() {
debug(8, "Shutting down scripting subsystem.");
-
- _mainStrings.freeMem();
- _globalVoiceLUT.freeMem();
-
- freeModules();
- free(_modules);
-
- free(_commonBuffer);
}
SAGA2Script::SAGA2Script(SagaEngine *vm) : Script(vm) {
- byte *resourcePointer;
- size_t resourceLength;
+ ByteArray resourceData;
debug(8, "Initializing scripting subsystem");
// Load script resource file context
@@ -184,14 +165,14 @@ SAGA2Script::SAGA2Script(SagaEngine *vm) : Script(vm) {
if (entryNum < 0)
error("Unable to locate the script's export segment");
debug(3, "Loading module LUT from resource %i", entryNum);
- _vm->_resource->loadResource(_scriptContext, (uint32)entryNum, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(_scriptContext, (uint32)entryNum, resourceData);
_modulesLUTEntryLen = sizeof(uint32);
// Calculate number of entries
- _modulesCount = resourceLength / _modulesLUTEntryLen + 1;
+ int modulesCount = resourceData.size() / _modulesLUTEntryLen + 1;
- debug(3, "LUT has %i entries", _modulesCount);
+ debug(3, "LUT has %i entries", modulesCount);
// Script data segment
/*
@@ -994,8 +975,8 @@ void Script::opSpeak(SCRIPTOP_PARAMS) {
}
} else {
#endif
- if (thread->_voiceLUT->voicesCount > first)
- sampleResourceId = thread->_voiceLUT->voices[first];
+ if (thread->_voiceLUT->size() > uint16(first))
+ sampleResourceId = (*thread->_voiceLUT)[uint16(first)];
#if 0
}
#endif
@@ -1067,12 +1048,11 @@ void Script::opJmpSeedRandom(SCRIPTOP_PARAMS) {
warning("opJmpSeedRandom");
}
-void Script::loadModule(int scriptModuleNumber) {
- byte *resourcePointer;
- size_t resourceLength;
+void Script::loadModule(uint scriptModuleNumber) {
+ ByteArray resourceData;
// Validate script number
- if ((scriptModuleNumber < 0) || (scriptModuleNumber >= _modulesCount)) {
+ if (scriptModuleNumber >= _modules.size()) {
error("Script::loadScript() Invalid script module number");
}
@@ -1083,79 +1063,70 @@ void Script::loadModule(int scriptModuleNumber) {
// Initialize script data structure
debug(3, "Loading script module #%d", scriptModuleNumber);
- _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].scriptResourceId, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].scriptResourceId, resourceData);
- loadModuleBase(_modules[scriptModuleNumber], resourcePointer, resourceLength);
- free(resourcePointer);
+ loadModuleBase(_modules[scriptModuleNumber], resourceData);
- _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].stringsResourceId, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].stringsResourceId, resourceData);
- _vm->loadStrings(_modules[scriptModuleNumber].strings, resourcePointer, resourceLength);
- free(resourcePointer);
+ _vm->loadStrings(_modules[scriptModuleNumber].strings, resourceData);
if (_modules[scriptModuleNumber].voicesResourceId > 0) {
- _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].voicesResourceId, resourcePointer, resourceLength);
+ _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].voicesResourceId, resourceData);
- loadVoiceLUT(_modules[scriptModuleNumber].voiceLUT, resourcePointer, resourceLength);
- free(resourcePointer);
+ loadVoiceLUT(_modules[scriptModuleNumber].voiceLUT, resourceData);
}
_modules[scriptModuleNumber].staticOffset = _staticSize;
_staticSize += _modules[scriptModuleNumber].staticSize;
- if (_staticSize > _commonBufferSize) {
- error("Script::loadModule() _staticSize > _commonBufferSize");
+ if (_staticSize > _commonBuffer.size()) {
+ error("Script::loadModule() _staticSize > _commonBuffer.size()");
}
_modules[scriptModuleNumber].loaded = true;
}
-void Script::freeModules() {
- int i;
- for (i = 0; i < _modulesCount; i++) {
+void Script::clearModules() {
+ uint i;
+ for (i = 0; i < _modules.size(); i++) {
if (_modules[i].loaded) {
- _modules[i].freeMem();
- _modules[i].loaded = false;
+ _modules[i].clear();
}
}
_staticSize = 0;
}
-void Script::loadModuleBase(ModuleData &module, const byte *resourcePointer, size_t resourceLength) {
- int i;
+void Script::loadModuleBase(ModuleData &module, const ByteArray &resourceData) {
+ uint i;
debug(3, "Loading module base...");
- module.moduleBase = (byte*)malloc(resourceLength);
- module.moduleBaseSize = resourceLength;
-
- memcpy(module.moduleBase, resourcePointer, resourceLength);
+ module.moduleBase.assign(resourceData);
- MemoryReadStreamEndian scriptS(module.moduleBase, module.moduleBaseSize, _scriptContext->isBigEndian());
+ ByteArrayReadStreamEndian scriptS(module.moduleBase, _scriptContext->isBigEndian());
- module.entryPointsCount = scriptS.readUint16();
+ uint entryPointsCount = scriptS.readUint16();
scriptS.readUint16(); //skip
- module.entryPointsTableOffset = scriptS.readUint16();
+ uint16 entryPointsTableOffset; // offset of entrypoint table in moduleBase
+ entryPointsTableOffset = scriptS.readUint16();
scriptS.readUint16(); //skip
- if ((module.moduleBaseSize - module.entryPointsTableOffset) < (module.entryPointsCount * SCRIPT_TBLENTRY_LEN)) {
+ if ((module.moduleBase.size() - entryPointsTableOffset) < (entryPointsCount * SCRIPT_TBLENTRY_LEN)) {
error("Script::loadModuleBase() Invalid table offset");
}
- if (module.entryPointsCount > SCRIPT_MAX) {
+ if (entryPointsCount > SCRIPT_MAX) {
error("Script::loadModuleBase()Script limit exceeded");
}
- module.entryPoints = (EntryPoint *)malloc(module.entryPointsCount * sizeof(*module.entryPoints));
- if (module.entryPoints == NULL) {
- memoryError("Script::loadModuleBase");
- }
+ module.entryPoints.resize(entryPointsCount);
// Read in the entrypoint table
module.staticSize = scriptS.readUint16();
- while (scriptS.pos() < module.entryPointsTableOffset)
+ while (scriptS.pos() < entryPointsTableOffset)
scriptS.readByte();
- for (i = 0; i < module.entryPointsCount; i++) {
+ for (i = 0; i < module.entryPoints.size(); i++) {
// First uint16 is the offset of the entrypoint name from the start
// of the bytecode resource, second uint16 is the offset of the
// bytecode itself for said entrypoint
@@ -1163,26 +1134,21 @@ void Script::loadModuleBase(ModuleData &module, const byte *resourcePointer, siz
module.entryPoints[i].offset = scriptS.readUint16();
// Perform a simple range check on offset values
- if ((module.entryPoints[i].nameOffset >= module.moduleBaseSize) || (module.entryPoints[i].offset >= module.moduleBaseSize)) {
+ if ((module.entryPoints[i].nameOffset >= module.moduleBase.size()) || (module.entryPoints[i].offset >= module.moduleBase.size())) {
error("Script::loadModuleBase() Invalid offset encountered in script entrypoint table");
}
}
}
-void Script::loadVoiceLUT(VoiceLUT &voiceLUT, const byte *resourcePointer, size_t resourceLength) {
+void Script::loadVoiceLUT(VoiceLUT &voiceLUT, const ByteArray &resourceData) {
uint16 i;
- voiceLUT.voicesCount = resourceLength / 2;
-
- voiceLUT.voices = (uint16 *)malloc(voiceLUT.voicesCount * sizeof(*voiceLUT.voices));
- if (voiceLUT.voices == NULL) {
- error("Script::loadVoiceLUT() not enough memory");
- }
+ voiceLUT.resize(resourceData.size() / 2);
- MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, _scriptContext->isBigEndian());
+ ByteArrayReadStreamEndian scriptS(resourceData, _scriptContext->isBigEndian());
- for (i = 0; i < voiceLUT.voicesCount; i++) {
- voiceLUT.voices[i] = scriptS.readUint16();
+ for (i = 0; i < voiceLUT.size(); i++) {
+ voiceLUT[i] = scriptS.readUint16();
}
}
@@ -1442,7 +1408,7 @@ void Script::doVerb() {
event.param4 = _pendingObject[0]; // Object
event.param5 = _pendingObject[1]; // With Object
event.param6 = (objectType == kGameObjectActor) ? _pendingObject[0] : ID_PROTAG; // Actor
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
} else {
// Show excuse text in ITE CD Versions
diff --git a/engines/saga/script.h b/engines/saga/script.h
index 21afeb5c44..e5054d5f4e 100644
--- a/engines/saga/script.h
+++ b/engines/saga/script.h
@@ -129,16 +129,7 @@ struct EntryPoint {
uint16 offset;
};
-struct VoiceLUT {
- uint16 voicesCount;
- uint16 *voices;
- void freeMem() {
- voicesCount = 0;
- free(voices);
- }
- VoiceLUT() {
- memset(this, 0, sizeof(*this));
- }
+class VoiceLUT : public Common::Array<uint16> {
};
struct ModuleData {
@@ -147,28 +138,29 @@ struct ModuleData {
int stringsResourceId;
int voicesResourceId;
- byte *moduleBase; // all base module
- uint16 moduleBaseSize; // base module size
+ ByteArray moduleBase; // all base module
uint16 staticSize; // size of static data
uint staticOffset; // offset of static data begining in _commonBuffer
-
- uint16 entryPointsTableOffset; // offset of entrypoint table in moduleBase
- uint16 entryPointsCount;
- EntryPoint *entryPoints;
+ Common::Array<EntryPoint> entryPoints;
StringsTable strings;
VoiceLUT voiceLUT;
- void freeMem() {
- strings.freeMem();
- voiceLUT.freeMem();
- free(moduleBase);
- free(entryPoints);
+
+ void clear() {
+ loaded = false;
+ strings.clear();
+ voiceLUT.clear();
+ moduleBase.clear();
+ entryPoints.clear();
+ }
+
+ ModuleData() : loaded(false), scriptResourceId(0), stringsResourceId(0), voicesResourceId(0), staticSize(0), staticOffset(0) {
}
};
class ScriptThread {
public:
- int16 *_stackBuf;
+ Common::Array<int16> _stackBuf;
uint16 _stackTopIndex;
uint16 _frameIndex;
@@ -264,41 +256,15 @@ public:
}
ScriptThread() {
- memset(this, 0xFE, sizeof(*this));
- _flags = kTFlagNone;
- _stackBuf = 0;
- }
-
- // copy constructor
- ScriptThread(const ScriptThread& s) {
- // Verify that s doesn't have a non-zero _stackBuf, for else
- // we would have to clone that buffer, too, which we currently
- // don't do. This case should never occur anyway, though (at
- // least as long as the thread handling code does not change).
- assert(!s._stackBuf);
+ memset(&_frameIndex, 0xFE, sizeof(_frameIndex));
+ memset(_threadVars, 0xFE, sizeof(_threadVars));
+ memset(&_waitType, 0xFE, sizeof(_waitType));
+ memset(&_sleepTime, 0xFE, sizeof(_sleepTime));
+ memset(&_threadObj, 0xFE, sizeof(_threadObj));
+ memset(&_returnValue, 0xFE, sizeof(_threadObj));
+ memset(&_frameWait, 0xFE, sizeof(_frameWait));
- memcpy(this, &s, sizeof(*this));
- }
-
- // assignment operator
- ScriptThread& operator=(const ScriptThread &s) {
- if (this == &s)
- return *this;
-
- // Verify that s doesn't have a non-zero _stackBuf, for else
- // we would have to clone that buffer, too, which we currently
- // don't do. This case should never occur anyway, though (at
- // least as long as the thread handling code does not change).
- assert(!s._stackBuf);
-
- free(_stackBuf);
- memcpy(this, &s, sizeof(*this));
-
- return *this;
- }
-
- ~ScriptThread() {
- free(_stackBuf);
+ _flags = kTFlagNone;
}
};
@@ -315,8 +281,8 @@ public:
Script(SagaEngine *vm);
virtual ~Script();
- void loadModule(int scriptModuleNumber);
- void freeModules();
+ void loadModule(uint scriptModuleNumber);
+ void clearModules();
void doVerb();
void showVerb(int statusColor = -1);
@@ -384,13 +350,11 @@ protected:
ResourceContext *_dataContext;
uint16 _modulesLUTEntryLen;
- ModuleData *_modules;
- int _modulesCount;
+ Common::Array<ModuleData> _modules;
TextListEntry *_placardTextEntry;
friend class SagaEngine;
- byte *_commonBuffer;
- uint _commonBufferSize;
+ ByteArray _commonBuffer;
uint _staticSize;
ScriptThreadList _threadList;
@@ -428,10 +392,10 @@ public:
void wakeUpThreads(int waitType);
void wakeUpThreadsDelayed(int waitType, int sleepTime);
- void loadVoiceLUT(VoiceLUT &voiceLUT, const byte *resourcePointer, size_t resourceLength);
+ void loadVoiceLUT(VoiceLUT &voiceLUT, const ByteArray &resourceData);
protected:
- void loadModuleBase(ModuleData &module, const byte *resourcePointer, size_t resourceLength);
+ void loadModuleBase(ModuleData &module, const ByteArray &resourceData);
// runThread returns true if we should break running of other threads
bool runThread(ScriptThread &thread);
diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp
index 328d4040af..1e34362dc4 100644
--- a/engines/saga/sfuncs.cpp
+++ b/engines/saga/sfuncs.cpp
@@ -327,7 +327,7 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) {
event.param4 = theObject; // Object
event.param5 = withObject; // With Object
event.param6 = objectId;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
// Script function #8 (0x08) nonblocking
@@ -782,11 +782,11 @@ void Script::sfSimulSpeech(SCRIPTFUNC_PARAMS) {
for (i = 0; i < actorsCount; i++)
actorsIds[i] = thread->pop();
- if (thread->_voiceLUT->voices) {
+ if (!thread->_voiceLUT->empty()) {
if (_vm->getGameId() == GID_IHNM && stringId >= 338) {
sampleResourceId = -1;
} else {
- sampleResourceId = thread->_voiceLUT->voices[stringId];
+ sampleResourceId = (*thread->_voiceLUT)[stringId];
if (sampleResourceId <= 0 || sampleResourceId > 4000)
sampleResourceId = -1;
}
@@ -953,7 +953,7 @@ void Script::sfPlaceActor(SCRIPTFUNC_PARAMS) {
int frameOffset = thread->pop();
ActorFrameRange *frameRange;
- debug(1, "sfPlaceActor(id = 0x%x, x=%d, y=%d, dir=%d, frameType=%d, frameOffset=%d)", actorId, actor->_location.x,
+ debug(1, "sfPlaceActor(id = 0x%X, x=%d, y=%d, dir=%d, frameType=%d, frameOffset=%d)", actorId, actor->_location.x,
actor->_location.y, actor->_facingDirection, frameType, frameOffset);
if (frameType >= 0) {
@@ -1042,8 +1042,8 @@ void Script::sfSimulSpeech2(SCRIPTFUNC_PARAMS) {
for (i = 0; i < actorsCount; i++)
actorsIds[i] = thread->pop();
- if (thread->_voiceLUT->voices) {
- sampleResourceId = thread->_voiceLUT->voices[stringId];
+ if (!thread->_voiceLUT->empty()) {
+ sampleResourceId = (*thread->_voiceLUT)[stringId];
if (sampleResourceId <= 0 || sampleResourceId > 4000)
sampleResourceId = -1;
}
@@ -1060,7 +1060,7 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
static PalEntry cur_pal[PAL_ENTRIES];
PalEntry *pal;
Event event;
- Event *q_event;
+ EventColumns *eventColumns;
thread->wait(kWaitTypePlacard);
@@ -1070,7 +1070,7 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
event.type = kEvTOneshot;
event.code = kCursorEvent;
event.op = kEventHide;
- q_event = _vm->_events->queue(&event);
+ eventColumns = _vm->_events->queue(event);
_vm->_interface->setFadeMode(kFadeOut);
@@ -1082,7 +1082,7 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// set fade mode
event.type = kEvTImmediate;
@@ -1091,12 +1091,12 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
event.param = kNoFade;
event.time = 0;
event.duration = 0;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
event.type = kEvTOneshot;
event.code = kInterfaceEvent;
event.op = kEventClearStatus;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
event.type = kEvTOneshot;
event.code = kGraphicsEvent;
@@ -1106,7 +1106,7 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
event.param3 = _vm->_scene->getHeight();
event.param4 = 0;
event.param5 = _vm->getDisplayInfo().width;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
// Put the text in the center of the viewport, assuming it will fit on
// one line. If we cannot make that assumption we'll need to extend
@@ -1130,7 +1130,7 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = _placardTextEntry;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
_vm->_scene->getBGPal(pal);
event.type = kEvTImmediate;
@@ -1139,13 +1139,13 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = pal;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
event.type = kEvTOneshot;
event.code = kScriptEvent;
event.op = kEventThreadWake;
event.param = kWaitTypePlacard;
- q_event = _vm->_events->chain(q_event, &event);
+ _vm->_events->chain(eventColumns, event);
}
@@ -1349,8 +1349,8 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) {
return;
}
- if (param1 >= _vm->_music->_songTableLen) {
- warning("sfPlayMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1);
+ if (uint(param1) >= _vm->_music->_songTable.size()) {
+ warning("sfPlayMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTable.size() - 1);
} else {
_vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(_vm->_music->_songTable[param1], param2 ? MUSIC_LOOP : MUSIC_NORMAL);
@@ -1440,7 +1440,7 @@ void Script::sfPlaySound(SCRIPTFUNC_PARAMS) {
int16 param = thread->pop();
int res;
- if (param >= 0 && param < _vm->_sndRes->_fxTableLen) {
+ if (uint(param) < _vm->_sndRes->_fxTable.size()) {
res = _vm->_sndRes->_fxTable[param].res;
if (_vm->getGameId() == GID_ITE && !(_vm->getFeatures() & GF_ITE_FLOPPY))
res -= 14;
@@ -1455,7 +1455,7 @@ void Script::sfPlayLoopedSound(SCRIPTFUNC_PARAMS) {
int16 param = thread->pop();
int res;
- if (param >= 0 && param < _vm->_sndRes->_fxTableLen) {
+ if (uint(param) < _vm->_sndRes->_fxTable.size()) {
res = _vm->_sndRes->_fxTable[param].res;
if (_vm->getGameId() == GID_ITE && !(_vm->getFeatures() & GF_ITE_FLOPPY))
res -= 14;
@@ -1527,7 +1527,7 @@ void Script::finishDialog(int strID, int replyID, int flags, int bitOffset) {
const char *str = _conversingThread->_strings->getString(strID);
if (*str != '[') {
int sampleResourceId = -1;
- sampleResourceId = _conversingThread->_voiceLUT->voices[strID];
+ sampleResourceId = (*_conversingThread->_voiceLUT)[strID];
if (sampleResourceId < 0 || sampleResourceId > 4000)
sampleResourceId = -1;
diff --git a/engines/saga/sfuncs_ihnm.cpp b/engines/saga/sfuncs_ihnm.cpp
index b98c1cb852..dd6bbbe6f8 100644
--- a/engines/saga/sfuncs_ihnm.cpp
+++ b/engines/saga/sfuncs_ihnm.cpp
@@ -247,7 +247,7 @@ void Script::sfScriptFade(SCRIPTFUNC_PARAMS) {
event.param2 = endingBrightness;
event.param3 = firstPalEntry;
event.param4 = lastPalEntry - firstPalEntry + 1;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
}
void Script::sfScriptStartVideo(SCRIPTFUNC_PARAMS) {
@@ -294,7 +294,7 @@ void Script::sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS) {
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = _psychicProfileTextEntry;
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
_ihnmDemoCurrentY += _vm->_font->getHeight(kKnownFontVerb, thread->_strings->getString(stringId), 226, kFontCentered);
}
@@ -413,8 +413,8 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
return;
}
- if (param1 >= _vm->_music->_songTableLen) {
- warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1);
+ if (uint(param1) >= _vm->_music->_songTable.size()) {
+ warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTable.size() - 1);
} else {
_vm->_music->setVolume(_vm->_musicVolume, 1);
event.type = kEvTOneshot;
@@ -424,7 +424,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
event.op = kEventPlay;
event.time = _vm->ticksToMSec(1000);
- _vm->_events->queue(&event);
+ _vm->_events->queue(event);
if (!_vm->_scene->haveChapterPointsChanged()) {
_vm->_scene->setCurrentMusicTrack(param1);
diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp
index 2137423a5a..592c2d0618 100644
--- a/engines/saga/shorten.cpp
+++ b/engines/saga/shorten.cpp
@@ -239,7 +239,7 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
return NULL;
}
- // Get block size
+ // Get block size
if (version > 0) {
blockSize = gReader->getUint32((int) (log((double) DEFAULT_BLOCK_SIZE) / M_LN2));
maxLPC = gReader->getUint32(2);
@@ -366,7 +366,12 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
if (maxLPC < lpcNum) {
warning("Safeguard: maxLPC < lpcNum (should never happen)");
maxLPC = lpcNum;
- lpc = (int32 *) realloc(lpc, maxLPC * 4);
+ int32 *tmp = (int32 *) realloc(lpc, maxLPC * 4);
+ if ((tmp != NULL) || (maxLPC == 0)) {
+ lpc = tmp;
+ } else {
+ error("loadShortenFromStream(): Error while reallocating memory");
+ }
}
for (i = 0; i < lpcNum; i++)
@@ -430,7 +435,12 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
prevSize = size;
size += (blockSize * dataSize);
- unpackedBuffer = (byte *) realloc(unpackedBuffer, size);
+ byte *tmp = (byte *) realloc(unpackedBuffer, size);
+ if ((tmp != NULL) || (size == 0)) {
+ unpackedBuffer = tmp;
+ } else {
+ error("loadShortenFromStream(): Error while reallocating memory");
+ }
pBuf = unpackedBuffer + prevSize;
if (flags & Audio::FLAG_16BITS) {
@@ -464,7 +474,12 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
uint32 vLen = (uint32)gReader->getURice(5);
prevSize = size;
size += vLen;
- unpackedBuffer = (byte *) realloc(unpackedBuffer, size);
+ byte *tmp = (byte *) realloc(unpackedBuffer, size);
+ if ((tmp != NULL) || (size == 0)) {
+ unpackedBuffer = tmp;
+ } else {
+ error("loadShortenFromStream(): Error while reallocating memory");
+ }
pBuf = unpackedBuffer + prevSize;
while (vLen--) {
diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp
index 9322918db5..74fde3e497 100644
--- a/engines/saga/sndres.cpp
+++ b/engines/saga/sndres.cpp
@@ -60,8 +60,11 @@ SndRes::SndRes(SagaEngine *vm) : _vm(vm), _sfxContext(NULL), _voiceContext(NULL)
setVoiceBank(0);
if (_vm->getGameId() == GID_ITE) {
- _fxTable = ITE_SfxTable;
- _fxTableLen = ITE_SFXCOUNT;
+ _fxTable.resize(ITE_SFXCOUNT);
+ for (uint i = 0; i < _fxTable.size(); i++) {
+ _fxTable[i].res = ITE_SfxTable[i].res;
+ _fxTable[i].vol = ITE_SfxTable[i].vol;
+ }
#ifdef ENABLE_IHNM
} else if (_vm->getGameId() == GID_IHNM) {
ResourceContext *resourceContext;
@@ -71,32 +74,24 @@ SndRes::SndRes(SagaEngine *vm) : _vm(vm), _sfxContext(NULL), _voiceContext(NULL)
error("Resource::loadGlobalResources() resource context not found");
}
- byte *resourcePointer;
- size_t resourceLength;
+ ByteArray resourceData;
if (_vm->isIHNMDemo()) {
- _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_SFX_LUT,
- resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_SFX_LUT, resourceData);
} else {
- _vm->_resource->loadResource(resourceContext, RID_IHNM_SFX_LUT,
- resourcePointer, resourceLength);
+ _vm->_resource->loadResource(resourceContext, RID_IHNM_SFX_LUT, resourceData);
}
- if (resourceLength == 0) {
+ if (resourceData.empty()) {
error("Sndres::SndRes can't read SfxIDs table");
}
- _fxTableIDsLen = resourceLength / 2;
- _fxTableIDs = (int16 *)malloc(_fxTableIDsLen * sizeof(int16));
+ _fxTableIDs.resize(resourceData.size() / 2);
- MemoryReadStream metaS(resourcePointer, resourceLength);
- for (int i = 0; i < _fxTableIDsLen; i++)
+ ByteArrayReadStreamEndian metaS(resourceData);
+ for (uint i = 0; i < _fxTableIDs.size(); i++) {
_fxTableIDs[i] = metaS.readSint16LE();
-
- free(resourcePointer);
-
- _fxTable = 0;
- _fxTableLen = 0;
+ }
#endif
#ifdef ENABLE_SAGA2
} else if (_vm->getGameId() == GID_DINO) {
@@ -108,12 +103,6 @@ SndRes::SndRes(SagaEngine *vm) : _vm(vm), _sfxContext(NULL), _voiceContext(NULL)
}
SndRes::~SndRes() {
-#ifdef ENABLE_IHNM
- if (_vm->getGameId() == GID_IHNM) {
- free(_fxTable);
- free(_fxTableIDs);
- }
-#endif
}
void SndRes::setVoiceBank(int serial) {
@@ -327,7 +316,7 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
#endif
} else if (resourceType == kSoundVOC) {
data = Audio::loadVOCFromStream(readS, size, rate);
- result = (data != 0);
+ result = (data != NULL);
if (onlyHeader)
free(data);
buffer.flags |= Audio::FLAG_UNSIGNED;
@@ -339,11 +328,13 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.frequency = rate;
buffer.size = size;
- if (!onlyHeader && resourceType != kSoundVOC) {
- buffer.buffer = (byte *)malloc(size);
- readS.read(buffer.buffer, size);
- } else if (!onlyHeader && resourceType == kSoundVOC) {
- buffer.buffer = data;
+ if (!onlyHeader) {
+ if (resourceType == kSoundVOC) {
+ buffer.buffer = data;
+ } else {
+ buffer.buffer = (byte *)malloc(size);
+ readS.read(buffer.buffer, size);
+ }
}
}
break;
diff --git a/engines/saga/sndres.h b/engines/saga/sndres.h
index d5507ebc55..e4bae1b143 100644
--- a/engines/saga/sndres.h
+++ b/engines/saga/sndres.h
@@ -33,6 +33,11 @@
namespace Saga {
+struct FxTable {
+ int16 res;
+ int16 vol;
+};
+
class SndRes {
public:
@@ -44,11 +49,9 @@ public:
int getVoiceLength(uint32 resourceId);
void setVoiceBank(int serial);
- FxTable *_fxTable;
- int _fxTableLen;
+ Common::Array<FxTable> _fxTable;
- int16 *_fxTableIDs;
- int _fxTableIDsLen;
+ Common::Array<int16> _fxTableIDs;
private:
bool load(ResourceContext *context, uint32 resourceId, SoundBuffer &buffer, bool onlyHeader);
diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp
index db979e8104..b3fcf4def3 100644
--- a/engines/saga/sound.cpp
+++ b/engines/saga/sound.cpp
@@ -36,7 +36,7 @@
namespace Saga {
Sound::Sound(SagaEngine *vm, Audio::Mixer *mixer) :
- _vm(vm), _mixer(mixer), _voxStream(0) {
+ _vm(vm), _mixer(mixer) {
for (int i = 0; i < SOUND_HANDLES; i++)
_handles[i].type = kFreeHandle;
@@ -45,7 +45,6 @@ Sound::Sound(SagaEngine *vm, Audio::Mixer *mixer) :
}
Sound::~Sound() {
- delete _voxStream;
}
SndHandle *Sound::getHandle() {
diff --git a/engines/saga/sound.h b/engines/saga/sound.h
index 7ee2765a0f..b5f82369f4 100644
--- a/engines/saga/sound.h
+++ b/engines/saga/sound.h
@@ -95,7 +95,6 @@ public:
SagaEngine *_vm;
Audio::Mixer *_mixer;
- MemoryReadStream *_voxStream;
SndHandle _handles[SOUND_HANDLES];
};
diff --git a/engines/saga/sprite.cpp b/engines/saga/sprite.cpp
index c1a9846b47..eb62fb20ff 100644
--- a/engines/saga/sprite.cpp
+++ b/engines/saga/sprite.cpp
@@ -51,13 +51,6 @@ Sprite::Sprite(SagaEngine *vm) : _vm(vm) {
error("Sprite::Sprite resource context not found");
}
- _decodeBufLen = DECODE_BUF_LEN;
-
- _decodeBuf = (byte *)malloc(_decodeBufLen);
- if (_decodeBuf == NULL) {
- memoryError("Sprite::Sprite");
- }
-
if (_vm->getGameId() == GID_ITE) {
loadList(_vm->getResourceDescription()->mainSpritesResourceId, _mainSprites);
_arrowSprites = _saveReminderSprites = _inventorySprites = _mainSprites;
@@ -78,67 +71,54 @@ Sprite::Sprite(SagaEngine *vm) : _vm(vm) {
Sprite::~Sprite() {
debug(8, "Shutting down sprite subsystem...");
- _mainSprites.freeMem();
- if (_vm->getGameId() == GID_IHNM) {
- _inventorySprites.freeMem();
- _arrowSprites.freeMem();
- _saveReminderSprites.freeMem();
- }
- free(_decodeBuf);
}
void Sprite::loadList(int resourceId, SpriteList &spriteList) {
SpriteInfo *spriteInfo;
- byte *spriteListData = 0;
- size_t spriteListLength = 0;
+ ByteArray spriteListData;
uint16 oldSpriteCount;
uint16 newSpriteCount;
uint16 spriteCount;
- int i;
+ uint i;
int outputLength, inputLength;
uint32 offset;
const byte *spritePointer;
const byte *spriteDataPointer;
- _vm->_resource->loadResource(_spriteContext, resourceId, spriteListData, spriteListLength);
+ _vm->_resource->loadResource(_spriteContext, resourceId, spriteListData);
- if (spriteListLength == 0) {
+ if (spriteListData.empty()) {
return;
}
- MemoryReadStreamEndian readS(spriteListData, spriteListLength, _spriteContext->isBigEndian());
+ ByteArrayReadStreamEndian readS(spriteListData, _spriteContext->isBigEndian());
spriteCount = readS.readUint16();
debug(9, "Sprites: %d", spriteCount);
- oldSpriteCount = spriteList.spriteCount;
- newSpriteCount = spriteList.spriteCount + spriteCount;
+ oldSpriteCount = spriteList.size();
+ newSpriteCount = oldSpriteCount + spriteCount;
- spriteList.infoList = (SpriteInfo *)realloc(spriteList.infoList, newSpriteCount * sizeof(*spriteList.infoList));
- if (spriteList.infoList == NULL) {
- memoryError("Sprite::loadList");
- }
-
- spriteList.spriteCount = newSpriteCount;
+ spriteList.resize(newSpriteCount);
bool bigHeader = _vm->getGameId() == GID_IHNM || _vm->isMacResources();
- for (i = oldSpriteCount; i < spriteList.spriteCount; i++) {
- spriteInfo = &spriteList.infoList[i];
+ for (i = oldSpriteCount; i < spriteList.size(); i++) {
+ spriteInfo = &spriteList[i];
if (bigHeader)
offset = readS.readUint32();
else
offset = readS.readUint16();
- if (offset >= spriteListLength) {
+ if (offset >= spriteListData.size()) {
// ITE Mac demos throw this warning
warning("Sprite::loadList offset exceeded");
- spriteList.spriteCount = i;
+ spriteList.resize(i);
return;
}
- spritePointer = spriteListData;
+ spritePointer = spriteListData.getBuffer();
spritePointer += offset;
if (bigHeader) {
@@ -163,114 +143,147 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) {
}
outputLength = spriteInfo->width * spriteInfo->height;
- inputLength = spriteListLength - (spriteDataPointer - spriteListData);
- decodeRLEBuffer(spriteDataPointer, inputLength, outputLength);
- spriteInfo->decodedBuffer = (byte *) malloc(outputLength);
- if (spriteInfo->decodedBuffer == NULL) {
- memoryError("Sprite::loadList");
- }
-
+ inputLength = spriteListData.size() - (spriteDataPointer - spriteListData.getBuffer());
+ spriteInfo->decodedBuffer.resize(outputLength);
+ if (outputLength > 0) {
+ decodeRLEBuffer(spriteDataPointer, inputLength, outputLength);
+ byte *dst = &spriteInfo->decodedBuffer.front();
#ifdef ENABLE_IHNM
- // IHNM sprites are upside-down, for reasons which i can only
- // assume are perverse. To simplify things, flip them now. Not
- // at drawing time.
-
- if (_vm->getGameId() == GID_IHNM) {
- byte *src = _decodeBuf + spriteInfo->width * (spriteInfo->height - 1);
- byte *dst = spriteInfo->decodedBuffer;
-
- for (int j = 0; j < spriteInfo->height; j++) {
- memcpy(dst, src, spriteInfo->width);
- src -= spriteInfo->width;
- dst += spriteInfo->width;
- }
- } else
+ // IHNM sprites are upside-down, for reasons which i can only
+ // assume are perverse. To simplify things, flip them now. Not
+ // at drawing time.
+
+ if (_vm->getGameId() == GID_IHNM) {
+ byte *src = &_decodeBuf[spriteInfo->width * (spriteInfo->height - 1)];
+
+ for (int j = 0; j < spriteInfo->height; j++) {
+ memcpy(dst, src, spriteInfo->width);
+ src -= spriteInfo->width;
+ dst += spriteInfo->width;
+ }
+ } else
#endif
- memcpy(spriteInfo->decodedBuffer, _decodeBuf, outputLength);
+ memcpy(dst, &_decodeBuf.front(), outputLength);
+ }
}
-
- free(spriteListData);
}
-void Sprite::getScaledSpriteBuffer(SpriteList &spriteList, int spriteNumber, int scale, int &width, int &height, int &xAlign, int &yAlign, const byte *&buffer) {
+void Sprite::getScaledSpriteBuffer(SpriteList &spriteList, uint spriteNumber, int scale, int &width, int &height, int &xAlign, int &yAlign, const byte *&buffer) {
SpriteInfo *spriteInfo;
- if (spriteList.spriteCount <= spriteNumber) {
+ if (spriteList.size() <= spriteNumber) {
// this can occur in IHNM while loading a saved game from chapter 1-5 when being in the end chapter
- warning("spriteList.spriteCount <= spriteNumber");
+ warning("spriteList.size() <= spriteNumber");
return;
}
- spriteInfo = &spriteList.infoList[spriteNumber];
+ spriteInfo = &spriteList[spriteNumber];
if (scale < 256) {
- xAlign = (spriteInfo->xAlign * scale) >> 8;
- yAlign = (spriteInfo->yAlign * scale) >> 8;
+ xAlign = (spriteInfo->xAlign * scale) >> 8; //TODO: do we need to take in account sprite x&y aligns ?
+ yAlign = (spriteInfo->yAlign * scale) >> 8; // ????
height = (spriteInfo->height * scale + 0x7f) >> 8;
width = (spriteInfo->width * scale + 0x7f) >> 8;
- scaleBuffer(spriteInfo->decodedBuffer, spriteInfo->width, spriteInfo->height, scale);
- buffer = _decodeBuf;
+ size_t outLength = width * height;
+ if (outLength > 0) {
+ scaleBuffer(&spriteInfo->decodedBuffer.front(), spriteInfo->width, spriteInfo->height, scale, outLength);
+ buffer = &_decodeBuf.front();
+ } else {
+ buffer = NULL;
+ }
} else {
xAlign = spriteInfo->xAlign;
yAlign = spriteInfo->yAlign;
height = spriteInfo->height;
width = spriteInfo->width;
- buffer = spriteInfo->decodedBuffer;
+ buffer = spriteInfo->decodedBuffer.getBuffer();
}
}
void Sprite::drawClip(const Point &spritePointer, int width, int height, const byte *spriteBuffer, bool clipToScene) {
- int clipWidth;
- int clipHeight;
Common::Rect clipRect = clipToScene ? _vm->_scene->getSceneClip() : _vm->getDisplayClip();
- int i, j, jo, io;
+ int xDstOffset, yDstOffset, xSrcOffset, ySrcOffset, xDiff, yDiff, cWidth, cHeight;
byte *bufRowPointer;
+ byte *bufPointer;
const byte *srcRowPointer;
+ const byte *srcPointer;
+
+ int backBufferPitch = _vm->_gfx->getBackBufferPitch();
+
+ //find Rects intersection
+ yDiff = clipRect.top - spritePointer.y;
+ if (yDiff > 0) {
+ ySrcOffset = yDiff;
+ yDstOffset = clipRect.top;
+ cHeight = height - yDiff;
+ } else {
+ ySrcOffset = 0;
+ yDstOffset = spritePointer.y;
+ cHeight = height;
+ }
- bufRowPointer = _vm->_gfx->getBackBufferPixels() + _vm->_gfx->getBackBufferPitch() * spritePointer.y;
- srcRowPointer = spriteBuffer;
-
- clipWidth = CLIP(width, 0, clipRect.right - spritePointer.x);
- clipHeight = CLIP(height, 0, clipRect.bottom - spritePointer.y);
-
- jo = 0;
- io = 0;
- if (spritePointer.x < clipRect.left) {
- jo = clipRect.left - spritePointer.x;
+ xDiff = clipRect.left - spritePointer.x;
+ if (xDiff > 0) {
+ xSrcOffset = xDiff;
+ xDstOffset = clipRect.left;
+ cWidth = width - xDiff;
+ } else {
+ xSrcOffset = 0;
+ xDstOffset = spritePointer.x;
+ cWidth = width;
}
- if (spritePointer.y < clipRect.top) {
- io = clipRect.top - spritePointer.y;
- bufRowPointer += _vm->_gfx->getBackBufferPitch() * io;
- srcRowPointer += width * io;
+
+ yDiff = yDstOffset + cHeight - clipRect.bottom;
+ if (yDiff > 0) {
+ cHeight -= yDiff;
}
- for (i = io; i < clipHeight; i++) {
- for (j = jo; j < clipWidth; j++) {
- assert(_vm->_gfx->getBackBufferPixels() <= (byte *)(bufRowPointer + j + spritePointer.x));
- assert((_vm->_gfx->getBackBufferPixels() + (_vm->getDisplayInfo().width *
- _vm->getDisplayInfo().height)) > (byte *)(bufRowPointer + j + spritePointer.x));
- assert((const byte *)spriteBuffer <= (const byte *)(srcRowPointer + j));
- assert(((const byte *)spriteBuffer + (width * height)) > (const byte *)(srcRowPointer + j));
+ xDiff = xDstOffset + cWidth - clipRect.right;
+ if (xDiff > 0) {
+ cWidth -= xDiff;
+ }
- if (*(srcRowPointer + j) != 0) {
- *(bufRowPointer + j + spritePointer.x) = *(srcRowPointer + j);
+ if ((cHeight <= 0) || (cWidth <= 0)) {
+ //no intersection
+ return;
+ }
+ bufRowPointer = _vm->_gfx->getBackBufferPixels() + backBufferPitch * yDstOffset + xDstOffset;
+ srcRowPointer = spriteBuffer + width * ySrcOffset + xSrcOffset;
+
+ // validate src, dst buffers
+ assert(_vm->_gfx->getBackBufferPixels() <= bufRowPointer);
+ assert((_vm->_gfx->getBackBufferPixels() + (_vm->getDisplayInfo().width * _vm->getDisplayInfo().height)) >=
+ (byte *)(bufRowPointer + backBufferPitch * (cHeight - 1) + cWidth));
+ assert((const byte *)spriteBuffer <= srcRowPointer);
+ assert(((const byte *)spriteBuffer + (width * height)) >= (const byte *)(srcRowPointer + width * (cHeight - 1) + cWidth));
+
+ const byte *srcPointerFinish2 = srcRowPointer + width * cHeight;
+ for (;;) {
+ srcPointer = srcRowPointer;
+ bufPointer = bufRowPointer;
+ const byte *srcPointerFinish = srcRowPointer + cWidth;
+ for (;;) {
+ if (*srcPointer != 0) {
+ *bufPointer = *srcPointer;
+ }
+ srcPointer++;
+ bufPointer++;
+ if (srcPointer == srcPointerFinish) {
+ break;
}
}
- bufRowPointer += _vm->_gfx->getBackBufferPitch();
srcRowPointer += width;
+ if (srcRowPointer == srcPointerFinish2) {
+ break;
+ }
+ bufRowPointer += backBufferPitch;
}
- int x1 = MAX<int>(spritePointer.x, 0);
- int y1 = MAX<int>(spritePointer.y, 0);
- int x2 = MIN<int>(MAX<int>(spritePointer.x + clipWidth, 0), clipRect.right);
- int y2 = MIN<int>(MAX<int>(spritePointer.y + clipHeight, 0), clipRect.bottom);
-
- if (x2 > x1 && y2 > y1)
- _vm->_render->addDirtyRect(Common::Rect(x1, y1, x2, y2));
+ _vm->_render->addDirtyRect(Common::Rect(xDstOffset, yDstOffset, xDstOffset + cWidth, yDstOffset + cHeight));
}
-void Sprite::draw(SpriteList &spriteList, int32 spriteNumber, const Point &screenCoord, int scale, bool clipToScene) {
+void Sprite::draw(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, bool clipToScene) {
const byte *spriteBuffer = NULL;
int width = 0;
int height = 0;
@@ -286,7 +299,7 @@ void Sprite::draw(SpriteList &spriteList, int32 spriteNumber, const Point &scree
drawClip(spritePointer, width, height, spriteBuffer, clipToScene);
}
-void Sprite::draw(SpriteList &spriteList, int32 spriteNumber, const Rect &screenRect, int scale, bool clipToScene) {
+void Sprite::draw(SpriteList &spriteList, uint spriteNumber, const Rect &screenRect, int scale, bool clipToScene) {
const byte *spriteBuffer = NULL;
int width = 0;
int height = 0;
@@ -310,7 +323,7 @@ void Sprite::draw(SpriteList &spriteList, int32 spriteNumber, const Rect &screen
drawClip(spritePointer, width, height, spriteBuffer, clipToScene);
}
-bool Sprite::hitTest(SpriteList &spriteList, int spriteNumber, const Point &screenCoord, int scale, const Point &testPoint) {
+bool Sprite::hitTest(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, const Point &testPoint) {
const byte *spriteBuffer = NULL;
int i, j;
const byte *srcRowPointer;
@@ -337,7 +350,7 @@ bool Sprite::hitTest(SpriteList &spriteList, int spriteNumber, const Point &scre
return *srcRowPointer != 0;
}
-void Sprite::drawOccluded(SpriteList &spriteList, int spriteNumber, const Point &screenCoord, int scale, int depth) {
+void Sprite::drawOccluded(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, int depth) {
const byte *spriteBuffer = NULL;
int x, y;
byte *destRowPointer;
@@ -356,7 +369,6 @@ void Sprite::drawOccluded(SpriteList &spriteList, int spriteNumber, const Point
int maskWidth;
int maskHeight;
byte *maskBuffer;
- size_t maskBufferLength;
byte *maskRowPointer;
int maskZ;
@@ -365,7 +377,7 @@ void Sprite::drawOccluded(SpriteList &spriteList, int spriteNumber, const Point
return;
}
- _vm->_scene->getBGMaskInfo(maskWidth, maskHeight, maskBuffer, maskBufferLength);
+ _vm->_scene->getBGMaskInfo(maskWidth, maskHeight, maskBuffer);
getScaledSpriteBuffer(spriteList, spriteNumber, scale, width, height, xAlign, yAlign, spriteBuffer);
@@ -420,15 +432,11 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou
byte *outPointerEnd;
int c;
- if (outLength > _decodeBufLen) { // TODO: may we should make dynamic growing?
- error("Sprite::decodeRLEBuffer outLength > _decodeBufLen");
- }
-
- outPointer = _decodeBuf;
- outPointerEnd = _decodeBuf + outLength;
- outPointerEnd--;
+ _decodeBuf.resize(outLength);
+ outPointer = &_decodeBuf.front();
+ outPointerEnd = &_decodeBuf.back();
- memset(outPointer, 0, outLength);
+ memset(outPointer, 0, _decodeBuf.size());
MemoryReadStream readS(inputBuffer, inLength);
@@ -458,10 +466,14 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou
}
}
-void Sprite::scaleBuffer(const byte *src, int width, int height, int scale) {
+void Sprite::scaleBuffer(const byte *src, int width, int height, int scale, size_t outLength) {
byte skip = 256 - scale; // skip factor
byte vskip = 0x80, hskip;
- byte *dst = _decodeBuf;
+
+ _decodeBuf.resize(outLength);
+ byte *dst = &_decodeBuf.front();
+
+ memset(dst, 0, _decodeBuf.size());
for (int i = 0; i < height; i++) {
vskip += skip;
diff --git a/engines/saga/sprite.h b/engines/saga/sprite.h
index b7365fd28f..4e463cdd88 100644
--- a/engines/saga/sprite.h
+++ b/engines/saga/sprite.h
@@ -33,32 +33,19 @@ namespace Saga {
#define SPRITE_ZMAX 16
#define SPRITE_ZMASK 0x0F
-#define DECODE_BUF_LEN 64000
-
struct SpriteInfo {
- byte *decodedBuffer;
+ ByteArray decodedBuffer;
int width;
int height;
int xAlign;
int yAlign;
-};
-struct SpriteList {
- int spriteListResourceId;
- int spriteCount;
- SpriteInfo *infoList;
-
- void freeMem() {
- for (int i = 0; i < spriteCount; i++) {
- free(infoList[i].decodedBuffer);
- }
- free(infoList);
- memset(this, 0, sizeof(*this));
+ SpriteInfo() : width(0), height(0), xAlign(0), yAlign(0) {
}
+};
- SpriteList() {
- memset(this, 0, sizeof(*this));
- }
+class SpriteList : public Common::Array<SpriteInfo> {
+// int spriteListResourceId;
};
@@ -73,28 +60,27 @@ public:
~Sprite();
// draw scaled sprite using background scene mask
- void drawOccluded(SpriteList &spriteList, int spriteNumber, const Point &screenCoord, int scale, int depth);
+ void drawOccluded(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, int depth);
// draw scaled sprite using background scene mask
- void draw(SpriteList &spriteList, int32 spriteNumber, const Point &screenCoord, int scale, bool clipToScene = false);
+ void draw(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, bool clipToScene = false);
// main function
void drawClip(const Point &spritePointer, int width, int height, const byte *spriteBuffer, bool clipToScene = false);
- void draw(SpriteList &spriteList, int32 spriteNumber, const Rect &screenRect, int scale, bool clipToScene = false);
+ void draw(SpriteList &spriteList, uint spriteNumber, const Rect &screenRect, int scale, bool clipToScene = false);
void loadList(int resourceId, SpriteList &spriteList); // load or append spriteList
- bool hitTest(SpriteList &spriteList, int spriteNumber, const Point &screenCoord, int scale, const Point &testPoint);
- void getScaledSpriteBuffer(SpriteList &spriteList, int spriteNumber, int scale, int &width, int &height, int &xAlign, int &yAlign, const byte *&buffer);
+ bool hitTest(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, const Point &testPoint);
+ void getScaledSpriteBuffer(SpriteList &spriteList, uint spriteNumber, int scale, int &width, int &height, int &xAlign, int &yAlign, const byte *&buffer);
private:
void decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t outLength);
- void scaleBuffer(const byte *src, int width, int height, int scale);
+ void scaleBuffer(const byte *src, int width, int height, int scale, size_t outLength);
SagaEngine *_vm;
ResourceContext *_spriteContext;
- byte *_decodeBuf;
- size_t _decodeBufLen;
+ ByteArray _decodeBuf;
};
} // End of namespace Saga
diff --git a/engines/saga/sthread.cpp b/engines/saga/sthread.cpp
index be674e5acd..098970f4e8 100644
--- a/engines/saga/sthread.cpp
+++ b/engines/saga/sthread.cpp
@@ -39,16 +39,18 @@ namespace Saga {
ScriptThread &Script::createThread(uint16 scriptModuleNumber, uint16 scriptEntryPointNumber) {
loadModule(scriptModuleNumber);
- if (_modules[scriptModuleNumber].entryPointsCount <= scriptEntryPointNumber) {
+ if (_modules[scriptModuleNumber].entryPoints.size() <= scriptEntryPointNumber) {
error("Script::createThread wrong scriptEntryPointNumber");
}
- ScriptThread newThread;
+ ScriptThread tmp;
+ _threadList.push_front(tmp);
+ ScriptThread &newThread = _threadList.front();
newThread._instructionOffset = _modules[scriptModuleNumber].entryPoints[scriptEntryPointNumber].offset;
- newThread._commonBase = _commonBuffer;
- newThread._staticBase = _commonBuffer + _modules[scriptModuleNumber].staticOffset;
- newThread._moduleBase = _modules[scriptModuleNumber].moduleBase;
- newThread._moduleBaseSize = _modules[scriptModuleNumber].moduleBaseSize;
+ newThread._commonBase = _commonBuffer.getBuffer();
+ newThread._staticBase = _commonBuffer.getBuffer() + _modules[scriptModuleNumber].staticOffset;
+ newThread._moduleBase = _modules[scriptModuleNumber].moduleBase.getBuffer();
+ newThread._moduleBaseSize = _modules[scriptModuleNumber].moduleBase.size();
newThread._strings = &_modules[scriptModuleNumber].strings;
if (_vm->getGameId() == GID_IHNM)
@@ -56,14 +58,10 @@ ScriptThread &Script::createThread(uint16 scriptModuleNumber, uint16 scriptEntry
else
newThread._voiceLUT = &_modules[scriptModuleNumber].voiceLUT;
- _threadList.push_front(newThread);
-
+ newThread._stackBuf.resize(ScriptThread::THREAD_STACK_SIZE);
+ newThread._stackTopIndex = ScriptThread::THREAD_STACK_SIZE - 2;
debug(3, "createThread(). Total threads: %d", _threadList.size());
-
- ScriptThread &tmp = *_threadList.begin();
- tmp._stackBuf = (int16 *)malloc(ScriptThread::THREAD_STACK_SIZE * sizeof(int16));
- tmp._stackTopIndex = ScriptThread::THREAD_STACK_SIZE - 2;
- return tmp;
+ return newThread;
}
void Script::wakeUpActorThread(int waitType, void *threadObj) {
@@ -211,7 +209,7 @@ bool Script::runThread(ScriptThread &thread) {
savedInstructionOffset = thread._instructionOffset;
operandChar = scriptS.readByte();
- debug(8, "Executing thread offset: %u (%x) stack: %d", thread._instructionOffset, operandChar, thread.pushedSize());
+ debug(8, "Executing thread offset: %u (0x%X) stack: %d", thread._instructionOffset, operandChar, thread.pushedSize());
stopParsing = false;
debug(4, "Calling op %s", this->_scriptOpsList[operandChar].scriptOpName);
diff --git a/engines/savestate.cpp b/engines/savestate.cpp
index 3cd81a2ff6..368f59ef51 100644
--- a/engines/savestate.cpp
+++ b/engines/savestate.cpp
@@ -70,3 +70,9 @@ void SaveStateDescriptor::setPlayTime(int hours, int minutes) {
snprintf(buffer, 32, "%.2d:%.2d", hours, minutes);
setVal("play_time", buffer);
}
+
+void SaveStateDescriptor::setPlayTime(uint32 msecs) {
+ uint minutes = msecs / 60000;
+ setPlayTime(minutes / 60, minutes % 60);
+}
+
diff --git a/engines/savestate.h b/engines/savestate.h
index ddbcea1acf..37f2b9bdd4 100644
--- a/engines/savestate.h
+++ b/engines/savestate.h
@@ -127,6 +127,11 @@ public:
* Sets the 'play_time' key properly, based on the given values.
*/
void setPlayTime(int hours, int minutes);
+
+ /**
+ * Sets the 'play_time' key properly, based on the given value.
+ */
+ void setPlayTime(uint32 msecs);
};
/** List of savestates. */
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 79f63fded4..42b1d06e11 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -39,6 +39,7 @@
#include "sci/sound/midiparser_sci.h"
#include "sci/sound/music.h"
#include "sci/sound/drivers/mididriver.h"
+#include "sci/sound/drivers/map-mt32-to-gm.h"
#include "sci/graphics/cursor.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint.h"
@@ -67,7 +68,7 @@ bool g_debug_track_mouse_clicks = false;
static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeValue);
Console::Console(SciEngine *engine) : GUI::Debugger(),
- _engine(engine), _debugState(engine->_debugState), _enterTime(0) {
+ _engine(engine), _debugState(engine->_debugState) {
// Variables
DVar_Register("sleeptime_factor", &g_debug_sleeptime_factor, DVAR_INT, 0);
@@ -103,7 +104,6 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
DCmd_Register("list", WRAP_METHOD(Console, cmdList));
DCmd_Register("hexgrep", WRAP_METHOD(Console, cmdHexgrep));
DCmd_Register("verify_scripts", WRAP_METHOD(Console, cmdVerifyScripts));
- DCmd_Register("show_instruments", WRAP_METHOD(Console, cmdShowInstruments));
// Game
DCmd_Register("save_game", WRAP_METHOD(Console, cmdSaveGame));
DCmd_Register("restore_game", WRAP_METHOD(Console, cmdRestoreGame));
@@ -145,6 +145,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
DCmd_Register("stopallsounds", WRAP_METHOD(Console, cmdStopAllSounds));
DCmd_Register("sfx01_header", WRAP_METHOD(Console, cmdSfx01Header));
DCmd_Register("sfx01_track", WRAP_METHOD(Console, cmdSfx01Track));
+ DCmd_Register("show_instruments", WRAP_METHOD(Console, cmdShowInstruments));
+ DCmd_Register("map_instrument", WRAP_METHOD(Console, cmdMapInstrument));
// Script
DCmd_Register("addresses", WRAP_METHOD(Console, cmdAddresses));
DCmd_Register("registers", WRAP_METHOD(Console, cmdRegisters));
@@ -166,6 +168,7 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
DCmd_Register("snk", WRAP_METHOD(Console, cmdStepCallk)); // alias
DCmd_Register("disasm", WRAP_METHOD(Console, cmdDisassemble));
DCmd_Register("disasm_addr", WRAP_METHOD(Console, cmdDisassembleAddress));
+ DCmd_Register("find_callk", WRAP_METHOD(Console, cmdFindKernelFunctionCall));
DCmd_Register("send", WRAP_METHOD(Console, cmdSend));
DCmd_Register("go", WRAP_METHOD(Console, cmdGo));
DCmd_Register("logkernel", WRAP_METHOD(Console, cmdLogKernel));
@@ -218,15 +221,10 @@ Console::~Console() {
}
void Console::preEnter() {
- if (g_sci && g_sci->_soundCmd)
- g_sci->_soundCmd->pauseAll(true);
- _enterTime = g_system->getMillis();
+ _engine->pauseEngine(true);
}
void Console::postEnter() {
- if (g_sci && g_sci->_soundCmd)
- g_sci->_soundCmd->pauseAll(false);
-
if (!_videoFile.empty()) {
_engine->_gfxCursor->kernelHide();
@@ -283,8 +281,7 @@ void Console::postEnter() {
_videoFrameDelay = 0;
}
- // Subtract the time we were running the debugger from the game running time
- _engine->_gamestate->gameStartTime += g_system->getMillis() - _enterTime;
+ _engine->pauseEngine(false);
}
bool Console::cmdHelp(int argc, const char **argv) {
@@ -332,7 +329,6 @@ bool Console::cmdHelp(int argc, const char **argv) {
DebugPrintf(" list - Lists all the resources of a given type\n");
DebugPrintf(" hexgrep - Searches some resources for a particular sequence of bytes, represented as hexadecimal numbers\n");
DebugPrintf(" verify_scripts - Performs sanity checks on SCI1.1-SCI2.1 game scripts (e.g. if they're up to 64KB in total)\n");
- DebugPrintf(" show_instruments - Shows the instruments of a specific song, or all songs\n");
DebugPrintf("\n");
DebugPrintf("Game:\n");
DebugPrintf(" save_game - Saves the current game state to the hard disk\n");
@@ -372,6 +368,8 @@ bool Console::cmdHelp(int argc, const char **argv) {
DebugPrintf(" is_sample - Shows information on a given sound resource, if it's a PCM sample\n");
DebugPrintf(" sfx01_header - Dumps the header of a SCI01 song\n");
DebugPrintf(" sfx01_track - Dumps a track of a SCI01 song\n");
+ DebugPrintf(" show_instruments - Shows the instruments of a specific song, or all songs\n");
+ DebugPrintf(" map_instrument - Dynamically maps an MT-32 instrument to a GM instrument\n");
DebugPrintf("\n");
DebugPrintf("Script:\n");
DebugPrintf(" addresses - Provides information on how to pass addresses\n");
@@ -763,7 +761,7 @@ bool Console::cmdHexgrep(int argc, const char **argv) {
if (argc < 4) {
DebugPrintf("Searches some resources for a particular sequence of bytes, represented as hexadecimal numbers.\n");
DebugPrintf("Usage: %s <resource type> <resource number> <search string>\n", argv[0]);
- DebugPrintf("<resource number> can be a specific resource number, or \"all\" for all of the resources of the specified type\n", argv[0]);
+ DebugPrintf("<resource number> can be a specific resource number, or \"all\" for all of the resources of the specified type\n");
DebugPrintf("EXAMPLES:\n hexgrep script all e8 03 c8 00\n hexgrep pic 042 fe");
cmdResourceTypes(argc, argv);
return true;
@@ -863,6 +861,14 @@ bool Console::cmdVerifyScripts(int argc, const char **argv) {
return true;
}
+// Same as in sound/drivers/midi.cpp
+uint8 getGmInstrument(const Mt32ToGmMap &Mt32Ins) {
+ if (Mt32Ins.gmInstr == MIDI_MAPPED_TO_RHYTHM)
+ return Mt32Ins.gmRhythmKey + 0x80;
+ else
+ return Mt32Ins.gmInstr;
+}
+
bool Console::cmdShowInstruments(int argc, const char **argv) {
int songNumber = -1;
@@ -1005,7 +1011,16 @@ bool Console::cmdShowInstruments(int argc, const char **argv) {
DebugPrintf("%d, ", i);
}
DebugPrintf("\n\n");
+ }
+
+ DebugPrintf("Instruments not mapped in the MT32->GM map: ");
+ for (int i = 0; i < 128; i++) {
+ if (instruments[i] > 0 && getGmInstrument(Mt32MemoryTimbreMaps[i]) == MIDI_UNMAPPED)
+ DebugPrintf("%d, ", i);
+ }
+ DebugPrintf("\n\n");
+ if (songNumber == -1) {
DebugPrintf("Used instruments in songs:\n");
for (int i = 0; i < 128; i++) {
if (instruments[i] > 0) {
@@ -1025,6 +1040,43 @@ bool Console::cmdShowInstruments(int argc, const char **argv) {
return true;
}
+bool Console::cmdMapInstrument(int argc, const char **argv) {
+ if (argc != 4) {
+ DebugPrintf("Maps an MT-32 custom instrument to a GM instrument on the fly\n\n");
+ DebugPrintf("Usage %s <MT-32 instrument name> <GM instrument> <GM rhythm key>\n", argv[0]);
+ DebugPrintf("Each MT-32 instrument is always 10 characters and is mapped to either a GM instrument, or a GM rhythm key\n");
+ DebugPrintf("A value of 255 (0xff) signifies an unmapped instrument\n");
+ DebugPrintf("Please replace the spaces in the instrument name with underscores (\"_\"). They'll be converted to spaces afterwards\n\n");
+ DebugPrintf("Example: %s test_0__XX 1 255\n", argv[0]);
+ DebugPrintf("The above example will map the MT-32 instrument \"test 0 XX\" to GM instrument 1\n\n");
+ } else {
+ if (Mt32dynamicMappings != NULL) {
+ Mt32ToGmMap newMapping;
+ char *instrumentName = new char[11];
+ Common::strlcpy(instrumentName, argv[1], 11);
+
+ for (uint16 i = 0; i < strlen(instrumentName); i++)
+ if (instrumentName[i] == '_')
+ instrumentName[i] = ' ';
+
+ newMapping.name = instrumentName;
+ newMapping.gmInstr = atoi(argv[2]);
+ newMapping.gmRhythmKey = atoi(argv[3]);
+ Mt32dynamicMappings->push_back(newMapping);
+ }
+ }
+
+ DebugPrintf("Current dynamic mappings:\n");
+ if (Mt32dynamicMappings != NULL) {
+ const Mt32ToGmMapList::iterator end = Mt32dynamicMappings->end();
+ for (Mt32ToGmMapList::iterator it = Mt32dynamicMappings->begin(); it != end; ++it) {
+ DebugPrintf("\"%s\" -> %d / %d\n", (*it).name, (*it).gmInstr, (*it).gmRhythmKey);
+ }
+ }
+
+ return true;
+}
+
bool Console::cmdList(int argc, const char **argv) {
if (argc < 2) {
DebugPrintf("Lists all the resources of a given type\n");
@@ -1140,14 +1192,18 @@ bool Console::cmdRestartGame(int argc, const char **argv) {
}
bool Console::cmdClassTable(int argc, const char **argv) {
- DebugPrintf("Available classes:\n");
+ DebugPrintf("Available classes (parse a parameter to filter the table by a specific class):\n");
+
for (uint i = 0; i < _engine->_gamestate->_segMan->classTableSize(); i++) {
Class temp = _engine->_gamestate->_segMan->_classTable[i];
if (temp.reg.segment) {
- DebugPrintf(" Class 0x%x (%s) at %04x:%04x (script 0x%x)\n", i,
- _engine->_gamestate->_segMan->getObjectName(temp.reg),
- PRINT_REG(temp.reg),
- temp.script);
+ const char *className = _engine->_gamestate->_segMan->getObjectName(temp.reg);
+ if (argc == 1 || (argc == 2 && !strcmp(className, argv[1]))) {
+ DebugPrintf(" Class 0x%x (%s) at %04x:%04x (script %d)\n", i,
+ className,
+ PRINT_REG(temp.reg),
+ temp.script);
+ }
}
}
@@ -1327,9 +1383,9 @@ bool Console::cmdSaid(int argc, const char **argv) {
}
spec[len++] = 0xFF;
- printf("Matching '%s' against:", string);
+ debugN("Matching '%s' against:", string);
_engine->getVocabulary()->debugDecipherSaidBlock(spec);
- printf("\n");
+ debugN("\n");
ResultWordListList words;
bool res = _engine->getVocabulary()->tokenizeString(words, string, &error);
@@ -2637,11 +2693,88 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) {
return true;
}
+bool Console::cmdFindKernelFunctionCall(int argc, const char **argv) {
+ if (argc < 2) {
+ DebugPrintf("Finds the scripts and methods that call a specific kernel function.\n");
+ DebugPrintf("Usage: %s <kernel function>\n", argv[0]);
+ DebugPrintf("Example: %s Display\n", argv[0]);
+ return true;
+ }
+
+ // Find the number of the kernel function call
+ int kernelFuncNum = _engine->getKernel()->findKernelFuncPos(argv[1]);
+
+ if (kernelFuncNum < 0) {
+ DebugPrintf("Invalid kernel function requested");
+ return true;
+ }
+
+ Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeScript);
+ Common::sort(resources->begin(), resources->end());
+ Common::List<ResourceId>::iterator itr = resources->begin();
+
+ DebugPrintf("%d scripts found, dissassembling...\n", resources->size());
+
+ int scriptSegment;
+ Script *script;
+ SegManager *segMan = _engine->getEngineState()->_segMan;
+
+ while (itr != resources->end()) {
+ // Load script
+ scriptSegment = segMan->instantiateScript(itr->getNumber());
+ script = segMan->getScript(scriptSegment);
+
+ // Iterate through all the script's objects
+ ObjMap::iterator it;
+ const ObjMap::iterator end = script->_objects.end();
+ for (it = script->_objects.begin(); it != end; ++it) {
+ const Object *obj = segMan->getObject(it->_value.getPos());
+ const char *objName = segMan->getObjectName(it->_value.getPos());
+
+ // Now dissassemble each method of the script object
+ for (uint16 i = 0; i < obj->getMethodCount(); i++) {
+ reg_t fptr = obj->getFunction(i);
+ uint16 offset = fptr.offset;
+ int16 opparams[4];
+ byte extOpcode;
+ byte opcode;
+
+ while (true) {
+ offset += readPMachineInstruction(script->getBuf(offset), extOpcode, opparams);
+ opcode = extOpcode >> 1;
+
+ if (opcode == op_callk) {
+ uint16 kFuncNum = opparams[0];
+ uint16 argc2 = opparams[1];
+
+ if (kFuncNum == kernelFuncNum) {
+ DebugPrintf("Called from script %d, object %s, method %s(%d) with %d parameters\n",
+ itr->getNumber(), objName,
+ _engine->getKernel()->getSelectorName(obj->getFuncSelector(i)).c_str(), i, argc2);
+ }
+ }
+
+ // Check for end of function/script
+ if (opcode == op_ret || offset >= script->getBufSize())
+ break;
+ } // while (true)
+ } // for (uint16 i = 0; i < obj->getMethodCount(); i++)
+ } // for (it = script->_objects.begin(); it != end; ++it)
+
+ segMan->uninstantiateScript(itr->getNumber());
+ ++itr;
+ }
+
+ delete resources;
+
+ return true;
+}
+
bool Console::cmdSend(int argc, const char **argv) {
if (argc < 3) {
DebugPrintf("Sends a message to an object.\n");
DebugPrintf("Usage: %s <object> <selector name> <param1> <param2> ... <paramn>\n", argv[0]);
- DebugPrintf("Example: send ?fooScript cue\n");
+ DebugPrintf("Example: %s ?fooScript cue\n", argv[0]);
return true;
}
@@ -3021,24 +3154,24 @@ static void midi_hexdump(byte *data, int size, int notational_offset) {
int blanks = 0;
offset += offset_mod;
- printf(" [%04x] %d\t",
+ debugN(" [%04x] %d\t",
old_offset + notational_offset, time);
cmd = data[offset];
if (!(cmd & 0x80)) {
cmd = prev;
if (prev < 0x80) {
- printf("Track broken at %x after"
+ debugN("Track broken at %x after"
" offset mod of %d\n",
offset + notational_offset, offset_mod);
Common::hexdump(data, size, 16, notational_offset);
return;
}
- printf("(rs %02x) ", cmd);
+ debugN("(rs %02x) ", cmd);
blanks += 8;
} else {
++offset;
- printf("%02x ", cmd);
+ debugN("%02x ", cmd);
blanks += 3;
}
prev = cmd;
@@ -3050,37 +3183,37 @@ static void midi_hexdump(byte *data, int size, int notational_offset) {
for (i = 0; i < pleft; i++) {
if (i == 0)
firstarg = data[offset];
- printf("%02x ", data[offset++]);
+ debugN("%02x ", data[offset++]);
blanks += 3;
}
while (blanks < 16) {
blanks += 4;
- printf(" ");
+ debugN(" ");
}
while (blanks < 20) {
++blanks;
- printf(" ");
+ debugN(" ");
}
if (cmd == SCI_MIDI_EOT)
- printf(";; EOT");
+ debugN(";; EOT");
else if (cmd == SCI_MIDI_SET_SIGNAL) {
if (firstarg == SCI_MIDI_SET_SIGNAL_LOOP)
- printf(";; LOOP point");
+ debugN(";; LOOP point");
else
- printf(";; CUE (%d)", firstarg);
+ debugN(";; CUE (%d)", firstarg);
} else if (SCI_MIDI_CONTROLLER(cmd)) {
if (firstarg == SCI_MIDI_CUMULATIVE_CUE)
- printf(";; CUE (cumulative)");
+ debugN(";; CUE (cumulative)");
else if (firstarg == SCI_MIDI_RESET_ON_SUSPEND)
- printf(";; RESET-ON-SUSPEND flag");
+ debugN(";; RESET-ON-SUSPEND flag");
}
- printf("\n");
+ debugN("\n");
if (old_offset >= offset) {
- printf("-- Not moving forward anymore,"
+ debugN("-- Not moving forward anymore,"
" aborting (%x/%x)\n", offset, old_offset);
return;
}
@@ -3559,22 +3692,22 @@ void Console::hexDumpReg(const reg_t *data, int len, int regsPerLine, int startO
byte c;
int offset = startOffset;
while (len >= regsPerLine) {
- printf("%06x: ", offset);
+ debugN("%06x: ", offset);
for (i = 0; i < regsPerLine; i++) {
- printf("%04x:%04x ", PRINT_REG(data[i]));
+ debugN("%04x:%04x ", PRINT_REG(data[i]));
}
- printf(" |");
+ debugN(" |");
for (i = 0; i < regsPerLine; i++) {
c = data[i].toUint16() & 0xff;
if (c < 32 || c >= 127)
c = '.';
- printf("%c", c);
+ debugN("%c", c);
c = data[i].toUint16() >> 8;
if (c < 32 || c >= 127)
c = '.';
- printf("%c", c);
+ debugN("%c", c);
}
- printf("|\n");
+ debugN("|\n");
data += regsPerLine;
len -= regsPerLine;
offset += regsPerLine * (isArray ? 1 : 2);
@@ -3583,27 +3716,27 @@ void Console::hexDumpReg(const reg_t *data, int len, int regsPerLine, int startO
if (len <= 0)
return;
- printf("%06x: ", offset);
+ debugN("%06x: ", offset);
for (i = 0; i < regsPerLine; i++) {
if (i < len)
- printf("%04x:%04x ", PRINT_REG(data[i]));
+ debugN("%04x:%04x ", PRINT_REG(data[i]));
else
- printf(" ");
+ debugN(" ");
}
- printf(" |");
+ debugN(" |");
for (i = 0; i < len; i++) {
c = data[i].toUint16() & 0xff;
if (c < 32 || c >= 127)
c = '.';
- printf("%c", c);
+ debugN("%c", c);
c = data[i].toUint16() >> 8;
if (c < 32 || c >= 127)
c = '.';
- printf("%c", c);
+ debugN("%c", c);
}
for (; i < regsPerLine; i++)
- printf(" ");
- printf("|\n");
+ debugN(" ");
+ debugN("|\n");
}
} // End of namespace Sci
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 8bc2da439c..68c2d21e38 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -75,7 +75,6 @@ private:
bool cmdList(int argc, const char **argv);
bool cmdHexgrep(int argc, const char **argv);
bool cmdVerifyScripts(int argc, const char **argv);
- bool cmdShowInstruments(int argc, const char **argv);
// Game
bool cmdSaveGame(int argc, const char **argv);
bool cmdRestoreGame(int argc, const char **argv);
@@ -115,6 +114,8 @@ private:
bool cmdStopAllSounds(int argc, const char **argv);
bool cmdSfx01Header(int argc, const char **argv);
bool cmdSfx01Track(int argc, const char **argv);
+ bool cmdShowInstruments(int argc, const char **argv);
+ bool cmdMapInstrument(int argc, const char **argv);
// Script
bool cmdAddresses(int argc, const char **argv);
bool cmdRegisters(int argc, const char **argv);
@@ -128,6 +129,7 @@ private:
bool cmdStepCallk(int argc, const char **argv);
bool cmdDisassemble(int argc, const char **argv);
bool cmdDisassembleAddress(int argc, const char **argv);
+ bool cmdFindKernelFunctionCall(int argc, const char **argv);
bool cmdSend(int argc, const char **argv);
bool cmdGo(int argc, const char **argv);
bool cmdLogKernel(int argc, const char **argv);
@@ -166,7 +168,6 @@ private:
bool _mouseVisible;
Common::String _videoFile;
int _videoFrameDelay;
- uint32 _enterTime;
};
} // End of namespace Sci
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index a4d1edf2ed..80da7b1375 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -624,7 +624,8 @@ bool SciMetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
- (f == kSavesSupportCreationDate);
+ (f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime);
}
bool SciEngine::hasFeature(EngineFeature f) const {
@@ -665,7 +666,7 @@ SaveStateList SciMetaEngine::listSaves(const char *target) const {
delete in;
continue;
}
- saveList.push_back(SaveStateDescriptor(slotNum, meta.savegame_name));
+ saveList.push_back(SaveStateDescriptor(slotNum, meta.name));
delete in;
}
}
@@ -675,7 +676,7 @@ SaveStateList SciMetaEngine::listSaves(const char *target) const {
}
SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
- Common::String fileName = Common::String::printf("%s.%03d", target, slot);
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
if (in) {
@@ -688,7 +689,7 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl
return desc;
}
- SaveStateDescriptor desc(slot, meta.savegame_name);
+ SaveStateDescriptor desc(slot, meta.name);
Graphics::Surface *thumbnail = new Graphics::Surface();
assert(thumbnail);
@@ -702,18 +703,18 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl
desc.setDeletableFlag(true);
desc.setWriteProtectedFlag(false);
- int day = (meta.savegame_date >> 24) & 0xFF;
- int month = (meta.savegame_date >> 16) & 0xFF;
- int year = meta.savegame_date & 0xFFFF;
+ int day = (meta.saveDate >> 24) & 0xFF;
+ int month = (meta.saveDate >> 16) & 0xFF;
+ int year = meta.saveDate & 0xFFFF;
desc.setSaveDate(year, month, day);
- int hour = (meta.savegame_time >> 16) & 0xFF;
- int minutes = (meta.savegame_time >> 8) & 0xFF;
+ int hour = (meta.saveTime >> 16) & 0xFF;
+ int minutes = (meta.saveTime >> 8) & 0xFF;
desc.setSaveTime(hour, minutes);
- // TODO: played time
+ desc.setPlayTime(meta.playTime * 1000);
delete in;
@@ -726,12 +727,12 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl
int SciMetaEngine::getMaximumSaveSlot() const { return 99; }
void SciMetaEngine::removeSaveState(const char *target, int slot) const {
- Common::String fileName = Common::String::printf("%s.%03d", target, slot);
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
g_system->getSavefileManager()->removeSavefile(fileName);
}
Common::Error SciEngine::loadGameState(int slot) {
- Common::String fileName = Common::String::printf("%s.%03d", _targetName.c_str(), slot);
+ Common::String fileName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
Common::SeekableReadStream *in = saveFileMan->openForLoading(fileName);
@@ -750,7 +751,7 @@ Common::Error SciEngine::loadGameState(int slot) {
}
Common::Error SciEngine::saveGameState(int slot, const char *desc) {
- Common::String fileName = Common::String::printf("%s.%03d", _targetName.c_str(), slot);
+ Common::String fileName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
Common::OutSaveFile *out = saveFileMan->openForSaving(fileName);
const char *version = "";
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index e1d03d9914..79acbf41b7 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -752,10 +752,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Hoyle 1 - English DOS (supplied by eddydrama in bug report #3052366)
+ // Hoyle 1 3.5' - English DOS (supplied by eddydrama in bug report #3052366 and dinnerx in bug report #3090841)
{"hoyle1", "", {
{"resource.map", 0, "0af9a3dcd72a091960de070432e1f524", 4386},
- {"resource.001", 0, "e0dd44069a62463fd124974b915f10d", 518127},
+ {"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 518127},
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
@@ -854,14 +854,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Hoyle 4 - English DOS Demo
+ // Hoyle 4 (Hoyle Classic Card Games) - English DOS Demo
{"hoyle4", "Demo", {
{"resource.map", 0, "60f764020a6b788bbbe415dbc2ccb9f3", 931},
{"resource.000", 0, "5fe3670e3ddcd4f85c10013b5453141a", 615522},
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
- // Hoyle 4 - English DOS Demo
+ // Hoyle 4 (Hoyle Classic Card Games) - English DOS Demo
// SCI interpreter version 1.001.200 (just a guess)
// Does anyone have this version? -clone2727
{"hoyle4", "Demo", {
@@ -871,7 +871,6 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Hoyle 4 (Hoyle Classic Card Games) - English DOS/Win
- // SCI1.1
// Supplied by abevi in bug report #3039291
{"hoyle4", "", {
{"resource.map", 0, "2b577c975cc8d8d43f61b6a756129fe3", 4352},
@@ -879,6 +878,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ // Hoyle 4 (Hoyle Classic Card Games) - English Macintosh Floppy
+ // VERSION file reports "2.0"
+ {"hoyle4", "", {
+ {"Data1", 0, "afad082944d36ce4d2a9e646efc49da1", 7731536},
+ {"Data2", 0, "615ed2efe969f845cd8f0686af0b06f2", 1543825},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_NOSPEECH },
+
// Jones in the Fast Lane EGA - English DOS
// SCI interpreter version 1.000.172 (not 100% sure FIXME)
{"jones", "EGA", {
@@ -1473,20 +1480,6 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Laura Bow - German DOS (from Tobis87, also includes english language)
- // SCI interpreter version 0.000.631 (or 0.000.685?)
- {"laurabow", "", {
- {"resource.map", 0, "b1905f6aa68ff65a057b080b1eae954c", 12030},
- {"resource.001", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 108032},
- {"resource.002", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 354680},
- {"resource.003", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 361815},
- {"resource.004", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 339714},
- {"resource.005", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 327465},
- {"resource.006", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 328390},
- {"resource.007", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 317687},
- AD_LISTEND},
- Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
-
// Laura Bow 2 - English DOS Non-Interactive Demo (from FRG)
// Executable scanning reports "x.yyy.zzz"
// SCI interpreter version 1.001.069 (just a guess)
@@ -3333,6 +3326,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO_NOSPEECH },
+ // Space Quest 4 - Russian DOS
+ // Executable scanning reports "1.000.753", VERSION file reports "1.994"
+ {"sq4", "", {
+ {"resource.map", 0, "e4f77dd99012d51e16903da07769a7bf", 5928},
+ {"resource.000", 0, "e1f46832cd2458796028e054a0466031", 186750},
+ {"resource.001", 0, "1110371c3bafbbf8968a324097c83fdb", 1283759},
+ {"resource.002", 0, "9c342cd76b421369406d6fafd7b1a285", 1234726},
+ {"resource.003", 0, "e617f09840d9f86181f7602c8bf2e8ad", 1266491},
+ {"resource.004", 0, "2763fe4f0cb74df716ec8b0c464b0988", 1217428},
+ {"resource.005", 0, "d608713197c5ba1cd8c6ed46299c3069", 1057924},
+ AD_LISTEND},
+ Common::RU_RUS, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
// Space Quest 5 - English DOS (from the Space Quest Collection)
// Executable scanning reports "1.001.068", VERSION file reports "1.04"
{"sq5", "", {
@@ -3376,6 +3382,23 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::IT_ITA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ // Space Quest 5 - Spanish DOS Floppy (from mirir, bug report #3090664)
+ {"sq5", "", {
+ {"resource.000", 0, "73748852548faa42927f7537b165582d", 6049994},
+ {"resource.map", 0, "5714a899033bdebf2d61ad333c8c6637", 6492},
+ {"resource.msg", 0, "46deca7ef9cf057f7d442df98c1a2ae2", 134612},
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
+ // Space Quest 5 - Russian DOS
+ // Executable scanning reports "1.001.068", VERSION file reports "1.994"
+ {"sq5", "", {
+ {"resource.map", 0, "82e6e9b4270a4007578a119b6a51860c", 6493},
+ {"resource.000", 0, "6f9ed21e1001526b4137f6703ed476af", 6103778},
+ {"resource.msg", 0, "0a8931990cd2eac1691602391c68ab85", 147580},
+ AD_LISTEND},
+ Common::RU_RUS, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
#ifdef ENABLE_SCI32
// Space Quest 6 - English DOS/Win3.11 CD (from the Space Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -3523,6 +3546,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
FANMADE("SCI Studio Template 3.0", "ca0dc8d586e0a8670b7621cde090b532", 354, "58a48ee692a86c0575e6bd0b00a92b9a", 113097),
FANMADE("SCI Quest", "9067e1f1e54436d2dbfce855524bc84a", 552, "ffa7d355cd9223f245289108a696bcd2", 149634),
FANMADE("SCI-Man", "3ab85bd39a86c11f85781764f9db09bb", 468, "bb8f9992f504a242bf0860e3588e150b", 131810),
+ FANMADE("The Black Cauldron", "5e1ff2833c7f33ebcfa456ba836e2067", 2592, "2f8e6264d2db91bb54982ab8aa18b3b4", 1881839),
FANMADE("The Farm Nightmare", "fb6cbfddaa7c055e2c3d8cf4c683a7db", 906, "50655e8b8925f717e698e08f006f40be", 338303),
FANMADE("The Gem Scenario", "ef5f61f4d2c6d31122d3e2baf89ad976", 642, "2f16be390dd90c3d7ca1c8a594ac0bfa", 244794),
FANMADE("The Legend of the Lost Jewel", "ba1bca315e3818c5626eda51bcfbcccf", 636, "9b0736d69924af0cff32a0f78db96855", 300398),
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index ff327a0049..408dc5f150 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -66,12 +66,12 @@ const Common::String &Kernel::getSelectorName(uint selector) {
// We need this for proper workaround tables
// TODO: maybe check, if there is a fixed selector-table and error() out in that case
for (uint loopSelector = _selectorNames.size(); loopSelector <= selector; ++loopSelector)
- _selectorNames.push_back(Common::String::printf("<noname%d>", loopSelector));
+ _selectorNames.push_back(Common::String::format("<noname%d>", loopSelector));
}
// Ensure that the selector has a name
if (_selectorNames[selector].empty())
- _selectorNames[selector] = Common::String::printf("<noname%d>", selector);
+ _selectorNames[selector] = Common::String::format("<noname%d>", selector);
return _selectorNames[selector];
}
@@ -88,6 +88,14 @@ const Common::String &Kernel::getKernelName(uint number) const {
return _kernelNames[number];
}
+int Kernel::findKernelFuncPos(Common::String kernelFuncName) {
+ for (uint32 i = 0; i < _kernelNames.size(); i++)
+ if (_kernelNames[i] == kernelFuncName)
+ return i;
+
+ return -1;
+}
+
int Kernel::findSelector(const char *selectorName) const {
for (uint pos = 0; pos < _selectorNames.size(); ++pos) {
if (_selectorNames[pos] == selectorName)
@@ -130,7 +138,7 @@ void Kernel::loadSelectorNames() {
Common::String tmp((const char *)r->data + offset + 2, len);
_selectorNames.push_back(tmp);
- //printf("%s\n", tmp.c_str()); // debug
+ //debug("%s", tmp.c_str());
// Early SCI versions used the LSB in the selector ID as a read/write
// toggle. To compensate for that, we add every selector name twice.
@@ -422,8 +430,8 @@ static void kernelSignatureDebugType(const uint16 type) {
while (list->typeCheck) {
if (type & list->typeCheck) {
if (!firstPrint)
- printf(", ");
- printf("%s", list->text);
+ debugN(", ");
+ debugN("%s", list->text);
firstPrint = false;
}
list++;
@@ -434,38 +442,38 @@ static void kernelSignatureDebugType(const uint16 type) {
void Kernel::signatureDebug(const uint16 *sig, int argc, const reg_t *argv) {
int argnr = 0;
while (*sig || argc) {
- printf("parameter %d: ", argnr++);
+ debugN("parameter %d: ", argnr++);
if (argc) {
reg_t parameter = *argv;
- printf("%04x:%04x (", PRINT_REG(parameter));
+ debugN("%04x:%04x (", PRINT_REG(parameter));
int regType = findRegType(parameter);
if (regType)
kernelSignatureDebugType(regType);
else
- printf("unknown type of %04x:%04x", PRINT_REG(parameter));
- printf(")");
+ debugN("unknown type of %04x:%04x", PRINT_REG(parameter));
+ debugN(")");
argv++;
argc--;
} else {
- printf("not passed");
+ debugN("not passed");
}
if (*sig) {
const uint16 signature = *sig;
if ((signature & SIG_MAYBE_ANY) == SIG_MAYBE_ANY) {
- printf(", may be any");
+ debugN(", may be any");
} else {
- printf(", should be ");
+ debugN(", should be ");
kernelSignatureDebugType(signature);
}
if (signature & SIG_IS_OPTIONAL)
- printf(" (optional)");
+ debugN(" (optional)");
if (signature & SIG_NEEDS_MORE)
- printf(" (needs more)");
+ debugN(" (needs more)");
if (signature & SIG_MORE_MAY_FOLLOW)
- printf(" (more may follow)");
+ debugN(" (more may follow)");
sig++;
}
- printf("\n");
+ debugN("\n");
}
}
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index e50c6aaae2..9833f91a5e 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -151,6 +151,7 @@ public:
uint getSelectorNamesSize() const;
const Common::String &getSelectorName(uint selector);
+ int findKernelFuncPos(Common::String kernelFuncName);
uint getKernelNamesSize() const;
const Common::String &getKernelName(uint number) const;
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index d2c95053d5..7aed908c5e 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -27,6 +27,7 @@
#define SCI_ENGINE_KERNEL_TABLES_H
#include "sci/engine/workarounds.h"
+#include "sci/engine/vm.h" // for opcode_formats
namespace Sci {
@@ -86,192 +87,192 @@ struct SciKernelMapSubEntry {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kDoSound_subops[] = {
- { SIG_SOUNDSCI0, 0, MAP_CALL(DoSoundInit), "o", NULL },
- { SIG_SOUNDSCI0, 1, MAP_CALL(DoSoundPlay), "o", NULL },
- { SIG_SOUNDSCI0, 2, MAP_CALL(DoSoundRestore), "(o)", NULL },
- { SIG_SOUNDSCI0, 3, MAP_CALL(DoSoundDispose), "o", NULL },
- { SIG_SOUNDSCI0, 4, MAP_CALL(DoSoundMute), "(i)", NULL },
- { SIG_SOUNDSCI0, 5, MAP_CALL(DoSoundStop), "o", NULL },
- { SIG_SOUNDSCI0, 6, MAP_CALL(DoSoundPause), "i", NULL },
- { SIG_SOUNDSCI0, 7, MAP_CALL(DoSoundResumeAfterRestore), "", NULL },
- { SIG_SOUNDSCI0, 8, MAP_CALL(DoSoundMasterVolume), "(i)", NULL },
- { SIG_SOUNDSCI0, 9, MAP_CALL(DoSoundUpdate), "o", NULL },
- { SIG_SOUNDSCI0, 10, MAP_CALL(DoSoundFade), "o", kDoSoundFade_workarounds },
- { SIG_SOUNDSCI0, 11, MAP_CALL(DoSoundGetPolyphony), "", NULL },
- { SIG_SOUNDSCI0, 12, MAP_CALL(DoSoundStopAll), "", NULL },
- { SIG_SOUNDSCI1EARLY, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 4, MAP_CALL(DoSoundUpdate), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 5, MAP_CALL(DoSoundInit), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 6, MAP_CALL(DoSoundDispose), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 7, MAP_CALL(DoSoundPlay), "oi", NULL },
- // ^^ TODO: In SCI1-SCI1.1 DoSound (play) is called by 2 methods of the Sound object: play and
- // playBed. The methods are the same, apart from the second integer parameter: it's 0 in
- // play and 1 in playBed, to distinguish the caller. It's passed on, we should find out what
- // it actually does internally
- { SIG_SOUNDSCI1EARLY, 8, MAP_CALL(DoSoundStop), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 9, MAP_CALL(DoSoundPause), "[o0]i", NULL },
- { SIG_SOUNDSCI1EARLY, 10, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds },
- { SIG_SOUNDSCI1EARLY, 11, MAP_CALL(DoSoundUpdateCues), "o", NULL },
- { SIG_SOUNDSCI1EARLY, 12, MAP_CALL(DoSoundSendMidi), "oiii", NULL },
- { SIG_SOUNDSCI1EARLY, 13, MAP_CALL(DoSoundReverb), "i", NULL },
- { SIG_SOUNDSCI1EARLY, 14, MAP_CALL(DoSoundSetHold), "oi", NULL },
- { SIG_SOUNDSCI1EARLY, 15, MAP_CALL(DoSoundDummy), "", NULL },
- // ^^ Longbow demo
- { SIG_SOUNDSCI1LATE, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 2, MAP_CALL(DoSoundRestore), "", NULL },
- { SIG_SOUNDSCI1LATE, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
- { SIG_SOUNDSCI1LATE, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
- { SIG_SOUNDSCI1LATE, 6, MAP_CALL(DoSoundInit), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 7, MAP_CALL(DoSoundDispose), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 8, MAP_CALL(DoSoundPlay), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 9, MAP_CALL(DoSoundStop), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 10, MAP_CALL(DoSoundPause), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 11, MAP_CALL(DoSoundFade), "oiiii(i)", kDoSoundFade_workarounds },
- { SIG_SOUNDSCI1LATE, 12, MAP_CALL(DoSoundSetHold), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 13, MAP_CALL(DoSoundDummy), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL },
- { SIG_SOUNDSCI1LATE, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL },
- { SIG_SOUNDSCI1LATE, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL },
- { SIG_SOUNDSCI1LATE, 17, MAP_CALL(DoSoundUpdateCues), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 18, MAP_CALL(DoSoundSendMidi), "oiii(i)", NULL },
- { SIG_SOUNDSCI1LATE, 19, MAP_CALL(DoSoundReverb), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
+ { SIG_SOUNDSCI0, 0, MAP_CALL(DoSoundInit), "o", NULL },
+ { SIG_SOUNDSCI0, 1, MAP_CALL(DoSoundPlay), "o", NULL },
+ { SIG_SOUNDSCI0, 2, MAP_CALL(DoSoundRestore), "(o)", NULL },
+ { SIG_SOUNDSCI0, 3, MAP_CALL(DoSoundDispose), "o", NULL },
+ { SIG_SOUNDSCI0, 4, MAP_CALL(DoSoundMute), "(i)", NULL },
+ { SIG_SOUNDSCI0, 5, MAP_CALL(DoSoundStop), "o", NULL },
+ { SIG_SOUNDSCI0, 6, MAP_CALL(DoSoundPause), "i", NULL },
+ { SIG_SOUNDSCI0, 7, MAP_CALL(DoSoundResumeAfterRestore), "", NULL },
+ { SIG_SOUNDSCI0, 8, MAP_CALL(DoSoundMasterVolume), "(i)", NULL },
+ { SIG_SOUNDSCI0, 9, MAP_CALL(DoSoundUpdate), "o", NULL },
+ { SIG_SOUNDSCI0, 10, MAP_CALL(DoSoundFade), "o", kDoSoundFade_workarounds },
+ { SIG_SOUNDSCI0, 11, MAP_CALL(DoSoundGetPolyphony), "", NULL },
+ { SIG_SOUNDSCI0, 12, MAP_CALL(DoSoundStopAll), "", NULL },
+ { SIG_SOUNDSCI1EARLY, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 1, MAP_CALL(DoSoundMute), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 4, MAP_CALL(DoSoundUpdate), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 5, MAP_CALL(DoSoundInit), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 6, MAP_CALL(DoSoundDispose), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 7, MAP_CALL(DoSoundPlay), "oi", NULL },
+ // ^^ TODO: In SCI1-SCI1.1 DoSound (play) is called by 2 methods of the Sound object: play and
+ // playBed. The methods are the same, apart from the second integer parameter: it's 0 in
+ // play and 1 in playBed, to distinguish the caller. It's passed on, we should find out what
+ // it actually does internally
+ { SIG_SOUNDSCI1EARLY, 8, MAP_CALL(DoSoundStop), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 9, MAP_CALL(DoSoundPause), "[o0]i", NULL },
+ { SIG_SOUNDSCI1EARLY, 10, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds },
+ { SIG_SOUNDSCI1EARLY, 11, MAP_CALL(DoSoundUpdateCues), "o", NULL },
+ { SIG_SOUNDSCI1EARLY, 12, MAP_CALL(DoSoundSendMidi), "oiii", NULL },
+ { SIG_SOUNDSCI1EARLY, 13, MAP_CALL(DoSoundReverb), "i", NULL },
+ { SIG_SOUNDSCI1EARLY, 14, MAP_CALL(DoSoundSetHold), "oi", NULL },
+ { SIG_SOUNDSCI1EARLY, 15, MAP_CALL(DoSoundDummy), "", NULL },
+ // ^^ Longbow demo
+ { SIG_SOUNDSCI1LATE, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 1, MAP_CALL(DoSoundMute), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 2, MAP_CALL(DoSoundRestore), "", NULL },
+ { SIG_SOUNDSCI1LATE, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
+ { SIG_SOUNDSCI1LATE, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
+ { SIG_SOUNDSCI1LATE, 6, MAP_CALL(DoSoundInit), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 7, MAP_CALL(DoSoundDispose), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 8, MAP_CALL(DoSoundPlay), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 9, MAP_CALL(DoSoundStop), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 10, MAP_CALL(DoSoundPause), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 11, MAP_CALL(DoSoundFade), "oiiii(i)", kDoSoundFade_workarounds },
+ { SIG_SOUNDSCI1LATE, 12, MAP_CALL(DoSoundSetHold), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 13, MAP_CALL(DoSoundDummy), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL },
+ { SIG_SOUNDSCI1LATE, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL },
+ { SIG_SOUNDSCI1LATE, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL },
+ { SIG_SOUNDSCI1LATE, 17, MAP_CALL(DoSoundUpdateCues), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 18, MAP_CALL(DoSoundSendMidi), "oiii(i)", NULL },
+ { SIG_SOUNDSCI1LATE, 19, MAP_CALL(DoSoundReverb), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
#ifdef ENABLE_SCI32
- { SIG_SOUNDSCI21, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
- { SIG_SOUNDSCI21, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI21, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
- { SIG_SOUNDSCI21, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
- { SIG_SOUNDSCI21, 4, MAP_CALL(DoSoundGetAudioCapability), NULL, NULL },
- { SIG_SOUNDSCI21, 5, MAP_CALL(DoSoundSuspend), NULL, NULL },
- { SIG_SOUNDSCI21, 6, MAP_CALL(DoSoundInit), NULL, NULL },
- { SIG_SOUNDSCI21, 7, MAP_CALL(DoSoundDispose), NULL, NULL },
- { SIG_SOUNDSCI21, 8, MAP_CALL(DoSoundPlay), "o(i)", NULL },
- // ^^ TODO: if this is really the only change between SCI1LATE AND SCI21, we could rename the
- // SIG_SOUNDSCI1LATE #define to SIG_SINCE_SOUNDSCI1LATE and make it being SCI1LATE+. Although
- // I guess there are many more changes somewhere
- // TODO: Quest for Glory 4 (SCI2.1) uses the old scheme, we need to detect it accordingly
- // signature for SCI21 should be "o"
- { SIG_SOUNDSCI21, 9, MAP_CALL(DoSoundStop), NULL, NULL },
- { SIG_SOUNDSCI21, 10, MAP_CALL(DoSoundPause), NULL, NULL },
- { SIG_SOUNDSCI21, 11, MAP_CALL(DoSoundFade), NULL, NULL },
- { SIG_SOUNDSCI21, 12, MAP_CALL(DoSoundSetHold), NULL, NULL },
- { SIG_SOUNDSCI21, 13, MAP_CALL(DoSoundDummy), NULL, NULL },
- { SIG_SOUNDSCI21, 14, MAP_CALL(DoSoundSetVolume), NULL, NULL },
- { SIG_SOUNDSCI21, 15, MAP_CALL(DoSoundSetPriority), NULL, NULL },
- { SIG_SOUNDSCI21, 16, MAP_CALL(DoSoundSetLoop), NULL, NULL },
- { SIG_SOUNDSCI21, 17, MAP_CALL(DoSoundUpdateCues), NULL, NULL },
- { SIG_SOUNDSCI21, 18, MAP_CALL(DoSoundSendMidi), NULL, NULL },
- { SIG_SOUNDSCI21, 19, MAP_CALL(DoSoundReverb), NULL, NULL },
- { SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
+ { SIG_SOUNDSCI21, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
+ { SIG_SOUNDSCI21, 1, MAP_CALL(DoSoundMute), NULL, NULL },
+ { SIG_SOUNDSCI21, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
+ { SIG_SOUNDSCI21, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
+ { SIG_SOUNDSCI21, 4, MAP_CALL(DoSoundGetAudioCapability), NULL, NULL },
+ { SIG_SOUNDSCI21, 5, MAP_CALL(DoSoundSuspend), NULL, NULL },
+ { SIG_SOUNDSCI21, 6, MAP_CALL(DoSoundInit), NULL, NULL },
+ { SIG_SOUNDSCI21, 7, MAP_CALL(DoSoundDispose), NULL, NULL },
+ { SIG_SOUNDSCI21, 8, MAP_CALL(DoSoundPlay), "o(i)", NULL },
+ // ^^ TODO: if this is really the only change between SCI1LATE AND SCI21, we could rename the
+ // SIG_SOUNDSCI1LATE #define to SIG_SINCE_SOUNDSCI1LATE and make it being SCI1LATE+. Although
+ // I guess there are many more changes somewhere
+ // TODO: Quest for Glory 4 (SCI2.1) uses the old scheme, we need to detect it accordingly
+ // signature for SCI21 should be "o"
+ { SIG_SOUNDSCI21, 9, MAP_CALL(DoSoundStop), NULL, NULL },
+ { SIG_SOUNDSCI21, 10, MAP_CALL(DoSoundPause), NULL, NULL },
+ { SIG_SOUNDSCI21, 11, MAP_CALL(DoSoundFade), NULL, NULL },
+ { SIG_SOUNDSCI21, 12, MAP_CALL(DoSoundSetHold), NULL, NULL },
+ { SIG_SOUNDSCI21, 13, MAP_CALL(DoSoundDummy), NULL, NULL },
+ { SIG_SOUNDSCI21, 14, MAP_CALL(DoSoundSetVolume), NULL, NULL },
+ { SIG_SOUNDSCI21, 15, MAP_CALL(DoSoundSetPriority), NULL, NULL },
+ { SIG_SOUNDSCI21, 16, MAP_CALL(DoSoundSetLoop), NULL, NULL },
+ { SIG_SOUNDSCI21, 17, MAP_CALL(DoSoundUpdateCues), NULL, NULL },
+ { SIG_SOUNDSCI21, 18, MAP_CALL(DoSoundSendMidi), NULL, NULL },
+ { SIG_SOUNDSCI21, 19, MAP_CALL(DoSoundReverb), NULL, NULL },
+ { SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
#endif
- SCI_SUBOPENTRY_TERMINATOR
+ SCI_SUBOPENTRY_TERMINATOR
};
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kGraph_subops[] = {
- { SIG_SCI32, 1, MAP_CALL(StubNull), "", NULL }, // called by gk1 sci32 right at the start
- { SIG_SCIALL, 2, MAP_CALL(GraphGetColorCount), "", NULL },
- // 3 - set palette via resource
- { SIG_SCIALL, 4, MAP_CALL(GraphDrawLine), "iiiii(i)(i)", kGraphDrawLine_workarounds },
- // 5 - nop
- // 6 - draw pattern
- { SIG_SCIALL, 7, MAP_CALL(GraphSaveBox), "iiiii", kGraphSaveBox_workarounds },
- { SIG_SCIALL, 8, MAP_CALL(GraphRestoreBox), "[r0!]", kGraphRestoreBox_workarounds },
- // ^ this may get called with invalid references, we check them within restoreBits() and sierra sci behaves the same
- { SIG_SCIALL, 9, MAP_CALL(GraphFillBoxBackground), "iiii", NULL },
- { SIG_SCIALL, 10, MAP_CALL(GraphFillBoxForeground), "iiii", kGraphFillBoxForeground_workarounds },
- { SIG_SCIALL, 11, MAP_CALL(GraphFillBoxAny), "iiiiii(i)(i)", kGraphFillBoxAny_workarounds },
- { SIG_SCI11, 12, MAP_CALL(GraphUpdateBox), "iiii(i)(r0)", kGraphUpdateBox_workarounds }, // kq6 hires
- { SIG_SCIALL, 12, MAP_CALL(GraphUpdateBox), "iiii(i)", kGraphUpdateBox_workarounds },
- { SIG_SCIALL, 13, MAP_CALL(GraphRedrawBox), "iiii", kGraphRedrawBox_workarounds },
- { SIG_SCIALL, 14, MAP_CALL(GraphAdjustPriority), "ii", NULL },
- { SIG_SCI11, 15, MAP_CALL(GraphSaveUpscaledHiresBox), "iiii", NULL }, // kq6 hires
- SCI_SUBOPENTRY_TERMINATOR
+ { SIG_SCI32, 1, MAP_CALL(StubNull), "", NULL }, // called by gk1 sci32 right at the start
+ { SIG_SCIALL, 2, MAP_CALL(GraphGetColorCount), "", NULL },
+ // 3 - set palette via resource
+ { SIG_SCIALL, 4, MAP_CALL(GraphDrawLine), "iiiii(i)(i)", kGraphDrawLine_workarounds },
+ // 5 - nop
+ // 6 - draw pattern
+ { SIG_SCIALL, 7, MAP_CALL(GraphSaveBox), "iiiii", kGraphSaveBox_workarounds },
+ { SIG_SCIALL, 8, MAP_CALL(GraphRestoreBox), "[r0!]", kGraphRestoreBox_workarounds },
+ // ^ this may get called with invalid references, we check them within restoreBits() and sierra sci behaves the same
+ { SIG_SCIALL, 9, MAP_CALL(GraphFillBoxBackground), "iiii", NULL },
+ { SIG_SCIALL, 10, MAP_CALL(GraphFillBoxForeground), "iiii", kGraphFillBoxForeground_workarounds },
+ { SIG_SCIALL, 11, MAP_CALL(GraphFillBoxAny), "iiiiii(i)(i)", kGraphFillBoxAny_workarounds },
+ { SIG_SCI11, 12, MAP_CALL(GraphUpdateBox), "iiii(i)(r0)", kGraphUpdateBox_workarounds }, // kq6 hires
+ { SIG_SCIALL, 12, MAP_CALL(GraphUpdateBox), "iiii(i)", kGraphUpdateBox_workarounds },
+ { SIG_SCIALL, 13, MAP_CALL(GraphRedrawBox), "iiii", kGraphRedrawBox_workarounds },
+ { SIG_SCIALL, 14, MAP_CALL(GraphAdjustPriority), "ii", NULL },
+ { SIG_SCI11, 15, MAP_CALL(GraphSaveUpscaledHiresBox), "iiii", NULL }, // kq6 hires
+ SCI_SUBOPENTRY_TERMINATOR
};
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kPalVary_subops[] = {
- { SIG_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL },
- { SIG_SCIALL, 0, MAP_CALL(PalVaryInit), "ii(i)(i)", NULL },
- { SIG_SCIALL, 1, MAP_CALL(PalVaryReverse), "(i)(i)(i)", NULL },
- { SIG_SCIALL, 2, MAP_CALL(PalVaryGetCurrentStep), "", NULL },
- { SIG_SCIALL, 3, MAP_CALL(PalVaryDeinit), "", NULL },
- { SIG_SCIALL, 4, MAP_CALL(PalVaryChangeTarget), "i", NULL },
- { SIG_SCIALL, 5, MAP_CALL(PalVaryChangeTicks), "i", NULL },
- { SIG_SCIALL, 6, MAP_CALL(PalVaryPauseResume), "i", NULL },
- { SIG_SCI32, 8, MAP_CALL(PalVaryUnknown), "i", NULL },
- SCI_SUBOPENTRY_TERMINATOR
+ { SIG_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL },
+ { SIG_SCIALL, 0, MAP_CALL(PalVaryInit), "ii(i)(i)", NULL },
+ { SIG_SCIALL, 1, MAP_CALL(PalVaryReverse), "(i)(i)(i)", NULL },
+ { SIG_SCIALL, 2, MAP_CALL(PalVaryGetCurrentStep), "", NULL },
+ { SIG_SCIALL, 3, MAP_CALL(PalVaryDeinit), "", NULL },
+ { SIG_SCIALL, 4, MAP_CALL(PalVaryChangeTarget), "i", NULL },
+ { SIG_SCIALL, 5, MAP_CALL(PalVaryChangeTicks), "i", NULL },
+ { SIG_SCIALL, 6, MAP_CALL(PalVaryPauseResume), "i", NULL },
+ { SIG_SCI32, 8, MAP_CALL(PalVaryUnknown), "i", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
};
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kPalette_subops[] = {
- { SIG_SCIALL, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL },
- { SIG_SCIALL, 2, MAP_CALL(PaletteSetFlag), "iii", NULL },
- { SIG_SCIALL, 3, MAP_CALL(PaletteUnsetFlag), "iii", kPaletteUnsetFlag_workarounds },
- { SIG_SCIALL, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL },
- { SIG_SCIALL, 5, MAP_CALL(PaletteFindColor), "iii", NULL },
- { SIG_SCIALL, 6, MAP_CALL(PaletteAnimate), "i*", NULL },
- { SIG_SCIALL, 7, MAP_CALL(PaletteSave), "", NULL },
- { SIG_SCIALL, 8, MAP_CALL(PaletteRestore), "[r0]", NULL },
- SCI_SUBOPENTRY_TERMINATOR
+ { SIG_SCIALL, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL },
+ { SIG_SCIALL, 2, MAP_CALL(PaletteSetFlag), "iii", NULL },
+ { SIG_SCIALL, 3, MAP_CALL(PaletteUnsetFlag), "iii", kPaletteUnsetFlag_workarounds },
+ { SIG_SCIALL, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL },
+ { SIG_SCIALL, 5, MAP_CALL(PaletteFindColor), "iii", NULL },
+ { SIG_SCIALL, 6, MAP_CALL(PaletteAnimate), "i*", NULL },
+ { SIG_SCIALL, 7, MAP_CALL(PaletteSave), "", NULL },
+ { SIG_SCIALL, 8, MAP_CALL(PaletteRestore), "[r0]", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
};
static const SciKernelMapSubEntry kFileIO_subops[] = {
- { SIG_SCI32, 0, MAP_CALL(FileIOOpen), "r(i)", NULL },
- { SIG_SCIALL, 0, MAP_CALL(FileIOOpen), "ri", NULL },
- { SIG_SCIALL, 1, MAP_CALL(FileIOClose), "i", NULL },
- { SIG_SCIALL, 2, MAP_CALL(FileIOReadRaw), "iri", NULL },
- { SIG_SCIALL, 3, MAP_CALL(FileIOWriteRaw), "iri", NULL },
- { SIG_SCIALL, 4, MAP_CALL(FileIOUnlink), "r", NULL },
- { SIG_SCIALL, 5, MAP_CALL(FileIOReadString), "rii", NULL },
- { SIG_SCIALL, 6, MAP_CALL(FileIOWriteString), "ir", NULL },
- { SIG_SCIALL, 7, MAP_CALL(FileIOSeek), "iii", NULL },
- { SIG_SCIALL, 8, MAP_CALL(FileIOFindFirst), "rri", NULL },
- { SIG_SCIALL, 9, MAP_CALL(FileIOFindNext), "r", NULL },
- { SIG_SCIALL, 10, MAP_CALL(FileIOExists), "r", NULL },
- { SIG_SINCE_SCI11, 11, MAP_CALL(FileIORename), "rr", NULL },
+ { SIG_SCI32, 0, MAP_CALL(FileIOOpen), "r(i)", NULL },
+ { SIG_SCIALL, 0, MAP_CALL(FileIOOpen), "ri", NULL },
+ { SIG_SCIALL, 1, MAP_CALL(FileIOClose), "i", NULL },
+ { SIG_SCIALL, 2, MAP_CALL(FileIOReadRaw), "iri", NULL },
+ { SIG_SCIALL, 3, MAP_CALL(FileIOWriteRaw), "iri", NULL },
+ { SIG_SCIALL, 4, MAP_CALL(FileIOUnlink), "r", NULL },
+ { SIG_SCIALL, 5, MAP_CALL(FileIOReadString), "rii", NULL },
+ { SIG_SCIALL, 6, MAP_CALL(FileIOWriteString), "ir", NULL },
+ { SIG_SCIALL, 7, MAP_CALL(FileIOSeek), "iii", NULL },
+ { SIG_SCIALL, 8, MAP_CALL(FileIOFindFirst), "rri", NULL },
+ { SIG_SCIALL, 9, MAP_CALL(FileIOFindNext), "r", NULL },
+ { SIG_SCIALL, 10, MAP_CALL(FileIOExists), "r", NULL },
+ { SIG_SINCE_SCI11, 11, MAP_CALL(FileIORename), "rr", NULL },
#ifdef ENABLE_SCI32
- { SIG_SCI32, 13, MAP_CALL(FileIOReadByte), "i", NULL },
- { SIG_SCI32, 14, MAP_CALL(FileIOWriteByte), "ii", NULL },
- { SIG_SCI32, 15, MAP_CALL(FileIOReadWord), "i", NULL },
- { SIG_SCI32, 16, MAP_CALL(FileIOWriteWord), "ii", NULL },
- { SIG_SCI32, 19, MAP_CALL(Stub), "r", NULL }, // for Torin / Torin demo
+ { SIG_SCI32, 13, MAP_CALL(FileIOReadByte), "i", NULL },
+ { SIG_SCI32, 14, MAP_CALL(FileIOWriteByte), "ii", NULL },
+ { SIG_SCI32, 15, MAP_CALL(FileIOReadWord), "i", NULL },
+ { SIG_SCI32, 16, MAP_CALL(FileIOWriteWord), "ii", NULL },
+ { SIG_SCI32, 19, MAP_CALL(Stub), "r", NULL }, // for Torin / Torin demo
#endif
- SCI_SUBOPENTRY_TERMINATOR
+ SCI_SUBOPENTRY_TERMINATOR
};
#ifdef ENABLE_SCI32
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kList_subops[] = {
- { SIG_SCI21, 0, MAP_CALL(NewList), "", NULL },
- { SIG_SCI21, 1, MAP_CALL(DisposeList), "l", NULL },
- { SIG_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL },
- { SIG_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL },
- { SIG_SCI21, 4, MAP_CALL(LastNode), "l", NULL },
- { SIG_SCI21, 5, MAP_CALL(EmptyList), "l", NULL },
- { SIG_SCI21, 6, MAP_CALL(NextNode), "n", NULL },
- { SIG_SCI21, 7, MAP_CALL(PrevNode), "n", NULL },
- { SIG_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL },
- { SIG_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL },
- { SIG_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL },
- { SIG_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL },
- { SIG_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL },
- { SIG_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL },
- { SIG_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL },
- { SIG_SCI21, 15, MAP_CALL(FindKey), "l.", NULL },
- { SIG_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL },
- { SIG_SCI21, 17, MAP_CALL(ListAt), "li", NULL },
- { SIG_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL },
- { SIG_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL },
- { SIG_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL },
- { SIG_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL },
- { SIG_SCI21, 22, MAP_CALL(Sort), "ooo", NULL },
- SCI_SUBOPENTRY_TERMINATOR
+ { SIG_SCI21, 0, MAP_CALL(NewList), "", NULL },
+ { SIG_SCI21, 1, MAP_CALL(DisposeList), "l", NULL },
+ { SIG_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL },
+ { SIG_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL },
+ { SIG_SCI21, 4, MAP_CALL(LastNode), "l", NULL },
+ { SIG_SCI21, 5, MAP_CALL(EmptyList), "l", NULL },
+ { SIG_SCI21, 6, MAP_CALL(NextNode), "n", NULL },
+ { SIG_SCI21, 7, MAP_CALL(PrevNode), "n", NULL },
+ { SIG_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL },
+ { SIG_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL },
+ { SIG_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL },
+ { SIG_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL },
+ { SIG_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL },
+ { SIG_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL },
+ { SIG_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL },
+ { SIG_SCI21, 15, MAP_CALL(FindKey), "l.", NULL },
+ { SIG_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL },
+ { SIG_SCI21, 17, MAP_CALL(ListAt), "li", NULL },
+ { SIG_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL },
+ { SIG_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL },
+ { SIG_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL },
+ { SIG_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL },
+ { SIG_SCI21, 22, MAP_CALL(Sort), "ooo", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
};
#endif
@@ -290,251 +291,299 @@ struct SciKernelMapEntry {
// name, version/platform, signature, sub-signatures, workarounds
static SciKernelMapEntry s_kernelMap[] = {
- { MAP_CALL(Abs), SIG_EVERYWHERE, "i", NULL, kAbs_workarounds },
- { MAP_CALL(AddAfter), SIG_EVERYWHERE, "lnn", NULL, NULL },
- { MAP_CALL(AddMenu), SIG_EVERYWHERE, "rr", NULL, NULL },
- { MAP_CALL(AddToEnd), SIG_EVERYWHERE, "ln", NULL, NULL },
- { MAP_CALL(AddToFront), SIG_EVERYWHERE, "ln", NULL, NULL },
- { MAP_CALL(AddToPic), SIG_EVERYWHERE, "[il](iiiiii)", NULL, NULL },
- { MAP_CALL(Animate), SIG_EVERYWHERE, "(l0)(i)", NULL, NULL },
- { MAP_CALL(AssertPalette), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(AvoidPath), SIG_EVERYWHERE, "ii(.*)", NULL, NULL },
- { MAP_CALL(BaseSetter), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(CanBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL },
+ { MAP_CALL(Abs), SIG_EVERYWHERE, "i", NULL, kAbs_workarounds },
+ { MAP_CALL(AddAfter), SIG_EVERYWHERE, "lnn", NULL, NULL },
+ { MAP_CALL(AddMenu), SIG_EVERYWHERE, "rr", NULL, NULL },
+ { MAP_CALL(AddToEnd), SIG_EVERYWHERE, "ln", NULL, NULL },
+ { MAP_CALL(AddToFront), SIG_EVERYWHERE, "ln", NULL, NULL },
+ { MAP_CALL(AddToPic), SIG_EVERYWHERE, "[il](iiiiii)", NULL, NULL },
+ { MAP_CALL(Animate), SIG_EVERYWHERE, "(l0)(i)", NULL, NULL },
+ { MAP_CALL(AssertPalette), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(AvoidPath), SIG_EVERYWHERE, "ii(.*)", NULL, NULL },
+ { MAP_CALL(BaseSetter), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(CanBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL },
#ifdef ENABLE_SCI32
- { "CantBeHere", kCantBeHere32, SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL },
+ { "CantBeHere", kCantBeHere32, SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL },
#endif
- { MAP_CALL(CantBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL },
- { MAP_CALL(CelHigh), SIG_EVERYWHERE, "ii(i)", NULL, kCelHigh_workarounds },
- { MAP_CALL(CelWide), SIG_EVERYWHERE, "ii(i)", NULL, kCelWide_workarounds },
- { MAP_CALL(CheckFreeSpace), SIG_SCI32, SIGFOR_ALL, "r.*", NULL, NULL },
- { MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL },
- { MAP_CALL(CheckFreeSpace), SIG_EVERYWHERE, "r", NULL, NULL },
- { MAP_CALL(CheckSaveGame), SIG_EVERYWHERE, ".*", NULL, NULL },
- { MAP_CALL(Clone), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(CoordPri), SIG_EVERYWHERE, "i(i)", NULL, NULL },
- { MAP_CALL(CosDiv), SIG_EVERYWHERE, "ii", NULL, NULL },
- { MAP_CALL(DeleteKey), SIG_EVERYWHERE, "l.", NULL, NULL },
- { MAP_CALL(DeviceInfo), SIG_EVERYWHERE, "i(r)(r)(i)", NULL, kDeviceInfo_workarounds }, // subop
- { MAP_CALL(Display), SIG_EVERYWHERE, "[ir]([ir!]*)", NULL, kDisplay_workarounds },
- // ^ we allow invalid references here, because kDisplay gets called with those in e.g. pq3 during intro
- // restoreBits() checks and skips invalid handles, so that's fine. Sierra SCI behaved the same
- { MAP_CALL(DirLoop), SIG_EVERYWHERE, "oi", NULL, kDirLoop_workarounds },
- { MAP_CALL(DisposeClone), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(DisposeList), SIG_EVERYWHERE, "l", NULL, NULL },
- { MAP_CALL(DisposeScript), SIG_EVERYWHERE, "i(i*)", NULL, kDisposeScript_workarounds },
- { MAP_CALL(DisposeWindow), SIG_EVERYWHERE, "i(i)", NULL, NULL },
- { MAP_CALL(DoAudio), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
- { MAP_CALL(DoAvoider), SIG_EVERYWHERE, "o(i)", NULL, NULL },
- { MAP_CALL(DoBresen), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(DoSound), SIG_EVERYWHERE, "i(.*)", kDoSound_subops, NULL },
- { MAP_CALL(DoSync), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
- { MAP_CALL(DrawCel), SIG_SCI11, SIGFOR_PC, "iiiii(i)(i)([ri])", NULL, NULL }, // reference for kq6 hires
- { MAP_CALL(DrawCel), SIG_EVERYWHERE, "iiiii(i)(i)", NULL, NULL },
- { MAP_CALL(DrawControl), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(DrawMenuBar), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(DrawPic), SIG_EVERYWHERE, "i(i)(i)(i)", NULL, NULL },
- { MAP_CALL(DrawStatus), SIG_EVERYWHERE, "[r0](i)(i)", NULL, NULL },
- { MAP_CALL(EditControl), SIG_EVERYWHERE, "[o0][o0]", NULL, NULL },
- { MAP_CALL(Empty), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(EmptyList), SIG_EVERYWHERE, "l", NULL, NULL },
- { MAP_CALL(FClose), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(FGets), SIG_EVERYWHERE, "rii", NULL, NULL },
- { MAP_CALL(FOpen), SIG_EVERYWHERE, "ri", NULL, NULL },
- { MAP_CALL(FPuts), SIG_EVERYWHERE, "ir", NULL, NULL },
- { MAP_CALL(FileIO), SIG_EVERYWHERE, "i(.*)", kFileIO_subops, NULL },
- { MAP_CALL(FindKey), SIG_EVERYWHERE, "l.", NULL, kFindKey_workarounds },
- { MAP_CALL(FirstNode), SIG_EVERYWHERE, "[l0]", NULL, NULL },
- { MAP_CALL(FlushResources), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(Format), SIG_EVERYWHERE, "r(.*)", NULL, NULL },
- { MAP_CALL(GameIsRestarting), SIG_EVERYWHERE, "(i)", NULL, NULL },
- { MAP_CALL(GetAngle), SIG_EVERYWHERE, "iiii", NULL, kGetAngle_workarounds },
- { MAP_CALL(GetCWD), SIG_EVERYWHERE, "r", NULL, NULL },
- { MAP_CALL(GetDistance), SIG_EVERYWHERE, "ii(i)(i)(i)(i)", NULL, NULL },
- { MAP_CALL(GetEvent), SIG_SCIALL, SIGFOR_MAC, "io(i*)", NULL, NULL },
- { MAP_CALL(GetEvent), SIG_EVERYWHERE, "io", NULL, NULL },
- { MAP_CALL(GetFarText), SIG_EVERYWHERE, "ii[r0]", NULL, NULL },
- { MAP_CALL(GetMenu), SIG_EVERYWHERE, "i.", NULL, NULL },
- { MAP_CALL(GetMessage), SIG_EVERYWHERE, "iiir", NULL, NULL },
- { MAP_CALL(GetPort), SIG_EVERYWHERE, "", NULL, NULL },
- { MAP_CALL(GetSaveDir), SIG_SCI32, SIGFOR_ALL, "(r*)", NULL, NULL },
- { MAP_CALL(GetSaveDir), SIG_EVERYWHERE, "", NULL, NULL },
- { MAP_CALL(GetSaveFiles), SIG_EVERYWHERE, "rrr", NULL, NULL },
- { MAP_CALL(GetTime), SIG_EVERYWHERE, "(i)", NULL, NULL },
- { MAP_CALL(GlobalToLocal), SIG_SCI32, SIGFOR_ALL, "oo", NULL, NULL },
- { MAP_CALL(GlobalToLocal), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(Graph), SIG_EVERYWHERE, NULL, kGraph_subops, NULL },
- { MAP_CALL(HaveMouse), SIG_EVERYWHERE, "", NULL, NULL },
- { MAP_CALL(HiliteControl), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(InitBresen), SIG_EVERYWHERE, "o(i)", NULL, NULL },
- { MAP_CALL(Intersections), SIG_EVERYWHERE, "iiiiriiiri", NULL, NULL },
- { MAP_CALL(IsItSkip), SIG_EVERYWHERE, "iiiii", NULL, NULL },
- { MAP_CALL(IsObject), SIG_EVERYWHERE, ".", NULL, kIsObject_workarounds },
- { MAP_CALL(Joystick), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
- { MAP_CALL(LastNode), SIG_EVERYWHERE, "l", NULL, NULL },
- { MAP_CALL(Load), SIG_EVERYWHERE, "ii(i*)", NULL, NULL },
- { MAP_CALL(LocalToGlobal), SIG_SCI32, SIGFOR_ALL, "oo", NULL, NULL },
- { MAP_CALL(LocalToGlobal), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(Lock), SIG_EVERYWHERE, "ii(i)", NULL, NULL },
- { MAP_CALL(MapKeyToDir), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(Memory), SIG_EVERYWHERE, "i(.*)", NULL, kMemory_workarounds }, // subop
- { MAP_CALL(MemoryInfo), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(MemorySegment), SIG_EVERYWHERE, "ir(i)", NULL, NULL }, // subop
- { MAP_CALL(MenuSelect), SIG_EVERYWHERE, "o(i)", NULL, NULL },
- { MAP_CALL(MergePoly), SIG_EVERYWHERE, "rli", NULL, NULL },
- { MAP_CALL(Message), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
- { MAP_CALL(MoveCursor), SIG_EVERYWHERE, "ii", NULL, NULL },
- { MAP_CALL(NewList), SIG_EVERYWHERE, "", NULL, NULL },
- { MAP_CALL(NewNode), SIG_EVERYWHERE, "..", NULL, NULL },
- { MAP_CALL(NewWindow), SIG_SCIALL, SIGFOR_MAC, ".*", NULL, NULL },
- { MAP_CALL(NewWindow), SIG_SCI0, SIGFOR_ALL, "iiii[r0]i(i)(i)(i)", NULL, NULL },
- { MAP_CALL(NewWindow), SIG_SCI1, SIGFOR_ALL, "iiii[ir]i(i)(i)([ir])(i)(i)(i)(i)", NULL, NULL },
- { MAP_CALL(NewWindow), SIG_SCI11, SIGFOR_ALL, "iiiiiiii[r0]i(i)(i)(i)", NULL, kNewWindow_workarounds },
- { MAP_CALL(NextNode), SIG_EVERYWHERE, "n", NULL, NULL },
- { MAP_CALL(NodeValue), SIG_EVERYWHERE, "[n0]", NULL, NULL },
- { MAP_CALL(NumCels), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(NumLoops), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(OnControl), SIG_EVERYWHERE, "ii(i)(i)(i)", NULL, NULL },
- { MAP_CALL(PalVary), SIG_EVERYWHERE, "i(i*)", kPalVary_subops, NULL },
- { MAP_CALL(Palette), SIG_EVERYWHERE, "i(.*)", kPalette_subops, NULL },
- { MAP_CALL(Parse), SIG_EVERYWHERE, "ro", NULL, NULL },
- { MAP_CALL(PicNotValid), SIG_EVERYWHERE, "(i)", NULL, NULL },
- { MAP_CALL(Platform), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(Portrait), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
- { MAP_CALL(PrevNode), SIG_EVERYWHERE, "n", NULL, NULL },
- { MAP_CALL(PriCoord), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(Random), SIG_EVERYWHERE, "i(i)(i)", NULL, NULL },
- { MAP_CALL(ReadNumber), SIG_EVERYWHERE, "r", NULL, NULL },
- { MAP_CALL(RemapColors), SIG_EVERYWHERE, "i(i)(i)(i)(i)(i)", NULL, NULL },
- { MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL },
- { MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL },
- { MAP_CALL(RestartGame), SIG_EVERYWHERE, "", NULL, NULL },
- { MAP_CALL(RestoreGame), SIG_EVERYWHERE, "[r0]i[r0]", NULL, NULL },
- { MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL },
- { MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r)", NULL, NULL },
- { MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL },
- { MAP_CALL(SetCursor), SIG_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL },
- // TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why
- { MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL },
- { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds },
- { MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL },
- { MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL },
- { MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
- { MAP_CALL(SetNowSeen), SIG_EVERYWHERE, "o(i)", NULL, NULL },
- { MAP_CALL(SetPort), SIG_EVERYWHERE, "i(iiiii)(i)", NULL, kSetPort_workarounds },
- { MAP_CALL(SetQuitStr), SIG_EVERYWHERE, "r", NULL, NULL },
- { MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(SetVideoMode), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(ShakeScreen), SIG_EVERYWHERE, "(i)(i)", NULL, NULL },
- { MAP_CALL(ShowMovie), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(Show), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(SinDiv), SIG_EVERYWHERE, "ii", NULL, NULL },
- { MAP_CALL(Sort), SIG_EVERYWHERE, "ooo", NULL, NULL },
- { MAP_CALL(Sqrt), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(StrAt), SIG_EVERYWHERE, "ri(i)", NULL, kStrAt_workarounds },
- { MAP_CALL(StrCat), SIG_EVERYWHERE, "rr", NULL, kStrCat_workarounds },
- { MAP_CALL(StrCmp), SIG_EVERYWHERE, "rr(i)", NULL, NULL },
- { MAP_CALL(StrCpy), SIG_EVERYWHERE, "r[r0](i)", NULL, NULL },
- { MAP_CALL(StrEnd), SIG_EVERYWHERE, "r", NULL, NULL },
- { MAP_CALL(StrLen), SIG_EVERYWHERE, "[r0]", NULL, NULL },
- { MAP_CALL(StrSplit), SIG_EVERYWHERE, "rr[r0]", NULL, NULL },
- { MAP_CALL(TextColors), SIG_EVERYWHERE, "(i*)", NULL, NULL },
- { MAP_CALL(TextFonts), SIG_EVERYWHERE, "(i*)", NULL, NULL },
- { MAP_CALL(TextSize), SIG_SCIALL, SIGFOR_MAC, "r[r0]i(i)(r0)(i)", NULL, NULL },
- { MAP_CALL(TextSize), SIG_EVERYWHERE, "r[r0]i(i)(r0)", NULL, NULL },
- { MAP_CALL(TimesCos), SIG_EVERYWHERE, "ii", NULL, NULL },
- { "CosMult", kTimesCos, SIG_EVERYWHERE, "ii", NULL, NULL },
- { MAP_CALL(TimesCot), SIG_EVERYWHERE, "ii", NULL, NULL },
- { 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(ValidPath), SIG_EVERYWHERE, "r", NULL, NULL },
- { MAP_CALL(Wait), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(CantBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL },
+ { MAP_CALL(CelHigh), SIG_EVERYWHERE, "ii(i)", NULL, kCelHigh_workarounds },
+ { MAP_CALL(CelWide), SIG_EVERYWHERE, "ii(i)", NULL, kCelWide_workarounds },
+ { MAP_CALL(CheckFreeSpace), SIG_SCI32, SIGFOR_ALL, "r.*", NULL, NULL },
+ { MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL },
+ { MAP_CALL(CheckFreeSpace), SIG_EVERYWHERE, "r", NULL, NULL },
+ { MAP_CALL(CheckSaveGame), SIG_EVERYWHERE, ".*", NULL, NULL },
+ { MAP_CALL(Clone), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(CoordPri), SIG_EVERYWHERE, "i(i)", NULL, NULL },
+ { MAP_CALL(CosDiv), SIG_EVERYWHERE, "ii", NULL, NULL },
+ { MAP_CALL(DeleteKey), SIG_EVERYWHERE, "l.", NULL, NULL },
+ { MAP_CALL(DeviceInfo), SIG_EVERYWHERE, "i(r)(r)(i)", NULL, kDeviceInfo_workarounds }, // subop
+ { MAP_CALL(Display), SIG_EVERYWHERE, "[ir]([ir!]*)", NULL, kDisplay_workarounds },
+ // ^ we allow invalid references here, because kDisplay gets called with those in e.g. pq3 during intro
+ // restoreBits() checks and skips invalid handles, so that's fine. Sierra SCI behaved the same
+ { MAP_CALL(DirLoop), SIG_EVERYWHERE, "oi", NULL, kDirLoop_workarounds },
+ { MAP_CALL(DisposeClone), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(DisposeList), SIG_EVERYWHERE, "l", NULL, NULL },
+ { MAP_CALL(DisposeScript), SIG_EVERYWHERE, "i(i*)", NULL, kDisposeScript_workarounds },
+ { MAP_CALL(DisposeWindow), SIG_EVERYWHERE, "i(i)", NULL, NULL },
+ { MAP_CALL(DoAudio), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
+ { MAP_CALL(DoAvoider), SIG_EVERYWHERE, "o(i)", NULL, NULL },
+ { MAP_CALL(DoBresen), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(DoSound), SIG_EVERYWHERE, "i(.*)", kDoSound_subops, NULL },
+ { MAP_CALL(DoSync), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
+ { MAP_CALL(DrawCel), SIG_SCI11, SIGFOR_PC, "iiiii(i)(i)([ri])", NULL, NULL }, // reference for kq6 hires
+ { MAP_CALL(DrawCel), SIG_EVERYWHERE, "iiiii(i)(i)", NULL, NULL },
+ { MAP_CALL(DrawControl), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(DrawMenuBar), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(DrawPic), SIG_EVERYWHERE, "i(i)(i)(i)", NULL, NULL },
+ { MAP_CALL(DrawStatus), SIG_EVERYWHERE, "[r0](i)(i)", NULL, NULL },
+ { MAP_CALL(EditControl), SIG_EVERYWHERE, "[o0][o0]", NULL, NULL },
+ { MAP_CALL(Empty), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(EmptyList), SIG_EVERYWHERE, "l", NULL, NULL },
+ { MAP_CALL(FClose), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(FGets), SIG_EVERYWHERE, "rii", NULL, NULL },
+ { MAP_CALL(FOpen), SIG_EVERYWHERE, "ri", NULL, NULL },
+ { MAP_CALL(FPuts), SIG_EVERYWHERE, "ir", NULL, NULL },
+ { MAP_CALL(FileIO), SIG_EVERYWHERE, "i(.*)", kFileIO_subops, NULL },
+ { MAP_CALL(FindKey), SIG_EVERYWHERE, "l.", NULL, kFindKey_workarounds },
+ { MAP_CALL(FirstNode), SIG_EVERYWHERE, "[l0]", NULL, NULL },
+ { MAP_CALL(FlushResources), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(Format), SIG_EVERYWHERE, "r(.*)", NULL, NULL },
+ { MAP_CALL(GameIsRestarting), SIG_EVERYWHERE, "(i)", NULL, NULL },
+ { MAP_CALL(GetAngle), SIG_EVERYWHERE, "iiii", NULL, kGetAngle_workarounds },
+ { MAP_CALL(GetCWD), SIG_EVERYWHERE, "r", NULL, NULL },
+ { MAP_CALL(GetDistance), SIG_EVERYWHERE, "ii(i)(i)(i)(i)", NULL, NULL },
+ { MAP_CALL(GetEvent), SIG_SCIALL, SIGFOR_MAC, "io(i*)", NULL, NULL },
+ { MAP_CALL(GetEvent), SIG_EVERYWHERE, "io", NULL, NULL },
+ { MAP_CALL(GetFarText), SIG_EVERYWHERE, "ii[r0]", NULL, NULL },
+ { MAP_CALL(GetMenu), SIG_EVERYWHERE, "i.", NULL, NULL },
+ { MAP_CALL(GetMessage), SIG_EVERYWHERE, "iiir", NULL, NULL },
+ { MAP_CALL(GetPort), SIG_EVERYWHERE, "", NULL, NULL },
+ { MAP_CALL(GetSaveDir), SIG_SCI32, SIGFOR_ALL, "(r*)", NULL, NULL },
+ { MAP_CALL(GetSaveDir), SIG_EVERYWHERE, "", NULL, NULL },
+ { MAP_CALL(GetSaveFiles), SIG_EVERYWHERE, "rrr", NULL, NULL },
+ { MAP_CALL(GetTime), SIG_EVERYWHERE, "(i)", NULL, NULL },
+ { MAP_CALL(GlobalToLocal), SIG_SCI32, SIGFOR_ALL, "oo", NULL, NULL },
+ { MAP_CALL(GlobalToLocal), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(Graph), SIG_EVERYWHERE, NULL, kGraph_subops, NULL },
+ { MAP_CALL(HaveMouse), SIG_EVERYWHERE, "", NULL, NULL },
+ { MAP_CALL(HiliteControl), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(InitBresen), SIG_EVERYWHERE, "o(i)", NULL, NULL },
+ { MAP_CALL(Intersections), SIG_EVERYWHERE, "iiiiriiiri", NULL, NULL },
+ { MAP_CALL(IsItSkip), SIG_EVERYWHERE, "iiiii", NULL, NULL },
+ { MAP_CALL(IsObject), SIG_EVERYWHERE, ".", NULL, kIsObject_workarounds },
+ { MAP_CALL(Joystick), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
+ { MAP_CALL(LastNode), SIG_EVERYWHERE, "l", NULL, NULL },
+ { MAP_CALL(Load), SIG_EVERYWHERE, "ii(i*)", NULL, NULL },
+ { MAP_CALL(LocalToGlobal), SIG_SCI32, SIGFOR_ALL, "oo", NULL, NULL },
+ { MAP_CALL(LocalToGlobal), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(Lock), SIG_EVERYWHERE, "ii(i)", NULL, NULL },
+ { MAP_CALL(MapKeyToDir), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(Memory), SIG_EVERYWHERE, "i(.*)", NULL, kMemory_workarounds }, // subop
+ { MAP_CALL(MemoryInfo), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(MemorySegment), SIG_EVERYWHERE, "ir(i)", NULL, NULL }, // subop
+ { MAP_CALL(MenuSelect), SIG_EVERYWHERE, "o(i)", NULL, NULL },
+ { MAP_CALL(MergePoly), SIG_EVERYWHERE, "rli", NULL, NULL },
+ { MAP_CALL(Message), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
+ { MAP_CALL(MoveCursor), SIG_EVERYWHERE, "ii", NULL, NULL },
+ { MAP_CALL(NewList), SIG_EVERYWHERE, "", NULL, NULL },
+ { MAP_CALL(NewNode), SIG_EVERYWHERE, "..", NULL, NULL },
+ { MAP_CALL(NewWindow), SIG_SCIALL, SIGFOR_MAC, ".*", NULL, NULL },
+ { MAP_CALL(NewWindow), SIG_SCI0, SIGFOR_ALL, "iiii[r0]i(i)(i)(i)", NULL, NULL },
+ { MAP_CALL(NewWindow), SIG_SCI1, SIGFOR_ALL, "iiii[ir]i(i)(i)([ir])(i)(i)(i)(i)", NULL, NULL },
+ { MAP_CALL(NewWindow), SIG_SCI11, SIGFOR_ALL, "iiiiiiii[r0]i(i)(i)(i)", NULL, kNewWindow_workarounds },
+ { MAP_CALL(NextNode), SIG_EVERYWHERE, "n", NULL, NULL },
+ { MAP_CALL(NodeValue), SIG_EVERYWHERE, "[n0]", NULL, NULL },
+ { MAP_CALL(NumCels), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(NumLoops), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(OnControl), SIG_EVERYWHERE, "ii(i)(i)(i)", NULL, NULL },
+ { MAP_CALL(PalVary), SIG_EVERYWHERE, "i(i*)", kPalVary_subops, NULL },
+ { MAP_CALL(Palette), SIG_EVERYWHERE, "i(.*)", kPalette_subops, NULL },
+ { MAP_CALL(Parse), SIG_EVERYWHERE, "ro", NULL, NULL },
+ { MAP_CALL(PicNotValid), SIG_EVERYWHERE, "(i)", NULL, NULL },
+ { MAP_CALL(Platform), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(Portrait), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
+ { MAP_CALL(PrevNode), SIG_EVERYWHERE, "n", NULL, NULL },
+ { MAP_CALL(PriCoord), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(Random), SIG_EVERYWHERE, "i(i)(i)", NULL, NULL },
+ { MAP_CALL(ReadNumber), SIG_EVERYWHERE, "r", NULL, NULL },
+ { MAP_CALL(RemapColors), SIG_EVERYWHERE, "i(i)(i)(i)(i)(i)", NULL, NULL },
+ { MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL },
+ { MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL },
+ { MAP_CALL(RestartGame), SIG_EVERYWHERE, "", NULL, NULL },
+ { MAP_CALL(RestoreGame), SIG_EVERYWHERE, "[r0]i[r0]", NULL, NULL },
+ { MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL },
+ { MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r)", NULL, NULL },
+ { MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL },
+ { MAP_CALL(SetCursor), SIG_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL },
+ // TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why
+ { MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL },
+ { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds },
+ { MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL },
+ { MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL },
+ { MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
+ { MAP_CALL(SetNowSeen), SIG_EVERYWHERE, "o(i)", NULL, NULL },
+ { MAP_CALL(SetPort), SIG_EVERYWHERE, "i(iiiii)(i)", NULL, kSetPort_workarounds },
+ { MAP_CALL(SetQuitStr), SIG_EVERYWHERE, "r", NULL, NULL },
+ { MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(SetVideoMode), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(ShakeScreen), SIG_EVERYWHERE, "(i)(i)", NULL, NULL },
+ { MAP_CALL(ShowMovie), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(Show), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(SinDiv), SIG_EVERYWHERE, "ii", NULL, NULL },
+ { MAP_CALL(Sort), SIG_EVERYWHERE, "ooo", NULL, NULL },
+ { MAP_CALL(Sqrt), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(StrAt), SIG_EVERYWHERE, "ri(i)", NULL, kStrAt_workarounds },
+ { MAP_CALL(StrCat), SIG_EVERYWHERE, "rr", NULL, kStrCat_workarounds },
+ { MAP_CALL(StrCmp), SIG_EVERYWHERE, "rr(i)", NULL, NULL },
+ { MAP_CALL(StrCpy), SIG_EVERYWHERE, "r[r0](i)", NULL, NULL },
+ { MAP_CALL(StrEnd), SIG_EVERYWHERE, "r", NULL, NULL },
+ { MAP_CALL(StrLen), SIG_EVERYWHERE, "[r0]", NULL, kStrLen_workarounds },
+ { MAP_CALL(StrSplit), SIG_EVERYWHERE, "rr[r0]", NULL, NULL },
+ { MAP_CALL(TextColors), SIG_EVERYWHERE, "(i*)", NULL, NULL },
+ { MAP_CALL(TextFonts), SIG_EVERYWHERE, "(i*)", NULL, NULL },
+ { MAP_CALL(TextSize), SIG_SCIALL, SIGFOR_MAC, "r[r0]i(i)(r0)(i)", NULL, NULL },
+ { MAP_CALL(TextSize), SIG_EVERYWHERE, "r[r0]i(i)(r0)", NULL, NULL },
+ { MAP_CALL(TimesCos), SIG_EVERYWHERE, "ii", NULL, NULL },
+ { "CosMult", kTimesCos, SIG_EVERYWHERE, "ii", NULL, NULL },
+ { MAP_CALL(TimesCot), SIG_EVERYWHERE, "ii", NULL, NULL },
+ { 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(ValidPath), SIG_EVERYWHERE, "r", NULL, NULL },
+ { MAP_CALL(Wait), SIG_EVERYWHERE, "i", NULL, NULL },
- // Unimplemented SCI0-SCI1.1 unused functions, always mapped to kDummy
- { MAP_DUMMY(InspectObj), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(ShowSends), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(ShowObjs), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(ShowFree), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(StackUsage), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(Profiler), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(ShiftScreen), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(ListOps), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(ATan), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(Record), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(PlayBack), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(DbugStr), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ // Unimplemented SCI0-SCI1.1 unused functions, always mapped to kDummy
+ { MAP_DUMMY(InspectObj), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(ShowSends), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(ShowObjs), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(ShowFree), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(StackUsage), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(Profiler), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(ShiftScreen), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(ListOps), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(ATan), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(Record), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(PlayBack), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(DbugStr), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- // =======================================================================================================
+ // =======================================================================================================
#ifdef ENABLE_SCI32
- // SCI2 Kernel Functions
- // TODO: whoever knows his way through those calls, fix the signatures.
- { MAP_CALL(AddPlane), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(AddScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(Array), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
- { MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(FrameOut), SIG_EVERYWHERE, "", NULL, NULL },
- { MAP_CALL(GetHighPlanePri), SIG_EVERYWHERE, "", NULL, NULL },
- { MAP_CALL(InPolygon), SIG_EVERYWHERE, "iio", NULL, NULL },
- { MAP_CALL(IsHiRes), SIG_EVERYWHERE, "", NULL, NULL },
- { MAP_CALL(ListAllTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
- { MAP_CALL(ListAt), SIG_EVERYWHERE, "li", NULL, NULL },
- { MAP_CALL(ListEachElementDo), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
- { MAP_CALL(ListFirstTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
- { MAP_CALL(ListIndexOf), SIG_EVERYWHERE, "l[o0]", NULL, NULL },
- { "OnMe", kIsOnMe, SIG_EVERYWHERE, "iioi", NULL, NULL },
- { MAP_CALL(RepaintPlane), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(SetShowStyle), SIG_EVERYWHERE, "ioiiiii(i)", NULL, NULL },
- { MAP_CALL(String), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(UpdatePlane), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
+ // SCI2 Kernel Functions
+ // TODO: whoever knows his way through those calls, fix the signatures.
+ { MAP_CALL(AddPlane), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(AddScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(Array), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
+ { MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(FrameOut), SIG_EVERYWHERE, "", NULL, NULL },
+ { MAP_CALL(GetHighPlanePri), SIG_EVERYWHERE, "", NULL, NULL },
+ { MAP_CALL(InPolygon), SIG_EVERYWHERE, "iio", NULL, NULL },
+ { MAP_CALL(IsHiRes), SIG_EVERYWHERE, "", NULL, NULL },
+ { MAP_CALL(ListAllTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
+ { MAP_CALL(ListAt), SIG_EVERYWHERE, "li", NULL, NULL },
+ { MAP_CALL(ListEachElementDo), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
+ { MAP_CALL(ListFirstTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
+ { MAP_CALL(ListIndexOf), SIG_EVERYWHERE, "l[o0]", NULL, NULL },
+ { "OnMe", kIsOnMe, SIG_EVERYWHERE, "iioi", NULL, NULL },
+ { MAP_CALL(RepaintPlane), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(SetShowStyle), SIG_EVERYWHERE, "ioiiiii([ri])(i)", NULL, NULL },
+ { MAP_CALL(String), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(UpdatePlane), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
- // SCI2 empty functions
+ // SCI2 unmapped functions - TODO!
+ // SetScroll
+ // AddMagnify // most probably similar to the SCI1.1 functions. We need a test case
+ // DeleteMagnify
+ // EditText
+ // DisposeTextBitmap
+ // VibrateMouse - used in QFG4 floppy
+ // PalCycle
+ // ObjectIntersect - used in QFG4 floppy
- // Purge is used by the memory manager in SSCI to ensure that X number of bytes (the so called "unmovable
- // memory") are available. We have our own memory manager and garbage collector, thus we ignore this call.
- { MAP_EMPTY(Purge), SIG_EVERYWHERE, "i", NULL, NULL },
+ // SCI2 empty functions
- // SCI2.1 Kernel Functions
- { MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL },
- { MAP_CALL(List), SIG_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL },
- { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL },
- { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(Save), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(Text), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii", NULL, NULL },
- { MAP_CALL(GetWindowsOption), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(WinHelp), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(WinDLL), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(PrintDebug), SIG_EVERYWHERE, "ri", NULL, NULL },
+ // Purge is used by the memory manager in SSCI to ensure that X number of bytes (the so called "unmovable
+ // memory") are available. We have our own memory manager and garbage collector, thus we ignore this call.
+ { MAP_EMPTY(Purge), SIG_EVERYWHERE, "i", NULL, NULL },
- // SCI2.1 empty functions
+ // Unused SCI2 unused functions, always mapped to kDummy
+ { MAP_DUMMY(InspectObject), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ // Profiler (same as SCI0-SCI1.1)
+ // Record (same as SCI0-SCI1.1)
+ // PlayBack (same as SCI0-SCI1.1)
+ { MAP_DUMMY(MonoOut), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(SetFatalStr), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(IntegrityChecking),SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(CheckIntegrity), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(MarkMemory), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(GetHighItemPri), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(ShowStylePercent), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(InvertRect), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(InputText), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(MakeSaveCatName), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(MakeSaveFileName), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(TextWidth), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(PointSize), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- // SetWindowsOption is used to set Windows specific options, like for example the title bar visibility of
- // the game window in Phantasmagoria 2. We ignore these settings completely.
- { MAP_EMPTY(SetWindowsOption), SIG_EVERYWHERE, "ii", NULL, NULL },
+ // SCI2.1 Kernel Functions
+ { MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL },
+ { MAP_CALL(List), SIG_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL },
+ { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL },
+ { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(Save), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(Text), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii", NULL, NULL },
+ { MAP_CALL(GetWindowsOption), SIG_EVERYWHERE, "i", NULL, NULL },
+ { MAP_CALL(WinHelp), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(WinDLL), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(PrintDebug), SIG_EVERYWHERE, "ri", NULL, NULL },
- // Unimplemented SCI2.1 unused functions, always mapped to kDummy
- { MAP_DUMMY(InspectObject), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- // Profiler (same as SCI0-SCI1.1)
- // Record (same as SCI0-SCI1.1)
- // PlayBack (same as SCI0-SCI1.1)
- { MAP_DUMMY(MonoOut), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(SetFatalStr), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(IntegrityChecking),SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(CheckIntegrity), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(MarkMemory), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(GetSierraProfileInt), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(GetSierraProfileString), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ // SCI2.1 unmapped functions - TODO!
+ // SetLanguage
+ // FindSelector
+ // FindClass
+ // CelRect
+ // BaseLineSpan
+ // CelInfo
+ // Bitmap
+ // CelLink
+ // MovePlaneItems
+ // Font
+ // ScrollWindow
+ // AddLine
+ // DeleteLine
+ // UpdateLine
+ // AddPolygon
+ // DeletePolygon
+ // UpdatePolygon
+ // GetConfig
+ // Table
+ // LoadChunk
+ // SetPalStyleRange
+ // NewRoom
+ // Priority
+ // MorphOn
+ // SetHotRectangles
+ // DeletePic
+
+ // SCI2.1 empty functions
+
+ // SetWindowsOption is used to set Windows specific options, like for example the title bar visibility of
+ // the game window in Phantasmagoria 2. We ignore these settings completely.
+ { MAP_EMPTY(SetWindowsOption), SIG_EVERYWHERE, "ii", NULL, NULL },
+
+ // Unused SCI2.1 unused functions, always mapped to kDummy
+ { MAP_DUMMY(GetSierraProfileInt), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(GetSierraProfileString), SIG_EVERYWHERE, "(.*)", NULL, NULL },
#endif
- { NULL, NULL, SIG_EVERYWHERE, NULL, NULL, NULL }
+ { NULL, NULL, SIG_EVERYWHERE, NULL, NULL, NULL }
};
/** Default kernel name table. */
@@ -724,7 +773,7 @@ static const char *sci2_default_knames[] = {
/*0x21*/ "DeleteMagnify",
/*0x22*/ "IsHiRes",
/*0x23*/ "Graph",
- /*0x24*/ "InvertRect",
+ /*0x24*/ "InvertRect", // only in SCI2, not used in any SCI2 game
/*0x25*/ "TextSize",
/*0x26*/ "Message",
/*0x27*/ "TextColors",
@@ -746,8 +795,8 @@ static const char *sci2_default_knames[] = {
/*0x37*/ "RestoreGame",
/*0x38*/ "RestartGame",
/*0x39*/ "GameIsRestarting",
- /*0x3a*/ "MakeSaveCatName",
- /*0x3b*/ "MakeSaveFileName",
+ /*0x3a*/ "MakeSaveCatName", // only in SCI2, not used in any SCI2 game
+ /*0x3b*/ "MakeSaveFileName", // only in SCI2, not used in any SCI2 game
/*0x3c*/ "GetSaveFiles",
/*0x3d*/ "GetSaveDir",
/*0x3e*/ "CheckSaveGame",
@@ -825,8 +874,8 @@ static const char *sci2_default_knames[] = {
/*0x86*/ "CheckIntegrity", // for debugging
/*0x87*/ "ObjectIntersect",
/*0x88*/ "MarkMemory", // for debugging
- /*0x89*/ "TextWidth",
- /*0x8a*/ "PointSize",
+ /*0x89*/ "TextWidth", // for debugging(?), only in SCI2, not used in any SCI2 game
+ /*0x8a*/ "PointSize", // for debugging(?), only in SCI2, not used in any SCI2 game
// GK2 Demo (and similar) only kernel functions
/*0x8b*/ "AddLine",
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index b6d67513d2..324cb642d4 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -422,7 +422,7 @@ static void listSavegames(Common::Array<SavegameDesc> &saves) {
Common::SeekableReadStream *in;
if ((in = saveFileMan->openForLoading(filename))) {
SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta) || meta.savegame_name.empty()) {
+ if (!get_savegame_metadata(in, &meta) || meta.name.empty()) {
// invalid
delete in;
continue;
@@ -431,17 +431,17 @@ static void listSavegames(Common::Array<SavegameDesc> &saves) {
SavegameDesc desc;
desc.id = strtol(filename.end() - 3, NULL, 10);
- desc.date = meta.savegame_date;
+ desc.date = meta.saveDate;
// We need to fix date in here, because we save DDMMYYYY instead of
// YYYYMMDD, so sorting wouldn't work
desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24);
- desc.time = meta.savegame_time;
- desc.version = meta.savegame_version;
+ desc.time = meta.saveTime;
+ desc.version = meta.version;
- if (meta.savegame_name.lastChar() == '\n')
- meta.savegame_name.deleteLastChar();
+ if (meta.name.lastChar() == '\n')
+ meta.name.deleteLastChar();
- Common::strlcpy(desc.name, meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH);
+ Common::strlcpy(desc.name, meta.name.c_str(), SCI_MAX_SAVENAME_LENGTH);
debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id);
@@ -584,7 +584,7 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
g_system->getTimeAndDate(curTime);
curTime.tm_year += 1900; // fixup year
curTime.tm_mon++; // fixup month
- game_description = Common::String::printf("%02d.%02d.%04d / %02d:%02d:%02d", curTime.tm_mday, curTime.tm_mon, curTime.tm_year, curTime.tm_hour, curTime.tm_min, curTime.tm_sec);
+ game_description = Common::String::format("%02d.%02d.%04d / %02d:%02d:%02d", curTime.tm_mday, curTime.tm_mon, curTime.tm_year, curTime.tm_hour, curTime.tm_min, curTime.tm_sec);
}
delete dialog;
g_sci->_soundCmd->pauseAll(false); // unpause music ( we can't have it paused during save)
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 07385fd3f9..c10f23adfd 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -256,10 +256,11 @@ reg_t kGraphDrawLine(EngineState *s, int argc, reg_t *argv) {
int16 priority = (argc > 5) ? argv[5].toSint16() : -1;
int16 control = (argc > 6) ? argv[6].toSint16() : -1;
- // TODO: Find out why we get > 15 for color in EGA
- // FIXME: EGA? Which EGA? SCI0 or SCI1? Check the
- // workarounds inside kGraphFillBoxAny and kNewWindow
- if (!g_sci->getResMan()->isVGA() && !g_sci->getResMan()->isAmiga32color())
+ // WORKAROUND: SCI1 EGA games can set invalid colors (above 0 - 15).
+ // Colors above 15 are all white in SCI1 EGA games, which is why this was never
+ // observed. We clip them all to (0, 15) instead, as colors above 15 are used
+ // for the undithering algorithm in EGA games - bug #3048908.
+ if (g_sci->getResMan()->getViewType() == kViewEga && getSciVersion() >= SCI_VERSION_1_EARLY)
color &= 0x0F;
g_sci->_gfxPaint16->kernelGraphDrawLine(getGraphPoint(argv), getGraphPoint(argv + 2), color, priority, control);
@@ -297,7 +298,7 @@ reg_t kGraphFillBoxAny(EngineState *s, int argc, reg_t *argv) {
int16 priority = argv[6].toSint16(); // yes, we may read from stack sometimes here
int16 control = argv[7].toSint16(); // sierra did the same
- // WORKAROUND: PQ3 EGA is setting invalid colors (above 0 - 15).
+ // WORKAROUND: SCI1 EGA games can set invalid colors (above 0 - 15).
// Colors above 15 are all white in SCI1 EGA games, which is why this was never
// observed. We clip them all to (0, 15) instead, as colors above 15 are used
// for the undithering algorithm in EGA games - bug #3048908.
@@ -341,6 +342,11 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) {
int maxwidth = (argc > 3) ? argv[3].toUint16() : 0;
int font_nr = argv[2].toUint16();
+ if (!dest) {
+ debugC(2, kDebugLevelStrings, "GetTextSize: Empty destination");
+ return s->r_acc;
+ }
+
Common::String sep_str;
const char *sep = NULL;
if ((argc > 4) && (argv[4].segment)) {
@@ -350,7 +356,7 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) {
dest[0] = dest[1] = NULL_REG;
- if (text.empty() || !dest) { // Empty text
+ if (text.empty()) { // Empty text
dest[2] = dest[3] = make_reg(0, 0);
debugC(2, kDebugLevelStrings, "GetTextSize: Empty string");
return s->r_acc;
@@ -1083,7 +1089,7 @@ reg_t kNewWindow(EngineState *s, int argc, reg_t *argv) {
int colorPen = (argc > 7 + argextra) ? argv[7 + argextra].toSint16() : 0;
int colorBack = (argc > 8 + argextra) ? argv[8 + argextra].toSint16() : 255;
- // WORKAROUND: PQ3 EGA is setting invalid colors (above 0 - 15).
+ // WORKAROUND: SCI1 EGA games can set invalid colors (above 0 - 15).
// Colors above 15 are all white in SCI1 EGA games, which is why this was never
// observed. We clip them all to (0, 15) instead, as colors above 15 are used
// for the undithering algorithm in EGA games - bug #3048908.
@@ -1448,6 +1454,7 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
// TODO: This is all a stub/skeleton, thus we're invoking kStub() for now
kStub(s, argc, argv);
+ // Can be called with 7, 8 or 9 parameters
// showStyle matches the style selector of the associated plane object
uint16 showStyle = argv[0].toUint16(); // 0 - 15
reg_t planeObj = argv[1];
@@ -1464,6 +1471,8 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+ // TODO: Check if the plane is in the list of planes to draw
+
return s->r_acc;
}
diff --git a/engines/sci/engine/kmath.cpp b/engines/sci/engine/kmath.cpp
index 792181b832..f90a5b4353 100644
--- a/engines/sci/engine/kmath.cpp
+++ b/engines/sci/engine/kmath.cpp
@@ -126,14 +126,14 @@ reg_t kTimesSin(EngineState *s, int argc, reg_t *argv) {
int angle = argv[0].toSint16();
int factor = argv[1].toSint16();
- return make_reg(0, (int)(factor * sin(angle * PI / 180.0)));
+ return make_reg(0, (int16)(factor * sin(angle * PI / 180.0)));
}
reg_t kTimesCos(EngineState *s, int argc, reg_t *argv) {
int angle = argv[0].toSint16();
int factor = argv[1].toSint16();
- return make_reg(0, (int)(factor * cos(angle * PI / 180.0)));
+ return make_reg(0, (int16)(factor * cos(angle * PI / 180.0)));
}
reg_t kCosDiv(EngineState *s, int argc, reg_t *argv) {
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index d8ae1a3418..a92a7a2645 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -164,7 +164,7 @@ reg_t kFlushResources(EngineState *s, int argc, reg_t *argv) {
}
reg_t kSetDebug(EngineState *s, int argc, reg_t *argv) {
- printf("Debug mode activated\n");
+ debug("Debug mode activated");
g_sci->_debugState.seeking = kDebugSeekNothing;
g_sci->_debugState.runningStep = 0;
@@ -180,11 +180,10 @@ enum {
reg_t kGetTime(EngineState *s, int argc, reg_t *argv) {
TimeDate loc_time;
- uint32 elapsedTime;
+ uint32 elapsedTime = g_engine->getTotalPlayTime();
int retval = 0; // Avoid spurious warning
g_system->getTimeAndDate(loc_time);
- elapsedTime = g_system->getMillis() - s->gameStartTime;
int mode = (argc > 0) ? argv[0].toUint16() : 0;
@@ -231,14 +230,18 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case K_MEMORY_ALLOCATE_CRITICAL: {
int byteCount = argv[1].toUint16();
- // WORKAROUND: pq3 (multilingual) when plotting crimes - allocates the
- // returned bytes from kStrLen on "W" and "E" and wants to put a
- // string in there, which doesn't fit of course. That's why we allocate
- // one byte more all the time inside that room
- if (g_sci->getGameId() == GID_PQ3) {
- if (s->currentRoomNumber() == 202)
- byteCount++;
- }
+ // WORKAROUND:
+ // - pq3 (multilingual) room 202
+ // when plotting crimes, allocates the returned bytes from kStrLen
+ // on "W" and "E" and wants to put a string in there, which doesn't
+ // fit of course.
+ // - lsl5 (multilingual) room 280
+ // allocates memory according to a previous kStrLen for the name of
+ // the airport ladies (bug #3093818), which isn't enough
+
+ // We always allocate 1 byte more, because of this
+ byteCount++;
+
if (!s->_segMan->allocDynmem(byteCount, "kMemory() critical", &s->r_acc)) {
error("Critical heap allocation failed");
}
@@ -421,12 +424,12 @@ reg_t kStub(EngineState *s, int argc, reg_t *argv) {
}
Common::String warningMsg = "Dummy function k" + kernel->getKernelName(kernelCallNr) +
- Common::String::printf("[%x]", kernelCallNr) +
+ Common::String::format("[%x]", kernelCallNr) +
" invoked. Params: " +
- Common::String::printf("%d", argc) + " (";
+ Common::String::format("%d", argc) + " (";
for (int i = 0; i < argc; i++) {
- warningMsg += Common::String::printf("%04x:%04x", PRINT_REG(argv[i]));
+ warningMsg += Common::String::format("%04x:%04x", PRINT_REG(argv[i]));
warningMsg += (i == argc - 1 ? ")" : ", ");
}
diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp
index 6a052a582d..0b55c0fce7 100644
--- a/engines/sci/engine/kparse.cpp
+++ b/engines/sci/engine/kparse.cpp
@@ -62,7 +62,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
}
#ifdef DEBUG_PARSER
- printf("Said block: ");
+ debugN("Said block: ");
g_sci->getVocabulary()->debugDecipherSaidBlock(said_block);
#endif
@@ -74,7 +74,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
if (new_lastmatch != SAID_NO_MATCH) { /* Build and possibly display a parse tree */
#ifdef DEBUG_PARSER
- printf("kSaid: Match.\n");
+ debugN("kSaid: Match.\n");
#endif
s->r_acc = make_reg(0, 1);
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index faf966af92..cfd455e7b6 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -1311,6 +1311,8 @@ static void AStar(PathfindingState *s) {
}
}
+ assert(vertex_min != 0); // the vertex cost should never be bigger than HUGE_DISTANCE
+
// Check if we are done
if (vertex_min == s->vertex_end)
break;
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index e97ae38702..f52068bc8b 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -287,10 +287,10 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
// Looks to be setting the video size and position. Called with 4 extra integer
// parameters (e.g. 86, 41, 235, 106)
default:
- warningMsg = Common::String::printf("PlayVMD - unsupported subop %d. Params: %d (", operation, argc);
+ warningMsg = Common::String::format("PlayVMD - unsupported subop %d. Params: %d (", operation, argc);
for (int i = 0; i < argc; i++) {
- warningMsg += Common::String::printf("%04x:%04x", PRINT_REG(argv[i]));
+ warningMsg += Common::String::format("%04x:%04x", PRINT_REG(argv[i]));
warningMsg += (i == argc - 1 ? ")" : ", ");
}
diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp
index 6e1b326c4f..046ed4e500 100644
--- a/engines/sci/engine/message.cpp
+++ b/engines/sci/engine/message.cpp
@@ -218,7 +218,7 @@ int MessageState::nextMessage(reg_t buf) {
return record.talker;
} else {
MessageTuple &t = _cursorStack.top();
- outputString(buf, Common::String::printf("Msg %d: %d %d %d %d not found", _cursorStack.getModule(), t.noun, t.verb, t.cond, t.seq));
+ outputString(buf, Common::String::format("Msg %d: %d %d %d %d not found", _cursorStack.getModule(), t.noun, t.verb, t.cond, t.seq));
return 0;
}
} else {
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 87e328592f..3ced5a4f9d 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -40,6 +40,7 @@
#include "sci/engine/selector.h"
#include "sci/engine/vm_types.h"
#include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS
+#include "sci/graphics/helpers.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/ports.h"
#include "sci/sound/audio.h"
@@ -155,9 +156,26 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
// Let the object sync custom data
mobj->saveLoadWithSerializer(s);
- // If we are loading a script, hook it up in the script->segment map.
- if (s.isLoading() && type == SEG_TYPE_SCRIPT)
- _scriptSegMap[((Script *)mobj)->getScriptNumber()] = i;
+ // If we are saving a script, save its string heap space too
+ if (s.isSaving() && type == SEG_TYPE_SCRIPT)
+ ((Script *)mobj)->syncStringHeap(s);
+
+ // If we are loading a script, perform some extra steps
+ if (s.isLoading() && type == SEG_TYPE_SCRIPT) {
+ Script *scr = (Script *)mobj;
+ // Hook the script up in the script->segment map
+ _scriptSegMap[scr->getScriptNumber()] = i;
+
+ // Now, load the script itself
+ scr->load(g_sci->getResMan());
+
+ for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it)
+ it->_value.syncBaseObject(scr->getBuf(it->_value.getPos().offset));
+
+ // Load the script's string heap
+ if (s.getVersion() >= 28)
+ scr->syncStringHeap(s);
+ }
}
s.syncAsSint32LE(_clonesSegId);
@@ -165,6 +183,29 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint32LE(_nodesSegId);
syncArray<Class>(s, _classTable);
+
+ // Now that all scripts are loaded, init their objects
+ for (uint i = 0; i < _heap.size(); i++) {
+ if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
+ continue;
+
+ Script *scr = (Script *)_heap[i];
+ scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]);
+
+ for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) {
+ reg_t addr = it->_value.getPos();
+ Object *obj = scr->scriptObjInit(addr, false);
+
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ if (!obj->initBaseObject(this, addr, false)) {
+ // TODO/FIXME: This should not be happening at all. It might indicate a possible issue
+ // with the garbage collector. It happens for example in LSL5 (German, perhaps English too).
+ warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
+ scr->scriptObjRemove(addr);
+ }
+ }
+ }
+ }
}
@@ -175,27 +216,34 @@ void syncWithSerializer(Common::Serializer &s, Class &obj) {
}
static void sync_SavegameMetadata(Common::Serializer &s, SavegameMetadata &obj) {
- // TODO: It would be a good idea to store a magic number & a header size here,
- // so that we can implement backward compatibility if the savegame format changes.
-
- s.syncString(obj.savegame_name);
+ s.syncString(obj.name);
s.syncVersion(CURRENT_SAVEGAME_VERSION);
- obj.savegame_version = s.getVersion();
- s.syncString(obj.game_version);
- s.syncAsSint32LE(obj.savegame_date);
- s.syncAsSint32LE(obj.savegame_time);
+ obj.version = s.getVersion();
+ s.syncString(obj.gameVersion);
+ s.syncAsSint32LE(obj.saveDate);
+ s.syncAsSint32LE(obj.saveTime);
if (s.getVersion() < 22) {
- obj.game_object_offset = 0;
- obj.script0_size = 0;
+ obj.gameObjectOffset = 0;
+ obj.script0Size = 0;
+ } else {
+ s.syncAsUint16LE(obj.gameObjectOffset);
+ s.syncAsUint16LE(obj.script0Size);
+ }
+
+ // Playtime
+ obj.playTime = 0;
+ if (s.isLoading()) {
+ if (s.getVersion() >= 26)
+ s.syncAsUint32LE(obj.playTime);
} else {
- s.syncAsUint16LE(obj.game_object_offset);
- s.syncAsUint16LE(obj.script0_size);
+ obj.playTime = g_engine->getTotalPlayTime() / 1000;
+ s.syncAsUint32LE(obj.playTime);
}
}
void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
Common::String tmp;
- s.syncString(tmp, VER(14), VER(23)); // OBSOLETE: Used to be game_version
+ s.syncString(tmp, VER(14), VER(23)); // OBSOLETE: Used to be gameVersion
if (getSciVersion() <= SCI_VERSION_1_1) {
// Save/Load picPort as well for SCI0-SCI1.1. Necessary for Castle of Dr. Brain,
@@ -352,6 +400,47 @@ void HunkTable::saveLoadWithSerializer(Common::Serializer &s) {
// Do nothing, hunk tables are not actually saved nor loaded.
}
+void Script::syncStringHeap(Common::Serializer &s) {
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ // Sync all if the SCI_OBJ_STRINGS blocks
+ byte *buf = _buf;
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+
+ if (oldScriptHeader)
+ buf += 2;
+
+ do {
+ int blockType = READ_LE_UINT16(buf);
+ int blockSize;
+ if (blockType == 0)
+ break;
+
+ blockSize = READ_LE_UINT16(buf + 2);
+ assert(blockSize > 0);
+
+
+ if (blockType == SCI_OBJ_STRINGS)
+ s.syncBytes(buf, blockSize);
+
+ buf += blockSize;
+
+ if (_buf - buf == 0)
+ break;
+ } while (1);
+
+ } else {
+ // Strings in SCI1.1 come after the object instances
+ byte *buf = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
+
+ // Skip all of the objects
+ while (READ_SCI11ENDIAN_UINT16(buf) == SCRIPT_OBJECT_MAGIC_NUMBER)
+ buf += READ_SCI11ENDIAN_UINT16(buf + 2) * 2;
+
+ // Now, sync everything till the end of the buffer
+ s.syncBytes(buf, _heapSize - (buf - _heapStart));
+ }
+}
+
void Script::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint32LE(_nr);
@@ -520,7 +609,7 @@ void SoundCommandParser::syncPlayList(Common::Serializer &s) {
_music->saveLoadWithSerializer(s);
}
-void SoundCommandParser::reconstructPlayList(int savegame_version) {
+void SoundCommandParser::reconstructPlayList() {
Common::StackLock lock(_music->_mutex);
const MusicList::iterator end = _music->getPlayListEnd();
@@ -595,50 +684,70 @@ void GfxPalette::saveLoadWithSerializer(Common::Serializer &s) {
}
}
-void SegManager::reconstructStack(EngineState *s) {
- DataStack *stack = (DataStack *)(_heap[findSegmentByType(SEG_TYPE_STACK)]);
- s->stack_base = stack->_entries;
- s->stack_top = s->stack_base + stack->_capacity;
-}
-
-// TODO: Move this function to a more appropriate place, such as vm.cpp or script.cpp
-void SegManager::reconstructScripts(EngineState *s) {
- uint i;
-
- for (i = 0; i < _heap.size(); i++) {
- if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
- continue;
-
- Script *scr = (Script *)_heap[i];
- scr->load(g_sci->getResMan());
- scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]);
-
- for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it)
- it->_value._baseObj = scr->getBuf(it->_value.getPos().offset);
- }
-
- for (i = 0; i < _heap.size(); i++) {
- if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
- continue;
-
- Script *scr = (Script *)_heap[i];
-
- for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) {
- reg_t addr = it->_value.getPos();
- Object *obj = scr->scriptObjInit(addr, false);
-
- if (getSciVersion() < SCI_VERSION_1_1) {
- if (!obj->initBaseObject(this, addr, false)) {
- // TODO/FIXME: This should not be happening at all. It might indicate a possible issue
- // with the garbage collector. It happens for example in LSL5 (German, perhaps English too).
- warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
- scr->scriptObjRemove(addr);
+void GfxPorts::saveLoadWithSerializer(Common::Serializer &s) {
+ if (s.isLoading())
+ reset(); // remove all script generated windows
+
+ if (s.getVersion() >= 27) {
+ uint windowCount = 0;
+ uint id = PORTS_FIRSTSCRIPTWINDOWID;
+ if (s.isSaving()) {
+ while (id < _windowsById.size()) {
+ if (_windowsById[id])
+ windowCount++;
+ id++;
+ }
+ }
+ // Save/Restore window count
+ s.syncAsUint32LE(windowCount);
+
+ if (s.isSaving()) {
+ id = PORTS_FIRSTSCRIPTWINDOWID;
+ while (id < _windowsById.size()) {
+ if (_windowsById[id]) {
+ Window *window = (Window *)_windowsById[id];
+ window->saveLoadWithSerializer(s);
}
+ id++;
+ }
+ } else {
+ id = PORTS_FIRSTSCRIPTWINDOWID;
+ while (windowCount) {
+ Window *window = new Window(0);
+ window->saveLoadWithSerializer(s);
+
+ // add enough entries inside _windowsById as needed
+ while (id <= window->id) {
+ _windowsById.push_back(0);
+ id++;
+ }
+ _windowsById[window->id] = window;
+ // _windowList may not be 100% correct using that way of restoring
+ // saving/restoring ports won't work perfectly anyway, because the contents
+ // of the window can only get repainted by the scripts and they dont do that
+ // so we will get empty, transparent windows instead. So perfect window order
+ // shouldn't really matter
+ if (window->counterTillFree) {
+ _freeCounter++;
+ } else {
+ if (window->wndStyle & SCI_WINDOWMGR_STYLE_TOPMOST)
+ _windowList.push_front(window);
+ else
+ _windowList.push_back(window);
+ }
+
+ windowCount--;
}
}
}
}
+void SegManager::reconstructStack(EngineState *s) {
+ DataStack *stack = (DataStack *)(_heap[findSegmentByType(SEG_TYPE_STACK)]);
+ s->stack_base = stack->_entries;
+ s->stack_top = s->stack_base + stack->_capacity;
+}
+
void SegManager::reconstructClones() {
for (uint i = 0; i < _heap.size(); i++) {
SegmentObj *mobj = _heap[i];
@@ -681,15 +790,15 @@ bool gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savenam
g_system->getTimeAndDate(curTime);
SavegameMetadata meta;
- meta.savegame_version = CURRENT_SAVEGAME_VERSION;
- meta.savegame_name = savename;
- meta.game_version = version;
- meta.savegame_date = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
- meta.savegame_time = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
+ meta.version = CURRENT_SAVEGAME_VERSION;
+ meta.name = savename;
+ meta.gameVersion = version;
+ meta.saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
+ meta.saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false);
- meta.script0_size = script0->size;
- meta.game_object_offset = g_sci->getGameObject().offset;
+ meta.script0Size = script0->size;
+ meta.gameObjectOffset = g_sci->getGameObject().offset;
// Checking here again
if (s->executionStackBase) {
@@ -701,6 +810,8 @@ bool gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savenam
sync_SavegameMetadata(ser, meta);
Graphics::saveThumbnail(*fh);
s->saveLoadWithSerializer(ser); // FIXME: Error handling?
+ if (g_sci->_gfxPorts)
+ g_sci->_gfxPorts->saveLoadWithSerializer(ser);
return true;
}
@@ -718,13 +829,13 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
return;
}
- if ((meta.savegame_version < MINIMUM_SAVEGAME_VERSION) ||
- (meta.savegame_version > CURRENT_SAVEGAME_VERSION)) {
+ if ((meta.version < MINIMUM_SAVEGAME_VERSION) ||
+ (meta.version > CURRENT_SAVEGAME_VERSION)) {
/*
- if (meta.savegame_version < MINIMUM_SAVEGAME_VERSION)
+ if (meta.version < MINIMUM_SAVEGAME_VERSION)
warning("Old savegame version detected, unable to load it");
else
- warning("Savegame version is %d, maximum supported is %0d", meta.savegame_version, CURRENT_SAVEGAME_VERSION);
+ warning("Savegame version is %d, maximum supported is %0d", meta.version, CURRENT_SAVEGAME_VERSION);
*/
showScummVMDialog("The format of this saved game is obsolete, unable to load it");
@@ -733,9 +844,9 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
return;
}
- if (meta.game_object_offset > 0 && meta.script0_size > 0) {
+ if (meta.gameObjectOffset > 0 && meta.script0Size > 0) {
Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false);
- if (script0->size != meta.script0_size || g_sci->getGameObject().offset != meta.game_object_offset) {
+ if (script0->size != meta.script0Size || g_sci->getGameObject().offset != meta.gameObjectOffset) {
//warning("This saved game was created with a different version of the game, unable to load it");
showScummVMDialog("This saved game was created with a different version of the game, unable to load it");
@@ -751,23 +862,22 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
s->reset(true);
s->saveLoadWithSerializer(ser); // FIXME: Error handling?
+
// Now copy all current state information
s->_segMan->reconstructStack(s);
- s->_segMan->reconstructScripts(s);
s->_segMan->reconstructClones();
s->initGlobals();
s->gcCountDown = GC_INTERVAL - 1;
// Time state:
s->lastWaitTime = g_system->getMillis();
- s->gameStartTime = g_system->getMillis();
s->_screenUpdateTime = g_system->getMillis();
+ g_engine->setTotalPlayTime(meta.playTime * 1000);
if (g_sci->_gfxPorts)
- g_sci->_gfxPorts->reset();
-
- g_sci->_soundCmd->reconstructPlayList(meta.savegame_version);
+ g_sci->_gfxPorts->saveLoadWithSerializer(ser);
+ g_sci->_soundCmd->reconstructPlayList();
// Message state:
delete s->_msgState;
@@ -789,12 +899,12 @@ bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata
if (stream->eos())
return false;
- if ((meta->savegame_version < MINIMUM_SAVEGAME_VERSION) ||
- (meta->savegame_version > CURRENT_SAVEGAME_VERSION)) {
- if (meta->savegame_version < MINIMUM_SAVEGAME_VERSION)
+ if ((meta->version < MINIMUM_SAVEGAME_VERSION) ||
+ (meta->version > CURRENT_SAVEGAME_VERSION)) {
+ if (meta->version < MINIMUM_SAVEGAME_VERSION)
warning("Old savegame version detected- can't load");
else
- warning("Savegame version is %d- maximum supported is %0d", meta->savegame_version, CURRENT_SAVEGAME_VERSION);
+ warning("Savegame version is %d- maximum supported is %0d", meta->version, CURRENT_SAVEGAME_VERSION);
return false;
}
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index 14eec4aafc..65a65f7cd5 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -36,19 +36,20 @@ namespace Sci {
struct EngineState;
enum {
- CURRENT_SAVEGAME_VERSION = 25,
+ CURRENT_SAVEGAME_VERSION = 28,
MINIMUM_SAVEGAME_VERSION = 14
};
// Savegame metadata
struct SavegameMetadata {
- Common::String savegame_name;
- int savegame_version;
- Common::String game_version;
- int savegame_date;
- int savegame_time;
- uint16 game_object_offset;
- uint16 script0_size;
+ Common::String name;
+ int version;
+ Common::String gameVersion;
+ int saveDate;
+ int saveTime;
+ uint32 playTime;
+ uint16 gameObjectOffset;
+ uint16 script0Size;
};
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index da9ab5106d..e3d43f4fd2 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -152,17 +152,17 @@ void Script::load(ResourceManager *resMan) {
_localsOffset = _scriptSize + 4;
_localsCount = READ_SCI11ENDIAN_UINT16(_buf + _localsOffset - 2);
} else {
- _exportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS);
+ _exportTable = (const uint16 *)findBlockSCI0(SCI_OBJ_EXPORTS);
if (_exportTable) {
_numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
_exportTable += 3; // skip header plus 2 bytes (_exportTable is a uint16 pointer)
}
- _synonyms = findBlock(SCI_OBJ_SYNONYMS);
+ _synonyms = findBlockSCI0(SCI_OBJ_SYNONYMS);
if (_synonyms) {
_numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
_synonyms += 4; // skip header
}
- const byte* localsBlock = findBlock(SCI_OBJ_LOCALVARS);
+ const byte* localsBlock = findBlockSCI0(SCI_OBJ_LOCALVARS);
if (localsBlock) {
_localsOffset = localsBlock - _buf + 4;
_localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1; // half block size
@@ -337,10 +337,10 @@ uint16 Script::validateExportFunc(int pubfunct) {
// in Camelot and script 306 in KQ4). Such offsets are usually small (i.e. < 10),
// thus easily distinguished from actual code offsets.
// This only makes sense for SCI0-SCI1, as the export table in SCI1.1+ games
- // is located at a specific address, thus findBlock() won't work.
+ // is located at a specific address, thus findBlockSCI0() won't work.
// Fixes bugs #3039785 and #3037595.
if (offset < 10 && getSciVersion() <= SCI_VERSION_1_LATE) {
- const uint16 *secondExportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS, 0);
+ const uint16 *secondExportTable = (const uint16 *)findBlockSCI0(SCI_OBJ_EXPORTS, 0);
if (secondExportTable) {
secondExportTable += 3; // skip header plus 2 bytes (secondExportTable is a uint16 pointer)
@@ -352,7 +352,7 @@ uint16 Script::validateExportFunc(int pubfunct) {
return offset;
}
-byte *Script::findBlock(int type, int skipBlockIndex) {
+byte *Script::findBlockSCI0(int type, int startBlockIndex) {
byte *buf = _buf;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
int blockIndex = 0;
@@ -361,16 +361,16 @@ byte *Script::findBlock(int type, int skipBlockIndex) {
buf += 2;
do {
- int seekerType = READ_LE_UINT16(buf);
+ int blockType = READ_LE_UINT16(buf);
- if (seekerType == 0)
+ if (blockType == 0)
break;
- if (seekerType == type && blockIndex != skipBlockIndex)
+ if (blockType == type && blockIndex > startBlockIndex)
return buf;
- int seekerSize = READ_LE_UINT16(buf + 2);
- assert(seekerSize > 0);
- buf += seekerSize;
+ int blockSize = READ_LE_UINT16(buf + 2);
+ assert(blockSize > 0);
+ buf += blockSize;
blockIndex++;
} while (1);
@@ -428,7 +428,7 @@ void Script::initialiseClasses(SegManager *segMan) {
seeker = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
mult = 2;
} else {
- seeker = findBlock(SCI_OBJ_CLASS);
+ seeker = findBlockSCI0(SCI_OBJ_CLASS);
mult = 1;
}
@@ -518,7 +518,7 @@ void Script::initialiseObjectsSci0(SegManager *segMan, SegmentId segmentId) {
seeker += READ_SCI11ENDIAN_UINT16(seeker + 2);
} while ((uint32)(seeker - _buf) < getScriptSize() - 2);
- byte *relocationBlock = findBlock(SCI_OBJ_POINTERS);
+ byte *relocationBlock = findBlockSCI0(SCI_OBJ_POINTERS);
if (relocationBlock)
relocate(make_reg(segmentId, relocationBlock - getBuf() + 4));
}
diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h
index e316fc0c8d..bc263edc8c 100644
--- a/engines/sci/engine/script.h
+++ b/engines/sci/engine/script.h
@@ -238,9 +238,15 @@ public:
void mcpyInOut(int dst, const void *src, size_t n);
/**
- * Finds the pointer where a block of a specific type starts from
+ * Finds the pointer where a block of a specific type starts from,
+ * in SCI0 - SCI1 games
*/
- byte *findBlock(int type, int skipBlockIndex = -1);
+ byte *findBlockSCI0(int type, int startBlockIndex = -1);
+
+ /**
+ * Syncs the string heap of a script. Used when saving/loading.
+ */
+ void syncStringHeap(Common::Serializer &ser);
private:
/**
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 42d7c4d9cd..7654290a5c 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -60,6 +60,8 @@ struct SciScriptSignature {
// - if not EOS, an adjust offset and the actual bytes
// - rinse and repeat
+#if 0
+
// ===========================================================================
// Castle of Dr. Brain
// cipher::init (script 391) is called on room 380 init. This resets the word
@@ -101,10 +103,12 @@ const uint16 castlebrainPatchCipherPuzzle[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature castlebrainSignatures[] = {
- { 391, "cipher puzzle save/restore break", 1, PATCH_MAGICDWORD(0xa3, 0x26, 0xa3, 0x25), -2, castlebrainSignatureCipherPuzzle, castlebrainPatchCipherPuzzle },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 391, "cipher puzzle save/restore break", 1, PATCH_MAGICDWORD(0xa3, 0x26, 0xa3, 0x25), -2, castlebrainSignatureCipherPuzzle, castlebrainPatchCipherPuzzle },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
+#endif
+
// ===========================================================================
// stayAndHelp::changeState (0) is called when ego swims to the left or right
// boundaries of room 660. Normally a textbox is supposed to get on screen
@@ -167,8 +171,8 @@ const uint16 ecoquest1PatchStayAndHelp[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature ecoquest1Signatures[] = {
- { 660, "CD: bad messagebox and freeze", 1, PATCH_MAGICDWORD(0x38, 0x22, 0x01, 0x78), -17, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 660, "CD: bad messagebox and freeze", 1, PATCH_MAGICDWORD(0x38, 0x22, 0x01, 0x78), -17, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -229,8 +233,8 @@ const uint16 ecoquest2PatchEcorder[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature ecoquest2Signatures[] = {
- { 50, "initial text not removed on ecorder", 1, PATCH_MAGICDWORD(0x39, 0x64, 0x39, 0x7d), -8, ecoquest2SignatureEcorder, ecoquest2PatchEcorder },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 50, "initial text not removed on ecorder", 1, PATCH_MAGICDWORD(0x39, 0x64, 0x39, 0x7d), -8, ecoquest2SignatureEcorder, ecoquest2PatchEcorder },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -322,10 +326,10 @@ const uint16 freddypharkasPatchLadderEvent[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature freddypharkasSignatures[] = {
- { 0, "CD: score early disposal", 1, PATCH_MAGICDWORD(0x39, 0x0d, 0x43, 0x75), -3, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal },
- { 235, "CD: cannister pickup hang", 3, PATCH_MAGICDWORD(0x39, 0x07, 0x39, 0x08), -4, freddypharkasSignatureCannisterHang, freddypharkasPatchCannisterHang },
- { 320, "ladder event issue", 2, PATCH_MAGICDWORD(0x6d, 0x76, 0x38, 0xf5), -1, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 0, "CD: score early disposal", 1, PATCH_MAGICDWORD(0x39, 0x0d, 0x43, 0x75), -3, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal },
+ { 235, "CD: cannister pickup hang", 3, PATCH_MAGICDWORD(0x39, 0x07, 0x39, 0x08), -4, freddypharkasSignatureCannisterHang, freddypharkasPatchCannisterHang },
+ { 320, "ladder event issue", 2, PATCH_MAGICDWORD(0x6d, 0x76, 0x38, 0xf5), -1, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -396,75 +400,79 @@ const uint16 gk1PatchDay5PhoneFreeze[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature gk1Signatures[] = {
- { 212, "day 5 phone freeze", 1, PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze },
- { 230, "day 6 police beignet timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet },
- { 230, "day 6 police sleep timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 212, "day 5 phone freeze", 1, PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze },
+ { 230, "day 6 police beignet timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet },
+ { 230, "day 6 police sleep timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
+#if 0
+
// ===========================================================================
// this here gets called on entry and when going out of game windows
// uEvt::port will not get changed after kDisposeWindow but a bit later, so
// we would get an invalid port handle to a kSetPort call. We just patch in
// resetting of the port selector. We destroy the stop/fade code in there,
// it seems it isn't used at all in the game.
-//const byte hoyle4SignaturePortFix[] = {
-// 28,
-// 0x39, 0x09, // pushi 09
-// 0x89, 0x0b, // lsg 0b
-// 0x39, 0x64, // pushi 64
-// 0x38, 0xc8, 0x00, // pushi 00c8
-// 0x38, 0x2c, 0x01, // pushi 012c
-// 0x38, 0x90, 0x01, // pushi 0190
-// 0x38, 0xf4, 0x01, // pushi 01f4
-// 0x38, 0x58, 0x02, // pushi 0258
-// 0x38, 0xbc, 0x02, // pushi 02bc
-// 0x38, 0x20, 0x03, // pushi 0320
-// 0x46, // calle [xxxx] [xxxx] [xx]
-// +5, 43, // [skip 5 bytes]
-// 0x30, 0x27, 0x00, // bnt 0027 -> end of routine
-// 0x87, 0x00, // lap 00
-// 0x30, 0x19, 0x00, // bnt 0019 -> fade out
-// 0x87, 0x01, // lap 01
-// 0x30, 0x14, 0x00, // bnt 0014 -> fade out
-// 0x38, 0xa7, 0x00, // pushi 00a7
-// 0x76, // push0
-// 0x80, 0x29, 0x01, // lag 0129
-// 0x4a, 0x04, // send 04 - call song::stop
-// 0x39, 0x27, // pushi 27
-// 0x78, // push1
-// 0x8f, 0x01, // lsp 01
-// 0x51, 0x54, // class 54
-// 0x4a, 0x06, // send 06 - call PlaySong::play
-// 0x33, 0x09, // jmp 09 -> end of routine
-// 0x38, 0xaa, 0x00, // pushi 00aa
-// 0x76, // push0
-// 0x80, 0x29, 0x01, // lag 0129
-// 0x4a, 0x04, // send 04
-// 0x48, // ret
-// 0
-//};
-
-//const uint16 hoyle4PatchPortFix[] = {
-// PATCH_ADDTOOFFSET | +33,
-// 0x38, 0x31, 0x01, // pushi 0131 (selector curEvent)
-// 0x76, // push0
-// 0x80, 0x50, 0x00, // lag 0050 (global var 80h, "User")
-// 0x4a, 0x04, // send 04 - read User::curEvent
-//
-// 0x38, 0x93, 0x00, // pushi 0093 (selector port)
-// 0x78, // push1
-// 0x76, // push0
-// 0x4a, 0x06, // send 06 - write 0 to that object::port
-// 0x48, // ret
-// PATCH_END
-//};
+const byte hoyle4SignaturePortFix[] = {
+ 28,
+ 0x39, 0x09, // pushi 09
+ 0x89, 0x0b, // lsg 0b
+ 0x39, 0x64, // pushi 64
+ 0x38, 0xc8, 0x00, // pushi 00c8
+ 0x38, 0x2c, 0x01, // pushi 012c
+ 0x38, 0x90, 0x01, // pushi 0190
+ 0x38, 0xf4, 0x01, // pushi 01f4
+ 0x38, 0x58, 0x02, // pushi 0258
+ 0x38, 0xbc, 0x02, // pushi 02bc
+ 0x38, 0x20, 0x03, // pushi 0320
+ 0x46, // calle [xxxx] [xxxx] [xx]
+ +5, 43, // [skip 5 bytes]
+ 0x30, 0x27, 0x00, // bnt 0027 -> end of routine
+ 0x87, 0x00, // lap 00
+ 0x30, 0x19, 0x00, // bnt 0019 -> fade out
+ 0x87, 0x01, // lap 01
+ 0x30, 0x14, 0x00, // bnt 0014 -> fade out
+ 0x38, 0xa7, 0x00, // pushi 00a7
+ 0x76, // push0
+ 0x80, 0x29, 0x01, // lag 0129
+ 0x4a, 0x04, // send 04 - call song::stop
+ 0x39, 0x27, // pushi 27
+ 0x78, // push1
+ 0x8f, 0x01, // lsp 01
+ 0x51, 0x54, // class 54
+ 0x4a, 0x06, // send 06 - call PlaySong::play
+ 0x33, 0x09, // jmp 09 -> end of routine
+ 0x38, 0xaa, 0x00, // pushi 00aa
+ 0x76, // push0
+ 0x80, 0x29, 0x01, // lag 0129
+ 0x4a, 0x04, // send 04
+ 0x48, // ret
+ 0
+};
+
+const uint16 hoyle4PatchPortFix[] = {
+ PATCH_ADDTOOFFSET | +33,
+ 0x38, 0x31, 0x01, // pushi 0131 (selector curEvent)
+ 0x76, // push0
+ 0x80, 0x50, 0x00, // lag 0050 (global var 80h, "User")
+ 0x4a, 0x04, // send 04 - read User::curEvent
+
+ 0x38, 0x93, 0x00, // pushi 0093 (selector port)
+ 0x78, // push1
+ 0x76, // push0
+ 0x4a, 0x06, // send 06 - write 0 to that object::port
+ 0x48, // ret
+ PATCH_END
+};
// script, description, magic DWORD, adjust
-//const SciScriptSignature hoyle4Signatures[] = {
-// { 0, "port fix when disposing windows", PATCH_MAGICDWORD(0x64, 0x38, 0xC8, 0x00), -5, hoyle4SignaturePortFix, hoyle4PatchPortFix },
-// { 0, NULL, 0, 0, NULL, NULL }
-//};
+const SciScriptSignature hoyle4Signatures[] = {
+ { 0, "port fix when disposing windows", PATCH_MAGICDWORD(0x64, 0x38, 0xC8, 0x00), -5, hoyle4SignaturePortFix, hoyle4PatchPortFix },
+ { 0, NULL, 0, 0, NULL, NULL }
+};
+
+#endif
// ===========================================================================
// at least during harpy scene export 29 of script 0 is called in kq5cd and
@@ -518,8 +526,8 @@ const uint16 kq5PatchCdHarpyVolume[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature kq5Signatures[] = {
- { 0, "CD: harpy volume change", 1, PATCH_MAGICDWORD(0x80, 0x91, 0x01, 0x18), 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 0, "CD: harpy volume change", 1, PATCH_MAGICDWORD(0x80, 0x91, 0x01, 0x18), 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -569,8 +577,8 @@ const uint16 larry6PatchDeathDialog[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature larry6Signatures[] = {
- { 82, "death dialog memory corruption", 1, PATCH_MAGICDWORD(0x3e, 0x33, 0x01, 0x35), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 82, "death dialog memory corruption", 1, PATCH_MAGICDWORD(0x3e, 0x33, 0x01, 0x35), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -600,8 +608,8 @@ const uint16 laurabow2PatchPaintingClosing[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature laurabow2Signatures[] = {
- { 560, "painting closing immediately", 1, PATCH_MAGICDWORD(0x36, 0x81, 0x0b, 0x1c), -2, laurabow2SignaturePaintingClosing, laurabow2PatchPaintingClosing },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 560, "painting closing immediately", 1, PATCH_MAGICDWORD(0x36, 0x81, 0x0b, 0x1c), -2, laurabow2SignaturePaintingClosing, laurabow2PatchPaintingClosing },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -642,10 +650,10 @@ const uint16 mothergoose256PatchSaveLimit[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature mothergoose256Signatures[] = {
- { 0, "replay save issue", 1, PATCH_MAGICDWORD(0x20, 0x04, 0xa1, 0xb3), -2, mothergoose256SignatureReplay, mothergoose256PatchReplay },
- { 0, "save limit dialog (SCI1.1)", 1, PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit },
- { 994, "save limit dialog (SCI1)", 1, PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 0, "replay save issue", 1, PATCH_MAGICDWORD(0x20, 0x04, 0xa1, 0xb3), -2, mothergoose256SignatureReplay, mothergoose256PatchReplay },
+ { 0, "save limit dialog (SCI1.1)", 1, PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit },
+ { 994, "save limit dialog (SCI1)", 1, PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -699,9 +707,9 @@ const uint16 qfg1vgaPatchFightEvents[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature qfg1vgaSignatures[] = {
- { 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
- { 216, "weapon master event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
+ { 216, "weapon master event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -729,8 +737,8 @@ const uint16 sq4FloppyPatchEndlessFlight[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature sq4Signatures[] = {
- { 298, "Floppy: endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x44), -3, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 298, "Floppy: endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x44), -3, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
@@ -777,8 +785,8 @@ const uint16 sq5PatchScrubbing[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature sq5Signatures[] = {
- { 119, "scrubbing send crash", 1, PATCH_MAGICDWORD(0x18, 0x31, 0x37, 0x78), 0, sq5SignatureScrubbing, sq5PatchScrubbing },
- SCI_SIGNATUREENTRY_TERMINATOR
+ { 119, "scrubbing send crash", 1, PATCH_MAGICDWORD(0x18, 0x31, 0x37, 0x78), 0, sq5SignatureScrubbing, sq5PatchScrubbing },
+ SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -874,9 +882,12 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr
void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
const SciScriptSignature *signatureTable = NULL;
switch (g_sci->getGameId()) {
+ // Dr. Brain now works because we properly maintain the state of the string heap in savegames
+#if 0
case GID_CASTLEBRAIN:
signatureTable = castlebrainSignatures;
break;
+#endif
case GID_ECOQUEST:
signatureTable = ecoquest1Signatures;
break;
@@ -890,9 +901,11 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin
signatureTable = gk1Signatures;
break;
// hoyle4 now works due to workaround inside GfxPorts
- //case GID_HOYLE4:
- // signatureTable = hoyle4Signatures;
- // break;
+#if 0
+ case GID_HOYLE4:
+ signatureTable = hoyle4Signatures;
+ break;
+#endif
case GID_KQ5:
signatureTable = kq5Signatures;
break;
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 9c08526fbb..d587db26b4 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -95,7 +95,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
opsize &= 1; // byte if true, word if false
- printf("%04x:%04x: ", PRINT_REG(pos));
+ debugN("%04x:%04x: ", PRINT_REG(pos));
if (print_bytecode) {
if (pos.offset + bytecount > scr_size) {
@@ -104,16 +104,16 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
}
for (i = 0; i < bytecount; i++)
- printf("%02x ", scr[pos.offset + i]);
+ debugN("%02x ", scr[pos.offset + i]);
for (i = bytecount; i < 5; i++)
- printf(" ");
+ debugN(" ");
}
if (print_bw_tag)
- printf("[%c] ", opsize ? 'B' : 'W');
+ debugN("[%c] ", opsize ? 'B' : 'W');
- printf("%s", opcodeNames[opcode]);
+ debugN("%s", opcodeNames[opcode]);
i = 0;
while (g_opcode_formats[opcode][i]) {
@@ -124,12 +124,12 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
case Script_SByte:
case Script_Byte:
- printf(" %02x", scr[retval.offset++]);
+ debugN(" %02x", scr[retval.offset++]);
break;
case Script_Word:
case Script_SWord:
- printf(" %04x", READ_SCI11ENDIAN_UINT16(&scr[retval.offset]));
+ debugN(" %04x", READ_SCI11ENDIAN_UINT16(&scr[retval.offset]));
retval.offset += 2;
break;
@@ -148,11 +148,11 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
}
if (opcode == op_callk)
- printf(" %s[%x]", (param_value < kernel->_kernelFuncs.size()) ?
+ debugN(" %s[%x]", (param_value < kernel->_kernelFuncs.size()) ?
((param_value < kernel->getKernelNamesSize()) ? kernel->getKernelName(param_value).c_str() : "[Unknown(postulated)]")
: "<invalid>", param_value);
else
- printf(opsize ? " %02x" : " %04x", param_value);
+ debugN(opsize ? " %02x" : " %04x", param_value);
break;
@@ -163,7 +163,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.offset]);
retval.offset += 2;
}
- printf(opsize ? " %02x" : " %04x", param_value);
+ debugN(opsize ? " %02x" : " %04x", param_value);
break;
case Script_SRelative:
@@ -173,7 +173,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.offset]);
retval.offset += 2;
}
- printf(opsize ? " %02x [%04x]" : " %04x [%04x]", param_value, (0xffff) & (retval.offset + param_value));
+ debugN(opsize ? " %02x [%04x]" : " %04x [%04x]", param_value, (0xffff) & (retval.offset + param_value));
break;
case Script_End:
@@ -193,11 +193,11 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
if (!obj)
warning("Attempted to reference on non-object at %04x:%04x", PRINT_REG(s->xs->objp));
else
- printf(" (%s)", g_sci->getKernel()->getSelectorName(obj->propertyOffsetToId(s->_segMan, scr[pos.offset + 1])).c_str());
+ debugN(" (%s)", g_sci->getKernel()->getSelectorName(obj->propertyOffsetToId(s->_segMan, scr[pos.offset + 1])).c_str());
}
}
- printf("\n");
+ debugN("\n");
if (pos == s->xs->addr.pc) { // Extra information if debugging the current opcode
if (opcode == op_callk) {
@@ -208,14 +208,14 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
if (!oldScriptHeader)
argc += (s->restAdjust);
- printf(" Kernel params: (");
+ debugN(" Kernel params: (");
for (int j = 0; j < argc; j++) {
- printf("%04x:%04x", PRINT_REG((s->xs->sp)[j - stackframe]));
+ debugN("%04x:%04x", PRINT_REG((s->xs->sp)[j - stackframe]));
if (j + 1 < argc)
- printf(", ");
+ debugN(", ");
}
- printf(")\n");
+ debugN(")\n");
} else if ((opcode == op_send) || (opcode == op_self)) {
int restmod = s->restAdjust;
int stackframe = (scr[pos.offset + 1] >> 1) + restmod;
@@ -240,32 +240,32 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
if (!name)
name = "<invalid>";
- printf(" %s::%s[", name, g_sci->getKernel()->getSelectorName(selector).c_str());
+ debugN(" %s::%s[", name, g_sci->getKernel()->getSelectorName(selector).c_str());
switch (lookupSelector(s->_segMan, called_obj_addr, selector, 0, &fun_ref)) {
case kSelectorMethod:
- printf("FUNCT");
+ debugN("FUNCT");
argc += restmod;
restmod = 0;
break;
case kSelectorVariable:
- printf("VAR");
+ debugN("VAR");
break;
case kSelectorNone:
- printf("INVALID");
+ debugN("INVALID");
break;
}
- printf("](");
+ debugN("](");
while (argc--) {
- printf("%04x:%04x", PRINT_REG(sb[- stackframe + 2]));
+ debugN("%04x:%04x", PRINT_REG(sb[- stackframe + 2]));
if (argc)
- printf(", ");
+ debugN(", ");
stackframe--;
}
- printf(")\n");
+ debugN(")\n");
stackframe -= 2;
} // while (stackframe > 0)
} // Send-like opcodes
@@ -334,7 +334,7 @@ void SciEngine::scriptDebug() {
// OK, found whatever we were looking for
}
- printf("Step #%d\n", s->scriptStepCounter);
+ debugN("Step #%d\n", s->scriptStepCounter);
disassemble(s, s->xs->addr.pc, 0, 1);
if (_debugState.runningStep) {
@@ -354,27 +354,27 @@ void Kernel::dumpScriptObject(char *data, int seeker, int objsize) {
int namepos = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 14 + seeker);
int i = 0;
- printf("Object\n");
+ debugN("Object\n");
Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
//-4 because the size includes the two-word header
- printf("Name: %s\n", namepos ? ((char *)(data + namepos)) : "<unknown>");
- printf("Superclass: %x\n", superclass);
- printf("Species: %x\n", species);
- printf("-info-:%x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 12 + seeker) & 0xffff);
+ debugN("Name: %s\n", namepos ? ((char *)(data + namepos)) : "<unknown>");
+ debugN("Superclass: %x\n", superclass);
+ debugN("Species: %x\n", species);
+ debugN("-info-:%x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 12 + seeker) & 0xffff);
- printf("Function area offset: %x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + seeker + 4));
- printf("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + seeker + 6)));
+ debugN("Function area offset: %x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + seeker + 4));
+ debugN("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + seeker + 6)));
seeker += 8;
while (selectors--) {
- printf(" [#%03x] = 0x%x\n", i++, (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker) & 0xffff);
+ debugN(" [#%03x] = 0x%x\n", i++, (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker) & 0xffff);
seeker += 2;
}
- printf("Overridden functions: %x\n", selectors = overloads = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker));
+ debugN("Overridden functions: %x\n", selectors = overloads = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker));
seeker += 2;
@@ -382,8 +382,8 @@ void Kernel::dumpScriptObject(char *data, int seeker, int objsize) {
while (overloads--) {
int selector = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + (seeker));
- printf(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>");
- printf("%04x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + selectors*2 + 2) & 0xffff);
+ debugN(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>");
+ debugN("%04x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + selectors*2 + 2) & 0xffff);
seeker += 2;
}
@@ -395,17 +395,17 @@ void Kernel::dumpScriptClass(char *data, int seeker, int objsize) {
int superclass = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 10 + seeker);
int namepos = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 14 + seeker);
- printf("Class\n");
+ debugN("Class\n");
Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
- printf("Name: %s\n", namepos ? ((char *)data + namepos) : "<unknown>");
- printf("Superclass: %x\n", superclass);
- printf("Species: %x\n", species);
- printf("-info-:%x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + 12 + seeker) & 0xffff);
+ debugN("Name: %s\n", namepos ? ((char *)data + namepos) : "<unknown>");
+ debugN("Superclass: %x\n", superclass);
+ debugN("Species: %x\n", species);
+ debugN("-info-:%x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + 12 + seeker) & 0xffff);
- printf("Function area offset: %x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + 4));
- printf("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + 6)));
+ debugN("Function area offset: %x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + 4));
+ debugN("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + 6)));
seeker += 8;
selectorsize <<= 1;
@@ -413,7 +413,7 @@ void Kernel::dumpScriptClass(char *data, int seeker, int objsize) {
while (selectors--) {
int selector = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + (seeker) + selectorsize);
- printf(" [%03x] %s = 0x%x\n", 0xffff & selector, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>",
+ debugN(" [%03x] %s = 0x%x\n", 0xffff & selector, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>",
(int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker) & 0xffff);
seeker += 2;
@@ -421,16 +421,16 @@ void Kernel::dumpScriptClass(char *data, int seeker, int objsize) {
seeker += selectorsize;
- printf("Overloaded functions: %x\n", selectors = overloads = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker));
+ debugN("Overloaded functions: %x\n", selectors = overloads = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker));
seeker += 2;
while (overloads--) {
int selector = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + (seeker));
- fprintf(stderr, "selector=%d; selectorNames.size() =%d\n", selector, _selectorNames.size());
- printf(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)_selectorNames.size()) ?
+ debugN("selector=%d; selectorNames.size() =%d\n", selector, _selectorNames.size());
+ debugN(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)_selectorNames.size()) ?
_selectorNames[selector].c_str() : "<?>");
- printf("%04x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + selectors * 2 + 2) & 0xffff);
+ debugN("%04x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + selectors * 2 + 2) & 0xffff);
seeker += 2;
}
@@ -452,17 +452,17 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
unsigned int seeker = _seeker + 4;
if (!objType) {
- printf("End of script object (#0) encountered.\n");
- printf("Classes: %i, Objects: %i, Export: %i,\n Var: %i (all base 10)",
+ debugN("End of script object (#0) encountered.\n");
+ debugN("Classes: %i, Objects: %i, Export: %i,\n Var: %i (all base 10)",
objectctr[6], objectctr[1], objectctr[7], objectctr[10]);
return;
}
- printf("\n");
+ debugN("\n");
objsize = (int16)READ_SCI11ENDIAN_UINT16(script->data + _seeker + 2);
- printf("Obj type #%x, size 0x%x: ", objType, objsize);
+ debugN("Obj type #%x, size 0x%x: ", objType, objsize);
_seeker += objsize;
@@ -474,28 +474,28 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
break;
case SCI_OBJ_CODE:
- printf("Code\n");
+ debugN("Code\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
break;
case 3:
- printf("<unknown>\n");
+ debugN("<unknown>\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
break;
case SCI_OBJ_SAID:
- printf("Said\n");
+ debugN("Said\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
- printf("%04x: ", seeker);
+ debugN("%04x: ", seeker);
vocab->debugDecipherSaidBlock(script->data + seeker);
- printf("\n");
+ debugN("\n");
break;
case SCI_OBJ_STRINGS:
- printf("Strings\n");
+ debugN("Strings\n");
while (script->data [seeker]) {
- printf("%04x: %s\n", seeker, script->data + seeker);
+ debugN("%04x: %s\n", seeker, script->data + seeker);
seeker += strlen((char *)script->data + seeker) + 1;
}
seeker++; // the ending zero byte
@@ -506,33 +506,33 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
break;
case SCI_OBJ_EXPORTS:
- printf("Exports\n");
+ debugN("Exports\n");
Common::hexdump((unsigned char *)script->data + seeker, objsize - 4, 16, seeker);
break;
case SCI_OBJ_POINTERS:
- printf("Pointers\n");
+ debugN("Pointers\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
break;
case 9:
- printf("<unknown>\n");
+ debugN("<unknown>\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
break;
case SCI_OBJ_LOCALVARS:
- printf("Local vars\n");
+ debugN("Local vars\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
break;
default:
- printf("Unsupported!\n");
+ debugN("Unsupported!\n");
return;
}
}
- printf("Script ends without terminator\n");
+ debugN("Script ends without terminator\n");
}
} // End of namespace Sci
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 1cbe9a56f4..d509046a15 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -301,9 +301,9 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) {
return NULL_REG;
if (result.size() > 1 && index < 0) {
- printf("Ambiguous:\n");
+ debug("findObjectByName(%s): multiple matches:", name.c_str());
for (i = 0; i < result.size(); i++)
- printf(" %3x: [%04x:%04x] %s\n", i, PRINT_REG(result[i]), name.c_str());
+ debug(" %3x: [%04x:%04x]", i, PRINT_REG(result[i]));
return NULL_REG; // Ambiguous
}
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 59ac6f39b6..55dd39d89b 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -92,11 +92,6 @@ public:
void deallocateScript(int script_nr);
/**
- * Reconstructs scripts. Used when restoring saved games
- */
- void reconstructScripts(EngineState *s);
-
- /**
* Reconstructs the stack. Used when restoring saved games
*/
void reconstructStack(EngineState *s);
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index b16dd5a5e5..8ae063c629 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -318,10 +318,8 @@ reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) const {
Common::Array<reg_t> DataStack::listAllOutgoingReferences(reg_t object) const {
Common::Array<reg_t> tmp;
- fprintf(stderr, "Emitting %d stack entries\n", _capacity);
for (int i = 0; i < _capacity; i++)
tmp.push_back(_entries[i]);
- fprintf(stderr, "DONE");
return tmp;
}
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 6eca708e2e..a2fe61729a 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -246,7 +246,7 @@ public:
reg_t getInfoSelector() const { return _variables[_offset + 2]; }
void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; }
- reg_t getNameSelector() const { return _variables[_offset + 3]; }
+ reg_t getNameSelector() const { return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG; }
void setNameSelector(reg_t value) { _variables[_offset + 3] = value; }
reg_t getPropDictSelector() const { return _variables[2]; }
@@ -318,13 +318,10 @@ public:
void initSpecies(SegManager *segMan, reg_t addr);
void initSuperClass(SegManager *segMan, reg_t addr);
bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true);
-
- // TODO: make private
- // Only SegManager::reconstructScripts() is left needing direct access to these
-public:
- const byte *_baseObj; /**< base + object offset within base */
+ void syncBaseObject(const byte *ptr) { _baseObj = ptr; }
private:
+ const byte *_baseObj; /**< base + object offset within base */
const uint16 *_baseVars; /**< Pointer to the varselector area for this object */
const uint16 *_baseMethod; /**< Pointer to the method selector area for this object */
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index b31f52aa13..798dbf529c 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -40,10 +40,10 @@ namespace Sci {
// The defines below can be used to construct static selector tables for games which don't have
// a vocab.997 resource, by dumping the selector table from other similar versions or games
#define FIND_SELECTOR(_slc_) _selectorCache._slc_ = findSelector(#_slc_); \
- printf("\t{ \"%s\", %d },\n", #_slc_, _selectorCache._slc_)
+ debugN("\t{ \"%s\", %d },\n", #_slc_, _selectorCache._slc_)
#define FIND_SELECTOR2(_slc_, _slcstr_) _selectorCache._slc_ = findSelector(_slcstr_); \
- printf("\t{ \"%s\", %d },\n", _slcstr_, _selectorCache._slc_)
+ debugN("\t{ \"%s\", %d },\n", _slcstr_, _selectorCache._slc_)
#endif
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index d0ddd5ca06..e5c9334315 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -125,7 +125,6 @@ public:
/* Non-VM information */
- uint32 gameStartTime; /**< The time at which the interpreter was started */
uint32 lastWaitTime; /**< The last time the game invoked Wait() */
uint32 _screenUpdateTime; /**< The last time the game updated the screen */
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 7342f8ca7b..cefb228c13 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -144,13 +144,13 @@ static bool validate_variable(reg_t *r, reg_t *stack_base, int type, int max, in
const char *names[4] = {"global", "local", "temp", "param"};
if (index < 0 || index >= max) {
- Common::String txt = Common::String::printf(
+ Common::String txt = Common::String::format(
"[VM] Attempt to use invalid %s variable %04x ",
names[type], index);
if (max == 0)
txt += "(variable type invalid)";
else
- txt += Common::String::printf("(out of range [%d..%d])", 0, max - 1);
+ txt += Common::String::format("(out of range [%d..%d])", 0, max - 1);
if (type == VAR_PARAM || type == VAR_TEMP) {
int total_offset = r - stack_base;
@@ -423,7 +423,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
}
#ifdef VM_DEBUG_SEND
- printf("Send to %04x:%04x (%s), selector %04x (%s):", PRINT_REG(send_obj),
+ debugN("Send to %04x:%04x (%s), selector %04x (%s):", PRINT_REG(send_obj),
s->_segMan->getObjectName(send_obj), selector,
g_sci->getKernel()->getSelectorName(selector).c_str());
#endif // VM_DEBUG_SEND
@@ -438,9 +438,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#ifdef VM_DEBUG_SEND
if (argc)
- printf("Varselector: Write %04x:%04x\n", PRINT_REG(argp[1]));
+ debugN("Varselector: Write %04x:%04x\n", PRINT_REG(argp[1]));
else
- printf("Varselector: Read\n");
+ debugN("Varselector: Read\n");
#endif // VM_DEBUG_SEND
// argc == 0: read selector
@@ -496,39 +496,39 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#ifndef VM_DEBUG_SEND
if (activeBreakpointTypes & BREAK_SELECTOREXEC) {
if (g_sci->checkSelectorBreakpoint(BREAK_SELECTOREXEC, send_obj, selector)) {
- printf("[execute selector]");
+ debugN("[execute selector]");
int displaySize = 0;
for (int argNr = 1; argNr <= argc; argNr++) {
if (argNr == 1)
- printf(" - ");
+ debugN(" - ");
reg_t curParam = argp[argNr];
if (curParam.segment) {
- printf("[%04x:%04x] ", PRINT_REG(curParam));
+ debugN("[%04x:%04x] ", PRINT_REG(curParam));
displaySize += 12;
} else {
- printf("[%04x] ", curParam.offset);
+ debugN("[%04x] ", curParam.offset);
displaySize += 7;
}
if (displaySize > 50) {
if (argNr < argc)
- printf("...");
+ debugN("...");
break;
}
}
- printf("\n");
+ debugN("\n");
}
}
#else // VM_DEBUG_SEND
if (activeBreakpointTypes & BREAK_SELECTOREXEC)
g_sci->checkSelectorBreakpoint(BREAK_SELECTOREXEC, send_obj, selector);
- printf("Funcselector(");
+ debugN("Funcselector(");
for (int i = 0; i < argc; i++) {
- printf("%04x:%04x", PRINT_REG(argp[i+1]));
+ debugN("%04x:%04x", PRINT_REG(argp[i+1]));
if (i + 1 < argc)
- printf(", ");
+ debugN(", ");
}
- printf(") at %04x:%04x\n", PRINT_REG(funcp));
+ debugN(") at %04x:%04x\n", PRINT_REG(funcp));
#endif // VM_DEBUG_SEND
{
@@ -583,7 +583,7 @@ static ExecStack *add_exec_stack_entry(Common::List<ExecStack> &execStack, reg_t
// Returns new TOS element for the execution stack
// _localsSegment may be -1 if derived from the called object
- //printf("Exec stack: [%d/%d], origin %d, at %p\n", s->execution_stack_pos, s->_executionStack.size(), origin, s->execution_stack);
+ //debug("Exec stack: [%d/%d], origin %d, at %p", s->execution_stack_pos, s->_executionStack.size(), origin, s->execution_stack);
ExecStack xstack;
@@ -655,46 +655,46 @@ static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int argc,
static void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *kernelSubCall, EngineState *s, int argc, reg_t *argv, reg_t result) {
Kernel *kernel = g_sci->getKernel();
if (!kernelSubCall) {
- printf("k%s: ", kernelCall->name);
+ debugN("k%s: ", kernelCall->name);
} else {
int callNameLen = strlen(kernelCall->name);
if (strncmp(kernelCall->name, kernelSubCall->name, callNameLen) == 0) {
const char *subCallName = kernelSubCall->name + callNameLen;
- printf("k%s(%s): ", kernelCall->name, subCallName);
+ debugN("k%s(%s): ", kernelCall->name, subCallName);
} else {
- printf("k%s(%s): ", kernelCall->name, kernelSubCall->name);
+ debugN("k%s(%s): ", kernelCall->name, kernelSubCall->name);
}
}
for (int parmNr = 0; parmNr < argc; parmNr++) {
if (parmNr)
- printf(", ");
+ debugN(", ");
uint16 regType = kernel->findRegType(argv[parmNr]);
if (regType & SIG_TYPE_NULL)
- printf("0");
+ debugN("0");
else if (regType & SIG_TYPE_UNINITIALIZED)
- printf("UNINIT");
+ debugN("UNINIT");
else if (regType & SIG_IS_INVALID)
- printf("INVALID");
+ debugN("INVALID");
else if (regType & SIG_TYPE_INTEGER)
- printf("%d", argv[parmNr].offset);
+ debugN("%d", argv[parmNr].offset);
else {
- printf("%04x:%04x", PRINT_REG(argv[parmNr]));
+ debugN("%04x:%04x", PRINT_REG(argv[parmNr]));
switch (regType) {
case SIG_TYPE_OBJECT:
- printf(" (%s)", s->_segMan->getObjectName(argv[parmNr]));
+ debugN(" (%s)", s->_segMan->getObjectName(argv[parmNr]));
break;
case SIG_TYPE_REFERENCE:
if (kernelCall->function == kSaid) {
SegmentRef saidSpec = s->_segMan->dereference(argv[parmNr]);
if (saidSpec.isRaw) {
- printf(" ('");
+ debugN(" ('");
g_sci->getVocabulary()->debugDecipherSaidBlock(saidSpec.raw);
- printf("')");
+ debugN("')");
} else {
- printf(" (non-raw said-spec)");
+ debugN(" (non-raw said-spec)");
}
} else {
- printf(" ('%s')", s->_segMan->getString(argv[parmNr]).c_str());
+ debugN(" ('%s')", s->_segMan->getString(argv[parmNr]).c_str());
}
default:
break;
@@ -702,9 +702,9 @@ static void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunct
}
}
if (result.segment)
- printf(" = %04x:%04x\n", PRINT_REG(result));
+ debugN(" = %04x:%04x\n", PRINT_REG(result));
else
- printf(" = %d\n", result.offset);
+ debugN(" = %d\n", result.offset);
}
static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
@@ -749,7 +749,7 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
if (kernelCall.debugLogging)
logKernelCall(&kernelCall, NULL, s, argc, argv, s->r_acc);
if (kernelCall.debugBreakpoint) {
- printf("Break on k%s\n", kernelCall.name);
+ debugN("Break on k%s\n", kernelCall.name);
g_sci->_debugState.debugging = true;
g_sci->_debugState.breakpointWasHit = true;
}
@@ -804,7 +804,7 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
if (kernelSubCall.debugLogging)
logKernelCall(&kernelCall, &kernelSubCall, s, argc, argv, s->r_acc);
if (kernelSubCall.debugBreakpoint) {
- printf("Break on k%s\n", kernelSubCall.name);
+ debugN("Break on k%s\n", kernelSubCall.name);
g_sci->_debugState.debugging = true;
g_sci->_debugState.breakpointWasHit = true;
}
@@ -830,7 +830,7 @@ int readPMachineInstruction(const byte *src, byte &extOpcode, int16 opparams[4])
memset(opparams, 0, sizeof(opparams));
for (int i = 0; g_opcode_formats[opcode][i]; ++i) {
- //printf("Opcode: 0x%x, Opnumber: 0x%x, temp: %d\n", opcode, opcode, temp);
+ //debugN("Opcode: 0x%x, Opnumber: 0x%x, temp: %d\n", opcode, opcode, temp);
assert(i < 3);
switch (g_opcode_formats[opcode][i]) {
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index d332c64a9d..b4bcdaa0ca 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -119,6 +119,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_HOYLE1, 3, 16, 0, "", "export 0", 0x37c, 3, { WORKAROUND_FAKE, 0 } }, // Hearts / during the game - bug #3052359
{ GID_HOYLE3, -1, 0, 1, "Character", "say", -1, -1, { WORKAROUND_FAKE, 0 } }, // when starting checkers or dominoes, first time a character says something - temps 504 and 505
{ GID_HOYLE3, -1, 700, 0, "gcWindow", "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu
+ { GID_HOYLE3, 100, 100, 0, "dominoHand2", "cue", -1, 1, { WORKAROUND_FAKE, 0 } }, // while playing domino - bug #3036918
{ GID_HOYLE4, -1, 0, 0, "gcWindow", "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when selecting "Control" from the menu (temp vars 0-3) - bug #3039294
{ GID_HOYLE4, 910, 18, 0, "Tray", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // during tutorial - bug #3042756
{ GID_HOYLE4, 910, 910, 0, "IconBarList", "setup", -1, 3, { WORKAROUND_FAKE, 0 } }, // when selecting "Tutorial" from the main menu - bug #3039294
@@ -337,6 +338,7 @@ const SciWorkaroundEntry kGraphRedrawBox_workarounds[] = {
{ GID_SQ4, 406, 406, 0, "swimAndShoot", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified
{ GID_SQ4, 410, 410, 0, "swimAfterEgo", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified
{ GID_SQ4, 411, 411, 0, "swimAndShoot", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified
+ { GID_SQ4, 150, 150, 0, "laserScript", "changeState", 0xb2, 0, { WORKAROUND_STILLCALL, 0 } }, // when visiting the pedestral where Roger Jr. is trapped, before trashing the brain icon in the programming chapter, accidental additional parameter specified - bug #3094235
{ GID_SQ4, -1, 704, 0, "shootEgo", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // When shot by Droid in Super Computer Maze (Rooms 500, 505, 510...) - accidental additional parameter specified
{ GID_KQ5, -1, 981, 0, "myWindow", "dispose", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // Happens in the floppy version, when closing any dialog box, accidental additional parameter specified - bug #3036331
{ GID_KQ5, -1, 995, 0, "invW", "doit", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // Happens in the floppy version, when closing the inventory window, accidental additional parameter specified
@@ -404,12 +406,19 @@ const SciWorkaroundEntry kStrCat_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
+const SciWorkaroundEntry kStrLen_workarounds[] = {
+ { GID_QFG2, 210, 2, 0, "", "export 21", 0xdeb, 0, { WORKAROUND_FAKE, 0 } }, // When saying something incorrect at the WIT, an integer is passed instead of a reference - bug #3100292
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kUnLoad_workarounds[] = {
{ GID_CAMELOT, 921, 921, 1, "Script", "changeState", 0x36, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: While showing Camelot (and other places), the reference is invalid - bug #3035000
{ GID_CAMELOT, 921, 921, 1, "Script", "init", 0x36, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: When being attacked by the boar (and other places), the reference is invalid - bug #3035000
{ GID_CASTLEBRAIN, 320, 377, 0, "SWord", "upDate", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after solving the cross-word-puzzle, trying to unload invalid reference
{ GID_CASTLEBRAIN, 320, 377, 0, "theWord", "show", -1, 0, { WORKAROUND_IGNORE, 0 } }, // 2nd word puzzle, when exiting before solving, trying to unload invalid reference - bug #3034473
{ GID_ECOQUEST, 380, 61, 0, "gotIt", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after talking to the dolphin the first time
+ { GID_ECOQUEST, 380, 69, 0, "lookAtBlackBoard", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // German version, when closing the blackboard closeup in the dolphin room - bug #3098353
{ GID_LAURABOW2, 1, 1, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902
{ GID_LAURABOW2, 2, 2, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902
{ GID_LAURABOW2, 4, 4, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: inside the museum, a 3rd parameter is passed by accident - bug #3034902
@@ -454,7 +463,7 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun
curMethodName = g_sci->getKernel()->getSelectorName(lastCall->debugSelector);
} else if (lastCall->debugExportId != -1) {
curObjectName = "";
- curMethodName = curMethodName.printf("export %d", lastCall->debugExportId);
+ curMethodName = Common::String::format("export %d", lastCall->debugExportId);
}
}
@@ -471,8 +480,9 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun
&& ((workaround->scriptNr == -1) || (workaround->scriptNr == curScriptNr))
&& ((workaround->roomNr == -1) || (workaround->roomNr == curRoomNumber))
&& ((workaround->inheritanceLevel == -1) || (workaround->inheritanceLevel == inheritanceLevel))
- && ((workaround->objectName == NULL) || (workaround->objectName == searchObjectName))
- && workaround->methodName == curMethodName && workaround->localCallOffset == lastCall->debugLocalCallOffset
+ && ((workaround->objectName == NULL) || (workaround->objectName == g_sci->getSciLanguageString(searchObjectName.c_str(), K_LANG_ENGLISH)))
+ && workaround->methodName == g_sci->getSciLanguageString(curMethodName.c_str(), K_LANG_ENGLISH)
+ && workaround->localCallOffset == lastCall->debugLocalCallOffset
&& ((workaround->index == -1) || (workaround->index == index))) {
// Workaround found
return workaround->newValue;
diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h
index bf1ac3a445..7d68d9c4a5 100644
--- a/engines/sci/engine/workarounds.h
+++ b/engines/sci/engine/workarounds.h
@@ -104,6 +104,7 @@ extern const SciWorkaroundEntry kSetCursor_workarounds[];
extern const SciWorkaroundEntry kSetPort_workarounds[];
extern const SciWorkaroundEntry kStrAt_workarounds[];
extern const SciWorkaroundEntry kStrCat_workarounds[];
+extern const SciWorkaroundEntry kStrLen_workarounds[];
extern const SciWorkaroundEntry kUnLoad_workarounds[];
extern SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciTrackOriginReply *trackOrigin);
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index 62c5f9c19e..92bdbd30c3 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -219,7 +219,7 @@ void GfxAnimate::applyGlobalScaling(AnimateList::iterator entry, GfxView *view)
writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY), entry->scaleY);
}
-void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) {
+void GfxAnimate::fill(byte &old_picNotValid) {
reg_t curObject;
uint16 signal;
GfxView *view = NULL;
@@ -274,7 +274,7 @@ void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) {
//warning("%s view %d, loop %d, cel %d, signal %x", _s->_segMan->getObjectName(curObject), it->viewId, it->loopNo, it->celNo, it->signal);
- bool setNsRect = maySetNsRect;
+ bool setNsRect = true;
// Create rect according to coordinates and given cel
if (it->scaleSignal & kScaleSignalDoScaling) {
@@ -283,18 +283,20 @@ void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) {
if ((signal & kSignalHidden) && !(signal & kSignalAlwaysUpdate))
setNsRect = false;
} else {
- view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
+ // This special handling is not included in the other SCI1.1 interpreters and MUST NOT be
+ // checked in those cases, otherwise we will break games (e.g. EcoQuest 2, room 200)
+ if ((g_sci->getGameId() == GID_HOYLE4) && (it->scaleSignal & kScaleSignalHoyle4SpecialHandling)) {
+ it->celRect.left = readSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft));
+ it->celRect.top = readSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop));
+ it->celRect.right = readSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight));
+ it->celRect.bottom = readSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom));
+ view->getCelSpecialHoyle4Rect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
+ setNsRect = false;
+ } else {
+ view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
+ }
}
- // This statement must be here for Hoyle4, otherwise cards are unclickable.
- // This is probably one of the experimental features that were occasionally
- // added to SCI interpreters; the corresponding check is absent in many SSCI
- // versions. m_kiewitz knew about this flag before I (lskovlun) implemented it,
- // so it is possible that more test cases are known. Also, some presently open
- // SCI1.1 bugs may be fixed by this and should be re-tested with this patch generalized.
- if (it->scaleSignal & kScaleSignalDontSetNsrect)
- setNsRect = false;
-
if (setNsRect) {
writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left);
writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top);
@@ -562,7 +564,7 @@ void GfxAnimate::addToPicDrawCels() {
// Get the corresponding view
view = _cache->getView(it->viewId);
- // kAddToPic does not do loop/cel-number fixups, it also doesn't support global scaling
+ // kAddToPic does not do loop/cel-number fixups
if (it->priority == -1)
it->priority = _ports->kernelCoordinateToPriority(it->y);
@@ -575,7 +577,9 @@ void GfxAnimate::addToPicDrawCels() {
// Create rect according to coordinates and given cel
if (it->scaleSignal & kScaleSignalDoScaling) {
- applyGlobalScaling(it, view);
+ if (it->scaleSignal & kScaleSignalGlobalScaling) {
+ applyGlobalScaling(it, view);
+ }
view->getCelScaledRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->scaleX, it->scaleY, it->celRect);
writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left);
writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top);
@@ -655,7 +659,7 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t
disposeLastCast();
makeSortedList(list);
- fill(old_picNotValid, true);
+ fill(old_picNotValid);
if (old_picNotValid) {
// beginUpdate()/endUpdate() were introduced SCI1.
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index 23e7a624d8..7b5ec8ee9b 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -51,9 +51,9 @@ enum ViewSignals {
};
enum ViewScaleSignals {
- kScaleSignalDoScaling = 0x0001, // enables scaling when drawing that cel (involves scaleX and scaleY)
- kScaleSignalGlobalScaling = 0x0002, // means that global scaling shall get applied on that cel (sets scaleX/scaleY)
- kScaleSignalDontSetNsrect = 0x0004 // do not set nsRect inside kAnimate(); for a test case see bug #3038424
+ kScaleSignalDoScaling = 0x0001, // enables scaling when drawing that cel (involves scaleX and scaleY)
+ kScaleSignalGlobalScaling = 0x0002, // means that global scaling shall get applied on that cel (sets scaleX/scaleY)
+ kScaleSignalHoyle4SpecialHandling = 0x0004 // HOYLE4-exclusive: special handling inside kAnimate, is used when giving out cards
};
@@ -97,7 +97,7 @@ public:
bool invoke(List *list, int argc, reg_t *argv);
void makeSortedList(List *list);
void applyGlobalScaling(AnimateList::iterator entry, GfxView *view);
- void fill(byte &oldPicNotValid, bool maySetNsRect);
+ void fill(byte &oldPicNotValid);
void update();
void drawCels();
void updateScreen(byte oldPicNotValid);
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index 7a37d7e865..8de9ced57c 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -281,10 +281,10 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu
// ffs. GfxCursor::setPosition (below)
// Game, newPosition, validRect
static const SciCursorSetPositionWorkarounds setPositionWorkarounds[] = {
- { GID_ISLANDBRAIN, 84, 109, 46, 76, 174, 243 }, // island of dr. brain / game menu
- { GID_LSL5, 23, 171, 0, 0, 26, 320 }, // larry 5 / skip forward helper
- { GID_QFG1VGA, 64, 174, 40, 37, 74, 284 }, // Quest For Glory 1 VGA / run/walk/sleep sub-menu
- { (SciGameId)0, -1, -1, -1, -1, -1, -1 }
+ { GID_ISLANDBRAIN, 84, 109, 46, 76, 174, 243 }, // island of dr. brain / game menu
+ { GID_LSL5, 23, 171, 0, 0, 26, 320 }, // larry 5 / skip forward helper
+ { GID_QFG1VGA, 64, 174, 40, 37, 74, 284 }, // Quest For Glory 1 VGA / run/walk/sleep sub-menu
+ { (SciGameId)0, -1, -1, -1, -1, -1, -1 }
};
void GfxCursor::setPosition(Common::Point pos) {
diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp
index 852771d081..3a6ab75cd0 100644
--- a/engines/sci/graphics/font.cpp
+++ b/engines/sci/graphics/font.cpp
@@ -88,7 +88,7 @@ void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bo
byte *pIn = getCharData(chr);
for (int i = 0; i < charHeight; i++, y++) {
if (greyedOutput)
- mask = greyedTop++ % 2 ? 0xAA : 0x55;
+ mask = ((greyedTop++) % 2) ? 0xAA : 0x55;
for (int done = 0; done < charWidth; done++) {
if ((done & 7) == 0) // fetching next data byte
b = *(pIn++) & mask;
@@ -99,4 +99,32 @@ void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bo
}
}
+#ifdef ENABLE_SCI32
+
+void GfxFontFromResource::drawToBuffer(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput, byte *buffer, int16 bufWidth, int16 bufHeight) {
+ int charWidth = MIN<int>(getCharWidth(chr), bufWidth - left);
+ int charHeight = MIN<int>(getCharHeight(chr), bufHeight - top);
+ byte b = 0, mask = 0xFF;
+ int y = 0;
+ int16 greyedTop = top;
+
+ byte *pIn = getCharData(chr);
+ for (int i = 0; i < charHeight; i++, y++) {
+ if (greyedOutput)
+ mask = ((greyedTop++) % 2) ? 0xAA : 0x55;
+ for (int done = 0; done < charWidth; done++) {
+ if ((done & 7) == 0) // fetching next data byte
+ b = *(pIn++) & mask;
+ if (b & 0x80) { // if MSB is set - paint it
+ _screen->putFontPixel(top, left + done, y, color);
+ int offset = (top + y) * bufWidth + (left + done);
+ buffer[offset] = color;
+ }
+ b = b << 1;
+ }
+ }
+}
+
+#endif
+
} // End of namespace Sci
diff --git a/engines/sci/graphics/font.h b/engines/sci/graphics/font.h
index b9bee0fa9e..d8afb73a73 100644
--- a/engines/sci/graphics/font.h
+++ b/engines/sci/graphics/font.h
@@ -56,6 +56,10 @@ public:
byte getHeight();
byte getCharWidth(uint16 chr);
void draw(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput);
+#ifdef ENABLE_SCI32
+ // SCI2/2.1 equivalent
+ void drawToBuffer(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput, byte *buffer, int16 width, int16 height);
+#endif
private:
byte getCharHeight(uint16 chr);
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index fc374ea143..b0d1315d2e 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -44,6 +44,8 @@
namespace Sci {
+// TODO/FIXME: This is all guesswork
+
GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette *palette, GfxPaint32 *paint32)
: _segMan(segMan), _resMan(resMan), _cache(cache), _screen(screen), _palette(palette), _paint32(paint32) {
@@ -130,6 +132,15 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) {
it->planeBack = readSelectorValue(_segMan, object, SELECTOR(back));
sortPlanes();
+
+ // Update the items in the plane
+ for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
+ reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane));
+ if (object == itemPlane) {
+ kernelUpdateScreenItem((*listIterator)->object);
+ }
+ }
+
return;
}
}
@@ -186,17 +197,50 @@ void GfxFrameout::deletePlanePictures(reg_t object) {
}
void GfxFrameout::kernelAddScreenItem(reg_t object) {
- _screenItems.push_back(object);
+ // Ignore invalid items
+ if (!_segMan->isObject(object))
+ return;
+
+ FrameoutEntry *itemEntry = new FrameoutEntry();
+ itemEntry->object = object;
+ itemEntry->givenOrderNr = _screenItems.size();
+ _screenItems.push_back(itemEntry);
+
+ kernelUpdateScreenItem(object);
}
void GfxFrameout::kernelUpdateScreenItem(reg_t object) {
- // TODO
+ // Ignore invalid items
+ if (!_segMan->isObject(object))
+ return;
+
+ for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
+ FrameoutEntry *itemEntry = *listIterator;
+
+ if (itemEntry->object == object) {
+ itemEntry->viewId = readSelectorValue(_segMan, object, SELECTOR(view));
+ itemEntry->loopNo = readSelectorValue(_segMan, object, SELECTOR(loop));
+ itemEntry->celNo = readSelectorValue(_segMan, object, SELECTOR(cel));
+ itemEntry->x = readSelectorValue(_segMan, object, SELECTOR(x));
+ itemEntry->y = readSelectorValue(_segMan, object, SELECTOR(y));
+ itemEntry->z = readSelectorValue(_segMan, object, SELECTOR(z));
+ itemEntry->priority = readSelectorValue(_segMan, object, SELECTOR(priority));
+ if (readSelectorValue(_segMan, object, SELECTOR(fixPriority)) == 0)
+ itemEntry->priority = itemEntry->y;
+
+ itemEntry->signal = readSelectorValue(_segMan, object, SELECTOR(signal));
+ itemEntry->scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX));
+ itemEntry->scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY));
+ return;
+ }
+ }
}
void GfxFrameout::kernelDeleteScreenItem(reg_t object) {
- for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) {
- if (_screenItems[itemNr] == object) {
- _screenItems.remove_at(itemNr);
+ for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
+ FrameoutEntry *itemEntry = *listIterator;
+ if (itemEntry->object == object) {
+ _screenItems.remove(itemEntry);
return;
}
}
@@ -207,7 +251,7 @@ int16 GfxFrameout::kernelGetHighPlanePri() {
return readSelectorValue(g_sci->getEngineState()->_segMan, _planes.back().object, SELECTOR(priority));
}
-// No idea yet how to implement this
+// TODO: No idea yet how to implement this
void GfxFrameout::kernelAddPicAt(reg_t planeObj, int16 forWidth, GuiResourceId pictureId) {
addPlanePicture(planeObj, pictureId, forWidth);
}
@@ -252,11 +296,6 @@ void GfxFrameout::sortPlanes() {
void GfxFrameout::kernelFrameout() {
_palette->palVaryUpdate();
- // Allocate enough space for all screen items
- // TODO: Modify _screenItems to hold FrameoutEntry entries instead.
- // Creating and destroying this in kernelFrameout() is overkill!
- FrameoutEntry *itemData = new FrameoutEntry[_screenItems.size()];
-
for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) {
reg_t planeObject = it->object;
uint16 planeLastPriority = it->lastPriority;
@@ -280,43 +319,14 @@ void GfxFrameout::kernelFrameout() {
_coordAdjuster->pictureSetDisplayArea(it->planeRect);
_palette->drewPicture(planeMainPictureId);
- // Fill our itemlist for this plane
- int16 itemCount = 0;
- FrameoutEntry *itemEntry = itemData;
FrameoutList itemList;
- for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) {
- reg_t itemObject = _screenItems[itemNr];
-
- // Remove any invalid items
- if (!_segMan->isObject(itemObject)) {
- _screenItems.remove_at(itemNr);
- itemNr--;
- continue;
- }
-
- reg_t itemPlane = readSelector(_segMan, itemObject, SELECTOR(plane));
+ // Copy screen items of the current frame to the list of items to be drawn
+ for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
+ reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane));
if (planeObject == itemPlane) {
- // Found an item on current plane
- itemEntry->viewId = readSelectorValue(_segMan, itemObject, SELECTOR(view));
- itemEntry->loopNo = readSelectorValue(_segMan, itemObject, SELECTOR(loop));
- itemEntry->celNo = readSelectorValue(_segMan, itemObject, SELECTOR(cel));
- itemEntry->x = readSelectorValue(_segMan, itemObject, SELECTOR(x));
- itemEntry->y = readSelectorValue(_segMan, itemObject, SELECTOR(y));
- itemEntry->z = readSelectorValue(_segMan, itemObject, SELECTOR(z));
- itemEntry->priority = readSelectorValue(_segMan, itemObject, SELECTOR(priority));
- if (readSelectorValue(_segMan, itemObject, SELECTOR(fixPriority)) == 0)
- itemEntry->priority = itemEntry->y;
-
- itemEntry->signal = readSelectorValue(_segMan, itemObject, SELECTOR(signal));
- itemEntry->scaleX = readSelectorValue(_segMan, itemObject, SELECTOR(scaleX));
- itemEntry->scaleY = readSelectorValue(_segMan, itemObject, SELECTOR(scaleY));
- itemEntry->object = itemObject;
- itemEntry->givenOrderNr = itemNr;
-
- itemList.push_back(itemEntry);
- itemEntry++;
- itemCount++;
+ kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary?
+ itemList.push_back(*listIterator);
}
}
@@ -348,13 +358,10 @@ void GfxFrameout::kernelFrameout() {
// Now sort our itemlist
Common::sort(itemList.begin(), itemList.end(), sortHelper);
- // Now display itemlist
- itemEntry = itemData;
-
// warning("Plane %s", _segMan->getObjectName(planeObject));
for (FrameoutList::iterator listIterator = itemList.begin(); listIterator != itemList.end(); listIterator++) {
- itemEntry = *listIterator;
+ FrameoutEntry *itemEntry = *listIterator;
if (itemEntry->object.isNull()) {
// Picture cel data
@@ -530,7 +537,6 @@ void GfxFrameout::kernelFrameout() {
}
}
- delete[] itemData;
_screen->copyToScreen();
g_sci->getEngineState()->_throttleTrigger = true;
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 07297a91af..bd708dbc79 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -109,7 +109,7 @@ private:
GfxScreen *_screen;
GfxPaint32 *_paint32;
- Common::Array<reg_t> _screenItems;
+ Common::List<FrameoutEntry *> _screenItems;
PlaneList _planes;
PlanePictureList _planePictures;
diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h
index 4b4cd673b4..f6cb214a2b 100644
--- a/engines/sci/graphics/helpers.h
+++ b/engines/sci/graphics/helpers.h
@@ -64,7 +64,7 @@ struct Port {
}
};
-struct Window : public Port {
+struct Window : public Port, public Common::Serializable {
Common::Rect dims; // client area of window
Common::Rect restoreRect; // total area of window including borders
uint16 wndStyle;
@@ -79,6 +79,40 @@ struct Window : public Port {
hSaved1(NULL_REG), hSaved2(NULL_REG),
bDrawn(false) {
}
+
+ void syncRect(Common::Serializer &ser, Common::Rect &targetRect) {
+ ser.syncAsSint16LE(targetRect.top);
+ ser.syncAsSint16LE(targetRect.left);
+ ser.syncAsSint16LE(targetRect.bottom);
+ ser.syncAsSint16LE(targetRect.right);
+ }
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser) {
+ ser.syncAsUint16LE(id);
+ ser.syncAsSint16LE(top);
+ ser.syncAsSint16LE(left);
+ syncRect(ser, rect);
+ ser.syncAsSint16LE(curTop);
+ ser.syncAsSint16LE(curLeft);
+ ser.syncAsSint16LE(fontHeight);
+ ser.syncAsSint32LE(fontId);
+ ser.syncAsByte(greyedOutput);
+ ser.syncAsSint16LE(penClr);
+ ser.syncAsSint16LE(backClr);
+ ser.syncAsSint16LE(penMode);
+ ser.syncAsUint16LE(counterTillFree);
+ syncRect(ser, dims);
+ syncRect(ser, restoreRect);
+ ser.syncAsUint16LE(wndStyle);
+ ser.syncAsUint16LE(saveScreenMask);
+ if (ser.isLoading()) {
+ // The hunk table isn't saved, so we just set both pointers to NULL
+ hSaved1 = NULL_REG;
+ hSaved2 = NULL_REG;
+ }
+ ser.syncString(title);
+ ser.syncAsByte(bDrawn);
+ }
};
struct Color {
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index 06470bc560..92644db037 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -296,7 +296,7 @@ void GfxMenu::kernelSetAttribute(uint16 menuId, uint16 itemId, uint16 attributeI
itemEntry->keyPress = tolower(value.offset);
itemEntry->keyModifier = 0;
// TODO: Find out how modifier is handled
- printf("setAttr keypress %X %X\n", value.segment, value.offset);
+ debug("setAttr keypress %X %X", value.segment, value.offset);
break;
case SCI_MENU_ATTRIBUTE_TAG:
itemEntry->tag = value.offset;
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 76b2ed53fc..f5689a956d 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -192,6 +192,16 @@ void GfxPalette::modifyAmigaPalette(byte *data) {
_screen->setPalette(&_sysPalette);
}
+static byte blendColours(byte c1, byte c2) {
+ // linear
+ // return (c1/2+c2/2)+((c1&1)+(c2&1))/2;
+
+ // gamma 2.2
+ double t = (pow(c1/255.0, 2.2/1.0) * 255.0) +
+ (pow(c2/255.0, 2.2/1.0) * 255.0);
+ return (byte)(0.5 + (pow(0.5*t/255.0, 1.0/2.2) * 255.0));
+}
+
void GfxPalette::setEGA() {
int curColor;
byte color1, color2;
@@ -219,9 +229,10 @@ void GfxPalette::setEGA() {
for (curColor = 0x10; curColor <= 0xFE; curColor++) {
_sysPalette.colors[curColor].used = 1;
color1 = curColor & 0x0F; color2 = curColor >> 4;
- _sysPalette.colors[curColor].r = (_sysPalette.colors[color1].r >> 1) + (_sysPalette.colors[color2].r >> 1);
- _sysPalette.colors[curColor].g = (_sysPalette.colors[color1].g >> 1) + (_sysPalette.colors[color2].g >> 1);
- _sysPalette.colors[curColor].b = (_sysPalette.colors[color1].b >> 1) + (_sysPalette.colors[color2].b >> 1);
+
+ _sysPalette.colors[curColor].r = blendColours(_sysPalette.colors[color1].r, _sysPalette.colors[color2].r);
+ _sysPalette.colors[curColor].g = blendColours(_sysPalette.colors[color1].g, _sysPalette.colors[color2].g);
+ _sysPalette.colors[curColor].b = blendColours(_sysPalette.colors[color1].b, _sysPalette.colors[color2].b);
}
_sysPalette.timestamp = 1;
setOnScreen();
diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp
index 39666b82cb..707096740a 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -754,6 +754,19 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
// Dithering EGA pictures
if (isEGA) {
_screen->dither(_addToFlag);
+ switch (g_sci->getGameId()) {
+ case GID_SQ3:
+ switch (_resourceId) {
+ case 154: // SQ3: intro, ship gets sucked in
+ _screen->ditherForceMemorial(0xD0);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
}
return;
default:
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index e7f319a25c..ef57e4014f 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -38,15 +38,6 @@
namespace Sci {
-// window styles
-enum {
- SCI_WINDOWMGR_STYLE_TRANSPARENT = (1 << 0),
- SCI_WINDOWMGR_STYLE_NOFRAME = (1 << 1),
- SCI_WINDOWMGR_STYLE_TITLE = (1 << 2),
- SCI_WINDOWMGR_STYLE_TOPMOST = (1 << 3),
- SCI_WINDOWMGR_STYLE_USER = (1 << 7)
-};
-
GfxPorts::GfxPorts(SegManager *segMan, GfxScreen *screen)
: _segMan(segMan), _screen(screen) {
}
diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h
index 453cb50986..21c6d31ebd 100644
--- a/engines/sci/graphics/ports.h
+++ b/engines/sci/graphics/ports.h
@@ -26,6 +26,7 @@
#ifndef SCI_GRAPHICS_PORTS_H
#define SCI_GRAPHICS_PORTS_H
+#include "common/serializer.h"
#include "common/list.h"
#include "common/array.h"
@@ -39,11 +40,20 @@ class GfxText16;
#define PORTS_FIRSTWINDOWID 2
#define PORTS_FIRSTSCRIPTWINDOWID 3
+// window styles
+enum {
+ SCI_WINDOWMGR_STYLE_TRANSPARENT = (1 << 0),
+ SCI_WINDOWMGR_STYLE_NOFRAME = (1 << 1),
+ SCI_WINDOWMGR_STYLE_TITLE = (1 << 2),
+ SCI_WINDOWMGR_STYLE_TOPMOST = (1 << 3),
+ SCI_WINDOWMGR_STYLE_USER = (1 << 7)
+};
+
/**
* Ports class, includes all port managment for SCI0->SCI1.1 games. Ports are some sort of windows in SCI
* this class also handles adjusting coordinates to a specific port
*/
-class GfxPorts {
+class GfxPorts : public Common::Serializable {
public:
GfxPorts(SegManager *segMan, GfxScreen *screen);
~GfxPorts();
@@ -103,6 +113,8 @@ public:
Common::Rect _menuLine;
Port *_curPort;
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+
private:
typedef Common::List<Port *> PortList;
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 6eabc7c9f0..f8dc3118b5 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -122,9 +122,9 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
// Initialize the actual screen
- if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1) {
- // For SCI1.1 Mac, we need to expand the screen to accommodate for
- // the icon bar. Of course, both KQ6 and QFG1 VGA differ in size.
+ if (g_sci->hasMacIconBar()) {
+ // For SCI1.1 Mac games with the custom icon bar, we need to expand the screen
+ // to accommodate for the icon bar. Of course, both KQ6 and QFG1 VGA differ in size.
if (g_sci->getGameId() == GID_KQ6)
initGraphics(_displayWidth, _displayHeight + 26, _displayWidth > 320);
else if (g_sci->getGameId() == GID_QFG1VGA)
@@ -616,6 +616,11 @@ void GfxScreen::dither(bool addToFlag) {
}
}
+// Force a color combination into memorial
+void GfxScreen::ditherForceMemorial(byte color) {
+ _unditherMemorial[color] = 256;
+}
+
void GfxScreen::debugUnditherSetState(bool flag) {
_unditherState = flag;
}
diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h
index 97f5736289..44746ae00b 100644
--- a/engines/sci/graphics/screen.h
+++ b/engines/sci/graphics/screen.h
@@ -115,6 +115,7 @@ public:
void adjustBackUpscaledCoordinates(int16 &y, int16 &x);
void dither(bool addToFlag);
+ void ditherForceMemorial(byte color);
void debugUnditherSetState(bool flag);
int16 *unditherGetMemorial();
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 6b22ed397e..36d48fe3c9 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -354,6 +354,16 @@ void GfxView::getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, C
outRect.top = outRect.bottom - celInfo->height;
}
+void GfxView::getCelSpecialHoyle4Rect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const {
+ const CelInfo *celInfo = getCelInfo(loopNo, celNo);
+ int16 adjustY = y - celInfo->height + celInfo->displaceY + 1;
+ int16 adjustX = x - ((celInfo->width - 1) >> 1) + celInfo->displaceX;
+ outRect.top += adjustY;
+ outRect.bottom += adjustY;
+ outRect.left += adjustX;
+ outRect.right += adjustX;
+}
+
void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, int16 scaleX, int16 scaleY, Common::Rect &outRect) const {
int16 scaledDisplaceX, scaledDisplaceY;
int16 scaledWidth, scaledHeight;
@@ -525,6 +535,10 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl
if (width <= 3)
return;
+ // We need at least 2 pixel lines
+ if (height < 2)
+ return;
+
// If EGA mapping is used for this view, dont do undithering as well
if (_EGAmapping)
return;
@@ -533,20 +547,28 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl
int16 bitmapMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE];
byte *curPtr;
byte color1, color2;
+ byte nextColor1, nextColor2;
int16 y, x;
memset(&bitmapMemorial, 0, sizeof(bitmapMemorial));
// Count all seemingly dithered pixel-combinations as soon as at least 4
- // pixels are adjacent
+ // pixels are adjacent and check pixels in the following line as well to
+ // be the reverse pixel combination
+ int16 checkHeight = height - 1;
curPtr = bitmapPtr;
- for (y = 0; y < height; y++) {
+ byte *nextPtr = curPtr + width;
+ for (y = 0; y < checkHeight; y++) {
color1 = curPtr[0]; color2 = (curPtr[1] << 4) | curPtr[2];
+ nextColor1 = nextPtr[0] << 4; nextColor2 = (nextPtr[2] << 4) | nextPtr[1];
curPtr += 3;
+ nextPtr += 3;
for (x = 3; x < width; x++) {
color1 = (color1 << 4) | (color2 >> 4);
color2 = (color2 << 4) | *curPtr++;
- if (color1 == color2)
+ nextColor1 = (nextColor1 >> 4) | (nextColor2 << 4);
+ nextColor2 = (nextColor2 >> 4) | *nextPtr++ << 4;
+ if ((color1 == color2) && (color1 == nextColor1) && (color1 == nextColor2))
bitmapMemorial[color1]++;
}
}
@@ -583,9 +605,10 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl
if (unditherTable[color]) {
// Some color with black? Turn colors around, otherwise it won't
// be the right color at all.
+ byte unditheredColor = color;
if ((color & 0xF0) == 0)
- color = (color << 4) | (color >> 4);
- curPtr[0] = color; curPtr[1] = color;
+ unditheredColor = (color << 4) | (color >> 4);
+ curPtr[0] = unditheredColor; curPtr[1] = unditheredColor;
}
curPtr++;
}
diff --git a/engines/sci/graphics/view.h b/engines/sci/graphics/view.h
index 990a7e2f71..f785e3c475 100644
--- a/engines/sci/graphics/view.h
+++ b/engines/sci/graphics/view.h
@@ -66,6 +66,7 @@ public:
int16 getHeight(int16 loopNo, int16 celNo) const;
const CelInfo *getCelInfo(int16 loopNo, int16 celNo) const;
void getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const;
+ void getCelSpecialHoyle4Rect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const;
void getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, int16 scaleX, int16 scaleY, Common::Rect &outRect) const;
const byte *getBitmap(int16 loopNo, int16 celNo);
void draw(const Common::Rect &rect, const Common::Rect &clipRect, const Common::Rect &clipRectTranslated, int16 loopNo, int16 celNo, byte priority, uint16 EGAmappingNr, bool upscaledHires);
diff --git a/engines/sci/parser/grammar.cpp b/engines/sci/parser/grammar.cpp
index 03e9d29660..8a6cd2dd4d 100644
--- a/engines/sci/parser/grammar.cpp
+++ b/engines/sci/parser/grammar.cpp
@@ -93,49 +93,49 @@ static void vocab_print_rule(ParseRule *rule) {
return;
}
- printf("[%03x] -> ", rule->_id);
+ debugN("[%03x] -> ", rule->_id);
if (rule->_data.empty())
- printf("e");
+ debugN("e");
for (uint i = 0; i < rule->_data.size(); i++) {
uint token = rule->_data[i];
if (token == TOKEN_OPAREN) {
if (i == rule->_firstSpecial)
- printf("_");
+ debugN("_");
- printf("(");
+ debugN("(");
wspace = 0;
} else if (token == TOKEN_CPAREN) {
if (i == rule->_firstSpecial)
- printf("_");
+ debugN("_");
- printf(")");
+ debugN(")");
wspace = 0;
} else {
if (wspace)
- printf(" ");
+ debugN(" ");
if (i == rule->_firstSpecial)
- printf("_");
+ debugN("_");
if (token & TOKEN_TERMINAL_CLASS)
- printf("C(%04x)", token & 0xffff);
+ debugN("C(%04x)", token & 0xffff);
else if (token & TOKEN_TERMINAL_GROUP)
- printf("G(%04x)", token & 0xffff);
+ debugN("G(%04x)", token & 0xffff);
else if (token & TOKEN_STUFFING_LEAF)
- printf("%03x", token & 0xffff);
+ debugN("%03x", token & 0xffff);
else if (token & TOKEN_STUFFING_WORD)
- printf("{%03x}", token & 0xffff);
+ debugN("{%03x}", token & 0xffff);
else
- printf("[%03x]", token); /* non-terminal */
+ debugN("[%03x]", token); /* non-terminal */
wspace = 1;
}
if (i == rule->_firstSpecial)
- printf("_");
+ debugN("_");
}
- printf(" [%d specials]", rule->_numSpecials);
+ debugN(" [%d specials]", rule->_numSpecials);
}
static ParseRule *_vdup(ParseRule *a) {
@@ -321,13 +321,13 @@ void ParseRuleList::print() const {
const ParseRuleList *list = this;
int pos = 0;
while (list) {
- printf("R%03d: ", pos);
+ debugN("R%03d: ", pos);
vocab_print_rule(list->rule);
- printf("\n");
+ debugN("\n");
list = list->next;
pos++;
}
- printf("%d rules total.\n", pos);
+ debugN("%d rules total.\n", pos);
}
static ParseRuleList *_vocab_split_rule_list(ParseRuleList *list) {
@@ -524,9 +524,9 @@ static int _vbpt_write_subexpression(ParseTreeNode *nodes, int *pos, ParseRule *
else
writepos = _vbpt_append_word(nodes, pos, writepos, token & 0xffff);
} else {
- printf("\nError in parser (grammar.cpp, _vbpt_write_subexpression()): Rule data broken in rule ");
+ warning("\nError in parser (grammar.cpp, _vbpt_write_subexpression()): Rule data broken in rule ");
vocab_print_rule(rule);
- printf(", at token position %d\n", *pos);
+ debugN(", at token position %d\n", *pos);
return rulepos;
}
}
diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp
index 7393874856..e9c6d9847f 100644
--- a/engines/sci/parser/said.cpp
+++ b/engines/sci/parser/said.cpp
@@ -39,7 +39,7 @@ namespace Sci {
#ifdef SCI_DEBUG_PARSE_TREE_AUGMENTATION
-#define scidprintf printf
+#define scidprintf debugN
#else
void print_nothing(...) { }
#define scidprintf print_nothing
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index f9989b22a8..b1f928cdd9 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -458,44 +458,44 @@ void Vocabulary::debugDecipherSaidBlock(const byte *addr) {
nextItem = *addr++;
if (nextItem != 0xff) {
if ((!first) && (nextItem != 0xf0))
- printf(" ");
+ debugN(" ");
first = false;
if (nextItem < 0xf0) {
nextItem = nextItem << 8 | *addr++;
- printf("%s{%03x}", getAnyWordFromGroup(nextItem), nextItem);
+ debugN("%s{%03x}", getAnyWordFromGroup(nextItem), nextItem);
nextItem = 0; // Make sure that group 0xff doesn't abort
} else switch (nextItem) {
case 0xf0:
- printf(",");
+ debugN(",");
break;
case 0xf1:
- printf("&");
+ debugN("&");
break;
case 0xf2:
- printf("/");
+ debugN("/");
break;
case 0xf3:
- printf("(");
+ debugN("(");
break;
case 0xf4:
- printf(")");
+ debugN(")");
break;
case 0xf5:
- printf("[");
+ debugN("[");
break;
case 0xf6:
- printf("]");
+ debugN("]");
break;
case 0xf7:
- printf("#");
+ debugN("#");
break;
case 0xf8:
- printf("<");
+ debugN("<");
break;
case 0xf9:
- printf(">");
+ debugN(">");
break;
case 0xff:
break;
@@ -611,48 +611,48 @@ void _vocab_recursive_ptree_dump(ParseTreeNode *tree, int blanks) {
int i;
if (tree->type == kParseTreeLeafNode) {
- printf("vocab_dump_parse_tree: Error: consp is nil\n");
+ debugN("vocab_dump_parse_tree: Error: consp is nil\n");
return;
}
if (lbranch) {
if (lbranch->type == kParseTreeBranchNode) {
- printf("\n");
+ debugN("\n");
for (i = 0; i < blanks; i++)
- printf(" ");
- printf("(");
+ debugN(" ");
+ debugN("(");
_vocab_recursive_ptree_dump(lbranch, blanks + 1);
- printf(")\n");
+ debugN(")\n");
for (i = 0; i < blanks; i++)
- printf(" ");
+ debugN(" ");
} else
- printf("%x", lbranch->value);
- printf(" ");
- }/* else printf ("nil");*/
+ debugN("%x", lbranch->value);
+ debugN(" ");
+ }/* else debugN ("nil");*/
if (rbranch) {
if (rbranch->type == kParseTreeBranchNode)
_vocab_recursive_ptree_dump(rbranch, blanks);
else {
- printf("%x", rbranch->value);
+ debugN("%x", rbranch->value);
while (rbranch->right) {
rbranch = rbranch->right;
- printf("/%x", rbranch->value);
+ debugN("/%x", rbranch->value);
}
}
- }/* else printf("nil");*/
+ }/* else debugN("nil");*/
}
void vocab_dump_parse_tree(const char *tree_name, ParseTreeNode *nodes) {
- printf("(setq %s \n'(", tree_name);
+ debugN("(setq %s \n'(", tree_name);
_vocab_recursive_ptree_dump(nodes, 1);
- printf("))\n");
+ debugN("))\n");
}
void Vocabulary::dumpParseTree() {
- printf("(setq parse-tree \n'(");
+ debugN("(setq parse-tree \n'(");
_vocab_recursive_ptree_dump(_parserNodes, 1);
- printf("))\n");
+ debugN("))\n");
}
void Vocabulary::synonymizeTokens(ResultWordListList &words) {
@@ -673,9 +673,15 @@ void Vocabulary::printParserNodes(int num) {
con->DebugPrintf(" Node %03x: ", i);
if (_parserNodes[i].type == kParseTreeLeafNode)
con->DebugPrintf("Leaf: %04x\n", _parserNodes[i].value);
- else
- con->DebugPrintf("Branch: ->%04x, ->%04x\n", _parserNodes[i].left,
- _parserNodes[i].right);
+ else {
+ // FIXME: Do we really want to print the *addresses*
+ // of the left & right child?
+ // Note that one or both may be zero pointers, so we can't just
+ // print their values.
+ con->DebugPrintf("Branch: ->%p, ->%p\n",
+ (const void *)_parserNodes[i].left,
+ (const void *)_parserNodes[i].right);
+ }
}
}
diff --git a/engines/sci/parser/vocabulary.h b/engines/sci/parser/vocabulary.h
index 620d50c09d..baf30a03d7 100644
--- a/engines/sci/parser/vocabulary.h
+++ b/engines/sci/parser/vocabulary.h
@@ -243,7 +243,7 @@ public:
ParseRuleList *buildGNF(bool verbose = false);
/**
- * Deciphers a said block and dumps its content via printf.
+ * Deciphers a said block and dumps its content via debugN.
* For debugging only.
* @param pos pointer to the data to dump
*/
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 9809f10576..501d305f54 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -779,7 +779,7 @@ void ChunkResourceSource::loadResource(ResourceManager *resMan, Resource *res) {
}
void ResourceManager::addResourcesFromChunk(uint16 id) {
- addSource(new ChunkResourceSource(Common::String::printf("Chunk %d", id), id));
+ addSource(new ChunkResourceSource(Common::String::format("Chunk %d", id), id));
scanNewSources();
}
@@ -940,7 +940,7 @@ void ResourceManager::freeOldResources() {
removeFromLRU(goner);
goner->unalloc();
#ifdef SCI_VERBOSE_RESMAN
- printf("resMan-debug: LRU: Freeing %s.%03d (%d bytes)\n", getResourceTypeName(goner->type), goner->number, goner->size);
+ debug("resMan-debug: LRU: Freeing %s.%03d (%d bytes)", getResourceTypeName(goner->type), goner->number, goner->size);
#endif
}
}
@@ -1583,10 +1583,12 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
return 0;
}
-struct {
+struct MacResTag {
uint32 tag;
ResourceType type;
-} static const macResTagMap[] = {
+};
+
+static const MacResTag macResTagMap[] = {
{ MKID_BE('V56 '), kResourceTypeView },
{ MKID_BE('P56 '), kResourceTypePic },
{ MKID_BE('SCR '), kResourceTypeScript },
@@ -2284,7 +2286,7 @@ bool ResourceManager::hasSci1Voc900() {
return offset == res->size;
}
-// Same function as Script::findBlock(). Slight code
+// Same function as Script::findBlockSCI0(). Slight code
// duplication here, but this has been done to keep the resource
// manager independent from the rest of the engine
static byte *findSci0ExportsBlock(byte *buffer) {
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 3fe398f426..c9b94d1a8b 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -180,7 +180,6 @@ Common::Error SciEngine::run() {
g_eventRec.registerRandomSource(_rng, "sci");
// Assign default values to the config manager, in case settings are missing
- ConfMan.registerDefault("sci_undither", "true");
ConfMan.registerDefault("sci_originalsaveload", "false");
ConfMan.registerDefault("native_fb01", "false");
@@ -210,7 +209,7 @@ Common::Error SciEngine::run() {
// Initialize the game screen
_gfxScreen = new GfxScreen(_resMan);
- _gfxScreen->debugUnditherSetState(ConfMan.getBool("sci_undither"));
+ _gfxScreen->debugUnditherSetState(ConfMan.getBool("disable_dithering"));
// Create debugger console. It requires GFX to be initialized
_console = new Console(this);
@@ -303,10 +302,10 @@ Common::Error SciEngine::run() {
if (buggyScript && (buggyScript->size == 12354 || buggyScript->size == 12362)) {
showScummVMDialog("A known buggy game script has been detected, which could "
- "prevent you from progressing later on in the game, during "
- "the sequence with the Green Man's riddles. Please, apply "
- "the latest patch for this game by Sierra to avoid possible "
- "problems");
+ "prevent you from progressing later on in the game, during "
+ "the sequence with the Green Man's riddles. Please, apply "
+ "the latest patch for this game by Sierra to avoid possible "
+ "problems");
}
}
@@ -325,16 +324,16 @@ Common::Error SciEngine::run() {
case GID_SQ4:
case GID_FAIRYTALES:
showScummVMDialog("You have selected General MIDI as a sound device. Sierra "
- "has provided after-market support for General MIDI for this "
- "game in their \"General MIDI Utility\". Please, apply this "
- "patch in order to enjoy MIDI music with this game. Once you "
- "have obtained it, you can unpack all of the included *.PAT "
- "files in your ScummVM extras folder and ScummVM will add the "
- "appropriate patch automatically. Alternatively, you can follow "
- "the instructions in the READ.ME file included in the patch and "
- "rename the associated *.PAT file to 4.PAT and place it in the "
- "game folder. Without this patch, General MIDI music for this "
- "game will sound badly distorted.");
+ "has provided after-market support for General MIDI for this "
+ "game in their \"General MIDI Utility\". Please, apply this "
+ "patch in order to enjoy MIDI music with this game. Once you "
+ "have obtained it, you can unpack all of the included *.PAT "
+ "files in your ScummVM extras folder and ScummVM will add the "
+ "appropriate patch automatically. Alternatively, you can follow "
+ "the instructions in the READ.ME file included in the patch and "
+ "rename the associated *.PAT file to 4.PAT and place it in the "
+ "game folder. Without this patch, General MIDI music for this "
+ "game will sound badly distorted.");
break;
default:
break;
@@ -342,6 +341,13 @@ Common::Error SciEngine::run() {
}
}
+ if (gameHasFanMadePatch()) {
+ showScummVMDialog("Your game is patched with a fan made script patch. Such patches have "
+ "been reported to cause issues, as they modify game scripts extensively. "
+ "The issues that these patches fix do not occur in ScummVM, so you are "
+ "advised to remove this patch from your game folder in order to avoid "
+ "having unexpected errors and/or issues later on.");
+ }
runGame();
@@ -350,6 +356,69 @@ Common::Error SciEngine::run() {
return Common::kNoError;
}
+bool SciEngine::gameHasFanMadePatch() {
+ struct FanMadePatchInfo {
+ SciGameId gameID;
+ uint16 targetScript;
+ uint16 targetSize;
+ uint16 patchedByteOffset;
+ byte patchedByte;
+ };
+
+ const FanMadePatchInfo patchInfo[] = {
+ // game script size offset byte
+ // ** NRS Patches **************************
+ { GID_HOYLE3, 994, 2580, 656, 0x78 },
+ { GID_KQ1, 85, 5156, 631, 0x02 },
+ { GID_LAURABOW2, 994, 4382, 0, 0x00 },
+ { GID_LONGBOW, 994, 4950, 1455, 0x78 }, // English
+ { GID_LONGBOW, 994, 5020, 1469, 0x78 }, // German
+ { GID_LSL1, 803, 592, 342, 0x01 },
+ { GID_LSL3, 380, 6148, 195, 0x35 },
+ { GID_LSL5, 994, 4810, 1342, 0x78 }, // English
+ { GID_LSL5, 994, 4942, 1392, 0x76 }, // German
+ { GID_PQ1, 994, 4332, 1473, 0x78 },
+ { GID_PQ2, 200, 10614, 0, 0x00 },
+ { GID_PQ3, 994, 4686, 1291, 0x78 }, // English
+ { GID_PQ3, 994, 4734, 1283, 0x78 }, // German
+ { GID_QFG1VGA, 994, 4388, 0, 0x00 },
+ { GID_QFG3, 994, 4714, 0, 0x00 },
+ // TODO: Disabled, as it fixes a whole lot of bugs which can't be tested till SCI2.1 support is finished
+ //{ GID_QFG4, 710, 11477, 0, 0x00 },
+ { GID_SQ1, 994, 4740, 0, 0x00 },
+ { GID_SQ5, 994, 4142, 1496, 0x78 }, // English/German/French
+ // TODO: Disabled, till we can test the Italian version
+ //{ GID_SQ5, 994, 4148, 0, 0x00 }, // Italian - patched file is the same size as the original
+ // TODO: The bugs in SQ6 can't be tested till SCI2.1 support is finished
+ //{ GID_SQ6, 380, 16308, 15042, 0x0C }, // English
+ //{ GID_SQ6, 380, 11652, 0, 0x00 }, // German - patched file is the same size as the original
+ // ** End marker ***************************
+ { GID_FANMADE, 0, 0, 0, 0x00 }
+ };
+
+ int curEntry = 0;
+
+ while (true) {
+ if (patchInfo[curEntry].targetSize == 0)
+ break;
+
+ if (patchInfo[curEntry].gameID == getGameId()) {
+ Resource *targetScript = _resMan->findResource(ResourceId(kResourceTypeScript, patchInfo[curEntry].targetScript), 0);
+
+ if (targetScript && targetScript->size + 2 == patchInfo[curEntry].targetSize) {
+ if (patchInfo[curEntry].patchedByteOffset == 0)
+ return true;
+ else if (targetScript->data[patchInfo[curEntry].patchedByteOffset - 2] == patchInfo[curEntry].patchedByte)
+ return true;
+ }
+ }
+
+ curEntry++;
+ }
+
+ return false;
+}
+
static byte patchGameRestoreSave[] = {
0x39, 0x03, // pushi 03
0x76, // push0
@@ -484,7 +553,7 @@ bool SciEngine::initGame() {
_vocabulary->reset();
}
- _gamestate->gameStartTime = _gamestate->lastWaitTime = _gamestate->_screenUpdateTime = g_system->getMillis();
+ _gamestate->lastWaitTime = _gamestate->_screenUpdateTime = g_system->getMillis();
// Load game language into printLang property of game object
setSciLanguage();
@@ -514,7 +583,7 @@ void SciEngine::initGraphics() {
_gfxPaint32 = 0;
#endif
- if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1)
+ if (hasMacIconBar())
_gfxMacIconBar = new GfxMacIconBar();
bool paletteMerging = true;
@@ -580,6 +649,8 @@ void SciEngine::initStackBaseWithSelector(Selector selector) {
}
void SciEngine::runGame() {
+ setTotalPlayTime(0);
+
initStackBaseWithSelector(SELECTOR(play)); // Call the play selector
// Attach the debug console on game startup, if requested
@@ -633,8 +704,10 @@ void SciEngine::exitGame() {
GUI::Debugger *SciEngine::getDebugger() {
if (_gamestate) {
ExecStack *xs = &(_gamestate->_executionStack.back());
- xs->addr.pc.offset = _debugState.old_pc_offset;
- xs->sp = _debugState.old_sp;
+ if (xs) {
+ xs->addr.pc.offset = _debugState.old_pc_offset;
+ xs->sp = _debugState.old_sp;
+ }
}
_debugState.runningStep = 0; // Stop multiple execution
@@ -664,8 +737,12 @@ bool SciEngine::isDemo() const {
return _gameDescription->flags & ADGF_DEMO;
}
+bool SciEngine::hasMacIconBar() const {
+ return _resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1 && getGameId() != GID_HOYLE4;
+}
+
Common::String SciEngine::getSavegameName(int nr) const {
- return _targetName + Common::String::printf(".%03d", nr);
+ return _targetName + Common::String::format(".%03d", nr);
}
Common::String SciEngine::getSavegamePattern() const {
@@ -702,6 +779,8 @@ int SciEngine::inQfGImportRoom() const {
void SciEngine::pauseEngineIntern(bool pause) {
_mixer->pauseAll(pause);
+ if (_soundCmd)
+ _soundCmd->pauseAll(pause);
}
void SciEngine::syncSoundSettings() {
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 7239abad17..606cc008ee 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -39,8 +39,11 @@ struct ADGameDescription;
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Newer Sierra adventure games (based on FreeSCI)
+ *
+ * @todo give a concrete list of supported games. Could also
+ * list future games, with status for each.
*/
namespace Sci {
@@ -228,6 +231,7 @@ public:
Common::Language getLanguage() const;
Common::Platform getPlatform() const;
bool isDemo() const;
+ bool hasMacIconBar() const;
inline ResourceManager *getResMan() const { return _resMan; }
inline Kernel *getKernel() const { return _kernel; }
@@ -344,6 +348,8 @@ private:
void initStackBaseWithSelector(Selector selector);
+ bool gameHasFanMadePatch();
+
const ADGameDescription *_gameDescription;
const SciGameId _gameId;
ResourceManager *_resMan; /**< The resource manager */
diff --git a/engines/sci/sound/drivers/amigamac.cpp b/engines/sci/sound/drivers/amigamac.cpp
index 4b591eb609..07c0582124 100644
--- a/engines/sci/sound/drivers/amigamac.cpp
+++ b/engines/sci/sound/drivers/amigamac.cpp
@@ -288,7 +288,7 @@ void MidiDriver_AmigaMac::playInstrument(int16 *dest, Voice *channel, int count)
void MidiDriver_AmigaMac::changeInstrument(int channel, int instrument) {
#ifdef DEBUG
if (_bank.instruments[instrument][0])
- printf("[sfx:seq:amiga] Setting channel %i to \"%s\" (%i)\n", channel, _bank.instruments[instrument]->name, instrument);
+ debugN("[sfx:seq:amiga] Setting channel %i to \"%s\" (%i)\n", channel, _bank.instruments[instrument]->name, instrument);
else
warning("[sfx:seq:amiga] instrument %i does not exist (channel %i)", instrument, channel);
#endif
@@ -488,13 +488,13 @@ MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::readInstrumentSCI0(C
instrument->name[29] = 0;
#ifdef DEBUG
- printf("[sfx:seq:amiga] Reading instrument %i: \"%s\" (%i bytes)\n",
+ debugN("[sfx:seq:amiga] Reading instrument %i: \"%s\" (%i bytes)\n",
*id, instrument->name, size);
- printf(" Mode: %02x\n", instrument->mode);
- printf(" Looping: %s\n", instrument->mode & kModeLoop ? "on" : "off");
- printf(" Pitch changes: %s\n", instrument->mode & kModePitch ? "on" : "off");
- printf(" Segment sizes: %i %i %i\n", seg_size[0], seg_size[1], seg_size[2]);
- printf(" Segment offsets: 0 %i %i\n", loop_offset, read_int32(header + 43));
+ debugN(" Mode: %02x\n", instrument->mode);
+ debugN(" Looping: %s\n", instrument->mode & kModeLoop ? "on" : "off");
+ debugN(" Pitch changes: %s\n", instrument->mode & kModePitch ? "on" : "off");
+ debugN(" Segment sizes: %i %i %i\n", seg_size[0], seg_size[1], seg_size[2]);
+ debugN(" Segment offsets: 0 %i %i\n", loop_offset, read_int32(header + 43));
#endif
instrument->samples = (int8 *) malloc(size + 1);
@@ -745,7 +745,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0(Common::File &file) {
strncpy(_bank.name, (char *) header + 8, 29);
_bank.name[29] = 0;
#ifdef DEBUG
- printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
+ debugN("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
#endif
for (uint i = 0; i < _bank.size; i++) {
@@ -784,7 +784,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0Mac(Common::SeekableReadStream &fil
strncpy(_bank.name, (char *) header + 8, 29);
_bank.name[29] = 0;
#ifdef DEBUG
- printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
+ debugN("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
#endif
Common::Array<uint32> instrumentOffsets;
diff --git a/engines/sci/sound/drivers/gm_names.h b/engines/sci/sound/drivers/gm_names.h
new file mode 100644
index 0000000000..b7883494f6
--- /dev/null
+++ b/engines/sci/sound/drivers/gm_names.h
@@ -0,0 +1,220 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SCI_SOUND_DRIVERS_GM_NAMES_H
+#define SCI_SOUND_DRIVERS_GM_NAMES_H
+
+namespace Sci {
+
+static const char *GmInstrumentNames[] = {
+ /*000*/ "Acoustic Grand Piano",
+ /*001*/ "Bright Acoustic Piano",
+ /*002*/ "Electric Grand Piano",
+ /*003*/ "Honky-tonk Piano",
+ /*004*/ "Electric Piano 1",
+ /*005*/ "Electric Piano 2",
+ /*006*/ "Harpsichord",
+ /*007*/ "Clavinet",
+ /*008*/ "Celesta",
+ /*009*/ "Glockenspiel",
+ /*010*/ "Music Box",
+ /*011*/ "Vibraphone",
+ /*012*/ "Marimba",
+ /*013*/ "Xylophone",
+ /*014*/ "Tubular Bells",
+ /*015*/ "Dulcimer",
+ /*016*/ "Drawbar Organ",
+ /*017*/ "Percussive Organ",
+ /*018*/ "Rock Organ",
+ /*019*/ "Church Organ",
+ /*020*/ "Reed Organ",
+ /*021*/ "Accordion",
+ /*022*/ "Harmonica",
+ /*023*/ "Tango Accordion",
+ /*024*/ "Acoustic Guitar (nylon)",
+ /*025*/ "Acoustic Guitar (steel)",
+ /*026*/ "Electric Guitar (jazz)",
+ /*027*/ "Electric Guitar (clean)",
+ /*028*/ "Electric Guitar (muted)",
+ /*029*/ "Overdriven Guitar",
+ /*030*/ "Distortion Guitar",
+ /*031*/ "Guitar Harmonics",
+ /*032*/ "Acoustic Bass",
+ /*033*/ "Electric Bass (finger)",
+ /*034*/ "Electric Bass (pick)",
+ /*035*/ "Fretless Bass",
+ /*036*/ "Slap Bass 1",
+ /*037*/ "Slap Bass 2",
+ /*038*/ "Synth Bass 1",
+ /*039*/ "Synth Bass 2",
+ /*040*/ "Violin",
+ /*041*/ "Viola",
+ /*042*/ "Cello",
+ /*043*/ "Contrabass",
+ /*044*/ "Tremolo Strings",
+ /*045*/ "Pizzicato Strings",
+ /*046*/ "Orchestral Harp",
+ /*047*/ "Timpani",
+ /*048*/ "String Ensemble 1",
+ /*049*/ "String Ensemble 2",
+ /*050*/ "SynthStrings 1",
+ /*051*/ "SynthStrings 2",
+ /*052*/ "Choir Aahs",
+ /*053*/ "Voice Oohs",
+ /*054*/ "Synth Voice",
+ /*055*/ "Orchestra Hit",
+ /*056*/ "Trumpet",
+ /*057*/ "Trombone",
+ /*058*/ "Tuba",
+ /*059*/ "Muted Trumpet",
+ /*060*/ "French Horn",
+ /*061*/ "Brass Section",
+ /*062*/ "SynthBrass 1",
+ /*063*/ "SynthBrass 2",
+ /*064*/ "Soprano Sax",
+ /*065*/ "Alto Sax",
+ /*066*/ "Tenor Sax",
+ /*067*/ "Baritone Sax",
+ /*068*/ "Oboe",
+ /*069*/ "English Horn",
+ /*070*/ "Bassoon",
+ /*071*/ "Clarinet",
+ /*072*/ "Piccolo",
+ /*073*/ "Flute",
+ /*074*/ "Recorder",
+ /*075*/ "Pan Flute",
+ /*076*/ "Blown Bottle",
+ /*077*/ "Shakuhachi",
+ /*078*/ "Whistle",
+ /*079*/ "Ocarina",
+ /*080*/ "Lead 1 (square)",
+ /*081*/ "Lead 2 (sawtooth)",
+ /*082*/ "Lead 3 (calliope)",
+ /*083*/ "Lead 4 (chiff)",
+ /*084*/ "Lead 5 (charang)",
+ /*085*/ "Lead 6 (voice)",
+ /*086*/ "Lead 7 (fifths)",
+ /*087*/ "Lead 8 (bass+lead)",
+ /*088*/ "Pad 1 (new age)",
+ /*089*/ "Pad 2 (warm)",
+ /*090*/ "Pad 3 (polysynth)",
+ /*091*/ "Pad 4 (choir)",
+ /*092*/ "Pad 5 (bowed)",
+ /*093*/ "Pad 6 (metallic)",
+ /*094*/ "Pad 7 (halo)",
+ /*095*/ "Pad 8 (sweep)",
+ /*096*/ "FX 1 (rain)",
+ /*097*/ "FX 2 (soundtrack)",
+ /*098*/ "FX 3 (crystal)",
+ /*099*/ "FX 4 (atmosphere)",
+ /*100*/ "FX 5 (brightness)",
+ /*101*/ "FX 6 (goblins)",
+ /*102*/ "FX 7 (echoes)",
+ /*103*/ "FX 8 (sci-fi)",
+ /*104*/ "Sitar",
+ /*105*/ "Banjo",
+ /*106*/ "Shamisen",
+ /*107*/ "Koto",
+ /*108*/ "Kalimba",
+ /*109*/ "Bag pipe",
+ /*110*/ "Fiddle",
+ /*111*/ "Shannai",
+ /*112*/ "Tinkle Bell",
+ /*113*/ "Agogo",
+ /*114*/ "Steel Drums",
+ /*115*/ "Woodblock",
+ /*116*/ "Taiko Drum",
+ /*117*/ "Melodic Tom",
+ /*118*/ "Synth Drum",
+ /*119*/ "Reverse Cymbal",
+ /*120*/ "Guitar Fret Noise",
+ /*121*/ "Breath Noise",
+ /*122*/ "Seashore",
+ /*123*/ "Bird Tweet",
+ /*124*/ "Telephone Ring",
+ /*125*/ "Helicopter",
+ /*126*/ "Applause",
+ /*127*/ "Gunshot"
+};
+
+// The GM Percussion map is downwards compatible to the MT32 map, which is used in SCI
+static const char *GmPercussionNames[] = {
+ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /*30*/ 0, 0, 0, 0, 0,
+ // The preceeding percussions are not covered by the GM standard
+ /*35*/ "Acoustic Bass Drum",
+ /*36*/ "Bass Drum 1",
+ /*37*/ "Side Stick",
+ /*38*/ "Acoustic Snare",
+ /*39*/ "Hand Clap",
+ /*40*/ "Electric Snare",
+ /*41*/ "Low Floor Tom",
+ /*42*/ "Closed Hi-Hat",
+ /*43*/ "High Floor Tom",
+ /*44*/ "Pedal Hi-Hat",
+ /*45*/ "Low Tom",
+ /*46*/ "Open Hi-Hat",
+ /*47*/ "Low-Mid Tom",
+ /*48*/ "Hi-Mid Tom",
+ /*49*/ "Crash Cymbal 1",
+ /*50*/ "High Tom",
+ /*51*/ "Ride Cymbal 1",
+ /*52*/ "Chinese Cymbal",
+ /*53*/ "Ride Bell",
+ /*54*/ "Tambourine",
+ /*55*/ "Splash Cymbal",
+ /*56*/ "Cowbell",
+ /*57*/ "Crash Cymbal 2",
+ /*58*/ "Vibraslap",
+ /*59*/ "Ride Cymbal 2",
+ /*60*/ "Hi Bongo",
+ /*61*/ "Low Bongo",
+ /*62*/ "Mute Hi Conga",
+ /*63*/ "Open Hi Conga",
+ /*64*/ "Low Conga",
+ /*65*/ "High Timbale",
+ /*66*/ "Low Timbale",
+ /*67*/ "High Agogo",
+ /*68*/ "Low Agogo",
+ /*69*/ "Cabasa",
+ /*70*/ "Maracas",
+ /*71*/ "Short Whistle",
+ /*72*/ "Long Whistle",
+ /*73*/ "Short Guiro",
+ /*74*/ "Long Guiro",
+ /*75*/ "Claves",
+ /*76*/ "Hi Wood Block",
+ /*77*/ "Low Wood Block",
+ /*78*/ "Mute Cuica",
+ /*79*/ "Open Cuica",
+ /*80*/ "Mute Triangle",
+ /*81*/ "Open Triangle"
+};
+
+} // End of namespace Sci
+
+#endif // SCI_SOUND_DRIVERS_GM_NAMES_H
diff --git a/engines/sci/sound/drivers/map-mt32-to-gm.h b/engines/sci/sound/drivers/map-mt32-to-gm.h
index 05d1aeba24..f7a6256ba4 100644
--- a/engines/sci/sound/drivers/map-mt32-to-gm.h
+++ b/engines/sci/sound/drivers/map-mt32-to-gm.h
@@ -23,11 +23,16 @@
*
*/
+#ifndef SCI_SOUND_DRIVERS_MAP_MT32_TO_GM_H
+#define SCI_SOUND_DRIVERS_MAP_MT32_TO_GM_H
+
namespace Sci {
-/* Patch not mapped */
+#include "common/list.h"
+
+// Patch not mapped
#define MIDI_UNMAPPED 0xff
-/* Patch mapped to rhythm key */
+// Patch mapped to rhythm key
#define MIDI_MAPPED_TO_RHYTHM 0xfe
struct Mt32ToGmMap {
@@ -36,193 +41,6 @@ struct Mt32ToGmMap {
uint8 gmRhythmKey;
};
-static const char *GmInstrumentNames[] = {
- /*000*/ "Acoustic Grand Piano",
- /*001*/ "Bright Acoustic Piano",
- /*002*/ "Electric Grand Piano",
- /*003*/ "Honky-tonk Piano",
- /*004*/ "Electric Piano 1",
- /*005*/ "Electric Piano 2",
- /*006*/ "Harpsichord",
- /*007*/ "Clavinet",
- /*008*/ "Celesta",
- /*009*/ "Glockenspiel",
- /*010*/ "Music Box",
- /*011*/ "Vibraphone",
- /*012*/ "Marimba",
- /*013*/ "Xylophone",
- /*014*/ "Tubular Bells",
- /*015*/ "Dulcimer",
- /*016*/ "Drawbar Organ",
- /*017*/ "Percussive Organ",
- /*018*/ "Rock Organ",
- /*019*/ "Church Organ",
- /*020*/ "Reed Organ",
- /*021*/ "Accordion",
- /*022*/ "Harmonica",
- /*023*/ "Tango Accordion",
- /*024*/ "Acoustic Guitar (nylon)",
- /*025*/ "Acoustic Guitar (steel)",
- /*026*/ "Electric Guitar (jazz)",
- /*027*/ "Electric Guitar (clean)",
- /*028*/ "Electric Guitar (muted)",
- /*029*/ "Overdriven Guitar",
- /*030*/ "Distortion Guitar",
- /*031*/ "Guitar Harmonics",
- /*032*/ "Acoustic Bass",
- /*033*/ "Electric Bass (finger)",
- /*034*/ "Electric Bass (pick)",
- /*035*/ "Fretless Bass",
- /*036*/ "Slap Bass 1",
- /*037*/ "Slap Bass 2",
- /*038*/ "Synth Bass 1",
- /*039*/ "Synth Bass 2",
- /*040*/ "Violin",
- /*041*/ "Viola",
- /*042*/ "Cello",
- /*043*/ "Contrabass",
- /*044*/ "Tremolo Strings",
- /*045*/ "Pizzicato Strings",
- /*046*/ "Orchestral Harp",
- /*047*/ "Timpani",
- /*048*/ "String Ensemble 1",
- /*049*/ "String Ensemble 2",
- /*050*/ "SynthStrings 1",
- /*051*/ "SynthStrings 2",
- /*052*/ "Choir Aahs",
- /*053*/ "Voice Oohs",
- /*054*/ "Synth Voice",
- /*055*/ "Orchestra Hit",
- /*056*/ "Trumpet",
- /*057*/ "Trombone",
- /*058*/ "Tuba",
- /*059*/ "Muted Trumpet",
- /*060*/ "French Horn",
- /*061*/ "Brass Section",
- /*062*/ "SynthBrass 1",
- /*063*/ "SynthBrass 2",
- /*064*/ "Soprano Sax",
- /*065*/ "Alto Sax",
- /*066*/ "Tenor Sax",
- /*067*/ "Baritone Sax",
- /*068*/ "Oboe",
- /*069*/ "English Horn",
- /*070*/ "Bassoon",
- /*071*/ "Clarinet",
- /*072*/ "Piccolo",
- /*073*/ "Flute",
- /*074*/ "Recorder",
- /*075*/ "Pan Flute",
- /*076*/ "Blown Bottle",
- /*077*/ "Shakuhachi",
- /*078*/ "Whistle",
- /*079*/ "Ocarina",
- /*080*/ "Lead 1 (square)",
- /*081*/ "Lead 2 (sawtooth)",
- /*082*/ "Lead 3 (calliope)",
- /*083*/ "Lead 4 (chiff)",
- /*084*/ "Lead 5 (charang)",
- /*085*/ "Lead 6 (voice)",
- /*086*/ "Lead 7 (fifths)",
- /*087*/ "Lead 8 (bass+lead)",
- /*088*/ "Pad 1 (new age)",
- /*089*/ "Pad 2 (warm)",
- /*090*/ "Pad 3 (polysynth)",
- /*091*/ "Pad 4 (choir)",
- /*092*/ "Pad 5 (bowed)",
- /*093*/ "Pad 6 (metallic)",
- /*094*/ "Pad 7 (halo)",
- /*095*/ "Pad 8 (sweep)",
- /*096*/ "FX 1 (rain)",
- /*097*/ "FX 2 (soundtrack)",
- /*098*/ "FX 3 (crystal)",
- /*099*/ "FX 4 (atmosphere)",
- /*100*/ "FX 5 (brightness)",
- /*101*/ "FX 6 (goblins)",
- /*102*/ "FX 7 (echoes)",
- /*103*/ "FX 8 (sci-fi)",
- /*104*/ "Sitar",
- /*105*/ "Banjo",
- /*106*/ "Shamisen",
- /*107*/ "Koto",
- /*108*/ "Kalimba",
- /*109*/ "Bag pipe",
- /*110*/ "Fiddle",
- /*111*/ "Shannai",
- /*112*/ "Tinkle Bell",
- /*113*/ "Agogo",
- /*114*/ "Steel Drums",
- /*115*/ "Woodblock",
- /*116*/ "Taiko Drum",
- /*117*/ "Melodic Tom",
- /*118*/ "Synth Drum",
- /*119*/ "Reverse Cymbal",
- /*120*/ "Guitar Fret Noise",
- /*121*/ "Breath Noise",
- /*122*/ "Seashore",
- /*123*/ "Bird Tweet",
- /*124*/ "Telephone Ring",
- /*125*/ "Helicopter",
- /*126*/ "Applause",
- /*127*/ "Gunshot"
-};
-
-/* The GM Percussion map is downwards compatible to the MT32 map, which is used in SCI */
-static const char *GmPercussionNames[] = {
- /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /*30*/ 0, 0, 0, 0, 0,
- /* The preceeding percussions are not covered by the GM standard */
- /*35*/ "Acoustic Bass Drum",
- /*36*/ "Bass Drum 1",
- /*37*/ "Side Stick",
- /*38*/ "Acoustic Snare",
- /*39*/ "Hand Clap",
- /*40*/ "Electric Snare",
- /*41*/ "Low Floor Tom",
- /*42*/ "Closed Hi-Hat",
- /*43*/ "High Floor Tom",
- /*44*/ "Pedal Hi-Hat",
- /*45*/ "Low Tom",
- /*46*/ "Open Hi-Hat",
- /*47*/ "Low-Mid Tom",
- /*48*/ "Hi-Mid Tom",
- /*49*/ "Crash Cymbal 1",
- /*50*/ "High Tom",
- /*51*/ "Ride Cymbal 1",
- /*52*/ "Chinese Cymbal",
- /*53*/ "Ride Bell",
- /*54*/ "Tambourine",
- /*55*/ "Splash Cymbal",
- /*56*/ "Cowbell",
- /*57*/ "Crash Cymbal 2",
- /*58*/ "Vibraslap",
- /*59*/ "Ride Cymbal 2",
- /*60*/ "Hi Bongo",
- /*61*/ "Low Bongo",
- /*62*/ "Mute Hi Conga",
- /*63*/ "Open Hi Conga",
- /*64*/ "Low Conga",
- /*65*/ "High Timbale",
- /*66*/ "Low Timbale",
- /*67*/ "High Agogo",
- /*68*/ "Low Agogo",
- /*69*/ "Cabasa",
- /*70*/ "Maracas",
- /*71*/ "Short Whistle",
- /*72*/ "Long Whistle",
- /*73*/ "Short Guiro",
- /*74*/ "Long Guiro",
- /*75*/ "Claves",
- /*76*/ "Hi Wood Block",
- /*77*/ "Low Wood Block",
- /*78*/ "Mute Cuica",
- /*79*/ "Open Cuica",
- /*80*/ "Mute Triangle",
- /*81*/ "Open Triangle"
-};
-
/*******************************************
* Fancy instrument mappings begin here... *
*******************************************/
@@ -344,19 +162,19 @@ static const Mt32ToGmMap Mt32PresetTimbreMaps[] = {
/*112*/ {"Timpani ", 47, MIDI_UNMAPPED},
/*113*/ {"MelodicTom", 117, MIDI_UNMAPPED},
/*114*/ {"Deep Snare", MIDI_MAPPED_TO_RHYTHM, 38},
- /*115*/ {"Elec Perc1", 115, MIDI_UNMAPPED}, /* ? */
- /*116*/ {"Elec Perc2", 118, MIDI_UNMAPPED}, /* ? */
+ /*115*/ {"Elec Perc1", 115, MIDI_UNMAPPED}, // ?
+ /*116*/ {"Elec Perc2", 118, MIDI_UNMAPPED}, // ?
/*117*/ {"Taiko ", 116, MIDI_UNMAPPED},
/*118*/ {"Taiko Rim ", 118, MIDI_UNMAPPED},
/*119*/ {"Cymbal ", MIDI_MAPPED_TO_RHYTHM, 51},
- /*120*/ {"Castanets ", MIDI_UNMAPPED, MIDI_UNMAPPED},
+ /*120*/ {"Castanets ", MIDI_MAPPED_TO_RHYTHM, 75}, // approximation
/*121*/ {"Triangle ", 112, MIDI_UNMAPPED},
/*122*/ {"Orche Hit ", 55, MIDI_UNMAPPED},
/*123*/ {"Telephone ", 124, MIDI_UNMAPPED},
/*124*/ {"Bird Tweet", 123, MIDI_UNMAPPED},
- /*125*/ {"OneNoteJam", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? */
+ /*125*/ {"OneNoteJam", 8, MIDI_UNMAPPED}, // approximation
/*126*/ {"WaterBells", 98, MIDI_UNMAPPED},
- /*127*/ {"JungleTune", MIDI_UNMAPPED, MIDI_UNMAPPED} /* ? */
+ /*127*/ {"JungleTune", 75, MIDI_UNMAPPED} // approximation
};
static const Mt32ToGmMap Mt32RhythmTimbreMaps[] = {
@@ -414,139 +232,146 @@ static const uint8 Mt32PresetRhythmKeymap[] = {
? - Where do I map this one?
?? - Any good ideas?
??? - I'm clueless?
- R - Rhythm... */
+ R - Rhythm...
+*/
static const Mt32ToGmMap Mt32MemoryTimbreMaps[] = {
- {"AccPnoKA2 ", 1, MIDI_UNMAPPED}, /* ++ (KQ1) */
- {"Acou BD ", MIDI_MAPPED_TO_RHYTHM, 35}, /* R (PQ2) */
- {"Acou SD ", MIDI_MAPPED_TO_RHYTHM, 38}, /* R (PQ2) */
- {"AcouPnoKA ", 0, MIDI_UNMAPPED}, /* ++ (KQ1) */
- {"BASS ", 32, MIDI_UNMAPPED}, /* + (LSL3) */
- {"BASSOONPCM", 70, MIDI_UNMAPPED}, /* + (LB1) */
- {"BEACH WAVE", 122, MIDI_UNMAPPED}, /* + (LSL3) */
+ {"AccPnoKA2 ", 1, MIDI_UNMAPPED}, // ++ (KQ1)
+ {"Acou BD ", MIDI_MAPPED_TO_RHYTHM, 35}, // R (PQ2)
+ {"Acou SD ", MIDI_MAPPED_TO_RHYTHM, 38}, // R (PQ2)
+ {"AcouPnoKA ", 0, MIDI_UNMAPPED}, // ++ (KQ1)
+ {"BASS ", 32, MIDI_UNMAPPED}, // + (LSL3)
+ {"BASSOONPCM", 70, MIDI_UNMAPPED}, // + (LB1)
+ {"BEACH WAVE", 122, MIDI_UNMAPPED}, // + (LSL3)
{"BagPipes ", 109, MIDI_UNMAPPED},
- {"BassPizzMS", 45, MIDI_UNMAPPED}, /* ++ (QFG1) */
- {"BassoonKA ", 70, MIDI_UNMAPPED}, /* ++ (KQ1) */
- {"Bell MS", 112, MIDI_UNMAPPED}, /* ++ (Iceman) */
- {"Bells MS", 112, MIDI_UNMAPPED}, /* + (QFG1) */
- {"Big Bell ", 14, MIDI_UNMAPPED}, /* + (LB1) */
+ {"BassPizzMS", 45, MIDI_UNMAPPED}, // ++ (QFG1)
+ {"BassoonKA ", 70, MIDI_UNMAPPED}, // ++ (KQ1)
+ {"Bell MS", 112, MIDI_UNMAPPED}, // ++ (Iceman)
+ {"Bells MS", 112, MIDI_UNMAPPED}, // + (QFG1)
+ {"Big Bell ", 14, MIDI_UNMAPPED}, // + (LB1)
{"Bird Tweet", 123, MIDI_UNMAPPED},
- {"BrsSect MS", 61, MIDI_UNMAPPED}, /* +++ (Iceman) */
- {"CLAPPING ", 126, MIDI_UNMAPPED}, /* ++ (LSL3) */
- {"Cabasa ", MIDI_MAPPED_TO_RHYTHM, 69}, /* R (Hoyle) */
- {"Calliope ", 82, MIDI_UNMAPPED}, /* +++ (QFG1) */
- {"CelticHarp", 46, MIDI_UNMAPPED}, /* ++ (Camelot) */
- {"Chicago MS", 1, MIDI_UNMAPPED}, /* ++ (Iceman) */
+ {"BrsSect MS", 61, MIDI_UNMAPPED}, // +++ (Iceman)
+ {"CLAPPING ", 126, MIDI_UNMAPPED}, // ++ (LSL3)
+ {"Cabasa ", MIDI_MAPPED_TO_RHYTHM, 69}, // R (Hoyle)
+ {"Calliope ", 82, MIDI_UNMAPPED}, // +++ (QFG1)
+ {"CelticHarp", 46, MIDI_UNMAPPED}, // ++ (Camelot)
+ {"Chicago MS", 1, MIDI_UNMAPPED}, // ++ (Iceman)
{"Chop ", 117, MIDI_UNMAPPED},
- {"Chorale MS", 52, MIDI_UNMAPPED}, /* + (Camelot) */
+ {"Chorale MS", 52, MIDI_UNMAPPED}, // + (Camelot)
{"ClarinetMS", 71, MIDI_UNMAPPED},
- {"Claves ", MIDI_MAPPED_TO_RHYTHM, 75}, /* R (PQ2) */
- {"Claw MS", 118, MIDI_UNMAPPED}, /* + (QFG1) */
- {"ClockBell ", 14, MIDI_UNMAPPED}, /* + (LB1) */
- {"ConcertCym", MIDI_MAPPED_TO_RHYTHM, 55}, /* R ? (KQ1) */
- {"Conga MS", MIDI_MAPPED_TO_RHYTHM, 64}, /* R (QFG1) */
- {"CoolPhone ", 124, MIDI_UNMAPPED}, /* ++ (LSL3) */
- {"CracklesMS", 115, MIDI_UNMAPPED}, /* ? (Camelot, QFG1) */
- {"CreakyD MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ??? (KQ1) */
- {"Cricket ", 120, MIDI_UNMAPPED}, /* ? (LB1) */
- {"CrshCymbMS", MIDI_MAPPED_TO_RHYTHM, 57}, /* R +++ (Iceman) */
- {"CstlGateMS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (QFG1) */
- {"CymSwellMS", MIDI_MAPPED_TO_RHYTHM, 55}, /* R ? (Camelot, QFG1) */
- {"CymbRollKA", MIDI_MAPPED_TO_RHYTHM, 57}, /* R ? (KQ1) */
- {"Cymbal Lo ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* R ? (LSL3) */
- {"card ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (Hoyle) */
- {"DirtGtr MS", 30, MIDI_UNMAPPED}, /* + (Iceman) */
- {"DirtGtr2MS", 29, MIDI_UNMAPPED}, /* + (Iceman) */
- {"E Bass MS", 33, MIDI_UNMAPPED}, /* + (SQ3) */
+ {"Claves ", MIDI_MAPPED_TO_RHYTHM, 75}, // R (PQ2)
+ {"Claw MS", 118, MIDI_UNMAPPED}, // + (QFG1)
+ {"ClockBell ", 14, MIDI_UNMAPPED}, // + (LB1)
+ {"ConcertCym", MIDI_MAPPED_TO_RHYTHM, 55}, // R ? (KQ1)
+ {"Conga MS", MIDI_MAPPED_TO_RHYTHM, 64}, // R (QFG1)
+ {"CoolPhone ", 124, MIDI_UNMAPPED}, // ++ (LSL3)
+ {"CracklesMS", 115, MIDI_UNMAPPED}, // ? (Camelot, QFG1)
+ {"CreakyD MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ??? (KQ1)
+ {"Cricket ", 120, MIDI_UNMAPPED}, // ? (LB1)
+ {"CrshCymbMS", MIDI_MAPPED_TO_RHYTHM, 57}, // R +++ (Iceman)
+ {"CstlGateMS", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (QFG1)
+ {"CymSwellMS", MIDI_MAPPED_TO_RHYTHM, 55}, // R ? (Camelot, QFG1)
+ {"CymbRollKA", MIDI_MAPPED_TO_RHYTHM, 57}, // R ? (KQ1)
+ {"Cymbal Lo ", MIDI_UNMAPPED, MIDI_UNMAPPED}, // R ? (LSL3)
+ {"card ", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (Hoyle)
+ {"DirtGtr MS", 30, MIDI_UNMAPPED}, // + (Iceman)
+ {"DirtGtr2MS", 29, MIDI_UNMAPPED}, // + (Iceman)
+ {"E Bass MS", 33, MIDI_UNMAPPED}, // + (SQ3)
{"ElecBassMS", 33, MIDI_UNMAPPED},
- {"ElecGtr MS", 27, MIDI_UNMAPPED}, /* ++ (Iceman) */
+ {"ElecGtr MS", 27, MIDI_UNMAPPED}, // ++ (Iceman)
{"EnglHornMS", 69, MIDI_UNMAPPED},
{"FantasiaKA", 88, MIDI_UNMAPPED},
- {"Fantasy ", 99, MIDI_UNMAPPED}, /* + (PQ2) */
- {"Fantasy2MS", 99, MIDI_UNMAPPED}, /* ++ (Camelot, QFG1) */
- {"Filter MS", 95, MIDI_UNMAPPED}, /* +++ (Iceman) */
- {"Filter2 MS", 95, MIDI_UNMAPPED}, /* ++ (Iceman) */
- {"Flame2 MS", 121, MIDI_UNMAPPED}, /* ? (QFG1) */
- {"Flames MS", 121, MIDI_UNMAPPED}, /* ? (QFG1) */
- {"Flute MS", 73, MIDI_UNMAPPED}, /* +++ (QFG1) */
+ {"Fantasy ", 99, MIDI_UNMAPPED}, // + (PQ2)
+ {"Fantasy2MS", 99, MIDI_UNMAPPED}, // ++ (Camelot, QFG1)
+ {"Filter MS", 95, MIDI_UNMAPPED}, // +++ (Iceman)
+ {"Filter2 MS", 95, MIDI_UNMAPPED}, // ++ (Iceman)
+ {"Flame2 MS", 121, MIDI_UNMAPPED}, // ? (QFG1)
+ {"Flames MS", 121, MIDI_UNMAPPED}, // ? (QFG1)
+ {"Flute MS", 73, MIDI_UNMAPPED}, // +++ (QFG1)
{"FogHorn MS", 58, MIDI_UNMAPPED},
- {"FrHorn1 MS", 60, MIDI_UNMAPPED}, /* +++ (QFG1) */
- {"FunnyTrmp ", 56, MIDI_UNMAPPED}, /* ++ (LB1) */
+ {"FrHorn1 MS", 60, MIDI_UNMAPPED}, // +++ (QFG1)
+ {"FunnyTrmp ", 56, MIDI_UNMAPPED}, // ++ (LB1)
{"GameSnd MS", 80, MIDI_UNMAPPED},
- {"Glock MS", 9, MIDI_UNMAPPED}, /* +++ (QFG1) */
- {"Gunshot ", 127, MIDI_UNMAPPED}, /* +++ (LB1) */
- {"Hammer MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (QFG1) */
- {"Harmonica2", 22, MIDI_UNMAPPED}, /* +++ (LB1) */
- {"Harpsi 1 ", 6, MIDI_UNMAPPED}, /* + (Hoyle) */
- {"Harpsi 2 ", 6, MIDI_UNMAPPED}, /* +++ (LB1) */
- {"Heart MS", 116, MIDI_UNMAPPED}, /* ? (Iceman) */
- {"Horse1 MS", 115, MIDI_UNMAPPED}, /* ? (Camelot, QFG1) */
- {"Horse2 MS", 115, MIDI_UNMAPPED}, /* ? (Camelot, QFG1) */
- {"InHale MS", 121, MIDI_UNMAPPED}, /* ++ (Iceman) */
- {"KNIFE ", 120, MIDI_UNMAPPED}, /* ? (LSL3) */
- {"KenBanjo ", 105, MIDI_UNMAPPED}, /* +++ (LB1) */
- {"Kiss MS", 25, MIDI_UNMAPPED}, /* ++ (QFG1) */
- {"KongHit ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ??? (KQ1) */
- {"Koto ", 107, MIDI_UNMAPPED}, /* +++ (PQ2) */
- {"Laser MS", 81, MIDI_UNMAPPED}, /* ?? (QFG1) */
- {"Meeps MS", 62, MIDI_UNMAPPED}, /* ? (QFG1) */
- {"MTrak MS", 62, MIDI_UNMAPPED}, /* ?? (Iceman) */
- {"MachGun MS", 127, MIDI_UNMAPPED}, /* ? (Iceman) */
- {"OCEANSOUND", 122, MIDI_UNMAPPED}, /* + (LSL3) */
- {"Oboe 2001 ", 68, MIDI_UNMAPPED}, /* + (PQ2) */
- {"Ocean MS", 122, MIDI_UNMAPPED}, /* + (Iceman) */
- {"PPG 2.3 MS", 75, MIDI_UNMAPPED}, /* ? (Iceman) */
- {"PianoCrank", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (LB1) */
- {"PicSnareMS", MIDI_MAPPED_TO_RHYTHM, 40}, /* R ? (Iceman) */
- {"PiccoloKA ", 72, MIDI_UNMAPPED}, /* +++ (KQ1) */
+ {"Glock MS", 9, MIDI_UNMAPPED}, // +++ (QFG1)
+ {"Gunshot ", 127, MIDI_UNMAPPED}, // +++ (LB1)
+ {"Hammer MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (QFG1)
+ {"Harmonica2", 22, MIDI_UNMAPPED}, // +++ (LB1)
+ {"Harpsi 1 ", 6, MIDI_UNMAPPED}, // + (Hoyle)
+ {"Harpsi 2 ", 6, MIDI_UNMAPPED}, // +++ (LB1)
+ {"Heart MS", 116, MIDI_UNMAPPED}, // ? (Iceman)
+ {"Horse1 MS", 115, MIDI_UNMAPPED}, // ? (Camelot, QFG1)
+ {"Horse2 MS", 115, MIDI_UNMAPPED}, // ? (Camelot, QFG1)
+ {"InHale MS", 121, MIDI_UNMAPPED}, // ++ (Iceman)
+ {"KNIFE ", 120, MIDI_UNMAPPED}, // ? (LSL3)
+ {"KenBanjo ", 105, MIDI_UNMAPPED}, // +++ (LB1)
+ {"Kiss MS", 25, MIDI_UNMAPPED}, // ++ (QFG1)
+ {"KongHit ", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ??? (KQ1)
+ {"Koto ", 107, MIDI_UNMAPPED}, // +++ (PQ2)
+ {"Laser MS", 81, MIDI_UNMAPPED}, // ?? (QFG1)
+ {"Meeps MS", 62, MIDI_UNMAPPED}, // ? (QFG1)
+ {"MTrak MS", 62, MIDI_UNMAPPED}, // ?? (Iceman)
+ {"MachGun MS", 127, MIDI_UNMAPPED}, // ? (Iceman)
+ {"OCEANSOUND", 122, MIDI_UNMAPPED}, // + (LSL3)
+ {"Oboe 2001 ", 68, MIDI_UNMAPPED}, // + (PQ2)
+ {"Ocean MS", 122, MIDI_UNMAPPED}, // + (Iceman)
+ {"PPG 2.3 MS", 75, MIDI_UNMAPPED}, // ? (Iceman)
+ {"PianoCrank", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (LB1)
+ {"PicSnareMS", MIDI_MAPPED_TO_RHYTHM, 40}, // R ? (Iceman)
+ {"PiccoloKA ", 72, MIDI_UNMAPPED}, // +++ (KQ1)
{"PinkBassMS", 39, MIDI_UNMAPPED},
- {"Pizz2 ", 45, MIDI_UNMAPPED}, /* ++ (LB1) */
- {"Portcullis", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (KQ1) */
- {"Raspbry MS", 81, MIDI_UNMAPPED}, /* ? (QFG1) */
- {"RatSqueek ", 72, MIDI_UNMAPPED}, /* ? (LauraBow1, Camelot) */
- {"Record78 ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* +++ (LB1) */
- {"RecorderMS", 74, MIDI_UNMAPPED}, /* +++ (Camelot) */
- {"Red Baron ", 125, MIDI_UNMAPPED}, /* ? (LB1) */
- {"ReedPipMS ", 20, MIDI_UNMAPPED}, /* +++ (Camelot) */
+ {"Pizz2 ", 45, MIDI_UNMAPPED}, // ++ (LB1)
+ {"Portcullis", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (KQ1)
+ {"Raspbry MS", 81, MIDI_UNMAPPED}, // ? (QFG1)
+ {"RatSqueek ", 72, MIDI_UNMAPPED}, // ? (LauraBow1, Camelot)
+ {"Record78 ", MIDI_UNMAPPED, MIDI_UNMAPPED}, // +++ (LB1)
+ {"RecorderMS", 74, MIDI_UNMAPPED}, // +++ (Camelot)
+ {"Red Baron ", 125, MIDI_UNMAPPED}, // ? (LB1)
+ {"ReedPipMS ", 20, MIDI_UNMAPPED}, // +++ (Camelot)
{"RevCymb MS", 119, MIDI_UNMAPPED},
- {"RifleShot ", 127, MIDI_UNMAPPED}, /* + (LB1) */
- {"RimShot MS", MIDI_MAPPED_TO_RHYTHM, 37}, /* R */
- {"SHOWER ", 52, MIDI_UNMAPPED}, /* ? (LSL3) */
- {"SQ Bass MS", 32, MIDI_UNMAPPED}, /* + (SQ3) */
- {"ShakuVibMS", 79, MIDI_UNMAPPED}, /* + (Iceman) */
- {"SlapBassMS", 36, MIDI_UNMAPPED}, /* +++ (Iceman) */
- {"Snare MS", MIDI_MAPPED_TO_RHYTHM, 38}, /* R (QFG1) */
- {"Some Birds", 123, MIDI_UNMAPPED}, /* + (LB1) */
- {"Sonar MS", 78, MIDI_UNMAPPED}, /* ? (Iceman) */
- {"Soundtrk2 ", 97, MIDI_UNMAPPED}, /* +++ (LB1) */
- {"Soundtrack", 97, MIDI_UNMAPPED}, /* ++ (Camelot) */
+ {"RifleShot ", 127, MIDI_UNMAPPED}, // + (LB1)
+ {"RimShot MS", MIDI_MAPPED_TO_RHYTHM, 37}, // R
+ {"SHOWER ", 52, MIDI_UNMAPPED}, // ? (LSL3)
+ {"SQ Bass MS", 32, MIDI_UNMAPPED}, // + (SQ3)
+ {"ShakuVibMS", 79, MIDI_UNMAPPED}, // + (Iceman)
+ {"SlapBassMS", 36, MIDI_UNMAPPED}, // +++ (Iceman)
+ {"Snare MS", MIDI_MAPPED_TO_RHYTHM, 38}, // R (QFG1)
+ {"Some Birds", 123, MIDI_UNMAPPED}, // + (LB1)
+ {"Sonar MS", 78, MIDI_UNMAPPED}, // ? (Iceman)
+ {"Soundtrk2 ", 97, MIDI_UNMAPPED}, // +++ (LB1)
+ {"Soundtrack", 97, MIDI_UNMAPPED}, // ++ (Camelot)
{"SqurWaveMS", 80, MIDI_UNMAPPED},
- {"StabBassMS", 34, MIDI_UNMAPPED}, /* + (Iceman) */
- {"SteelDrmMS", 114, MIDI_UNMAPPED}, /* +++ (Iceman) */
- {"StrSect1MS", 48, MIDI_UNMAPPED}, /* ++ (QFG1) */
- {"String MS", 45, MIDI_UNMAPPED}, /* + (Camelot) */
+ {"StabBassMS", 34, MIDI_UNMAPPED}, // + (Iceman)
+ {"SteelDrmMS", 114, MIDI_UNMAPPED}, // +++ (Iceman)
+ {"StrSect1MS", 48, MIDI_UNMAPPED}, // ++ (QFG1)
+ {"String MS", 45, MIDI_UNMAPPED}, // + (Camelot)
{"Syn-Choir ", 91, MIDI_UNMAPPED},
- {"Syn Brass4", 63, MIDI_UNMAPPED}, /* ++ (PQ2) */
+ {"Syn Brass4", 63, MIDI_UNMAPPED}, // ++ (PQ2)
{"SynBass MS", 38, MIDI_UNMAPPED},
- {"SwmpBackgr", 120, MIDI_UNMAPPED}, /* ?? (LB1, QFG1) */
- {"T-Bone2 MS", 57, MIDI_UNMAPPED}, /* +++ (QFG1) */
- {"Taiko ", 116, 35}, /* +++ (Camelot) */
- {"Taiko Rim ", 118, 37}, /* +++ (LSL3) */
- {"Timpani1 ", 47, MIDI_UNMAPPED}, /* +++ (LB1) */
- {"Tom MS", 117, 48}, /* +++ (Iceman) */
- {"Toms MS", 117, 48}, /* +++ (Camelot, QFG1) */
- {"Tpt1prtl ", 56, MIDI_UNMAPPED}, /* +++ (KQ1) */
- {"TriangleMS", 112, 81}, /* R (Camelot) */
- {"Trumpet 1 ", 56, MIDI_UNMAPPED}, /* +++ (Camelot) */
- {"Type MS", MIDI_MAPPED_TO_RHYTHM, 39}, /* + (Iceman) */
- {"WaterBells", 98, MIDI_UNMAPPED}, /* + (PQ2) */
- {"WaterFallK", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (KQ1) */
- {"Whiporill ", 123, MIDI_UNMAPPED}, /* + (LB1) */
- {"Wind ", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (LB1) */
- {"Wind MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (QFG1, Iceman) */
- {"Wind2 MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (Camelot) */
- {"Woodpecker", 115, MIDI_UNMAPPED}, /* ? (LB1) */
- {"WtrFall MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, /* ? (Camelot, QFG1, Iceman) */
+ {"SwmpBackgr", 120, MIDI_UNMAPPED}, // ?? (LB1, QFG1)
+ {"T-Bone2 MS", 57, MIDI_UNMAPPED}, // +++ (QFG1)
+ {"Taiko ", 116, 35}, // +++ (Camelot)
+ {"Taiko Rim ", 118, 37}, // +++ (LSL3)
+ {"Timpani1 ", 47, MIDI_UNMAPPED}, // +++ (LB1)
+ {"Tom MS", 117, 48}, // +++ (Iceman)
+ {"Toms MS", 117, 48}, // +++ (Camelot, QFG1)
+ {"Tpt1prtl ", 56, MIDI_UNMAPPED}, // +++ (KQ1)
+ {"TriangleMS", 112, 81}, // R (Camelot)
+ {"Trumpet 1 ", 56, MIDI_UNMAPPED}, // +++ (Camelot)
+ {"Type MS", MIDI_MAPPED_TO_RHYTHM, 39}, // + (Iceman)
+ {"Warm Pad" , 89, MIDI_UNMAPPED}, // ++ (PQ3)
+ {"WaterBells", 98, MIDI_UNMAPPED}, // + (PQ2)
+ {"WaterFallK", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (KQ1)
+ {"Whiporill ", 123, MIDI_UNMAPPED}, // + (LB1)
+ {"Wind ", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (LB1)
+ {"Wind MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (QFG1, Iceman)
+ {"Wind2 MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (Camelot)
+ {"Woodpecker", 115, MIDI_UNMAPPED}, // ? (LB1)
+ {"WtrFall MS", MIDI_UNMAPPED, MIDI_UNMAPPED}, // ? (Camelot, QFG1, Iceman)
{0, 0, 0}
};
+ typedef Common::List<Mt32ToGmMap> Mt32ToGmMapList;
+ extern Mt32ToGmMapList *Mt32dynamicMappings;
+
} // End of namespace Sci
+
+#endif // SCI_SOUND_DRIVERS_MAP_MT32_TO_GM_H
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 8ba7a6a352..6611753420 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -32,11 +32,14 @@
#include "sound/softsynth/emumidi.h"
#include "sci/resource.h"
+#include "sci/sound/drivers/gm_names.h"
#include "sci/sound/drivers/mididriver.h"
#include "sci/sound/drivers/map-mt32-to-gm.h"
namespace Sci {
+Mt32ToGmMapList *Mt32dynamicMappings = NULL;
+
class MidiPlayer_Midi : public MidiPlayer {
public:
enum {
@@ -131,10 +134,21 @@ MidiPlayer_Midi::MidiPlayer_Midi(SciVersion version) : MidiPlayer(version), _pla
_sysExBuf[1] = 0x10;
_sysExBuf[2] = 0x16;
_sysExBuf[3] = 0x12;
+
+ Mt32dynamicMappings = new Mt32ToGmMapList();
}
MidiPlayer_Midi::~MidiPlayer_Midi() {
delete _driver;
+
+ const Mt32ToGmMapList::iterator end = Mt32dynamicMappings->end();
+ for (Mt32ToGmMapList::iterator it = Mt32dynamicMappings->begin(); it != end; ++it) {
+ delete[] (*it).name;
+ (*it).name = 0;
+ }
+
+ Mt32dynamicMappings->clear();
+ delete Mt32dynamicMappings;
}
void MidiPlayer_Midi::noteOn(int channel, int note, int velocity) {
@@ -615,22 +629,40 @@ void MidiPlayer_Midi::readMt32DrvData() {
byte MidiPlayer_Midi::lookupGmInstrument(const char *iname) {
int i = 0;
+ if (Mt32dynamicMappings != NULL) {
+ const Mt32ToGmMapList::iterator end = Mt32dynamicMappings->end();
+ for (Mt32ToGmMapList::iterator it = Mt32dynamicMappings->begin(); it != end; ++it) {
+ if (scumm_strnicmp(iname, (*it).name, 10) == 0)
+ return getGmInstrument((*it));
+ }
+ }
+
while (Mt32MemoryTimbreMaps[i].name) {
if (scumm_strnicmp(iname, Mt32MemoryTimbreMaps[i].name, 10) == 0)
return getGmInstrument(Mt32MemoryTimbreMaps[i]);
i++;
}
+
return MIDI_UNMAPPED;
}
byte MidiPlayer_Midi::lookupGmRhythmKey(const char *iname) {
int i = 0;
+ if (Mt32dynamicMappings != NULL) {
+ const Mt32ToGmMapList::iterator end = Mt32dynamicMappings->end();
+ for (Mt32ToGmMapList::iterator it = Mt32dynamicMappings->begin(); it != end; ++it) {
+ if (scumm_strnicmp(iname, (*it).name, 10) == 0)
+ return (*it).gmRhythmKey;
+ }
+ }
+
while (Mt32MemoryTimbreMaps[i].name) {
if (scumm_strnicmp(iname, Mt32MemoryTimbreMaps[i].name, 10) == 0)
return Mt32MemoryTimbreMaps[i].gmRhythmKey;
i++;
}
+
return MIDI_UNMAPPED;
}
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 0dfa02c83f..252ea5489c 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -158,8 +158,10 @@ void SciMusic::sendMidiCommandsFromQueue() {
}
void SciMusic::clearPlayList() {
- Common::StackLock lock(_mutex);
-
+ // we must NOT lock our mutex here. Playlist is modified inside soundKill() which will lock the mutex
+ // during deletion. If we lock it here, a deadlock may occur within soundStop() because that one
+ // calls the mixer, which will also lock the mixer mutex and if the mixer thread is active during
+ // that time, we will get a deadlock.
while (!_playList.empty()) {
soundStop(_playList[0]);
soundKill(_playList[0]);
diff --git a/engines/sci/sound/soundcmd.h b/engines/sci/sound/soundcmd.h
index 61371d903f..b457ad4618 100644
--- a/engines/sci/sound/soundcmd.h
+++ b/engines/sci/sound/soundcmd.h
@@ -53,7 +53,7 @@ public:
// Functions used for game state loading
void clearPlayList();
void syncPlayList(Common::Serializer &s);
- void reconstructPlayList(int savegame_version);
+ void reconstructPlayList();
// Functions used for the ScummVM menus
void setMasterVolume(int vol);
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 1bcb065b25..ca1dc8869f 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -691,6 +691,7 @@ void Actor_v3::walkActor() {
int Actor::remapDirection(int dir, bool is_walking) {
int specdir;
byte flags;
+ byte mask;
bool flipX;
bool flipY;
@@ -769,6 +770,14 @@ int Actor::remapDirection(int dir, bool is_walking) {
case 6:
return 180;
}
+
+ // MM C64 stores flags as a part of the mask
+ if (_vm->_game.version == 0) {
+ mask = _vm->getMaskFromBox(_walkbox);
+ // face the wall if climbing/descending a ladder
+ if ((mask & 0x8C) == 0x84)
+ return 0;
+ }
}
// OR 1024 in to signal direction interpolation should be done
return normalizeAngle(dir) | 1024;
@@ -1043,9 +1052,17 @@ static int checkXYInBoxBounds(int boxnum, int x, int y, int &destX, int &destY)
// yDist must be divided by 4, as we are using 8x2 pixels
// blocks for actor coordinates).
int xDist = ABS(x - destX);
- int yDist = ABS(y - destY) / 4;
+ int yDist;
int dist;
+ // MM C64: This fixes the trunk bug (#3070065), as well
+ // as the fruit bowl, however im not sure if its
+ // the proper solution or not.
+ if( g_scumm->_game.version == 0 )
+ yDist = ABS(y - destY);
+ else
+ yDist = ABS(y - destY) / 4;
+
if (xDist < yDist)
dist = (xDist >> 1) + yDist;
else
@@ -1073,6 +1090,7 @@ AdjustBoxResult Actor_v2::adjustXYToBeInBox(const int dstX, const int dstY) {
abr.x = foundX;
abr.y = foundY;
abr.box = box;
+
break;
}
if (dist < bestDist) {
@@ -2259,7 +2277,7 @@ void Actor::setActorCostume(int c) {
}
}
-static const char* v0ActorNames[0x19] = {
+static const char* v0ActorNames_English[25] = {
"Syd",
"Razor",
"Dave",
@@ -2275,10 +2293,36 @@ static const char* v0ActorNames[0x19] = {
"Purple Tentacle",
"Green Tentacle",
"Meteor",
+ "",
+ "",
+ "",
"Plant",
"",
"",
"",
+ "Sandy"
+};
+
+static const char* v0ActorNames_German[25] = {
+ "Syd",
+ "Razor",
+ "Dave",
+ "Michael",
+ "Bernard",
+ "Wendy",
+ "Jeff",
+ "",
+ "Dr.Fred",
+ "Schwester Edna",
+ "Weird Ed",
+ "Ted",
+ "Lila Tentakel",
+ "Gr<nes Tentakel",
+ "Meteor",
+ "",
+ "",
+ "",
+ "Pflanze",
"",
"",
"",
@@ -2289,8 +2333,15 @@ const byte *Actor::getActorName() {
const byte *ptr = NULL;
if (_vm->_game.version == 0) {
- if (_number)
- ptr = (const byte *)v0ActorNames[_number - 1];
+ if (_number) {
+ switch (_vm->_language) {
+ case Common::DE_DEU:
+ ptr = (const byte *)v0ActorNames_German[_number - 1];
+ break;
+ default:
+ ptr = (const byte *)v0ActorNames_English[_number - 1];
+ }
+ }
} else {
ptr = _vm->getResourceAddress(rtActorName, _number);
}
@@ -2561,6 +2612,21 @@ void ScummEngine_v71he::queueAuxEntry(int actorNum, int subIndex) {
#endif
+void ActorC64::saveLoadWithSerializer(Serializer *ser) {
+ Actor::saveLoadWithSerializer(ser);
+
+ static const SaveLoadEntry actorEntries[] = {
+ MKLINE(ActorC64, _costCommand, sleByte, VER(84)),
+ MKLINE(ActorC64, _costFrame, sleByte, VER(84)),
+ MKLINE(ActorC64, _miscflags, sleByte, VER(84)),
+ MKLINE(ActorC64, _speaking, sleByte, VER(84)),
+ MKLINE(ActorC64, _speakingPrev, sleByte, VER(84)),
+ MKEND()
+ };
+
+ ser->saveLoadEntries(this, actorEntries);
+}
+
void Actor::saveLoadWithSerializer(Serializer *ser) {
static const SaveLoadEntry actorEntries[] = {
MKLINE(Actor, _pos.x, sleInt16, VER(8)),
diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h
index 88ba9902b4..98854ec5ba 100644
--- a/engines/scumm/actor.h
+++ b/engines/scumm/actor.h
@@ -305,7 +305,7 @@ public:
void classChanged(int cls, bool value);
// Used by the save/load system:
- void saveLoadWithSerializer(Serializer *ser);
+ virtual void saveLoadWithSerializer(Serializer *ser);
protected:
bool isInClass(int cls);
@@ -381,14 +381,16 @@ protected:
class ActorC64 : public Actor_v2 {
public:
- // FIXME: These vars are never saved, which might lead to broken save states.
- byte _miscflags;
- byte _speaking, _speakingPrev;
byte _costCommand, _costFrame;
+ byte _miscflags; // 0x1: strong, 0x8: Ed's enemy, 0x40: stop moving, 0x80: hide(dead/radiation suit)
+ byte _speaking, _speakingPrev;
public:
ActorC64(ScummEngine *scumm, int id) : Actor_v2(scumm, id) {
- _speaking = _speakingPrev = _costCommand = _costFrame = 0;
+ _costCommand = 0;
+ _costFrame = 0;
+ _speaking = 0;
+ _speakingPrev = 0;
}
virtual void initActor(int mode) {
Actor_v2::initActor(mode);
@@ -397,6 +399,9 @@ public:
}
}
+ // Used by the save/load system:
+ virtual void saveLoadWithSerializer(Serializer *ser);
+
protected:
};
diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp
index d5d6b6182b..354a1d4491 100644
--- a/engines/scumm/akos.cpp
+++ b/engines/scumm/akos.cpp
@@ -1087,10 +1087,10 @@ void AkosRenderer::akos16SetupBitReader(const byte *src) {
}
#define AKOS16_FILL_BITS() \
- if (_akos16.numbits <= 8) { \
- _akos16.bits |= (*_akos16.dataptr++) << _akos16.numbits; \
- _akos16.numbits += 8; \
- }
+ if (_akos16.numbits <= 8) { \
+ _akos16.bits |= (*_akos16.dataptr++) << _akos16.numbits; \
+ _akos16.numbits += 8; \
+ }
#define AKOS16_EAT_BITS(n) \
_akos16.numbits -= (n); \
diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp
index dc6f10696f..15d5f04ed5 100644
--- a/engines/scumm/boxes.cpp
+++ b/engines/scumm/boxes.cpp
@@ -614,10 +614,8 @@ BoxCoords ScummEngine::getBoxCoordinates(int boxnum) {
box->lr.x = bp->c64.x2;
box->lr.y = bp->c64.y2;
- if (bp->c64.mask & 0x88) {
+ if ((bp->c64.mask & 0x88) == 0x88) {
// walkbox for (right/left) corner
- // TODO: ladders (incl. man-eating plant) have mask 0x8A,
- // must those walkboxes be adjusted?
if (bp->c64.mask & 0x04)
box->ur = box->ul;
else
@@ -923,32 +921,32 @@ bool Actor::findPathTowards(byte box1nr, byte box2nr, byte box3nr, Common::Point
static void printMatrix(byte *boxm, int num) {
int i;
for (i = 0; i < num; i++) {
- printf("%d: ", i);
+ debugN("%d: ", i);
while (*boxm != 0xFF) {
- printf("%d, ", *boxm);
+ debug("%d, ", *boxm);
boxm++;
}
boxm++;
- printf("\n");
+ debug("\n");
}
}
static void printMatrix2(byte *matrix, int num) {
int i, j;
- printf(" ");
+ debug(" ");
for (i = 0; i < num; i++)
- printf("%2d ", i);
- printf("\n");
+ debug("%2d ", i);
+ debug("\n");
for (i = 0; i < num; i++) {
- printf("%2d: ", i);
+ debug("%2d: ", i);
for (j = 0; j < num; j++) {
int val = matrix[i * num + j];
if (val == Actor::kInvalidBox)
- printf(" ? ");
+ debug(" ? ");
else
- printf("%2d ", val);
+ debug("%2d ", val);
}
- printf("\n");
+ debug("\n");
}
}
#endif
@@ -1055,9 +1053,9 @@ void ScummEngine::createBoxMatrix() {
#if BOX_DEBUG
- printf("Itinerary matrix:\n");
+ debug("Itinerary matrix:\n");
printMatrix2(itineraryMatrix, num);
- printf("compressed matrix:\n");
+ debug("compressed matrix:\n");
printMatrix(getBoxMatrixBaseAddr(), num);
#endif
diff --git a/engines/scumm/charset-fontdata.cpp b/engines/scumm/charset-fontdata.cpp
index 904e40d9ea..378e8e9d8d 100644
--- a/engines/scumm/charset-fontdata.cpp
+++ b/engines/scumm/charset-fontdata.cpp
@@ -589,20 +589,20 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language)
b = data[offset+3];
len = data[offset+4];
while (len--) {
- printf("0x%02x, ", b);
+ debugN("0x%02x, ", b);
count++;
if (count % 8 == 0)
- printf("\n");
+ debugN("\n");
}
offset += 6;
} else {
- printf("0x%02x, ", data[offset]);
+ debugN("0x%02x, ", data[offset]);
count++;
if (count % 8 == 0)
- printf("\n");
+ debugN("\n");
}
}
- printf("\n");
+ debugN("\n");
_vm->_system->quit();
#endif
}
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 5b33fee742..8d7f9c9e9f 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -55,20 +55,12 @@ void ScummEngine::loadCJKFont() {
#ifdef DISABLE_TOWNS_DUAL_LAYER_MODE
error("FM-Towns Kanji font drawing requires dual graphics layer support which is disabled in this build");
#endif
- int numChar = 256 * 32;
- _2byteWidth = 16;
- _2byteHeight = 16;
- // use FM-TOWNS font rom, since game files don't have kanji font resources
- if (!fp.open("fmt_fnt.rom")) {
- error("SCUMM::Font: Couldn't open fmt_fnt.rom");
- } else {
- _useCJKMode = true;
- debug(2, "Loading FM-TOWNS Kanji rom");
- _2byteFontPtr = new byte[((_2byteWidth + 7) / 8) * _2byteHeight * numChar];
- fp.read(_2byteFontPtr, ((_2byteWidth + 7) / 8) * _2byteHeight * numChar);
- fp.close();
- }
+ // use FM-TOWNS font rom, since game files don't have kanji font resources
+ _cjkFont = Graphics::FontSJIS::createFont(Common::kPlatformFMTowns);
+ if (!_cjkFont)
+ error("SCUMM::Font: Couldn't open file 'FMT_FNT.ROM'");
_textSurfaceMultiplier = 2;
+ _useCJKMode = true;
} else if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine && _language == Common::JA_JPN) {
int numChar = 3418;
_2byteWidth = 12;
@@ -170,90 +162,6 @@ void ScummEngine::loadCJKFont() {
}
}
-static int SJIStoFMTChunk(int f, int s) { //converts sjis code to fmt font offset
- enum {
- KANA = 0,
- KANJI = 1,
- EKANJI = 2
- };
- int base = s - ((s + 1) % 32);
- int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA;
-
- if (f >= 0x81 && f <= 0x84) kanjiType = KANA;
- if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI;
- if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI;
-
- if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) {
- c = 48; //correction
- p = -8; //correction
- }
-
- if (kanjiType == KANA) {//Kana
- chunk_f = (f - 0x81) * 2;
- } else if (kanjiType == KANJI) {//Standard Kanji
- p += f - 0x88;
- chunk_f = c + 2 * p;
- } else if (kanjiType == EKANJI) {//Enhanced Kanji
- p += f - 0xe0;
- chunk_f = c + 2 * p;
- }
-
- // Base corrections
- if (base == 0x7f && s == 0x7f)
- base -= 0x20;
- if (base == 0x9f && s == 0xbe)
- base += 0x20;
- if (base == 0xbf && s == 0xde)
- base += 0x20;
- //if (base == 0x7f && s == 0x9e)
- // base += 0x20;
-
- switch (base) {
- case 0x3f:
- cr = 0; //3f
- if (kanjiType == KANA) chunk = 1;
- else if (kanjiType == KANJI) chunk = 31;
- else if (kanjiType == EKANJI) chunk = 111;
- break;
- case 0x5f:
- cr = 0; //5f
- if (kanjiType == KANA) chunk = 17;
- else if (kanjiType == KANJI) chunk = 47;
- else if (kanjiType == EKANJI) chunk = 127;
- break;
- case 0x7f:
- cr = -1; //80
- if (kanjiType == KANA) chunk = 9;
- else if (kanjiType == KANJI) chunk = 63;
- else if (kanjiType == EKANJI) chunk = 143;
- break;
- case 0x9f:
- cr = 1; //9e
- if (kanjiType == KANA) chunk = 2;
- else if (kanjiType == KANJI) chunk = 32;
- else if (kanjiType == EKANJI) chunk = 112;
- break;
- case 0xbf:
- cr = 1; //be
- if (kanjiType == KANA) chunk = 18;
- else if (kanjiType == KANJI) chunk = 48;
- else if (kanjiType == EKANJI) chunk = 128;
- break;
- case 0xdf:
- cr = 1; //de
- if (kanjiType == KANA) chunk = 10;
- else if (kanjiType == KANJI) chunk = 64;
- else if (kanjiType == EKANJI) chunk = 144;
- break;
- default:
- debug(4, "Invalid Char! f %x s %x base %x c %d p %d", f, s, base, c, p);
- return 0;
- }
-
- debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr);
- return ((chunk_f + chunk) * 32 + (s - base)) + cr;
-}
-
static int SJIStoPCEChunk(int f, int s) { //converts sjis code to pce font offset
// rangeTbl maps SJIS char-codes to the PCE System Card font rom.
// Each pair {<upperBound>,<lowerBound>} in the array represents a SJIS range.
@@ -330,9 +238,8 @@ byte *ScummEngine::get2byteCharPtr(int idx) {
}
idx = (SWAP_CONSTANT_16(idx) & 0x7fff) - 1;
- } else {
- idx = SJIStoFMTChunk((idx % 256), (idx / 256));
}
+
break;
case Common::ZH_TWN:
{
@@ -458,11 +365,11 @@ void CharsetRendererV3::setCurID(int32 id) {
int CharsetRendererCommon::getFontHeight() {
if (_vm->_useCJKMode) {
if (_vm->_game.platform == Common::kPlatformFMTowns) {
- static const uint8 sjisFontHeightM1[] = { 0, 9, 10, 9, 10, 9, 10, 0, 0 };
- static const uint8 sjisFontHeightM2[] = { 8, 8, 9, 9, 9, 8, 9, 9, 9, 8 };
- static const uint8 sjisFontHeightI4[] = { 8, 8, 9, 9, 9, 8, 8, 8, 8, 8 };
+ static const uint8 sjisFontHeightM1[] = { 0, 8, 9, 8, 9, 8, 9, 0, 0, 0 };
+ static const uint8 sjisFontHeightM2[] = { 0, 8, 9, 9, 9, 8, 9, 9, 9, 8 };
+ static const uint8 sjisFontHeightI4[] = { 0, 8, 9, 9, 9, 8, 8, 8, 8, 8 };
const uint8 *htbl = (_vm->_game.id == GID_MONKEY) ? sjisFontHeightM1 : ((_vm->_game.id == GID_INDY4) ? sjisFontHeightI4 : sjisFontHeightM2);
- return htbl[_curId];
+ return (_vm->_game.version == 3) ? 8 : htbl[_curId];
} else {
return MAX(_vm->_2byteHeight + 1, _fontHeight);
}
@@ -474,26 +381,29 @@ int CharsetRendererCommon::getFontHeight() {
int CharsetRendererClassic::getCharWidth(uint16 chr) {
int spacing = 0;
- if (_vm->_game.platform == Common::kPlatformFMTowns) {
- if (_vm->_useCJKMode) {
+ if (_vm->_useCJKMode) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
if ((chr & 0xff00) == 0xfd00) {
chr &= 0xff;
} else if (chr >= 256) {
- spacing = 9;
- } else if (chr >= 128) {
- spacing = 5;
+ spacing = 8;
+ } else if (useTownsFontRomCharacter(chr)) {
+ spacing = 4;
}
if (spacing) {
- static const uint8 sjisWidthM1[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
- static const uint8 sjisWidthM2[] = { 0, 1, 1, 1, 1, 0, 1, 1, 1, 0 };
- static const uint8 sjisWidthI4[] = { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 };
- const uint8 *wtbl = (_vm->_game.id == GID_MONKEY) ? sjisWidthM1 : ((_vm->_game.id == GID_INDY4) ? sjisWidthI4 : sjisWidthM2);
- spacing += wtbl[_curId];
+ if (_vm->_game.id == GID_MONKEY) {
+ spacing++;
+ if (_curId == 2)
+ spacing++;
+ } else if (_vm->_game.id != GID_INDY4 && _curId == 1) {
+ spacing++;
+ }
}
+
+ } else if (chr >= 0x80) {
+ return _vm->_2byteWidth / 2;
}
- } else if (chr >= 0x80 && _vm->_useCJKMode) {
- return _vm->_2byteWidth / 2;
}
if (!spacing) {
@@ -506,10 +416,26 @@ int CharsetRendererClassic::getCharWidth(uint16 chr) {
return spacing;
}
+bool CharsetRendererClassic::useTownsFontRomCharacter(uint16 chr) {
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (_vm->_game.platform != Common::kPlatformFMTowns || !_vm->_useCJKMode)
+ return false;
+
+ if (chr < 128) {
+ if (((_vm->_game.id == GID_MONKEY2 && _curId != 0) || (_vm->_game.id == GID_INDY4 && _curId != 3)) && (chr > 31 && chr != 94 && chr != 95 && chr != 126 && chr != 127))
+ return true;
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
int CharsetRenderer::getStringWidth(int arg, const byte *text) {
int pos = 0;
int width = 1;
- uint16 chr;
+ int chr;
int oldID = getCurID();
int code = (_vm->_game.heversion >= 80) ? 127 : 64;
@@ -570,8 +496,10 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
if (_vm->_useCJKMode) {
if (_vm->_game.platform == Common::kPlatformFMTowns) {
- if ((chr >= 0x80 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfd))
- chr = (chr << 8) | text[pos++];
+ if (checkSJISCode(chr))
+ // This strange character conversion is the exact way the original does it here.
+ // This is the only way to get an accurate text formatting in the MI1 intro.
+ chr = (int8)text[pos++] | (chr << 8);
} else if (chr & 0x80) {
pos++;
width += _vm->_2byteWidth;
@@ -589,7 +517,7 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
int lastspace = -1;
int curw = 1;
- byte chr;
+ int chr;
int oldID = getCurID();
int code = (_vm->_game.heversion >= 80) ? 127 : 64;
@@ -651,9 +579,17 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
if (chr == _vm->_newLineCharacter)
lastspace = pos - 1;
- if ((chr & 0x80) && _vm->_useCJKMode) {
- pos++;
- curw += _vm->_2byteWidth;
+ if (_vm->_useCJKMode) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ if (checkSJISCode(chr))
+ // This strange character conversion is the exact way the original does it here.
+ // This is the only way to get an accurate text formatting in the MI1 intro.
+ chr = (int8)str[pos++] | (chr << 8);
+ curw += getCharWidth(chr);
+ } else if (chr & 0x80) {
+ pos++;
+ curw += _vm->_2byteWidth;
+ }
} else {
curw += getCharWidth(chr);
}
@@ -671,11 +607,21 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
}
int CharsetRendererV3::getCharWidth(uint16 chr) {
- if (chr & 0x80 && _vm->_useCJKMode)
- return _vm->_2byteWidth / 2;
int spacing = 0;
- spacing = *(_widthTable + chr);
+ if (_vm->_useCJKMode) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ if (chr >= 256)
+ spacing = 8;
+ else if (chr >= 128)
+ spacing = 4;
+ } else if (chr & 0x80) {
+ spacing = _vm->_2byteWidth / 2;
+ }
+ }
+
+ if (!spacing)
+ spacing = *(_widthTable + chr);
return spacing;
}
@@ -719,11 +665,23 @@ void CharsetRendererPCE::setColor(byte color) {
void CharsetRendererCommon::enableShadow(bool enable) {
if (enable) {
if (_vm->_game.platform == Common::kPlatformFMTowns) {
- _shadowColor =
+ _shadowColor = 8;
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
- _vm->_game.version == 5 ? _vm->_townsCharsetColorMap[0] : 0x88;
-#else
- 8;
+ _shadowColor = _vm->_game.version == 5 ? _vm->_townsCharsetColorMap[0] : 0x88;
+ if (_vm->_cjkFont) {
+ if (_vm->_game.version == 5) {
+ if (((_vm->_game.id == GID_MONKEY) && (_curId == 2 || _curId == 4 || _curId == 6)) ||
+ ((_vm->_game.id == GID_MONKEY2) && (_curId != 1 && _curId != 5 && _curId != 9)) ||
+ ((_vm->_game.id == GID_INDY4) && (_curId == 2 || _curId == 3 || _curId == 4))) {
+ _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kOutlineMode);
+ } else {
+ _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kDefaultMode);
+ }
+ _vm->_cjkFont->toggleFlippedMode((_vm->_game.id == GID_MONKEY || _vm->_game.id == GID_MONKEY2) && _curId == 3);
+ } else {
+ _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kShadowMode);
+ }
+ }
#endif
_shadowMode = kFMTOWNSShadowMode;
} else {
@@ -731,6 +689,10 @@ void CharsetRendererCommon::enableShadow(bool enable) {
_shadowMode = kNormalShadowMode;
}
} else {
+ if (_vm->_cjkFont) {
+ _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kDefaultMode);
+ _vm->_cjkFont->toggleFlippedMode(false);
+ }
_shadowMode = kNoShadowMode;
}
}
@@ -747,7 +709,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
VirtScreen *vs;
const byte *charPtr;
byte *dst;
- int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;
+ int is2byte = (chr >= 256 && _vm->_useCJKMode) ? 1 : 0;
assertRange(0, _curId, _vm->_numCharsets - 1, "charset");
@@ -757,10 +719,16 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
if (chr == '@')
return;
- if (is2byte) {
- charPtr = _vm->get2byteCharPtr(chr);
- width = _vm->_2byteWidth;
- height = _vm->_2byteHeight;
+ if (_vm->_useCJKMode && chr > 127) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ charPtr = 0;
+ width = _vm->_cjkFont->getCharWidth(chr);
+ height = _vm->_cjkFont->getFontHeight();
+ } else {
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ charPtr = _vm->get2byteCharPtr(chr);
+ }
} else {
charPtr = _fontPtr + chr * 8;
width = getCharWidth(chr);
@@ -775,8 +743,8 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
origHeight = height;
if (_shadowMode != kNoShadowMode) {
- width += _vm->_textSurfaceMultiplier;
- height += _vm->_textSurfaceMultiplier;
+ width++;
+ height++;
}
if (_firstChar) {
@@ -798,20 +766,28 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
if (
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
- (_vm->_game.platform != Common::kPlatformFMTowns || (_vm->_game.id == GID_LOOM && !is2byte)) &&
-#endif
+ (_vm->_game.platform != Common::kPlatformFMTowns) &&
+#endif
(ignoreCharsetMask || !vs->hasTwoBuffers)) {
dst = vs->getPixels(_left, drawTop);
- drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight, vs->bytesPerPixel);
+ if (charPtr)
+ drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight, vs->bytesPerPixel);
+ else if (_vm->_cjkFont)
+ _vm->_cjkFont->drawChar(vs, chr, _left, drawTop, _color, _shadowColor);
} else {
dst = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier);
- drawBits1(_vm->_textSurface, dst, charPtr, drawTop, origWidth, origHeight, _vm->_textSurface.bytesPerPixel);
+ if (charPtr)
+ drawBits1(_vm->_textSurface, dst, charPtr, drawTop, origWidth, origHeight, _vm->_textSurface.bytesPerPixel, (_vm->_textSurfaceMultiplier == 2 && !is2byte));
+ else if (_vm->_cjkFont)
+ _vm->_cjkFont->drawChar(_vm->_textSurface, chr, _left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier, _color, _shadowColor);
+ if (is2byte)
+ origWidth /= _vm->_textSurfaceMultiplier;
}
if (_str.left > _left)
_str.left = _left;
- _left += origWidth / _vm->_textSurfaceMultiplier;
+ _left += origWidth;
if (_str.right < _left) {
_str.right = _left;
@@ -823,15 +799,20 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
_str.bottom = _top + height / _vm->_textSurfaceMultiplier;
}
-void CharsetRendererV3::drawChar(int chr, const Graphics::Surface &s, int x, int y) {
+void CharsetRendererV3::drawChar(int chr, Graphics::Surface &s, int x, int y) {
const byte *charPtr;
byte *dst;
int width, height;
int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;
if (is2byte) {
- charPtr = _vm->get2byteCharPtr(chr);
- width = _vm->_2byteWidth;
- height = _vm->_2byteHeight;
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ _vm->_cjkFont->drawChar(s, chr, x * _vm->_textSurfaceMultiplier, y * _vm->_textSurfaceMultiplier, _color, _shadowColor);
+ return;
+ } else {
+ charPtr = _vm->get2byteCharPtr(chr);
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ }
} else {
charPtr = _fontPtr + chr * 8;
// width = height = 8;
@@ -901,7 +882,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
int offsX, offsY;
VirtScreen *vs;
const byte *charPtr;
- bool is2byte = (chr >= 0x80 && _vm->_useCJKMode);
+ bool is2byte = (chr >= 256 && _vm->_useCJKMode);
assertRange(1, _curId, _vm->_numCharsets - 1, "charset");
@@ -917,14 +898,42 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
processTownsCharsetColors(_bytesPerPixel);
-#endif
+ bool noSjis = false;
- if (is2byte) {
+ if (_vm->_game.platform == Common::kPlatformFMTowns && _vm->_useCJKMode) {
+ if ((chr & 0x00ff) == 0x00fd) {
+ chr >>= 8;
+ noSjis = true;
+ }
+ }
+
+ if (useTownsFontRomCharacter(chr) && !noSjis) {
+ charPtr = 0;
+ _vm->_cjkChar = chr;
+ enableShadow(true);
+
+ width = getCharWidth(chr);
+ // For whatever reason MI1 uses a different font width
+ // for alignment calculation and for drawing when
+ // charset 2 is active. This fixes some subtle glitches.
+ if (_vm->_game.id == GID_MONKEY && _curId == 2)
+ width--;
+ origWidth = width;
+
+ origHeight = height = getFontHeight();
+ offsX = offsY = 0;
+ } else
+#endif
+ if (_vm->_useCJKMode && (chr >= 128) && !noSjis) {
enableShadow(true);
+ origWidth = width = _vm->_2byteWidth;
+ origHeight = height = _vm->_2byteHeight;
charPtr = _vm->get2byteCharPtr(chr);
- width = _vm->_2byteWidth;
- height = _vm->_2byteHeight;
offsX = offsY = 0;
+ if (_shadowMode != kNoShadowMode) {
+ width++;
+ height++;
+ }
} else {
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
assert(charOffs < 0x14000);
@@ -932,9 +941,9 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
return;
charPtr = _fontPtr + charOffs;
- width = charPtr[0];
- height = charPtr[1];
-
+ width = origWidth = charPtr[0];
+ height = origHeight = charPtr[1];
+
if (_disableOffsX) {
offsX = 0;
} else {
@@ -945,13 +954,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
charPtr += 4; // Skip over char header
}
- origWidth = width;
- origHeight = height;
- if (_shadowMode != kNoShadowMode) {
- width += _vm->_textSurfaceMultiplier;
- height += _vm->_textSurfaceMultiplier;
- }
if (_firstChar) {
_str.left = 0;
_str.top = 0;
@@ -962,8 +965,8 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
_top += offsY;
_left += offsX;
- if (_left + origWidth / _vm->_textSurfaceMultiplier > _right + 1 || _left < 0) {
- _left += origWidth / _vm->_textSurfaceMultiplier;
+ if (_left + origWidth > _right + 1 || _left < 0) {
+ _left += origWidth;
_top -= offsY;
return;
}
@@ -1001,16 +1004,16 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
printCharIntern(is2byte, charPtr, origWidth, origHeight, width, height, vs, ignoreCharsetMask);
- _left += origWidth / _vm->_textSurfaceMultiplier;
+ _left += origWidth;
if (_str.right < _left) {
_str.right = _left;
- if (_shadowMode != kNoShadowMode)
+ if (_vm->_game.platform != Common::kPlatformFMTowns && _shadowMode != kNoShadowMode)
_str.right++;
}
- if (_str.bottom < _top + height / _vm->_textSurfaceMultiplier)
- _str.bottom = _top + height / _vm->_textSurfaceMultiplier;
+ if (_str.bottom < _top + origHeight)
+ _str.bottom = _top + origHeight;
_top -= offsY;
}
@@ -1073,10 +1076,12 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
drawTop = _top - _vm->_screenTop;
}
- if (is2byte) {
+ if (!charPtr && _vm->_cjkFont) {
+ _vm->_cjkFont->drawChar(dstSurface, _vm->_cjkChar, _left * _vm->_textSurfaceMultiplier, (_top - _vm->_screenTop) * _vm->_textSurfaceMultiplier, _vm->_townsCharsetColorMap[1], _shadowColor);
+ } else if (is2byte) {
drawBits1(dstSurface, dstPtr, charPtr, drawTop, origWidth, origHeight, dstSurface.bytesPerPixel);
} else {
- drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight);
+ drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight, _vm->_textSurfaceMultiplier == 2);
}
if (_blitAlso && vs->hasTwoBuffers) {
@@ -1116,7 +1121,7 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
}
}
-void CharsetRendererClassic::drawChar(int chr, const Graphics::Surface &s, int x, int y) {
+void CharsetRendererClassic::drawChar(int chr, Graphics::Surface &s, int x, int y) {
const byte *charPtr;
byte *dst;
int width, height;
@@ -1124,9 +1129,14 @@ void CharsetRendererClassic::drawChar(int chr, const Graphics::Surface &s, int x
if (is2byte) {
enableShadow(true);
- charPtr = _vm->get2byteCharPtr(chr);
- width = _vm->_2byteWidth;
- height = _vm->_2byteHeight;
+ if (_vm->_game.platform == Common::kPlatformFMTowns) {
+ _vm->_cjkFont->drawChar(s, chr, x * _vm->_textSurfaceMultiplier, y * _vm->_textSurfaceMultiplier, _color, _shadowColor);
+ return;
+ } else {
+ charPtr = _vm->get2byteCharPtr(chr);
+ width = _vm->_2byteWidth;
+ height = _vm->_2byteHeight;
+ }
} else {
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
assert(charOffs < 0x10000);
@@ -1149,19 +1159,33 @@ void CharsetRendererClassic::drawChar(int chr, const Graphics::Surface &s, int x
}
}
-void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) {
+void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height,
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ bool scale2x) {
+#else
+ bool) {
+#endif
+
int y, x;
int color;
byte numbits, bits;
+ byte *dst2 = dst;
+ int pitch = s.pitch - width;
+
assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8);
bits = *src++;
numbits = 8;
- byte *cmap =
+ byte *cmap = _vm->_charsetColorMap;
+
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
- (_vm->_game.platform == Common::kPlatformFMTowns) ? _vm->_townsCharsetColorMap :
+ if (_vm->_game.platform == Common::kPlatformFMTowns)
+ cmap = _vm->_townsCharsetColorMap;
+ if (scale2x) {
+ dst2 += s.pitch;
+ pitch <<= 1;
+ }
#endif
- _vm->_charsetColorMap;
for (y = 0; y < height && y + drawTop < s.h; y++) {
for (x = 0; x < width; x++) {
@@ -1169,8 +1193,21 @@ void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, co
if (color && y + drawTop >= 0) {
*dst = cmap[color];
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x)
+ dst[1] = dst2[0] = dst2[1] = dst[0];
+#endif
}
dst++;
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x) {
+ dst++;
+ dst2 += 2;
+ }
+#endif
+
bits <<= bpp;
numbits -= bpp;
if (numbits == 0) {
@@ -1178,18 +1215,37 @@ void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, co
numbits = 8;
}
}
- dst += s.pitch - width;
+ dst += pitch;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ dst2 += pitch;
+#endif
}
}
-void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) {
+void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth,
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ bool scale2x) {
+#else
+ bool) {
+#endif
+
int y, x;
byte bits = 0;
- uint8 col =
+ uint8 col = _color;
+ int pitch = s.pitch - width * bitDepth;
+ byte *dst2 = dst + s.pitch;
+
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
- (_vm->_game.platform == Common::kPlatformFMTowns && _vm->_game.version == 5) ? _vm->_townsCharsetColorMap[1] :
-#endif
- _color;
+ byte *dst3 = dst2;
+ byte *dst4 = dst2;
+ if (scale2x) {
+ dst3 = dst2 + s.pitch;
+ dst4 = dst3 + s.pitch;
+ pitch <<= 1;
+ }
+ if (_vm->_game.platform == Common::kPlatformFMTowns && _vm->_game.version == 5)
+ col = _vm->_townsCharsetColorMap[1];
+#endif
for (y = 0; y < height && y + drawTop < s.h; y++) {
for (x = 0; x < width; x++) {
@@ -1206,23 +1262,49 @@ void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, con
WRITE_UINT16(dst, _vm->_16BitPalette[_color]);
} else {
if (_shadowMode != kNoShadowMode) {
- *(dst + 1) = _shadowColor;
- *(dst + s.pitch) = _shadowColor;
- if (_shadowMode != kFMTOWNSShadowMode)
- *(dst + s.pitch + 1) = _shadowColor;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x) {
+ dst[2] = dst[3] = dst2[2] = dst2[3] = _shadowColor;
+ dst3[0] = dst4[0] = dst3[1] = dst4[1] = _shadowColor;
+ } else
+#endif
+ {
+ dst[1] = dst2[0] = _shadowColor;
+ if (_shadowMode != kFMTOWNSShadowMode)
+ dst2[1] = _shadowColor;
+ }
}
- *dst = col;
+ dst[0] = col;
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x)
+ dst[1] = dst2[0] = dst2[1] = col;
+#endif
}
}
dst += bitDepth;
+ dst2 += bitDepth;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (scale2x) {
+ dst++;
+ dst2++;
+ dst3 += 2;
+ dst4 += 2;
+ }
+#endif
}
- dst += s.pitch - width * bitDepth;
+ dst += pitch;
+ dst2 += pitch;
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ dst3 += pitch;
+ dst4 += pitch;
+#endif
}
}
#ifdef USE_RGB_COLOR
-void CharsetRendererPCE::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) {
+void CharsetRendererPCE::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scalex) {
int y, x;
int bitCount = 0;
byte bits = 0;
@@ -1437,7 +1519,7 @@ void CharsetRendererNES::printChar(int chr, bool ignoreCharsetMask) {
_str.bottom = _top + height;
}
-void CharsetRendererNES::drawChar(int chr, const Graphics::Surface &s, int x, int y) {
+void CharsetRendererNES::drawChar(int chr, Graphics::Surface &s, int x, int y) {
byte *charPtr, *dst;
int width, height;
@@ -1452,7 +1534,7 @@ void CharsetRendererNES::drawChar(int chr, const Graphics::Surface &s, int x, in
drawBits1(s, dst, charPtr, y, width, height, s.bytesPerPixel);
}
-void CharsetRendererNES::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) {
+void CharsetRendererNES::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scalex) {
for (int i = 0; i < 8; i++) {
byte c0 = src[i];
byte c1 = src[i + 8];
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index b5fc7b1b15..4b2e053c6d 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -27,6 +27,7 @@
#include "common/scummsys.h"
#include "common/rect.h"
+#include "graphics/sjis.h"
#include "scumm/gfx.h"
#include "scumm/saveload.h"
@@ -37,9 +38,9 @@ class NutRenderer;
struct VirtScreen;
static inline bool checkSJISCode(byte c) {
- if ((c > 0x84 && c < 0x88) || (c > 0x9f && c < 0xe0) || (c > 0xea /* && c <= 0xff */))
- return false;
- return true;
+ if ((c >= 0x80 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfd))
+ return true;
+ return false;
}
@@ -74,7 +75,7 @@ public:
virtual ~CharsetRenderer();
virtual void printChar(int chr, bool ignoreCharsetMask) = 0;
- virtual void drawChar(int chr, const Graphics::Surface &s, int x, int y) {}
+ virtual void drawChar(int chr, Graphics::Surface &s, int x, int y) {}
int getStringWidth(int a, const byte *str);
void addLinebreaks(int a, byte *str, int pos, int maxwidth);
@@ -112,7 +113,8 @@ protected:
ShadowMode _shadowMode;
void enableShadow(bool enable);
- virtual void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth);
+ virtual void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scale2x = false);
+
public:
CharsetRendererCommon(ScummEngine *vm);
@@ -124,7 +126,7 @@ public:
class CharsetRendererClassic : public CharsetRendererCommon {
protected:
- void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height);
+ void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height, bool scale2x = false);
void printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask);
@@ -132,23 +134,28 @@ public:
CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {}
void printChar(int chr, bool ignoreCharsetMask);
- void drawChar(int chr, const Graphics::Surface &s, int x, int y);
+ void drawChar(int chr, Graphics::Surface &s, int x, int y);
int getCharWidth(uint16 chr);
+
+ // Some SCUMM 5 games contain hard coded logic to determine whether to use
+ // the SCUMM fonts or the FM-Towns font rom to draw a character. For the other
+ // games we will simply check for a character greater 127.
+ bool useTownsFontRomCharacter(uint16 chr);
};
class CharsetRendererNES : public CharsetRendererCommon {
protected:
byte *_trTable;
- void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth);
+ void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scale2x = false);
public:
CharsetRendererNES(ScummEngine *vm) : CharsetRendererCommon(vm) {}
void setCurID(int32 id) {}
void printChar(int chr, bool ignoreCharsetMask);
- void drawChar(int chr, const Graphics::Surface &s, int x, int y);
+ void drawChar(int chr, Graphics::Surface &s, int x, int y);
int getFontHeight() { return 8; }
int getCharWidth(uint16 chr) { return 8; }
@@ -162,7 +169,7 @@ public:
CharsetRendererV3(ScummEngine *vm) : CharsetRendererCommon(vm) {}
void printChar(int chr, bool ignoreCharsetMask);
- void drawChar(int chr, const Graphics::Surface &s, int x, int y);
+ void drawChar(int chr, Graphics::Surface &s, int x, int y);
void setCurID(int32 id);
void setColor(byte color);
int getCharWidth(uint16 chr);
@@ -171,7 +178,7 @@ public:
#ifdef USE_RGB_COLOR
class CharsetRendererPCE : public CharsetRendererV3 {
protected:
- void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth);
+ void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scale2x = false);
public:
CharsetRendererPCE(ScummEngine *vm) : CharsetRendererV3(vm) {}
diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp
index d0d8eb2240..cd366fcfd4 100644
--- a/engines/scumm/costume.cpp
+++ b/engines/scumm/costume.cpp
@@ -648,7 +648,7 @@ void ClassicCostumeRenderer::procPCEngine(Codec1 &v1) {
}
}
if (index != 128) {
- printf("%d\n", index);
+ warning("ClassicCostumeRenderer::procPCEngine: index %d != 128\n", index);
}
for (int row = 0; row < 16; ++row) {
diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp
index b5a4070f0b..a348d9c942 100644
--- a/engines/scumm/debugger.cpp
+++ b/engines/scumm/debugger.cpp
@@ -35,7 +35,6 @@
#include "scumm/debugger.h"
#include "scumm/imuse/imuse.h"
#include "scumm/object.h"
-#include "scumm/player_v2.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
@@ -87,7 +86,7 @@ ScummDebugger::ScummDebugger(ScummEngine *s)
if (_vm->_game.id == GID_LOOM)
DCmd_Register("drafts", WRAP_METHOD(ScummDebugger, Cmd_PrintDraft));
- if (_vm->_game.id == GID_MONKEY && Common::kPlatformSegaCD)
+ if (_vm->_game.id == GID_MONKEY && _vm->_game.platform == Common::kPlatformSegaCD)
DCmd_Register("passcode", WRAP_METHOD(ScummDebugger, Cmd_Passcode));
DCmd_Register("loadgame", WRAP_METHOD(ScummDebugger, Cmd_LoadGame));
@@ -529,7 +528,7 @@ bool ScummDebugger::Cmd_Debug(int argc, const char **argv) {
} else {
DebugPrintf("Usage: debug [+CHANNEL|-CHANNEL]\n");
DebugPrintf("Enables or disables the given debug channel.\n");
- DebugPrintf("When used without parameters, lists all avaiable debug channels and their status.\n");
+ DebugPrintf("When used without parameters, lists all available debug channels and their status.\n");
}
return true;
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 9010cb84c3..10224d997d 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -422,7 +422,6 @@ static void composeFileHashMap(const Common::FSList &fslist, DescMap &fileMD5Map
static void detectGames(const Common::FSList &fslist, Common::List<DetectorResult> &results, const char *gameid) {
DescMap fileMD5Map;
DetectorResult dr;
- char md5str[32+1];
// Dive one level down since mac indy3/loom has its files split into directories. See Bug #1438631
composeFileHashMap(fslist, fileMD5Map, 2, directoryGlobs);
@@ -479,10 +478,13 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul
tmp->open(d.node);
}
- if (tmp && tmp->isOpen() && Common::md5_file_string(*tmp, md5str, kMD5FileSizeLimit)) {
+ Common::String md5str;
+ if (tmp && tmp->isOpen())
+ md5str = computeStreamMD5AsString(*tmp, kMD5FileSizeLimit);
+ if (!md5str.empty()) {
d.md5 = md5str;
- d.md5Entry = findInMD5Table(md5str);
+ d.md5Entry = findInMD5Table(md5str.c_str());
dr.md5 = d.md5;
@@ -494,7 +496,7 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul
int filesize = tmp->size();
if (d.md5Entry->filesize != filesize)
debug(1, "SCUMM detector found matching file '%s' with MD5 %s, size %d\n",
- file.c_str(), md5str, filesize);
+ file.c_str(), md5str.c_str(), filesize);
// Sanity check: We *should* have found a matching gameid / variant at this point.
// If not, then there's a bug in our data tables...
@@ -1198,12 +1200,7 @@ SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int
int minutes = infos.time & 0xFF;
desc.setSaveTime(hour, minutes);
-
- minutes = infos.playtime / 60;
- hour = minutes / 60;
- minutes %= 60;
-
- desc.setPlayTime(hour, minutes);
+ desc.setPlayTime(infos.playtime * 1000);
}
return desc;
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 4428185774..a5542ca868 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -370,7 +370,7 @@ static const GameSettings gameVariantsTable[] = {
#ifdef USE_RGB_COLOR
// Added 16bit color
{"arttime", 0, 0, GID_HEGAME, 6, 99, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI},
- {"baseball2001", 0, 0, GID_HEGAME, 6, 99, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI},
+ {"baseball2001", 0, 0, GID_BASEBALL2001, 6, 99, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI},
{"readtime", 0, 0, GID_HEGAME, 6, 99, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI},
{"SoccerMLS", 0, 0, GID_SOCCER, 6, 99, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI},
{"spyozon", 0, 0, GID_HEGAME, 6, 99, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI},
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index a48e54c05a..1cdc9e3ff0 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -45,7 +45,6 @@
#include "scumm/scumm.h"
#include "scumm/imuse/imuse.h"
#include "scumm/imuse_digi/dimuse.h"
-#include "scumm/player_v2.h"
#include "scumm/verbs.h"
#include "sound/mididrv.h"
#include "sound/mixer.h"
@@ -58,8 +57,6 @@
#include "gui/KeysDialog.h"
#endif
-using GUI::CommandSender;
-using GUI::StaticTextWidget;
using Graphics::kTextAlignCenter;
using Graphics::kTextAlignLeft;
using GUI::WIDGET_ENABLED;
@@ -258,7 +255,7 @@ ScummMenuDialog::~ScummMenuDialog() {
delete _helpDialog;
}
-void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+void ScummMenuDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kHelpCmd:
_helpDialog->runModal();
@@ -277,7 +274,7 @@ enum {
HelpDialog::HelpDialog(const GameSettings &game)
: ScummDialog("ScummHelp"), _game(game) {
- _title = new StaticTextWidget(this, "ScummHelp.Title", "");
+ _title = new GUI::StaticTextWidget(this, "ScummHelp.Title", "");
_page = 1;
_backgroundType = GUI::ThemeEngine::kDialogBackgroundDefault;
@@ -293,8 +290,8 @@ HelpDialog::HelpDialog(const GameSettings &game)
// Dummy entries
for (int i = 0; i < HELP_NUM_LINES; i++) {
- _key[i] = new StaticTextWidget(this, 0, 0, 10, 10, "", Graphics::kTextAlignRight);
- _dsc[i] = new StaticTextWidget(this, 0, 0, 10, 10, "", Graphics::kTextAlignLeft);
+ _key[i] = new GUI::StaticTextWidget(this, 0, 0, 10, 10, "", Graphics::kTextAlignRight);
+ _dsc[i] = new GUI::StaticTextWidget(this, 0, 0, 10, 10, "", Graphics::kTextAlignLeft);
}
}
@@ -346,7 +343,7 @@ void HelpDialog::displayKeyBindings() {
delete[] dscStr;
}
-void HelpDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+void HelpDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kNextCmd:
@@ -386,7 +383,7 @@ InfoDialog::InfoDialog(ScummEngine *scumm, int res)
_message = queryResString(res);
// Width and height are dummy
- _text = new StaticTextWidget(this, 0, 0, 10, 10, _message, kTextAlignCenter);
+ _text = new GUI::StaticTextWidget(this, 0, 0, 10, 10, _message, kTextAlignCenter);
}
InfoDialog::InfoDialog(ScummEngine *scumm, const String& message)
@@ -395,7 +392,7 @@ InfoDialog::InfoDialog(ScummEngine *scumm, const String& message)
_message = message;
// Width and height are dummy
- _text = new StaticTextWidget(this, 0, 0, 10, 10, _message, kTextAlignCenter);
+ _text = new GUI::StaticTextWidget(this, 0, 0, 10, 10, _message, kTextAlignCenter);
}
void InfoDialog::setInfoText(const String& message) {
diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index 0081720d03..08feb7ffd5 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -27,8 +27,6 @@
#include "scumm/scumm.h"
-using Common::File;
-
namespace Scumm {
#pragma mark -
diff --git a/engines/scumm/file_nes.cpp b/engines/scumm/file_nes.cpp
index 0caf63b410..5403354830 100644
--- a/engines/scumm/file_nes.cpp
+++ b/engines/scumm/file_nes.cpp
@@ -28,8 +28,6 @@
#include "common/endian.h"
#include "common/md5.h"
-using Common::File;
-
namespace Scumm {
#pragma mark -
@@ -1077,7 +1075,7 @@ uint16 ScummNESFile::extractResource(Common::WriteStream *output, const Resource
case NES_PREPLIST:
len = res->length;
- reslen += write_word(output, 0x002A);
+ reslen += write_word(output, 0x002A);
reslen += write_byte(output, ' ');
for (i = 1; i < 8; i++)
@@ -1371,34 +1369,36 @@ bool ScummNESFile::generateIndex() {
bool ScummNESFile::open(const Common::String &filename) {
if (_ROMset == kROMsetNum) {
- char md5str[32+1];
+ Common::String md5str;
File f;
f.open(filename);
- if (f.isOpen() && Common::md5_file_string(f, md5str)) {
+ if (f.isOpen())
+ md5str = Common::computeStreamMD5AsString(f);
+ if (!md5str.empty()) {
- if (!strcmp(md5str, "3905799e081b80a61d4460b7b733c206")) {
+ if (md5str == "3905799e081b80a61d4460b7b733c206") {
_ROMset = kROMsetUSA;
debug(1, "ROM contents verified as Maniac Mansion (USA)");
- } else if (!strcmp(md5str, "d8d07efcb88f396bee0b402b10c3b1c9")) {
+ } else if (md5str == "d8d07efcb88f396bee0b402b10c3b1c9") {
_ROMset = kROMsetEurope;
debug(1, "ROM contents verified as Maniac Mansion (Europe)");
- } else if (!strcmp(md5str, "22d07d6c386c9c25aca5dac2a0c0d94b")) {
+ } else if (md5str == "22d07d6c386c9c25aca5dac2a0c0d94b") {
_ROMset = kROMsetSweden;
debug(1, "ROM contents verified as Maniac Mansion (Sweden)");
- } else if (!strcmp(md5str, "81bbfa181184cb494e7a81dcfa94fbd9")) {
+ } else if (md5str == "81bbfa181184cb494e7a81dcfa94fbd9") {
_ROMset = kROMsetFrance;
debug(2, "ROM contents verified as Maniac Mansion (France)");
- } else if (!strcmp(md5str, "257f8c14d8c584f7ddd601bcb00920c7")) {
+ } else if (md5str == "257f8c14d8c584f7ddd601bcb00920c7") {
_ROMset = kROMsetGermany;
debug(2, "ROM contents verified as Maniac Mansion (Germany)");
- } else if (!strcmp(md5str, "f163cf53f7850e43fb482471e5c52e1a")) {
+ } else if (md5str == "f163cf53f7850e43fb482471e5c52e1a") {
_ROMset = kROMsetSpain;
debug(2, "ROM contents verified as Maniac Mansion (Spain)");
- } else if (!strcmp(md5str, "54a68a5f5e3c86da42b7ca5f51e79b1d")) {
+ } else if (md5str == "54a68a5f5e3c86da42b7ca5f51e79b1d") {
_ROMset = kROMsetItaly;
debug(2, "ROM contents verified as Maniac Mansion (Italy)");
} else {
- error("Unsupported Maniac Mansion ROM, md5: %s", md5str);
+ error("Unsupported Maniac Mansion ROM, md5: %s", md5str.c_str());
return false;
}
} else {
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index e7c81bd418..313e8b88c0 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -1013,11 +1013,6 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) {
if (rect.left > vs->w)
return;
-
-#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
- if (_game.platform == Common::kPlatformFMTowns && _game.id == GID_MONKEY && vs->number == kVerbVirtScreen && rect.bottom <= 154)
- rect.right = 320;
-#endif
// Convert 'rect' to local (virtual screen) coordinates
rect.top -= vs->topline;
@@ -1025,13 +1020,18 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) {
rect.clip(vs->w, vs->h);
+ const int height = rect.height();
+ const int width = rect.width();
+
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (_game.platform == Common::kPlatformFMTowns && _game.id == GID_MONKEY && vs->number == kVerbVirtScreen && rect.bottom <= 154)
+ rect.right = 319;
+#endif
+
markRectAsDirty(vs->number, rect, USAGE_BIT_RESTORED);
screenBuf = vs->getPixels(rect.left, rect.top);
- const int height = rect.height();
- const int width = rect.width();
-
if (!height)
return;
@@ -2457,7 +2457,7 @@ void ScummEngine::decodeNESBaseTiles() {
}
static const int v1MMNEScostTables[2][6] = {
- /* desc lens offs data gfx pal */
+ /* desc lens offs data gfx pal */
{ 25, 27, 29, 31, 33, 35},
{ 26, 28, 30, 32, 34, 36}
};
@@ -3737,6 +3737,10 @@ void ScummEngine::fadeOut(int effect) {
// Just blit screen 0 to the display (i.e. display will be black)
vs->setDirtyRange(0, vs->h);
updateDirtyScreen(kMainVirtScreen);
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+ if (_townsScreen)
+ _townsScreen->update();
+#endif
break;
case 134:
dissolveEffect(1, 1);
diff --git a/engines/scumm/he/logic_he.cpp b/engines/scumm/he/logic_he.cpp
index add9b982e2..ed92c33105 100644
--- a/engines/scumm/he/logic_he.cpp
+++ b/engines/scumm/he/logic_he.cpp
@@ -77,11 +77,11 @@ int32 LogicHE::dispatch(int op, int numArgs, int32 *args) {
#if 1
Common::String str;
- str = Common::String::printf("LogicHE::dispatch(%d, %d, [", op, numArgs);
+ str = Common::String::format("LogicHE::dispatch(%d, %d, [", op, numArgs);
if (numArgs > 0)
- str += Common::String::printf("%d", args[0]);
+ str += Common::String::format("%d", args[0]);
for (int i = 1; i < numArgs; i++) {
- str += Common::String::printf(", %d", args[i]);
+ str += Common::String::format(", %d", args[i]);
}
str += "])";
@@ -232,7 +232,7 @@ int32 LogicHErace::op_1101(int32 *args) {
int32 retval;
float temp;
- temp = args[0] / _userData[532];
+ temp = args[0] / _userData[532];
if (_userData[519] != temp) {
_userData[519] = temp;
op_sub3(temp);
@@ -955,6 +955,30 @@ int LogicHEsoccer::op_1021(int32 *args) {
}
/***********************
+ * Backyard Baseball 2001
+ *
+ */
+
+int LogicHEbaseball2001::versionID() {
+ return 1;
+}
+
+int32 LogicHEbaseball2001::dispatch(int op, int numArgs, int32 *args) {
+ int res = 0;
+
+ switch (op) {
+ case 3001:
+ // Check network status
+ break;
+
+ default:
+ LogicHE::dispatch(op, numArgs, args);
+ }
+
+ return res;
+}
+
+/***********************
* Backyard Basketball
*
*/
diff --git a/engines/scumm/he/logic_he.h b/engines/scumm/he/logic_he.h
index 7dd141c5b1..ab952abd5e 100644
--- a/engines/scumm/he/logic_he.h
+++ b/engines/scumm/he/logic_he.h
@@ -133,6 +133,14 @@ private:
int op_1021(int32 *args);
};
+class LogicHEbaseball2001 : public LogicHE {
+public:
+ LogicHEbaseball2001(ScummEngine_v90he *vm) : LogicHE(vm) {}
+
+ int versionID();
+ int32 dispatch(int op, int numArgs, int32 *args);
+};
+
class LogicHEbasketball : public LogicHE {
public:
LogicHEbasketball(ScummEngine_v90he *vm) : LogicHE(vm) {}
diff --git a/engines/scumm/he/palette_he.cpp b/engines/scumm/he/palette_he.cpp
index 6ef68d981e..ad3f90b8eb 100644
--- a/engines/scumm/he/palette_he.cpp
+++ b/engines/scumm/he/palette_he.cpp
@@ -203,8 +203,8 @@ void ScummEngine_v90he::setHEPaletteFromImage(int palSlot, int resId, int state)
uint8 *data = getResourceAddress(rtImage, resId);
assert(data);
const uint8 *rgbs = findWrappedBlock(MKID_BE('RGBS'), data, state, 0);
- assert(rgbs);
- setHEPaletteFromPtr(palSlot, rgbs);
+ if (rgbs)
+ setHEPaletteFromPtr(palSlot, rgbs);
}
void ScummEngine_v90he::setHEPaletteFromRoom(int palSlot, int resId, int state) {
diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp
index c259c3ffd2..f7a7d3a567 100644
--- a/engines/scumm/he/resource_he.cpp
+++ b/engines/scumm/he/resource_he.cpp
@@ -23,7 +23,6 @@
*
*/
-
#include "scumm/scumm.h"
#include "scumm/file.h"
#include "scumm/he/intern_he.h"
@@ -40,9 +39,13 @@
namespace Scumm {
+#if defined(SCUMM_LITTLE_ENDIAN)
+#define LE16(x)
+#define LE32(x)
+#elif defined(SCUMM_BIG_ENDIAN)
#define LE16(x) ((x) = TO_LE_16(x))
#define LE32(x) ((x) = TO_LE_32(x))
-
+#endif
ResExtractor::ResExtractor(ScummEngine_v70he *scumm)
: _vm(scumm) {
@@ -207,9 +210,9 @@ int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte
}
-/* res_type_id_to_string:
- * Translate a numeric resource type to it's corresponding string type.
- * (For informative-ness.)
+/**
+ * Translate a numeric resource type to it's corresponding string type.
+ * (For informative-ness.)
*/
const char *Win32ResExtractor::res_type_id_to_string(int id) {
if (id == 241)
@@ -219,9 +222,9 @@ const char *Win32ResExtractor::res_type_id_to_string(int id) {
return NULL;
}
-/* res_type_string_to_id:
- * Translate a resource type string to integer.
- * (Used to convert the --type option.)
+/**
+ * Translate a resource type string to integer.
+ * (Used to convert the --type option.)
*/
const char *Win32ResExtractor::res_type_string_to_id(const char *type) {
static const char *res_type_ids[] = {
@@ -242,22 +245,18 @@ const char *Win32ResExtractor::res_type_string_to_id(const char *type) {
return type;
}
-/* return the resource id quoted if it's a string, otherwise just return it */
-char *Win32ResExtractor::WinResource::get_resource_id_quoted() {
- // FIXME: Using a static var here is EVIL and in fact, broken when
- // used multiple times in a row, e.g. in a single call to printf()
- // or debug()... which is in fact how we use this function... :-)
- static char tmp[WINRES_ID_MAXLEN+2];
-
+/**
+ * Return the resource id quoted if it is a string, otherwise (i.e. if
+ * it is numeric) just return it.
+ */
+Common::String Win32ResExtractor::WinResource::getQuotedResourceId() const {
if (numeric_id || id[0] == '\0')
return id;
-
- sprintf(tmp, "'%s'", id);
- return tmp;
+ return '"' + Common::String(id) + '"';
}
int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr,
- WinResource *type_wr, WinResource *name_wr,
+ WinResource *type_wr, WinResource *name_wr,
WinResource *lang_wr, byte **data) {
int size;
bool free_it;
@@ -281,19 +280,21 @@ int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr,
if ((id = strtol(type_wr->id, 0, 10)) != 0)
type = res_type_id_to_string(id);
- debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s%s%s [size=%d]",
- name_wr->get_resource_id_quoted(),
- (lang_wr->id[0] != '\0' ? " language: " : ""),
- lang_wr->get_resource_id_quoted(), size);
-
+ if (lang_wr != NULL && lang_wr->id[0] != '\0') {
+ debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s language: %s [size=%d]",
+ name_wr->getQuotedResourceId().c_str(), lang_wr->getQuotedResourceId().c_str(), size);
+ } else {
+ debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s [size=%d]",
+ name_wr->getQuotedResourceId().c_str(), size);
+ }
return size;
}
-/* extract_resource:
- * Extract a resource, returning pointer to data.
+/**
+ * Extract a resource, returning pointer to data.
*/
byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size,
- bool *free_it, char *type, char *lang, bool raw) {
+ bool *free_it, char *type, char *lang, bool raw) {
char *str;
int32 intval;
@@ -320,20 +321,20 @@ byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *
return NULL;
}
-/* extract_group_icon_resource:
- * Create a complete RT_GROUP_ICON resource, that can be written to
- * an `.ico' file without modifications. Returns an allocated
- * memory block that should be freed with free() once used.
+/**
+ * Create a complete RT_GROUP_ICON resource, that can be written to
+ * an `.ico' file without modifications. Returns an allocated
+ * memory block that should be freed with free() once used.
*
- * `root' is the offset in file that specifies the resource.
- * `base' is the offset that string pointers are calculated from.
- * `ressize' should point to an integer variable where the size of
- * the returned memory block will be placed.
- * `is_icon' indicates whether resource to be extracted is icon
- * or cursor group.
+ * `root' is the offset in file that specifies the resource.
+ * `base' is the offset that string pointers are calculated from.
+ * `ressize' should point to an integer variable where the size of
+ * the returned memory block will be placed.
+ * `is_icon' indicates whether resource to be extracted is icon
+ * or cursor group.
*/
byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang,
- int *ressize, bool is_icon) {
+ int *ressize, bool is_icon) {
Win32CursorIconDir *icondir;
Win32CursorIconFileDir *fileicondir;
byte *memory;
@@ -357,7 +358,7 @@ byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinR
WinResource *fwr;
RETURN_IF_BAD_POINTER(NULL, icondir->entries[c]);
- /*printf("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d\n", c,
+ /*debug("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d", c,
FROM_LE_32(icondir->entries[c].bytes_in_res),
(is_icon ? icondir->entries[c].res_info.icon.width : FROM_LE_16(icondir->entries[c].res_info.cursor.width)),
(is_icon ? icondir->entries[c].res_info.icon.height : FROM_LE_16(icondir->entries[c].res_info.cursor.height)),
@@ -374,20 +375,20 @@ byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinR
}
if (get_resource_entry(fi, fwr, &iconsize) != NULL) {
- if (iconsize == 0) {
+ if (iconsize == 0) {
debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", _fileName.c_str(), name);
skipped++;
continue;
- }
- if ((uint32)iconsize != FROM_LE_32(icondir->entries[c].bytes_in_res)) {
+ }
+ if ((uint32)iconsize != FROM_LE_32(icondir->entries[c].bytes_in_res)) {
debugC(DEBUG_RESOURCE, "%s: mismatch of size in icon resource `%s' and group (%d != %d)",
_fileName.c_str(), name, iconsize, FROM_LE_32(icondir->entries[c].bytes_in_res));
- }
- size += iconsize; /* size += FROM_LE_32(icondir->entries[c].bytes_in_res); */
+ }
+ size += iconsize; /* size += FROM_LE_32(icondir->entries[c].bytes_in_res); */
- /* cursor resources have two additional WORDs that contain
- * hotspot info */
- if (!is_icon)
+ /* cursor resources have two additional WORDs that contain
+ * hotspot info */
+ if (!is_icon)
size -= sizeof(uint16)*2;
}
}
@@ -428,8 +429,8 @@ byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinR
return NULL;
}
if (size == 0) {
- skipped++;
- continue;
+ skipped++;
+ continue;
}
/* copy ICONDIRENTRY (not including last dwImageOffset) */
@@ -465,10 +466,10 @@ byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinR
return memory;
}
-/* check_offset:
- * Check if a chunk of data (determined by offset and size)
- * is within the bounds of the WinLibrary file.
- * Usually not called directly.
+/**
+ * Check if a chunk of data (determined by offset and size)
+ * is within the bounds of the WinLibrary file.
+ * Usually not called directly.
*/
bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *name, void *offset, int size) {
int need_size = (int)((byte *)offset - memory + size);
@@ -485,8 +486,8 @@ bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *n
}
-/* do_resources:
- * Do something for each resource matching type, name and lang.
+/**
+ * Do something for each resource matching type, name and lang.
*/
int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, byte **data) {
WinResource *type_wr;
@@ -494,7 +495,7 @@ int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name
WinResource *lang_wr;
int size;
- type_wr = (WinResource *)calloc(sizeof(WinResource)*3, 1);
+ type_wr = (WinResource *)calloc(3, sizeof(WinResource));
name_wr = type_wr + 1;
lang_wr = type_wr + 2;
@@ -521,14 +522,11 @@ int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base,
/* get a list of all resources at this level */
wr = list_resources(fi, base, &rescnt);
if (wr == NULL) {
- if (size != 0)
- return size;
- else
- return 0;
+ return size;
}
/* process each resource listed */
- for (c = 0 ; c < rescnt ; c++) {
+ for (c = 0; c < rescnt; c++) {
/* (over)write the corresponding WinResource holder with the current */
memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource));
@@ -555,7 +553,9 @@ bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) {
return false;
if (id[0] == '-')
id++;
- if (!(cmp1 = strtol(wr->id, 0, 10)) || !(cmp2 = strtol(id, 0, 10)) || cmp1 != cmp2)
+ cmp1 = strtol(wr->id, 0, 10);
+ cmp2 = strtol(id, 0, 10);
+ if (!cmp1 || !cmp2 || cmp1 != cmp2)
return false;
} else {
if (id[0] == '-')
@@ -643,9 +643,9 @@ Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary
}
-/* list_resources:
- * Return an array of WinResource's in the current
- * resource level specified by _res->
+/**
+ * Return an array of WinResource's in the current
+ * resource level specified by _res->
*/
Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) {
if (res != NULL && !res->is_directory)
@@ -657,10 +657,9 @@ Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi
count);
}
-/* read_library:
- * Read header and get resource directory offset in a Windows library
- * (AKA module).
- *
+/**
+ * Read header and get resource directory offset in a Windows library
+ * (AKA module).
*/
bool Win32ResExtractor::read_library(WinLibrary *fi) {
/* check for DOS header signature `MZ' */
@@ -695,7 +694,9 @@ bool Win32ResExtractor::read_library(WinLibrary *fi) {
/* calc_vma_size has reported error */
return false;
}
- fi->memory = (byte *)realloc(fi->memory, fi->total_size);
+ byte *ptr = (byte *)realloc(fi->memory, fi->total_size);
+ assert(ptr);
+ fi->memory = ptr;
/* relocate memory, start from last section */
pe_header = PE_HEADER(fi->memory);
@@ -739,13 +740,13 @@ bool Win32ResExtractor::read_library(WinLibrary *fi) {
return false;
}
-/* calc_vma_size:
- * Calculate the total amount of memory needed for a 32-bit Windows
- * module. Returns -1 if file was too small.
+/**
+ * Calculate the total amount of memory needed for a 32-bit Windows
+ * module. Returns -1 if file was too small.
*/
int Win32ResExtractor::calc_vma_size(WinLibrary *fi) {
- Win32ImageSectionHeader *seg;
- int c, segcount, size;
+ Win32ImageSectionHeader *seg;
+ int c, segcount, size;
size = 0;
RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections);
@@ -760,7 +761,7 @@ int Win32ResExtractor::calc_vma_size(WinLibrary *fi) {
seg = PE_SECTIONS(fi->memory);
RETURN_IF_BAD_POINTER(-1, *seg);
- for (c = 0 ; c < segcount ; c++) {
+ for (c = 0 ; c < segcount ; c++) {
RETURN_IF_BAD_POINTER(0, *seg);
fix_win32_image_section_header(seg);
@@ -768,9 +769,9 @@ int Win32ResExtractor::calc_vma_size(WinLibrary *fi) {
/* I have no idea what misc.virtual_size is for... */
size = MAX((uint32)size, seg->virtual_address + seg->misc.virtual_size);
seg++;
- }
+ }
- return size;
+ return size;
}
Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) {
@@ -914,8 +915,8 @@ int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int
if (entries[c].dib_size != bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
debugC(DEBUG_RESOURCE, "incorrect total size of bitmap (%d specified; %d real)",
- entries[c].dib_size,
- (int)(bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
+ entries[c].dib_size,
+ (int)(bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
);
image_data = (byte *)malloc(image_size);
@@ -977,9 +978,9 @@ int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int
row[4*x+2] = (color >> 0) & 0xFF;
}
if (bitmap.bit_count == 32)
- row[4*x+3] = (color >> 24) & 0xFF;
+ row[4*x+3] = (color >> 24) & 0xFF;
else
- row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF;
+ row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF;
*/
}
@@ -1051,93 +1052,93 @@ uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) {
}
void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) {
- LE16(obj->reserved);
+ LE16(obj->reserved);
LE16(obj->type);
- LE16(obj->count);
+ LE16(obj->count);
}
void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) {
- LE32(obj->size);
- LE32(obj->width);
- LE32(obj->height);
- LE16(obj->planes);
- LE16(obj->bit_count);
- LE32(obj->compression);
- LE32(obj->size_image);
- LE32(obj->x_pels_per_meter);
- LE32(obj->y_pels_per_meter);
- LE32(obj->clr_used);
- LE32(obj->clr_important);
+ LE32(obj->size);
+ LE32(obj->width);
+ LE32(obj->height);
+ LE16(obj->planes);
+ LE16(obj->bit_count);
+ LE32(obj->compression);
+ LE32(obj->size_image);
+ LE32(obj->x_pels_per_meter);
+ LE32(obj->y_pels_per_meter);
+ LE32(obj->clr_used);
+ LE32(obj->clr_important);
}
void Win32ResExtractor::fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj) {
- LE16(obj->hotspot_x);
- LE16(obj->hotspot_y);
- LE32(obj->dib_size);
- LE32(obj->dib_offset);
+ LE16(obj->hotspot_x);
+ LE16(obj->hotspot_y);
+ LE32(obj->dib_size);
+ LE32(obj->dib_offset);
}
void Win32ResExtractor::fix_win32_image_section_header(Win32ImageSectionHeader *obj) {
- LE32(obj->misc.physical_address);
- LE32(obj->virtual_address);
- LE32(obj->size_of_raw_data);
- LE32(obj->pointer_to_raw_data);
- LE32(obj->pointer_to_relocations);
- LE32(obj->pointer_to_linenumbers);
- LE16(obj->number_of_relocations);
- LE16(obj->number_of_linenumbers);
- LE32(obj->characteristics);
+ LE32(obj->misc.physical_address);
+ LE32(obj->virtual_address);
+ LE32(obj->size_of_raw_data);
+ LE32(obj->pointer_to_raw_data);
+ LE32(obj->pointer_to_relocations);
+ LE32(obj->pointer_to_linenumbers);
+ LE16(obj->number_of_relocations);
+ LE16(obj->number_of_linenumbers);
+ LE32(obj->characteristics);
}
/* fix_win32_image_header_endian:
* NOTE: This assumes that the optional header is always available.
*/
void Win32ResExtractor::fix_win32_image_header_endian(Win32ImageNTHeaders *obj) {
- LE32(obj->signature);
- LE16(obj->file_header.machine);
- LE16(obj->file_header.number_of_sections);
- LE32(obj->file_header.time_date_stamp);
- LE32(obj->file_header.pointer_to_symbol_table);
- LE32(obj->file_header.number_of_symbols);
- LE16(obj->file_header.size_of_optional_header);
- LE16(obj->file_header.characteristics);
+ LE32(obj->signature);
+ LE16(obj->file_header.machine);
+ LE16(obj->file_header.number_of_sections);
+ LE32(obj->file_header.time_date_stamp);
+ LE32(obj->file_header.pointer_to_symbol_table);
+ LE32(obj->file_header.number_of_symbols);
+ LE16(obj->file_header.size_of_optional_header);
+ LE16(obj->file_header.characteristics);
// FIXME: Does this assert ever trigger? If so, we should modify this function
// to properly deal with it.
assert(obj->file_header.size_of_optional_header >= sizeof(obj->optional_header));
- LE16(obj->optional_header.magic);
- LE32(obj->optional_header.size_of_code);
- LE32(obj->optional_header.size_of_initialized_data);
- LE32(obj->optional_header.size_of_uninitialized_data);
- LE32(obj->optional_header.address_of_entry_point);
- LE32(obj->optional_header.base_of_code);
- LE32(obj->optional_header.base_of_data);
- LE32(obj->optional_header.image_base);
- LE32(obj->optional_header.section_alignment);
- LE32(obj->optional_header.file_alignment);
- LE16(obj->optional_header.major_operating_system_version);
- LE16(obj->optional_header.minor_operating_system_version);
- LE16(obj->optional_header.major_image_version);
- LE16(obj->optional_header.minor_image_version);
- LE16(obj->optional_header.major_subsystem_version);
- LE16(obj->optional_header.minor_subsystem_version);
- LE32(obj->optional_header.win32_version_value);
- LE32(obj->optional_header.size_of_image);
- LE32(obj->optional_header.size_of_headers);
- LE32(obj->optional_header.checksum);
- LE16(obj->optional_header.subsystem);
- LE16(obj->optional_header.dll_characteristics);
- LE32(obj->optional_header.size_of_stack_reserve);
- LE32(obj->optional_header.size_of_stack_commit);
- LE32(obj->optional_header.size_of_heap_reserve);
- LE32(obj->optional_header.size_of_heap_commit);
- LE32(obj->optional_header.loader_flags);
- LE32(obj->optional_header.number_of_rva_and_sizes);
+ LE16(obj->optional_header.magic);
+ LE32(obj->optional_header.size_of_code);
+ LE32(obj->optional_header.size_of_initialized_data);
+ LE32(obj->optional_header.size_of_uninitialized_data);
+ LE32(obj->optional_header.address_of_entry_point);
+ LE32(obj->optional_header.base_of_code);
+ LE32(obj->optional_header.base_of_data);
+ LE32(obj->optional_header.image_base);
+ LE32(obj->optional_header.section_alignment);
+ LE32(obj->optional_header.file_alignment);
+ LE16(obj->optional_header.major_operating_system_version);
+ LE16(obj->optional_header.minor_operating_system_version);
+ LE16(obj->optional_header.major_image_version);
+ LE16(obj->optional_header.minor_image_version);
+ LE16(obj->optional_header.major_subsystem_version);
+ LE16(obj->optional_header.minor_subsystem_version);
+ LE32(obj->optional_header.win32_version_value);
+ LE32(obj->optional_header.size_of_image);
+ LE32(obj->optional_header.size_of_headers);
+ LE32(obj->optional_header.checksum);
+ LE16(obj->optional_header.subsystem);
+ LE16(obj->optional_header.dll_characteristics);
+ LE32(obj->optional_header.size_of_stack_reserve);
+ LE32(obj->optional_header.size_of_stack_commit);
+ LE32(obj->optional_header.size_of_heap_reserve);
+ LE32(obj->optional_header.size_of_heap_commit);
+ LE32(obj->optional_header.loader_flags);
+ LE32(obj->optional_header.number_of_rva_and_sizes);
}
void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) {
- LE32(obj->virtual_address);
- LE32(obj->size);
+ LE32(obj->virtual_address);
+ LE32(obj->size);
}
diff --git a/engines/scumm/he/resource_he.h b/engines/scumm/he/resource_he.h
index 4567c598a3..65190ea41c 100644
--- a/engines/scumm/he/resource_he.h
+++ b/engines/scumm/he/resource_he.h
@@ -184,7 +184,7 @@ class Win32ResExtractor : public ResExtractor {
bool numeric_id;
bool is_directory;
- char *get_resource_id_quoted();
+ Common::String getQuotedResourceId() const;
} PACKED_STRUCT;
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index 3555f55d95..ca4a65ac74 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -34,7 +34,6 @@
#include "scumm/he/intern_he.h"
#include "scumm/object.h"
#include "scumm/resource.h"
-#include "scumm/he/resource_he.h"
#include "scumm/scumm.h"
#include "scumm/he/sound_he.h"
#include "scumm/he/sprite_he.h"
@@ -1623,13 +1622,11 @@ void ScummEngine_v100he::o100_roomOps() {
case 137:
byte buffer[256];
- int r;
copyScriptString((byte *)buffer, sizeof(buffer));
- r = convertFilePath(buffer, sizeof(buffer));
- memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r);
- debug(1, "o100_roomOps: case 137: filename %s", _saveLoadFileName);
+ _saveLoadFileName = (char *)buffer + convertFilePath(buffer, sizeof(buffer));
+ debug(1, "o100_roomOps: case 137: filename %s", _saveLoadFileName.c_str());
_saveLoadFlag = pop();
_saveLoadSlot = 255;
diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp
index 8ade78c1b5..9d62a31f6d 100644
--- a/engines/scumm/he/script_v60he.cpp
+++ b/engines/scumm/he/script_v60he.cpp
@@ -283,15 +283,14 @@ void ScummEngine_v60he::o60_roomOps() {
break;
case 221:
byte buffer[100];
- int len, r;
+ int len;
convertMessageToString(_scriptPointer, buffer, sizeof(buffer));
len = resStrLen(_scriptPointer);
_scriptPointer += len + 1;
- r = convertFilePath(buffer, sizeof(buffer));
- memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r);
- debug(1, "o60_roomOps: case 221: filename %s", _saveLoadFileName);
+ _saveLoadFileName = (char *)buffer + convertFilePath(buffer, sizeof(buffer));
+ debug(1, "o60_roomOps: case 221: filename %s", _saveLoadFileName.c_str());
_saveLoadFlag = pop();
_saveLoadSlot = 255;
diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp
index 979b2b3df4..9b160151b0 100644
--- a/engines/scumm/he/script_v70he.cpp
+++ b/engines/scumm/he/script_v70he.cpp
@@ -31,7 +31,6 @@
#include "scumm/he/intern_he.h"
#include "scumm/object.h"
#include "scumm/resource.h"
-#include "scumm/he/resource_he.h"
#include "scumm/scumm.h"
#include "scumm/he/sound_he.h"
#include "scumm/verbs.h"
diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp
index baa57c7821..76daacbd54 100644
--- a/engines/scumm/he/script_v72he.cpp
+++ b/engines/scumm/he/script_v72he.cpp
@@ -36,7 +36,6 @@
#include "scumm/he/intern_he.h"
#include "scumm/object.h"
#include "scumm/resource.h"
-#include "scumm/he/resource_he.h"
#include "scumm/scumm.h"
#include "scumm/he/sound_he.h"
#include "scumm/util.h"
@@ -173,7 +172,7 @@ int ScummEngine_v72he::readArray(int array, int idx2, int idx1) {
}
const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
- (idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1;
+ (idx2 - FROM_LE_32(ah->dim2start)) + (idx1 - FROM_LE_32(ah->dim1start));
switch (FROM_LE_32(ah->type)) {
case kByteArray:
@@ -711,13 +710,11 @@ void ScummEngine_v72he::o72_roomOps() {
case 221:
byte buffer[256];
- int r;
copyScriptString((byte *)buffer, sizeof(buffer));
- r = convertFilePath(buffer, sizeof(buffer));
- memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r);
- debug(1, "o72_roomOps: case 221: filename %s", _saveLoadFileName);
+ _saveLoadFileName = (char *)buffer + convertFilePath(buffer, sizeof(buffer));
+ debug(1, "o72_roomOps: case 221: filename %s", _saveLoadFileName.c_str());
_saveLoadFlag = pop();
_saveLoadSlot = 255;
diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp
index dd44180fa0..b06dc712d9 100644
--- a/engines/scumm/he/script_v80he.cpp
+++ b/engines/scumm/he/script_v80he.cpp
@@ -35,7 +35,6 @@
#include "scumm/he/intern_he.h"
#include "scumm/object.h"
#include "scumm/resource.h"
-#include "scumm/he/resource_he.h"
#include "scumm/scumm.h"
#include "scumm/he/sound_he.h"
diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp
index 6acc16a804..841eba960d 100644
--- a/engines/scumm/he/script_v90he.cpp
+++ b/engines/scumm/he/script_v90he.cpp
@@ -32,7 +32,6 @@
#include "scumm/he/logic_he.h"
#include "scumm/object.h"
#include "scumm/resource.h"
-#include "scumm/he/resource_he.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
#include "scumm/he/sprite_he.h"
@@ -1948,42 +1947,51 @@ void ScummEngine_v90he::getArrayDim(int array, int *dim2start, int *dim2end, int
}
}
+static int sortArrayOffset;
+
static int compareByteArray(const void *a, const void *b) {
- int va = *((const uint8 *)a);
- int vb = *((const uint8 *)a);
+ int va = *((const uint8 *)a + sortArrayOffset);
+ int vb = *((const uint8 *)b + sortArrayOffset);
return va - vb;
}
static int compareByteArrayReverse(const void *a, const void *b) {
- int va = *((const uint8 *)a);
- int vb = *((const uint8 *)a);
+ int va = *((const uint8 *)a + sortArrayOffset);
+ int vb = *((const uint8 *)b + sortArrayOffset);
return vb - va;
}
static int compareIntArray(const void *a, const void *b) {
- int va = (int16)READ_LE_UINT16((const uint8 *)a);
- int vb = (int16)READ_LE_UINT16((const uint8 *)b);
+ int va = (int16)READ_LE_UINT16((const uint8 *)a + sortArrayOffset * 2);
+ int vb = (int16)READ_LE_UINT16((const uint8 *)b + sortArrayOffset * 2);
return va - vb;
}
static int compareIntArrayReverse(const void *a, const void *b) {
- int va = (int16)READ_LE_UINT16((const uint8 *)a);
- int vb = (int16)READ_LE_UINT16((const uint8 *)b);
+ int va = (int16)READ_LE_UINT16((const uint8 *)a + sortArrayOffset * 2);
+ int vb = (int16)READ_LE_UINT16((const uint8 *)b + sortArrayOffset * 2);
return vb - va;
}
static int compareDwordArray(const void *a, const void *b) {
- int va = (int32)READ_LE_UINT32((const uint8 *)a);
- int vb = (int32)READ_LE_UINT32((const uint8 *)b);
+ int va = (int32)READ_LE_UINT32((const uint8 *)a + sortArrayOffset * 4);
+ int vb = (int32)READ_LE_UINT32((const uint8 *)b + sortArrayOffset * 4);
return va - vb;
}
static int compareDwordArrayReverse(const void *a, const void *b) {
- int va = (int32)READ_LE_UINT32((const uint8 *)a);
- int vb = (int32)READ_LE_UINT32((const uint8 *)b);
+ int va = (int32)READ_LE_UINT32((const uint8 *)a + sortArrayOffset * 4);
+ int vb = (int32)READ_LE_UINT32((const uint8 *)b + sortArrayOffset * 4);
return vb - va;
}
+
+/**
+ * Sort a row range in a two-dimensional array by the value in a given column.
+ *
+ * We sort the data in the row range [dim2start..dim2end], according to the value
+ * in column dim1start == dim1end.
+ */
void ScummEngine_v90he::sortArray(int array, int dim2start, int dim2end, int dim1start, int dim1end, int sortOrder) {
debug(9, "sortArray(%d, [%d,%d,%d,%d], %d)", array, dim2start, dim2end, dim1start, dim1end, sortOrder);
@@ -1992,11 +2000,21 @@ void ScummEngine_v90he::sortArray(int array, int dim2start, int dim2end, int dim
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
assert(ah);
- const int num = dim2end - dim2start + 1;
- const int pitch = FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1;
- const int offset = pitch * (dim2start - FROM_LE_32(ah->dim2start))
- + dim1start - FROM_LE_32(ah->dim1start);
-
+ const int num = dim2end - dim2start + 1; // number of rows to sort
+ const int pitch = FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1; // length of a row = number of columns in it
+ const int offset = pitch * (dim2start - FROM_LE_32(ah->dim2start)); // memory offset to the first row to be sorted
+ sortArrayOffset = dim1start - FROM_LE_32(ah->dim1start); // offset to the column by which we sort
+
+ // Now we just have to invoke qsort on the appropriate row range. We
+ // need to pass sortArrayOffset as an implicit parameter to the
+ // comparison functions, which makes it necessary to use a global
+ // (albeit local to this file) variable.
+ // This could be avoided by using qsort_r or a self-written portable
+ // analog (this function passes an additional, user determined
+ // parameter to the comparison function).
+ // Another idea would be to use Common::sort, but that only is
+ // suitable if you sort objects of fixed size, which must be known
+ // during compilation time; clearly this not the case here.
switch (FROM_LE_32(ah->type)) {
case kByteArray:
case kStringArray:
@@ -2039,7 +2057,6 @@ void ScummEngine_v90he::o90_sortArray() {
int dim2end = pop();
int dim2start = pop();
getArrayDim(array, &dim2start, &dim2end, &dim1start, &dim1end);
- checkArrayLimits(array, dim2start, dim2end, dim1start, dim1end);
sortArray(array, dim2start, dim2end, dim1start, dim1end, sortOrder);
}
break;
diff --git a/engines/scumm/he/sound_he.cpp b/engines/scumm/he/sound_he.cpp
index 314697869c..1d02a95b30 100644
--- a/engines/scumm/he/sound_he.cpp
+++ b/engines/scumm/he/sound_he.cpp
@@ -240,7 +240,7 @@ int SoundHE::isSoundCodeUsed(int sound) {
chan = i;
}
- if (_mixer->isSoundHandleActive(_heSoundChannels[chan]) && chan != -1) {
+ if (chan != -1 && _mixer->isSoundHandleActive(_heSoundChannels[chan])) {
return _heChannel[chan].sbngBlock;
} else {
return 0;
@@ -254,7 +254,7 @@ int SoundHE::getSoundPos(int sound) {
chan = i;
}
- if (_mixer->isSoundHandleActive(_heSoundChannels[chan]) && chan != -1) {
+ if (chan != -1 && _mixer->isSoundHandleActive(_heSoundChannels[chan])) {
int time = _vm->getHETimer(chan + 4) * _heChannel[chan].rate / 1000;
return time;
} else {
@@ -275,7 +275,7 @@ int SoundHE::getSoundVar(int sound, int var) {
chan = i;
}
- if (_mixer->isSoundHandleActive(_heSoundChannels[chan]) && chan != -1) {
+ if (chan != -1 && _mixer->isSoundHandleActive(_heSoundChannels[chan])) {
debug(5, "getSoundVar: sound %d var %d result %d", sound, var, _heChannel[chan].soundVars[var]);
return _heChannel[chan].soundVars[var];
} else {
diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp
index 361a3bc165..ddbbb2101f 100644
--- a/engines/scumm/he/wiz_he.cpp
+++ b/engines/scumm/he/wiz_he.cpp
@@ -358,6 +358,7 @@ static bool calcClipRects(int dst_w, int dst_h, int src_x, int src_y, int src_w,
void Wiz::writeColor(uint8 *dstPtr, int dstType, uint16 color) {
switch (dstType) {
+ case kDstCursor:
case kDstScreen:
WRITE_UINT16(dstPtr, color);
break;
@@ -1519,7 +1520,7 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int
cw = width;
ch = height;
dstPitch = cw * _vm->_bytesPerPixel;
- dstType = kDstMemory;
+ dstType = (_cursorImage) ? kDstCursor : kDstMemory;
} else {
if (dstResNum) {
uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum);
diff --git a/engines/scumm/he/wiz_he.h b/engines/scumm/he/wiz_he.h
index 1fa9564486..c255e27d14 100644
--- a/engines/scumm/he/wiz_he.h
+++ b/engines/scumm/he/wiz_he.h
@@ -145,7 +145,8 @@ enum {
enum DstSurface {
kDstScreen = 0,
kDstMemory = 1,
- kDstResource = 2
+ kDstResource = 2,
+ kDstCursor = 3
};
class ScummEngine_v71he;
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index 3a672d57b5..8cccbc227a 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -700,9 +700,9 @@ int32 IMuseInternal::doCommand_internal(int numargs, int a[]) {
{
Common::String string = "doCommand - ";
- string += Common::String::printf("%d (%d/%d)", a[0], (int)param, (int)cmd);
+ string += Common::String::format("%d (%d/%d)", a[0], (int)param, (int)cmd);
for (i = 1; i < numargs; ++i)
- string += Common::String::printf(", %d", a[i]);
+ string += Common::String::format(", %d", a[i]);
debugC(DEBUG_IMUSE, "%s", string.c_str());
}
diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index 3876bd4e80..f2e50382b3 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -944,7 +944,7 @@ bool Insane::actor1StateFlags(int state) {
bool retvalue = 0;
unsigned int i;
- for (i = 0; i < sizeof(spans); i++) {
+ for (i = 0; i < ARRAYSIZE(spans); i++) {
retvalue = !retvalue;
if (spans[i] <= state)
break;
@@ -1099,7 +1099,7 @@ bool Insane::actor0StateFlags1(int state) {
bool retvalue = 1;
unsigned int i;
- for (i = 0; i < sizeof(spans); i++) {
+ for (i = 0; i < ARRAYSIZE(spans); i++) {
retvalue = !retvalue;
if (spans[i] >= state)
break;
@@ -1119,7 +1119,7 @@ bool Insane::actor0StateFlags2(int state) {
bool retvalue = 1;
unsigned int i;
- for (i = 0; i < sizeof(spans); i++) {
+ for (i = 0; i < ARRAYSIZE(spans); i++) {
retvalue = !retvalue;
if (spans[i] >= state)
break;
diff --git a/engines/scumm/insane/insane_ben.cpp b/engines/scumm/insane/insane_ben.cpp
index 9ddb4c6670..05775f1585 100644
--- a/engines/scumm/insane/insane_ben.cpp
+++ b/engines/scumm/insane/insane_ben.cpp
@@ -1163,7 +1163,7 @@ void Insane::actor02Reaction(int32 buttons) {
setBenState();
_actor[0].act[2].tilt = 0;
// for some reason there is no break at this
- // place, so tilt gets overriden on next line
+ // place, so tilt gets overridden on next line
}
_actor[0].act[2].tilt = calcTilt(_actor[0].tilt);
break;
diff --git a/engines/scumm/insane/insane_enemy.cpp b/engines/scumm/insane/insane_enemy.cpp
index 2291b2c37b..e8d97d3875 100644
--- a/engines/scumm/insane/insane_enemy.cpp
+++ b/engines/scumm/insane/insane_enemy.cpp
@@ -1328,7 +1328,7 @@ void Insane::turnEnemy(bool battle) {
if (_actor[1].damage < _actor[1].maxdamage) {
_actor[1].lost = false;
} else {
- if (!_actor[1].lost && !_actor[1].lost) {
+ if (!_actor[1].lost && !_actor[0].lost) {
_actor[1].lost = true;
_actor[1].act[2].state = 36;
_actor[1].act[1].state = 36;
@@ -2072,7 +2072,7 @@ void Insane::actor12Reaction(int32 buttons) {
setEnemyState();
_actor[1].act[2].tilt = 0;
// for some reason there is no break at this
- // place, so tilt gets overriden on next line
+ // place, so tilt gets overridden on next line
}
_actor[1].act[2].tilt = calcTilt(_actor[1].tilt);
break;
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index cd89f5ffad..1a60564a9e 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -41,6 +41,7 @@ MODULE_OBJS := \
player_v1.o \
player_v2.o \
player_v2a.o \
+ player_v2base.o \
player_v2cms.o \
player_v3a.o \
player_v4a.o \
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp
index e2b68f8d3b..c44043ca81 100644
--- a/engines/scumm/object.cpp
+++ b/engines/scumm/object.cpp
@@ -315,6 +315,10 @@ int ScummEngine::getObjectIndex(int object) const {
return -1;
for (i = (_numLocalObjects-1); i > 0; i--) {
+ if (_game.version == 0 )
+ if( _objs[i].flags != _v0ObjectFlag )
+ continue;
+
if (_objs[i].obj_nr == object)
return i;
}
@@ -526,6 +530,9 @@ int ScummEngine::findObject(int x, int y) {
#endif
if (_objs[i].x_pos <= x && _objs[i].width + _objs[i].x_pos > x &&
_objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y) {
+ // MMC64: Set the object search flag
+ if (_game.version == 0)
+ _v0ObjectFlag = _objs[i].flags;
if (_game.version == 0 && _v0ObjectIndex)
return i;
else
@@ -993,6 +1000,7 @@ void ScummEngine::resetRoomObject(ObjectData *od, const byte *room, const byte *
od->flags = Gdi::dbAllowMaskOr;
if (_game.version == 8) {
+ assert(imhd);
od->obj_nr = READ_LE_UINT16(&(cdhd->v7.obj_id));
od->parent = cdhd->v7.parent;
@@ -1008,6 +1016,7 @@ void ScummEngine::resetRoomObject(ObjectData *od, const byte *room, const byte *
od->flags = ((((byte)READ_LE_UINT32(&imhd->v8.flags)) & 16) == 0) ? Gdi::dbAllowMaskOr : 0;
} else if (_game.version == 7) {
+ assert(imhd);
od->obj_nr = READ_LE_UINT16(&(cdhd->v7.obj_id));
od->parent = cdhd->v7.parent;
@@ -1020,6 +1029,7 @@ 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/palette.cpp b/engines/scumm/palette.cpp
index 5c0c58595b..672af1e191 100644
--- a/engines/scumm/palette.cpp
+++ b/engines/scumm/palette.cpp
@@ -71,7 +71,7 @@ void ScummEngine::resetPalette() {
// Use 17 color table for v1 games to allow correct color for inventory and
// sentence line. Original games used some kind of dynamic color table
// remapping between rooms.
- 0xFF, 0x55, 0xFF
+ 0x7F, 0x3B, 0xA6
};
static const byte tableNESPalette[] = {
@@ -498,7 +498,7 @@ void ScummEngine::cyclePalette() {
int i, j;
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
- if (_game.platform == Common::kPlatformFMTowns && (!_townsPaletteFlags & 1))
+ if (_game.platform == Common::kPlatformFMTowns && !(_townsPaletteFlags & 1))
return;
#endif
@@ -544,7 +544,7 @@ void ScummEngine::moveMemInPalRes(int start, int end, byte direction) {
void ScummEngine::palManipulateInit(int resID, int start, int end, int time) {
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
- if (_game.platform == Common::kPlatformFMTowns && (!_townsPaletteFlags & 1))
+ if (_game.platform == Common::kPlatformFMTowns && !(_townsPaletteFlags & 1))
return;
#endif
diff --git a/engines/scumm/player_nes.h b/engines/scumm/player_nes.h
index b2eafb79b0..89292f7c24 100644
--- a/engines/scumm/player_nes.h
+++ b/engines/scumm/player_nes.h
@@ -75,8 +75,6 @@ private:
void APU_writeControl(byte value);
byte APU_readStatus();
- void do_mix(int16 *buf, uint len);
-
ScummEngine *_vm;
Audio::Mixer *_mixer;
Audio::SoundHandle _soundHandle;
diff --git a/engines/scumm/player_pce.cpp b/engines/scumm/player_pce.cpp
index a17aab4d59..4236fb2d6b 100644
--- a/engines/scumm/player_pce.cpp
+++ b/engines/scumm/player_pce.cpp
@@ -152,7 +152,7 @@ static const uint16 sounds[13][6] = {
// 0xB2A1
static const byte data_table[482] = {
/* 0*/ 0xE2, 0x0A, 0xE1, 0x0D, 0xE6, 0xED, 0xE0, 0x0F, 0xE2, 0x00, 0xE1, 0x00,
- 0xF2, 0xF2, 0xB2, 0xE1, 0x01, 0xF2, 0xF2, 0xB2, 0xE1, 0x02, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xB2, 0xE1, 0x01, 0xF2, 0xF2, 0xB2, 0xE1, 0x02, 0xF2, 0xF2,
0xB2, 0xE1, 0x03, 0xF2, 0xF2, 0xB2, 0xE1, 0x04, 0xF2, 0xF2, 0xB2, 0xE1,
0x05, 0xF2, 0xF2, 0xB2, 0xE1, 0x06, 0xF2, 0xF2, 0xB2, 0xE1, 0x07, 0xF2,
0xF2, 0xB2, 0xE1, 0x08, 0xF2, 0xF2, 0xB2, 0xE1, 0x09, 0xF2, 0xF2, 0xB2,
@@ -208,10 +208,10 @@ static const byte data_table[482] = {
/*395*/ 0xE2, 0x0C, 0xE1, 0x00, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0x0B, 0xE8, 0x0B, 0xFF,
/*408*/ 0xE2, 0x0C, 0xE1, 0x03, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x00,
- 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
- 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
- 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
- 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xFF,
+ 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
+ 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
+ 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
+ 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xFF,
/*467*/ 0xE2, 0x0C, 0xE1, 0x00, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0x1B, 0xE8, 0x1B, 0xFF,
/*480*/ 0xFF,
@@ -238,11 +238,11 @@ private:
double _clock;
double _rate;
uint8 _select;
- uint8 _balance;
- channel_t _channel[8];
- int16 _volumeTable[32];
- uint32 _noiseFreqTable[32];
- uint32 _waveFreqTable[4096];
+ uint8 _balance;
+ channel_t _channel[8];
+ int16 _volumeTable[32];
+ uint32 _noiseFreqTable[32];
+ uint32 _waveFreqTable[4096];
public:
void init();
@@ -255,180 +255,180 @@ public:
PSG_HuC6280::PSG_HuC6280(double clock, double samplerate) {
_clock = clock;
- _rate = samplerate;
+ _rate = samplerate;
- // Initialize PSG_HuC6280 emulator
- init();
+ // Initialize PSG_HuC6280 emulator
+ init();
}
void PSG_HuC6280::init() {
- int i;
- double step;
+ int i;
+ double step;
- // Loudest volume level for table
- double level = 65535.0 / 6.0 / 32.0;
+ // Loudest volume level for table
+ double level = 65535.0 / 6.0 / 32.0;
- // Clear context
+ // Clear context
reset();
- // Make waveform frequency table
- for(i = 0; i < 4096; i++) {
- step = ((_clock / _rate) * 4096) / (i+1);
- _waveFreqTable[(1 + i) & 0xFFF] = (uint32)step;
- }
-
- // Make noise frequency table
- for(i = 0; i < 32; i++) {
- step = ((_clock / _rate) * 32) / (i+1);
- _noiseFreqTable[i] = (uint32)step;
- }
-
- // Make volume table
- // PSG_HuC6280 has 48dB volume range spread over 32 steps
- step = 48.0 / 32.0;
- for(i = 0; i < 31; i++) {
- _volumeTable[i] = (uint16)level;
- level /= pow(10.0, step / 20.0);
- }
- _volumeTable[31] = 0;
+ // Make waveform frequency table
+ for(i = 0; i < 4096; i++) {
+ step = ((_clock / _rate) * 4096) / (i+1);
+ _waveFreqTable[(1 + i) & 0xFFF] = (uint32)step;
+ }
+
+ // Make noise frequency table
+ for(i = 0; i < 32; i++) {
+ step = ((_clock / _rate) * 32) / (i+1);
+ _noiseFreqTable[i] = (uint32)step;
+ }
+
+ // Make volume table
+ // PSG_HuC6280 has 48dB volume range spread over 32 steps
+ step = 48.0 / 32.0;
+ for(i = 0; i < 31; i++) {
+ _volumeTable[i] = (uint16)level;
+ level /= pow(10.0, step / 20.0);
+ }
+ _volumeTable[31] = 0;
}
void PSG_HuC6280::reset() {
_select = 0;
- _balance = 0xFF;
- memset(_channel, 0, sizeof(_channel));
- memset(_volumeTable, 0, sizeof(_volumeTable));
- memset(_noiseFreqTable, 0, sizeof(_noiseFreqTable));
- memset(_waveFreqTable, 0, sizeof(_waveFreqTable));
+ _balance = 0xFF;
+ memset(_channel, 0, sizeof(_channel));
+ memset(_volumeTable, 0, sizeof(_volumeTable));
+ memset(_noiseFreqTable, 0, sizeof(_noiseFreqTable));
+ memset(_waveFreqTable, 0, sizeof(_waveFreqTable));
}
void PSG_HuC6280::write(int offset, byte data) {
- channel_t *chan = &_channel[_select];
-
- switch(offset & 0x0F) {
- case 0x00: // Channel select
- _select = data & 0x07;
- break;
-
- case 0x01: // Global balance
- _balance = data;
- break;
-
- case 0x02: // Channel frequency (LSB)
- chan->frequency = (chan->frequency & 0x0F00) | data;
- chan->frequency &= 0x0FFF;
- break;
-
- case 0x03: // Channel frequency (MSB)
- chan->frequency = (chan->frequency & 0x00FF) | (data << 8);
- chan->frequency &= 0x0FFF;
- break;
-
- case 0x04: // Channel control (key-on, DDA mode, volume)
- // 1-to-0 transition of DDA bit resets waveform index
- if((chan->control & 0x40) && ((data & 0x40) == 0)) {
- chan->index = 0;
- }
- chan->control = data;
- break;
-
- case 0x05: // Channel balance
- chan->balance = data;
- break;
-
- case 0x06: // Channel waveform data
- switch(chan->control & 0xC0) {
- case 0x00:
- chan->waveform[chan->index & 0x1F] = data & 0x1F;
- chan->index = (chan->index + 1) & 0x1F;
- break;
-
- case 0x40:
- break;
-
- case 0x80:
- chan->waveform[chan->index & 0x1F] = data & 0x1F;
- chan->index = (chan->index + 1) & 0x1F;
- break;
-
- case 0xC0:
- chan->dda = data & 0x1F;
- break;
- }
-
- break;
-
- case 0x07: // Noise control (enable, frequency)
- case 0x08: // LFO frequency
- case 0x09: // LFO control (enable, mode)
- break;
-
- default:
- break;
- }
+ channel_t *chan = &_channel[_select];
+
+ switch(offset & 0x0F) {
+ case 0x00: // Channel select
+ _select = data & 0x07;
+ break;
+
+ case 0x01: // Global balance
+ _balance = data;
+ break;
+
+ case 0x02: // Channel frequency (LSB)
+ chan->frequency = (chan->frequency & 0x0F00) | data;
+ chan->frequency &= 0x0FFF;
+ break;
+
+ case 0x03: // Channel frequency (MSB)
+ chan->frequency = (chan->frequency & 0x00FF) | (data << 8);
+ chan->frequency &= 0x0FFF;
+ break;
+
+ case 0x04: // Channel control (key-on, DDA mode, volume)
+ // 1-to-0 transition of DDA bit resets waveform index
+ if((chan->control & 0x40) && ((data & 0x40) == 0)) {
+ chan->index = 0;
+ }
+ chan->control = data;
+ break;
+
+ case 0x05: // Channel balance
+ chan->balance = data;
+ break;
+
+ case 0x06: // Channel waveform data
+ switch(chan->control & 0xC0) {
+ case 0x00:
+ chan->waveform[chan->index & 0x1F] = data & 0x1F;
+ chan->index = (chan->index + 1) & 0x1F;
+ break;
+
+ case 0x40:
+ break;
+
+ case 0x80:
+ chan->waveform[chan->index & 0x1F] = data & 0x1F;
+ chan->index = (chan->index + 1) & 0x1F;
+ break;
+
+ case 0xC0:
+ chan->dda = data & 0x1F;
+ break;
+ }
+
+ break;
+
+ case 0x07: // Noise control (enable, frequency)
+ case 0x08: // LFO frequency
+ case 0x09: // LFO control (enable, mode)
+ break;
+
+ default:
+ break;
+ }
}
void PSG_HuC6280::update(int16* samples, int sampleCnt) {
- static const int scale_tab[] = {
- 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
- 0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F
- };
- int ch;
- int i;
+ static const int scale_tab[] = {
+ 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
+ 0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F
+ };
+ int ch;
+ int i;
- int lmal = (_balance >> 4) & 0x0F;
- int rmal = (_balance >> 0) & 0x0F;
- int vll, vlr;
+ int lmal = (_balance >> 4) & 0x0F;
+ int rmal = (_balance >> 0) & 0x0F;
+ int vll, vlr;
- lmal = scale_tab[lmal];
- rmal = scale_tab[rmal];
+ lmal = scale_tab[lmal];
+ rmal = scale_tab[rmal];
- // Clear buffer
+ // Clear buffer
memset(samples, 0, 2 * sampleCnt * sizeof(int16));
- for(ch = 0; ch < 6; ch++) {
- // Only look at enabled channels
- if(_channel[ch].control & 0x80) {
- int lal = (_channel[ch].balance >> 4) & 0x0F;
- int ral = (_channel[ch].balance >> 0) & 0x0F;
- int al = _channel[ch].control & 0x1F;
-
- lal = scale_tab[lal];
- ral = scale_tab[ral];
-
- // Calculate volume just as the patent says
- vll = (0x1F - lal) + (0x1F - al) + (0x1F - lmal);
- if(vll > 0x1F) vll = 0x1F;
-
- vlr = (0x1F - ral) + (0x1F - al) + (0x1F - rmal);
- if(vlr > 0x1F) vlr = 0x1F;
-
- vll = _volumeTable[vll];
- vlr = _volumeTable[vlr];
-
- // Check channel mode
- if(_channel[ch].control & 0x40) {
- /* DDA mode */
- for(i = 0; i < sampleCnt; i++) {
- samples[2*i] += (int16)(vll * (_channel[ch].dda - 16));
- samples[2*i + 1] += (int16)(vlr * (_channel[ch].dda - 16));
- }
- } else {
- /* Waveform mode */
- uint32 step = _waveFreqTable[_channel[ch].frequency];
- for(i = 0; i < sampleCnt; i += 1) {
- int offset;
- int16 data;
- offset = (_channel[ch].counter >> 12) & 0x1F;
- _channel[ch].counter += step;
- _channel[ch].counter &= 0x1FFFF;
- data = _channel[ch].waveform[offset];
- samples[2*i] += (int16)(vll * (data - 16));
- samples[2*i + 1] += (int16)(vlr * (data - 16));
- }
- }
- }
- }
+ for(ch = 0; ch < 6; ch++) {
+ // Only look at enabled channels
+ if(_channel[ch].control & 0x80) {
+ int lal = (_channel[ch].balance >> 4) & 0x0F;
+ int ral = (_channel[ch].balance >> 0) & 0x0F;
+ int al = _channel[ch].control & 0x1F;
+
+ lal = scale_tab[lal];
+ ral = scale_tab[ral];
+
+ // Calculate volume just as the patent says
+ vll = (0x1F - lal) + (0x1F - al) + (0x1F - lmal);
+ if(vll > 0x1F) vll = 0x1F;
+
+ vlr = (0x1F - ral) + (0x1F - al) + (0x1F - rmal);
+ if(vlr > 0x1F) vlr = 0x1F;
+
+ vll = _volumeTable[vll];
+ vlr = _volumeTable[vlr];
+
+ // Check channel mode
+ if(_channel[ch].control & 0x40) {
+ /* DDA mode */
+ for(i = 0; i < sampleCnt; i++) {
+ samples[2*i] += (int16)(vll * (_channel[ch].dda - 16));
+ samples[2*i + 1] += (int16)(vlr * (_channel[ch].dda - 16));
+ }
+ } else {
+ /* Waveform mode */
+ uint32 step = _waveFreqTable[_channel[ch].frequency];
+ for(i = 0; i < sampleCnt; i += 1) {
+ int offset;
+ int16 data;
+ offset = (_channel[ch].counter >> 12) & 0x1F;
+ _channel[ch].counter += step;
+ _channel[ch].counter &= 0x1FFFF;
+ data = _channel[ch].waveform[offset];
+ samples[2*i] += (int16)(vll * (data - 16));
+ samples[2*i + 1] += (int16)(vlr * (data - 16));
+ }
+ }
+ }
+ }
}
@@ -466,7 +466,7 @@ void Player_PCE::procA541(channel_t *channel) {
channel->controlVec24 = false;
channel->controlVec21 = 0;
- channel->waveformCtrl = 0x80;
+ channel->waveformCtrl = 0x80;
}
// A592
diff --git a/engines/scumm/player_v2.cpp b/engines/scumm/player_v2.cpp
index c1c9b3930e..60103b20fb 100644
--- a/engines/scumm/player_v2.cpp
+++ b/engines/scumm/player_v2.cpp
@@ -23,8 +23,6 @@
*
*/
-
-#include "engines/engine.h"
#include "scumm/player_v2.h"
#include "scumm/scumm.h"
#include "sound/mididrv.h"
@@ -32,373 +30,51 @@
namespace Scumm {
-#define FREQ_HZ 236 // Don't change!
-
#define SPK_DECAY 0xa000 /* Depends on sample rate */
#define PCJR_DECAY 0xa000 /* Depends on sample rate */
-#define FIXP_SHIFT 16
-#define MAX_OUTPUT 0x7fff
-
#define NG_PRESET 0x0f35 /* noise generator preset */
#define FB_WNOISE 0x12000 /* feedback for white noise */
#define FB_PNOISE 0x08000 /* feedback for periodic noise */
-const uint8 note_lengths[] = {
- 0,
- 0, 0, 2,
- 0, 3, 4,
- 5, 6, 8,
- 9, 12, 16,
- 18, 24, 32,
- 36, 48, 64,
- 72, 96
-};
-
-static const uint16 hull_offsets[] = {
- 0, 12, 24, 36, 48, 60,
- 72, 88, 104, 120, 136, 256,
- 152, 164, 180
-};
-
-static const int16 hulls[] = {
- // hull 0
- 3, -1, 0, 0, 0, 0, 0, 0,
- 0, -1, 0, 0,
- // hull 1 (staccato)
- 3, -1, 0, 32, 0, -1, 0, 0,
- 0, -1, 0, 0,
- // hull 2 (legato)
- 3, -1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- // hull 3 (staccatissimo)
- 3, -1, 0, 2, 0, -1, 0, 0,
- 0, -1, 0, 0,
- // hull 4
- 3, -1, 0, 6, 0, -1, 0, 0,
- 0, -1, 0, 0,
- // hull 5
- 3, -1, 0, 16, 0, -1, 0, 0,
- 0, -1, 0, 0,
- // hull 6
- (int16) 60000, -1, -1000, 20, 0, 0, 0, 0,
- (int16) 40000, -1, -5000, 5, 0, -1, 0, 0,
- // hull 7
- (int16) 50000, -1, 0, 8, 30000, -1, 0, 0,
- 28000, -1, -5000, 5, 0, -1, 0, 0,
- // hull 8
- (int16) 60000, -1, -2000, 16, 0, 0, 0, 0,
- 28000, -1, -6000, 5, 0, -1, 0, 0,
- // hull 9
- (int16) 55000, -1, 0, 8, (int16) 35000, -1, 0, 0,
- (int16) 40000, -1, -2000, 10, 0, -1, 0, 0,
- // hull 10
- (int16) 60000, -1, 0, 4, -2000, 8, 0, 0,
- (int16) 40000, -1, -6000, 5, 0, -1, 0, 0,
- // hull 12
- 0, -1, 150, 340, -150, 340, 0, -1,
- 0, -1, 0, 0,
- // hull 13 == 164
- 20000, -1, 4000, 7, 1000, 15, 0, 0,
- (int16) 35000, -1, -2000, 15, 0, -1, 0, 0,
-
- // hull 14 == 180
- (int16) 35000, -1, 500, 20, 0, 0, 0, 0,
- (int16) 45000, -1, -500, 60, 0, -1, 0, 0,
-
- // hull misc = 196
- (int16) 44000, -1, -4400, 10, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 53000, -1, -5300, 10, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 63000, -1, -6300, 10, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 44000, -1, -1375, 32, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 53000, -1, -1656, 32, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- // hull 11 == 256
- (int16) 63000, -1, -1968, 32, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 44000, -1, - 733, 60, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 53000, -1, - 883, 60, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 63000, -1, -1050, 60, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 44000, -1, - 488, 90, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 53000, -1, - 588, 90, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 63000, -1, - 700, 90, 0, -1, 0, 0,
- 0, -1, 0, 0
-};
-
-static const uint16 freqmod_lengths[] = {
- 0x1000, 0x1000, 0x20, 0x2000, 0x1000
-};
-
-static const uint16 freqmod_offsets[] = {
- 0, 0x100, 0x200, 0x302, 0x202
-};
-
-static const int8 freqmod_table[0x502] = {
- 0, 3, 6, 9, 12, 15, 18, 21,
- 24, 27, 30, 33, 36, 39, 42, 45,
- 48, 51, 54, 57, 59, 62, 65, 67,
- 70, 73, 75, 78, 80, 82, 85, 87,
- 89, 91, 94, 96, 98, 100, 102, 103,
- 105, 107, 108, 110, 112, 113, 114, 116,
- 117, 118, 119, 120, 121, 122, 123, 123,
- 124, 125, 125, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 125, 125,
- 124, 123, 123, 122, 121, 120, 119, 118,
- 117, 116, 114, 113, 112, 110, 108, 107,
- 105, 103, 102, 100, 98, 96, 94, 91,
- 89, 87, 85, 82, 80, 78, 75, 73,
- 70, 67, 65, 62, 59, 57, 54, 51,
- 48, 45, 42, 39, 36, 33, 30, 27,
- 24, 21, 18, 15, 12, 9, 6, 3,
- 0, -3, -6, -9, -12, -15, -18, -21,
- -24, -27, -30, -33, -36, -39, -42, -45,
- -48, -51, -54, -57, -59, -62, -65, -67,
- -70, -73, -75, -78, -80, -82, -85, -87,
- -89, -91, -94, -96, -98,-100,-102,-103,
- -105,-107,-108,-110,-112,-113,-114,-116,
- -117,-118,-119,-120,-121,-122,-123,-123,
- -124,-125,-125,-126,-126,-126,-126,-126,
- -126,-126,-126,-126,-126,-126,-125,-125,
- -124,-123,-123,-122,-121,-120,-119,-118,
- -117,-116,-114,-113,-112,-110,-108,-107,
- -105,-103,-102,-100, -98, -96, -94, -91,
- -89, -87, -85, -82, -80, -78, -75, -73,
- -70, -67, -65, -62, -59, -57, -54, -51,
- -48, -45, -42, -39, -36, -33, -30, -27,
- -24, -21, -18, -15, -12, -9, -6, -3,
-
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127,
- -128,-127,-126,-125,-124,-123,-122,-121,
- -120,-119,-118,-117,-116,-115,-114,-113,
- -112,-111,-110,-109,-108,-107,-106,-105,
- -104,-103,-102,-101,-100, -99, -98, -97,
- -96, -95, -94, -93, -92, -91, -90, -89,
- -88, -87, -86, -85, -84, -83, -82, -81,
- -80, -79, -78, -77, -76, -75, -74, -73,
- -72, -71, -70, -69, -68, -67, -66, -65,
- -64, -63, -62, -61, -60, -59, -58, -57,
- -56, -55, -54, -53, -52, -51, -50, -49,
- -48, -47, -46, -45, -44, -43, -42, -41,
- -40, -39, -38, -37, -36, -35, -34, -33,
- -32, -31, -30, -29, -28, -27, -26, -25,
- -24, -23, -22, -21, -20, -19, -18, -17,
- -16, -15, -14, -13, -12, -11, -10, -9,
- -8, -7, -6, -5, -4, -3, -2, -1,
-
- -120, 120,
-
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
-
- 41, 35, -66,-124, -31, 108, -42, -82,
- 82,-112, 73, -15, -15, -69, -23, -21,
- -77, -90, -37, 60,-121, 12, 62,-103,
- 36, 94, 13, 28, 6, -73, 71, -34,
- -77, 18, 77, -56, 67, -69,-117, -90,
- 31, 3, 90, 125, 9, 56, 37, 31,
- 93, -44, -53, -4,-106, -11, 69, 59,
- 19, 13,-119, 10, 28, -37, -82, 50,
- 32,-102, 80, -18, 64, 120, 54, -3,
- 18, 73, 50, -10, -98, 125, 73, -36,
- -83, 79, 20, -14, 68, 64, 102, -48,
- 107, -60, 48, -73, 50, 59, -95, 34,
- -10, 34,-111, -99, -31,-117, 31, -38,
- -80, -54,-103, 2, -71, 114, -99, 73,
- 44,-128, 126, -59,-103, -43, -23,-128,
- -78, -22, -55, -52, 83, -65, 103, -42,
- -65, 20, -42, 126, 45, -36,-114, 102,
- -125, -17, 87, 73, 97, -1, 105,-113,
- 97, -51, -47, 30, -99,-100, 22, 114,
- 114, -26, 29, -16,-124, 79, 74, 119,
- 2, -41, -24, 57, 44, 83, -53, -55,
- 18, 30, 51, 116, -98, 12, -12, -43,
- -44, -97, -44, -92, 89, 126, 53, -49,
- 50, 34, -12, -52, -49, -45,-112, 45,
- 72, -45,-113, 117, -26, -39, 29, 42,
- -27, -64, -9, 43, 120,-127,-121, 68,
- 14, 95, 80, 0, -44, 97,-115, -66,
- 123, 5, 21, 7, 59, 51,-126, 31,
- 24, 112,-110, -38, 100, 84, -50, -79,
- -123, 62, 105, 21, -8, 70, 106, 4,
- -106, 115, 14, -39, 22, 47, 103, 104,
- -44, -9, 74, 74, -48, 87, 104, 118,
- -6, 22, -69, 17, -83, -82, 36,-120,
- 121, -2, 82, -37, 37, 67, -27, 60,
- -12, 69, -45, -40, 40, -50, 11, -11,
- -59, 96, 89, 61,-105, 39,-118, 89,
- 118, 45, -48, -62, -55, -51, 104, -44,
- 73, 106, 121, 37, 8, 97, 64, 20,
- -79, 59, 106, -91, 17, 40, -63,-116,
- -42, -87, 11,-121,-105,-116, 47, -15,
- 21, 29,-102,-107, -63,-101, -31, -64,
- 126, -23, -88,-102, -89,-122, -62, -75,
- 84, -65,-102, -25, -39, 35, -47, 85,
- -112, 56, 40, -47, -39, 108, -95, 102,
- 94, 78, -31, 48,-100, -2, -39, 113,
- -97, -30, -91, -30, 12,-101, -76, 71,
- 101, 56, 42, 70,-119, -87,-126, 121,
- 122, 118, 120, -62, 99, -79, 38, -33,
- -38, 41, 109, 62, 98, -32,-106, 18,
- 52, -65, 57, -90, 63,-119, 94, -15,
- 109, 14, -29, 108, 40, -95, 30, 32,
- 29, -53, -62, 3, 63, 65, 7,-124,
- 15, 20, 5, 101, 27, 40, 97, -55,
- -59, -25, 44,-114, 70, 54, 8, -36,
- -13, -88,-115, -2, -66, -14, -21, 113,
- -1, -96, -48, 59, 117, 6,-116, 126,
- -121, 120, 115, 77, -48, -66,-126, -66,
- -37, -62, 70, 65, 43,-116, -6, 48,
- 127, 112, -16, -89, 84,-122, 50,-107,
- -86, 91, 104, 19, 11, -26, -4, -11,
- -54, -66, 125, -97,-119,-118, 65, 27,
- -3, -72, 79, 104, -10, 114, 123, 20,
- -103, -51, -45, 13, -16, 68, 58, -76,
- -90, 102, 83, 51, 11, -53, -95, 16
-};
-
-
-static const uint16 spk_freq_table[12] = {
- 36484, 34436, 32503, 30679, 28957, 27332,
- 25798, 24350, 22983, 21693, 20476, 19326
-};
-
-static const uint16 pcjr_freq_table[12] = {
- 65472, 61760, 58304, 55040, 52032, 49024,
- 46272, 43648, 41216, 38912, 36736, 34624
-};
-
-
-Player_V2::Player_V2(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr) {
- int i;
-
- _isV3Game = (scumm->_game.version >= 3);
- _vm = scumm;
- _mixer = mixer;
- _sampleRate = _mixer->getOutputRate();
-
- _header_len = (scumm->_game.features & GF_OLD_BUNDLE) ? 4 : 6;
- // Initialize sound queue
- _current_nr = _next_nr = 0;
- _current_data = _next_data = 0;
+Player_V2::Player_V2(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr)
+ : Player_V2Base(scumm, mixer, pcjr) {
- // Initialize channel code
- for (i = 0; i < 4; ++i)
- clear_channel(i);
-
- _next_tick = 0;
- _tick_len = (_sampleRate << FIXP_SHIFT) / FREQ_HZ;
-
- // Initialize V3 music timer
- _music_timer_ctr = _music_timer = 0;
- _ticks_per_music_timer = 65535;
+ int i;
// Initialize square generator
_level = 0;
_RNG = NG_PRESET;
- set_pcjr(pcjr);
- setMusicVolume(255);
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-}
-
-Player_V2::~Player_V2() {
- Common::StackLock lock(_mutex);
- _mixer->stopHandle(_soundHandle);
-}
-
-void Player_V2::set_pcjr(bool pcjr) {
- Common::StackLock lock(_mutex);
-
_pcjr = pcjr;
if (_pcjr) {
_decay = PCJR_DECAY;
_update_step = (_sampleRate << FIXP_SHIFT) / (111860 * 2);
- _freqs_table = pcjr_freq_table;
} else {
_decay = SPK_DECAY;
_update_step = (_sampleRate << FIXP_SHIFT) / (1193000 * 2);
- _freqs_table = spk_freq_table;
}
- /* adapt _decay to sample rate. It must be squared when
- * sample rate doubles.
- */
- int i;
+ // Adapt _decay to sample rate. It must be squared when
+ // sample rate doubles.
for (i = 0; (_sampleRate << i) < 30000; i++)
_decay = _decay * _decay / 65536;
_timer_output = 0;
for (i = 0; i < 4; i++)
_timer_count[i] = 0;
+
+ setMusicVolume(255);
+
+ _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+}
+
+Player_V2::~Player_V2() {
+ Common::StackLock lock(_mutex);
+ _mixer->stopHandle(_soundHandle);
}
void Player_V2::setMusicVolume (int vol) {
@@ -421,33 +97,6 @@ void Player_V2::setMusicVolume (int vol) {
_volumetable[15] = 0;
}
-void Player_V2::chainSound(int nr, byte *data) {
- int offset = _header_len + (_pcjr ? 10 : 2);
-
- _current_nr = nr;
- _current_data = data;
-
- for (int i = 0; i < 4; i++) {
- clear_channel(i);
-
- _channels[i].d.music_script_nr = nr;
- if (data) {
- _channels[i].d.next_cmd = READ_LE_UINT16(data + offset + 2 * i);
- if (_channels[i].d.next_cmd)
- _channels[i].d.time_left = 1;
- }
- }
- _music_timer = 0;
-}
-
-void Player_V2::chainNextSound() {
- if (_next_nr) {
- chainSound(_next_nr, _next_data);
- _next_nr = 0;
- _next_data = 0;
- }
-}
-
void Player_V2::stopAllSounds() {
Common::StackLock lock(_mutex);
@@ -476,11 +125,11 @@ void Player_V2::stopSound(int nr) {
}
void Player_V2::startSound(int nr) {
+ Common::StackLock lock(_mutex);
+
byte *data = _vm->getResourceAddress(rtSound, nr);
assert(data);
- Common::StackLock lock(_mutex);
-
int cprio = _current_data ? *(_current_data + _header_len) : 0;
int prio = *(data + _header_len);
int nprio = _next_data ? *(_next_data + _header_len) : 0;
@@ -519,272 +168,11 @@ int Player_V2::getSoundStatus(int nr) const {
return _current_nr == nr || _next_nr == nr;
}
-
-void Player_V2::clear_channel(int i) {
- ChannelInfo *channel = &_channels[i];
- memset(channel, 0, sizeof(ChannelInfo));
-}
-
-int Player_V2::getMusicTimer() {
- if (_isV3Game)
- return _music_timer;
- else
- return _channels[0].d.music_timer;
-}
-
-void Player_V2::execute_cmd(ChannelInfo *channel) {
- uint16 value;
- int16 offset;
- uint8 *script_ptr;
- ChannelInfo * current_channel;
- ChannelInfo * dest_channel;
-
- current_channel = channel;
-
- if (channel->d.next_cmd == 0)
- goto check_stopped;
- script_ptr = &_current_data[channel->d.next_cmd];
-
- for (;;) {
- uint8 opcode = *script_ptr++;
- if (opcode >= 0xf8) {
- switch (opcode) {
- case 0xf8: // set hull curve
- debug(7, "channels[%lu]: hull curve %2d",
- (long)(channel - _channels), *script_ptr);
- channel->d.hull_curve = hull_offsets[*script_ptr / 2];
- script_ptr++;
- break;
-
- case 0xf9: // set freqmod curve
- debug(7, "channels[%lu]: freqmod curve %2d",
- (long)(channel - _channels), *script_ptr);
- channel->d.freqmod_table = freqmod_offsets[*script_ptr / 4];
- channel->d.freqmod_modulo = freqmod_lengths[*script_ptr / 4];
- script_ptr++;
- break;
-
- case 0xfd: // clear other channel
- value = READ_LE_UINT16 (script_ptr) / sizeof (ChannelInfo);
- debug(7, "clear channel %d", value);
- script_ptr += 2;
- // In Indy3, when traveling to Venice a command is
- // issued to clear channel 4. So we introduce a 4th
- // channel, which is never used. All OOB accesses are
- // mapped to this channel.
- //
- // The original game had room for 8 channels, but only
- // channels 0-3 are read, changes to other channels
- // had no effect.
- if (value >= ARRAYSIZE (_channels))
- value = 4;
- channel = &_channels[value];
- // fall through
-
- case 0xfa: // clear current channel
- if (opcode == 0xfa)
- debug(7, "clear channel");
- channel->d.next_cmd = 0;
- channel->d.base_freq = 0;
- channel->d.freq_delta = 0;
- channel->d.freq = 0;
- channel->d.volume = 0;
- channel->d.volume_delta = 0;
- channel->d.inter_note_pause = 0;
- channel->d.transpose = 0;
- channel->d.hull_curve = 0;
- channel->d.hull_offset = 0;
- channel->d.hull_counter = 0;
- channel->d.freqmod_table = 0;
- channel->d.freqmod_offset = 0;
- channel->d.freqmod_incr = 0;
- channel->d.freqmod_multiplier = 0;
- channel->d.freqmod_modulo = 0;
- break;
-
- case 0xfb: // ret from subroutine
- debug(7, "ret from sub");
- script_ptr = _retaddr;
- break;
-
- case 0xfc: // call subroutine
- offset = READ_LE_UINT16 (script_ptr);
- debug(7, "subroutine %d", offset);
- script_ptr += 2;
- _retaddr = script_ptr;
- script_ptr = _current_data + offset;
- break;
-
- case 0xfe: // loop music
- opcode = *script_ptr++;
- offset = READ_LE_UINT16 (script_ptr);
- script_ptr += 2;
- debug(7, "loop if %d to %d", opcode, offset);
- if (!channel->array[opcode / 2] || --channel->array[opcode/2])
- script_ptr += offset;
- break;
-
- case 0xff: // set parameter
- opcode = *script_ptr++;
- value = READ_LE_UINT16 (script_ptr);
- channel->array[opcode / 2] = value;
- debug(7, "channels[%lu]: set param %2d = %5d",
- (long)(channel - _channels), opcode, value);
- script_ptr += 2;
- if (opcode == 14) {
- /* tempo var */
- _ticks_per_music_timer = 125;
- }
- if (opcode == 0)
- goto end;
- break;
- }
- } else { // opcode < 0xf8
- for (;;) {
- int16 note, octave;
- int is_last_note;
- dest_channel = &_channels[(opcode >> 5) & 3];
-
- if (!(opcode & 0x80)) {
-
- int tempo = channel->d.tempo;
- if (!tempo)
- tempo = 1;
- channel->d.time_left = tempo * note_lengths[opcode & 0x1f];
-
- note = *script_ptr++;
- is_last_note = note & 0x80;
- note &= 0x7f;
- if (note == 0x7f) {
- debug(8, "channels[%lu]: pause %d",
- (long)(channel - _channels), channel->d.time_left);
- goto end;
- }
- } else {
-
- channel->d.time_left = ((opcode & 7) << 8) | *script_ptr++;
-
- if ((opcode & 0x10)) {
- debug(8, "channels[%lu]: pause %d",
- (long)(channel - _channels), channel->d.time_left);
- goto end;
- }
-
- is_last_note = 0;
- note = (*script_ptr++) & 0x7f;
- }
-
- debug(8, "channels[%lu]: @%04lx note: %3d+%d len: %2d hull: %d mod: %d/%d/%d %s",
- (long)(dest_channel - channel), (long)(script_ptr ? script_ptr - _current_data - 2 : 0),
- note, (signed short) dest_channel->d.transpose, channel->d.time_left,
- dest_channel->d.hull_curve, dest_channel->d.freqmod_table,
- dest_channel->d.freqmod_incr,dest_channel->d.freqmod_multiplier,
- is_last_note ? "last":"");
-
- uint16 myfreq;
- dest_channel->d.time_left = channel->d.time_left;
- dest_channel->d.note_length =
- channel->d.time_left - dest_channel->d.inter_note_pause;
- note += dest_channel->d.transpose;
- while (note < 0)
- note += 12;
- octave = note / 12;
- note = note % 12;
- dest_channel->d.hull_offset = 0;
- dest_channel->d.hull_counter = 1;
- if (_pcjr && dest_channel == &_channels[3]) {
- dest_channel->d.hull_curve = 196 + note * 12;
- myfreq = 384 - 64 * octave;
- } else {
- myfreq = _freqs_table[note] >> octave;
- }
- dest_channel->d.freq = dest_channel->d.base_freq = myfreq;
- if (is_last_note)
- goto end;
- opcode = *script_ptr++;
- }
- }
- }
-
-end:
- channel = current_channel;
- if (channel->d.time_left) {
- channel->d.next_cmd = script_ptr - _current_data;
- return;
- }
-
- channel->d.next_cmd = 0;
-
-check_stopped:
- int i;
- for (i = 0; i < 4; i++) {
- if (_channels[i].d.time_left)
- return;
- }
-
- _current_nr = 0;
- _current_data = 0;
- chainNextSound();
- return;
-}
-
-void Player_V2::next_freqs(ChannelInfo *channel) {
- channel->d.volume += channel->d.volume_delta;
- channel->d.base_freq += channel->d.freq_delta;
-
- channel->d.freqmod_offset += channel->d.freqmod_incr;
- if (channel->d.freqmod_offset > channel->d.freqmod_modulo)
- channel->d.freqmod_offset -= channel->d.freqmod_modulo;
- channel->d.freq =
- (int) (freqmod_table[channel->d.freqmod_table + (channel->d.freqmod_offset >> 4)])
- * (int) channel->d.freqmod_multiplier / 256
- + channel->d.base_freq;
-
- debug(9, "Freq: %d/%d, %d/%d/%d*%d %d",
- channel->d.base_freq, (int16)channel->d.freq_delta,
- channel->d.freqmod_table, channel->d.freqmod_offset,
- channel->d.freqmod_incr, channel->d.freqmod_multiplier,
- channel->d.freq);
-
- if (channel->d.note_length && !--channel->d.note_length) {
- channel->d.hull_offset = 16;
- channel->d.hull_counter = 1;
- }
-
- if (!--channel->d.time_left) {
- execute_cmd(channel);
- }
-
-#if 0
- debug(9, "channels[%d]: freq %d hull %d/%d/%d",
- channel - &_channels[0], channel->d.freq,
- channel->d.hull_curve, channel->d.hull_offset,
- channel->d.hull_counter);
-#endif
-
- if (channel->d.hull_counter && !--channel->d.hull_counter) {
- for (;;) {
- const int16 *hull_ptr = hulls
- + channel->d.hull_curve + channel->d.hull_offset / 2;
- if (hull_ptr[1] == -1) {
- channel->d.volume = hull_ptr[0];
- if (hull_ptr[0] == 0)
- channel->d.volume_delta = 0;
- channel->d.hull_offset += 4;
- } else {
- channel->d.volume_delta = hull_ptr[0];
- channel->d.hull_counter = hull_ptr[1];
- channel->d.hull_offset += 4;
- break;
- }
- }
- }
-}
-
-void Player_V2::do_mix(int16 *data, uint len) {
+int Player_V2::readBuffer(int16 *data, const int numSamples) {
Common::StackLock lock(_mutex);
uint step;
+ uint len = numSamples / 2;
do {
if (!(_next_tick >> FIXP_SHIFT)) {
@@ -802,18 +190,8 @@ void Player_V2::do_mix(int16 *data, uint len) {
data += 2 * step;
_next_tick -= step << FIXP_SHIFT;
} while (len -= step);
-}
-void Player_V2::nextTick() {
- for (int i = 0; i < 4; i++) {
- if (!_channels[i].d.time_left)
- continue;
- next_freqs(&_channels[i]);
- }
- if (_music_timer_ctr++ >= _ticks_per_music_timer) {
- _music_timer_ctr = 0;
- _music_timer++;
- }
+ return numSamples;
}
void Player_V2::lowPassFilter(int16 *sample, uint len) {
diff --git a/engines/scumm/player_v2.h b/engines/scumm/player_v2.h
index 2c3e784928..6a0b3d6d5e 100644
--- a/engines/scumm/player_v2.h
+++ b/engines/scumm/player_v2.h
@@ -26,84 +26,35 @@
#ifndef SCUMM_PLAYER_V2_H
#define SCUMM_PLAYER_V2_H
-#include "common/scummsys.h"
-#include "common/mutex.h"
-#include "scumm/music.h"
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
+#include "scumm/player_v2base.h"
namespace Scumm {
-class ScummEngine;
-
-#include "common/pack-start.h" // START STRUCT PACKING
-
-struct channel_data {
- uint16 time_left; // 00
- uint16 next_cmd; // 02
- uint16 base_freq; // 04
- uint16 freq_delta; // 06
- uint16 freq; // 08
- uint16 volume; // 10
- uint16 volume_delta; // 12
- uint16 tempo; // 14
- uint16 inter_note_pause; // 16
- uint16 transpose; // 18
- uint16 note_length; // 20
- uint16 hull_curve; // 22
- uint16 hull_offset; // 24
- uint16 hull_counter; // 26
- uint16 freqmod_table; // 28
- uint16 freqmod_offset; // 30
- uint16 freqmod_incr; // 32
- uint16 freqmod_multiplier; // 34
- uint16 freqmod_modulo; // 36
- uint16 unknown[4]; // 38 - 44
- uint16 music_timer; // 46
- uint16 music_script_nr; // 48
-} PACKED_STRUCT;
-
-#include "common/pack-end.h" // END STRUCT PACKING
-
-
/**
* Scumm V2 PC-Speaker MIDI driver.
* This simulates the pc speaker sound, which is driven by the 8253 (square
* wave generator) and a low-band filter.
*/
-class Player_V2 : public Audio::AudioStream, public MusicEngine {
+class Player_V2 : public Player_V2Base {
public:
Player_V2(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr);
virtual ~Player_V2();
+ // MusicEngine API
virtual void setMusicVolume(int vol);
virtual void startSound(int sound);
virtual void stopSound(int sound);
virtual void stopAllSounds();
- virtual int getMusicTimer();
+// virtual int getMusicTimer();
virtual int getSoundStatus(int sound) const;
// AudioStream API
- int readBuffer(int16 *buffer, const int numSamples) {
- do_mix(buffer, numSamples / 2);
- return numSamples;
- }
+ int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return true; }
bool endOfData() const { return false; }
int getRate() const { return _sampleRate; }
protected:
- bool _isV3Game;
- Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
- ScummEngine *_vm;
-
- bool _pcjr;
- int _header_len;
-
- uint32 _sampleRate;
- uint32 _next_tick;
- uint32 _tick_len;
unsigned int _update_step;
unsigned int _decay;
int _level;
@@ -113,218 +64,13 @@ protected:
int _timer_count[4];
int _timer_output;
- int _current_nr;
- byte *_current_data;
- int _next_nr;
- byte *_next_data;
- byte *_retaddr;
-
- Common::Mutex _mutex;
-
-private:
- union ChannelInfo {
- channel_data d;
- uint16 array[sizeof(channel_data)/2];
- };
-
- int _music_timer;
- int _music_timer_ctr;
- int _ticks_per_music_timer;
-
- const uint16 *_freqs_table;
-
- ChannelInfo _channels[5];
-
protected:
- virtual void nextTick();
- virtual void clear_channel(int i);
- virtual void chainSound(int nr, byte *data);
- virtual void chainNextSound();
-
virtual void generateSpkSamples(int16 *data, uint len);
virtual void generatePCjrSamples(int16 *data, uint len);
void lowPassFilter(int16 *data, uint len);
void squareGenerator(int channel, int freq, int vol,
int noiseFeedback, int16 *sample, uint len);
-
-private:
- void do_mix(int16 *buf, uint len);
-
- void set_pcjr(bool pcjr);
- void execute_cmd(ChannelInfo *channel);
- void next_freqs(ChannelInfo *channel);
-};
-
-/**
- * Scumm V2 CMS/Gameblaster MIDI driver.
- */
-class Player_V2CMS : public Audio::AudioStream, public MusicEngine {
-public:
- Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer);
- virtual ~Player_V2CMS();
-
- virtual void setMusicVolume(int vol);
- virtual void startSound(int sound);
- virtual void stopSound(int sound);
- virtual void stopAllSounds();
- virtual int getMusicTimer();
- virtual int getSoundStatus(int sound) const;
-
- // AudioStream API
- int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const { return true; }
- bool endOfData() const { return false; }
- int getRate() const { return _sampleRate; }
-
-protected:
-
-#include "common/pack-start.h" // START STRUCT PACKING
- struct Voice {
- byte attack;
- byte decay;
- byte sustain;
- byte release;
- byte octadd;
- int16 vibrato;
- int16 vibrato2;
- int16 noise;
- } PACKED_STRUCT;
-
- struct Voice2 {
- byte *amplitudeOutput;
- byte *freqOutput;
- byte *octaveOutput;
-
- uint8 channel;
- int8 sustainLevel;
- int8 attackRate;
- uint8 maxAmpl;
- int8 decayRate;
- int8 sustainRate;
- int8 releaseRate;
- int8 releaseTime;
- int8 vibratoRate;
- int8 vibratoDepth;
-
- int8 curVibratoRate;
- int8 curVibratoUnk;
-
- int8 unkVibratoRate;
- int8 unkVibratoDepth;
-
- int8 unkRate;
- int8 unkCount;
-
- int nextProcessState;
- int8 curVolume;
- int8 curOctave;
- int8 curFreq;
-
- int8 octaveAdd;
-
- int8 playingNote;
- Voice2 *nextVoice;
-
- byte chanNumber;
- } PACKED_STRUCT;
-
- struct MusicChip {
- byte ampl[4];
- byte freq[4];
- byte octave[2];
- } PACKED_STRUCT;
-#include "common/pack-end.h" // END STRUCT PACKING
-
- Voice _cmsVoicesBase[16];
- Voice2 _cmsVoices[8];
- MusicChip _cmsChips[2];
-
- int8 _tempo;
- int8 _tempoSum;
- byte _looping;
- byte _octaveMask;
- int16 _midiDelay;
- Voice2 *_midiChannel[16];
- byte _midiChannelUse[16];
- byte *_midiData;
- byte *_midiSongBegin;
-
- int _loadedMidiSong;
-
- byte _lastMidiCommand;
- uint _outputTableReady;
- byte _clkFrequenz;
- byte _restart;
- byte _curSno;
-
- void loadMidiData(byte *data, int sound);
- void play();
-
- void processChannel(Voice2 *channel);
- void processRelease(Voice2 *channel);
- void processAttack(Voice2 *channel);
- void processDecay(Voice2 *channel);
- void processSustain(Voice2 *channel);
- void processVibrato(Voice2 *channel);
-
- void playMusicChips(const MusicChip *table);
- void playNote(byte *&data);
- void clearNote(byte *&data);
- void offAllChannels();
- void playVoice();
- void processMidiData(uint ticks);
-
- Voice2 *getFreeVoice();
- Voice2 *getPlayVoice(byte param);
-
- // from Player_V2
-protected:
- bool _isV3Game;
- Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
- ScummEngine *_vm;
-
- int _header_len;
-
- uint32 _sampleRate;
- uint32 _next_tick;
- uint32 _tick_len;
-
- int _timer_count[4];
- int _timer_output;
-
- int _current_nr;
- byte *_current_data;
- int _next_nr;
- byte *_next_data;
- byte *_retaddr;
-
- Common::Mutex _mutex;
-
-private:
- union ChannelInfo {
- channel_data d;
- uint16 array[sizeof(channel_data)/2];
- };
-
- int _music_timer;
- int _music_timer_ctr;
- int _ticks_per_music_timer;
-
- ChannelInfo _channels[5];
-
-protected:
- virtual void nextTick();
- virtual void clear_channel(int i);
- virtual void chainSound(int nr, byte *data);
- virtual void chainNextSound();
-
-private:
- void do_mix(int16 *buf, uint len);
-
- void execute_cmd(ChannelInfo *channel);
- void next_freqs(ChannelInfo *channel);
};
} // End of namespace Scumm
diff --git a/engines/scumm/player_v2base.cpp b/engines/scumm/player_v2base.cpp
new file mode 100644
index 0000000000..61c91aae85
--- /dev/null
+++ b/engines/scumm/player_v2base.cpp
@@ -0,0 +1,657 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "scumm/player_v2base.h"
+#include "scumm/scumm.h"
+
+#define FREQ_HZ 236 // Don't change!
+
+#define MAX_OUTPUT 0x7fff
+
+namespace Scumm {
+
+const uint8 note_lengths[] = {
+ 0,
+ 0, 0, 2,
+ 0, 3, 4,
+ 5, 6, 8,
+ 9, 12, 16,
+ 18, 24, 32,
+ 36, 48, 64,
+ 72, 96
+};
+
+static const uint16 hull_offsets[] = {
+ 0, 12, 24, 36, 48, 60,
+ 72, 88, 104, 120, 136, 256,
+ 152, 164, 180
+};
+
+static const int16 hulls[] = {
+ // hull 0
+ 3, -1, 0, 0, 0, 0, 0, 0,
+ 0, -1, 0, 0,
+ // hull 1 (staccato)
+ 3, -1, 0, 32, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+ // hull 2 (legato)
+ 3, -1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ // hull 3 (staccatissimo)
+ 3, -1, 0, 2, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+ // hull 4
+ 3, -1, 0, 6, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+ // hull 5
+ 3, -1, 0, 16, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+ // hull 6
+ (int16) 60000, -1, -1000, 20, 0, 0, 0, 0,
+ (int16) 40000, -1, -5000, 5, 0, -1, 0, 0,
+ // hull 7
+ (int16) 50000, -1, 0, 8, 30000, -1, 0, 0,
+ 28000, -1, -5000, 5, 0, -1, 0, 0,
+ // hull 8
+ (int16) 60000, -1, -2000, 16, 0, 0, 0, 0,
+ 28000, -1, -6000, 5, 0, -1, 0, 0,
+ // hull 9
+ (int16) 55000, -1, 0, 8, (int16) 35000, -1, 0, 0,
+ (int16) 40000, -1, -2000, 10, 0, -1, 0, 0,
+ // hull 10
+ (int16) 60000, -1, 0, 4, -2000, 8, 0, 0,
+ (int16) 40000, -1, -6000, 5, 0, -1, 0, 0,
+ // hull 12
+ 0, -1, 150, 340, -150, 340, 0, -1,
+ 0, -1, 0, 0,
+ // hull 13 == 164
+ 20000, -1, 4000, 7, 1000, 15, 0, 0,
+ (int16) 35000, -1, -2000, 15, 0, -1, 0, 0,
+
+ // hull 14 == 180
+ (int16) 35000, -1, 500, 20, 0, 0, 0, 0,
+ (int16) 45000, -1, -500, 60, 0, -1, 0, 0,
+
+ // hull misc = 196
+ (int16) 44000, -1, -4400, 10, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 53000, -1, -5300, 10, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 63000, -1, -6300, 10, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 44000, -1, -1375, 32, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 53000, -1, -1656, 32, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ // hull 11 == 256
+ (int16) 63000, -1, -1968, 32, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 44000, -1, - 733, 60, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 53000, -1, - 883, 60, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 63000, -1, -1050, 60, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 44000, -1, - 488, 90, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 53000, -1, - 588, 90, 0, -1, 0, 0,
+ 0, -1, 0, 0,
+
+ (int16) 63000, -1, - 700, 90, 0, -1, 0, 0,
+ 0, -1, 0, 0
+};
+
+static const uint16 freqmod_lengths[] = {
+ 0x1000, 0x1000, 0x20, 0x2000, 0x1000
+};
+
+static const uint16 freqmod_offsets[] = {
+ 0, 0x100, 0x200, 0x302, 0x202
+};
+
+static const int8 freqmod_table[0x502] = {
+ 0, 3, 6, 9, 12, 15, 18, 21,
+ 24, 27, 30, 33, 36, 39, 42, 45,
+ 48, 51, 54, 57, 59, 62, 65, 67,
+ 70, 73, 75, 78, 80, 82, 85, 87,
+ 89, 91, 94, 96, 98, 100, 102, 103,
+ 105, 107, 108, 110, 112, 113, 114, 116,
+ 117, 118, 119, 120, 121, 122, 123, 123,
+ 124, 125, 125, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 125, 125,
+ 124, 123, 123, 122, 121, 120, 119, 118,
+ 117, 116, 114, 113, 112, 110, 108, 107,
+ 105, 103, 102, 100, 98, 96, 94, 91,
+ 89, 87, 85, 82, 80, 78, 75, 73,
+ 70, 67, 65, 62, 59, 57, 54, 51,
+ 48, 45, 42, 39, 36, 33, 30, 27,
+ 24, 21, 18, 15, 12, 9, 6, 3,
+ 0, -3, -6, -9, -12, -15, -18, -21,
+ -24, -27, -30, -33, -36, -39, -42, -45,
+ -48, -51, -54, -57, -59, -62, -65, -67,
+ -70, -73, -75, -78, -80, -82, -85, -87,
+ -89, -91, -94, -96, -98,-100,-102,-103,
+ -105,-107,-108,-110,-112,-113,-114,-116,
+ -117,-118,-119,-120,-121,-122,-123,-123,
+ -124,-125,-125,-126,-126,-126,-126,-126,
+ -126,-126,-126,-126,-126,-126,-125,-125,
+ -124,-123,-123,-122,-121,-120,-119,-118,
+ -117,-116,-114,-113,-112,-110,-108,-107,
+ -105,-103,-102,-100, -98, -96, -94, -91,
+ -89, -87, -85, -82, -80, -78, -75, -73,
+ -70, -67, -65, -62, -59, -57, -54, -51,
+ -48, -45, -42, -39, -36, -33, -30, -27,
+ -24, -21, -18, -15, -12, -9, -6, -3,
+
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,
+ -128,-127,-126,-125,-124,-123,-122,-121,
+ -120,-119,-118,-117,-116,-115,-114,-113,
+ -112,-111,-110,-109,-108,-107,-106,-105,
+ -104,-103,-102,-101,-100, -99, -98, -97,
+ -96, -95, -94, -93, -92, -91, -90, -89,
+ -88, -87, -86, -85, -84, -83, -82, -81,
+ -80, -79, -78, -77, -76, -75, -74, -73,
+ -72, -71, -70, -69, -68, -67, -66, -65,
+ -64, -63, -62, -61, -60, -59, -58, -57,
+ -56, -55, -54, -53, -52, -51, -50, -49,
+ -48, -47, -46, -45, -44, -43, -42, -41,
+ -40, -39, -38, -37, -36, -35, -34, -33,
+ -32, -31, -30, -29, -28, -27, -26, -25,
+ -24, -23, -22, -21, -20, -19, -18, -17,
+ -16, -15, -14, -13, -12, -11, -10, -9,
+ -8, -7, -6, -5, -4, -3, -2, -1,
+
+ -120, 120,
+
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ -120,-120,-120,-120,-120,-120,-120,-120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120,
+
+ 41, 35, -66,-124, -31, 108, -42, -82,
+ 82,-112, 73, -15, -15, -69, -23, -21,
+ -77, -90, -37, 60,-121, 12, 62,-103,
+ 36, 94, 13, 28, 6, -73, 71, -34,
+ -77, 18, 77, -56, 67, -69,-117, -90,
+ 31, 3, 90, 125, 9, 56, 37, 31,
+ 93, -44, -53, -4,-106, -11, 69, 59,
+ 19, 13,-119, 10, 28, -37, -82, 50,
+ 32,-102, 80, -18, 64, 120, 54, -3,
+ 18, 73, 50, -10, -98, 125, 73, -36,
+ -83, 79, 20, -14, 68, 64, 102, -48,
+ 107, -60, 48, -73, 50, 59, -95, 34,
+ -10, 34,-111, -99, -31,-117, 31, -38,
+ -80, -54,-103, 2, -71, 114, -99, 73,
+ 44,-128, 126, -59,-103, -43, -23,-128,
+ -78, -22, -55, -52, 83, -65, 103, -42,
+ -65, 20, -42, 126, 45, -36,-114, 102,
+ -125, -17, 87, 73, 97, -1, 105,-113,
+ 97, -51, -47, 30, -99,-100, 22, 114,
+ 114, -26, 29, -16,-124, 79, 74, 119,
+ 2, -41, -24, 57, 44, 83, -53, -55,
+ 18, 30, 51, 116, -98, 12, -12, -43,
+ -44, -97, -44, -92, 89, 126, 53, -49,
+ 50, 34, -12, -52, -49, -45,-112, 45,
+ 72, -45,-113, 117, -26, -39, 29, 42,
+ -27, -64, -9, 43, 120,-127,-121, 68,
+ 14, 95, 80, 0, -44, 97,-115, -66,
+ 123, 5, 21, 7, 59, 51,-126, 31,
+ 24, 112,-110, -38, 100, 84, -50, -79,
+ -123, 62, 105, 21, -8, 70, 106, 4,
+ -106, 115, 14, -39, 22, 47, 103, 104,
+ -44, -9, 74, 74, -48, 87, 104, 118,
+ -6, 22, -69, 17, -83, -82, 36,-120,
+ 121, -2, 82, -37, 37, 67, -27, 60,
+ -12, 69, -45, -40, 40, -50, 11, -11,
+ -59, 96, 89, 61,-105, 39,-118, 89,
+ 118, 45, -48, -62, -55, -51, 104, -44,
+ 73, 106, 121, 37, 8, 97, 64, 20,
+ -79, 59, 106, -91, 17, 40, -63,-116,
+ -42, -87, 11,-121,-105,-116, 47, -15,
+ 21, 29,-102,-107, -63,-101, -31, -64,
+ 126, -23, -88,-102, -89,-122, -62, -75,
+ 84, -65,-102, -25, -39, 35, -47, 85,
+ -112, 56, 40, -47, -39, 108, -95, 102,
+ 94, 78, -31, 48,-100, -2, -39, 113,
+ -97, -30, -91, -30, 12,-101, -76, 71,
+ 101, 56, 42, 70,-119, -87,-126, 121,
+ 122, 118, 120, -62, 99, -79, 38, -33,
+ -38, 41, 109, 62, 98, -32,-106, 18,
+ 52, -65, 57, -90, 63,-119, 94, -15,
+ 109, 14, -29, 108, 40, -95, 30, 32,
+ 29, -53, -62, 3, 63, 65, 7,-124,
+ 15, 20, 5, 101, 27, 40, 97, -55,
+ -59, -25, 44,-114, 70, 54, 8, -36,
+ -13, -88,-115, -2, -66, -14, -21, 113,
+ -1, -96, -48, 59, 117, 6,-116, 126,
+ -121, 120, 115, 77, -48, -66,-126, -66,
+ -37, -62, 70, 65, 43,-116, -6, 48,
+ 127, 112, -16, -89, 84,-122, 50,-107,
+ -86, 91, 104, 19, 11, -26, -4, -11,
+ -54, -66, 125, -97,-119,-118, 65, 27,
+ -3, -72, 79, 104, -10, 114, 123, 20,
+ -103, -51, -45, 13, -16, 68, 58, -76,
+ -90, 102, 83, 51, 11, -53, -95, 16
+};
+
+static const uint16 spk_freq_table[12] = {
+ 36484, 34436, 32503, 30679, 28957, 27332,
+ 25798, 24350, 22983, 21693, 20476, 19326
+};
+
+static const uint16 pcjr_freq_table[12] = {
+ 65472, 61760, 58304, 55040, 52032, 49024,
+ 46272, 43648, 41216, 38912, 36736, 34624
+};
+
+
+Player_V2Base::Player_V2Base(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr)
+ : _vm(scumm),
+ _mixer(mixer),
+ _pcjr(pcjr),
+ _sampleRate(_mixer->getOutputRate()) {
+
+ _isV3Game = (scumm->_game.version >= 3);
+
+ _header_len = (scumm->_game.features & GF_OLD_BUNDLE) ? 4 : 6;
+
+ // Initialize sound queue
+ _current_nr = _next_nr = 0;
+ _current_data = _next_data = 0;
+
+ // Initialize channel code
+ for (int i = 0; i < 4; ++i)
+ clear_channel(i);
+
+ _next_tick = 0;
+ _tick_len = (_sampleRate << FIXP_SHIFT) / FREQ_HZ;
+
+ // Initialize V3 music timer
+ _music_timer_ctr = _music_timer = 0;
+ _ticks_per_music_timer = 65535;
+
+ if (_pcjr) {
+ _freqs_table = pcjr_freq_table;
+ } else {
+ _freqs_table = spk_freq_table;
+ }
+}
+
+Player_V2Base::~Player_V2Base() {
+}
+
+void Player_V2Base::chainSound(int nr, byte *data) {
+ int offset = _header_len + (_pcjr ? 10 : 2);
+
+ _current_nr = nr;
+ _current_data = data;
+
+ for (int i = 0; i < 4; i++) {
+ clear_channel(i);
+
+ _channels[i].d.music_script_nr = nr;
+ if (data) {
+ _channels[i].d.next_cmd = READ_LE_UINT16(data + offset + 2 * i);
+ if (_channels[i].d.next_cmd) {
+ _channels[i].d.time_left = 1;
+ }
+ }
+ }
+ _music_timer = 0;
+}
+
+void Player_V2Base::chainNextSound() {
+ if (_next_nr) {
+ chainSound(_next_nr, _next_data);
+ _next_nr = 0;
+ _next_data = 0;
+ }
+}
+
+// TODO: Merge stopAllSounds, stopSound() and startSound(), using some overriding
+// perhaps? Player_V2CMS's implementations start like that of Player_V2
+// but then add some MIDI related stuff.
+
+void Player_V2Base::clear_channel(int i) {
+ ChannelInfo *channel = &_channels[i];
+ memset(channel, 0, sizeof(ChannelInfo));
+}
+
+int Player_V2Base::getMusicTimer() {
+ if (_isV3Game)
+ return _music_timer;
+ else
+ return _channels[0].d.music_timer;
+}
+
+void Player_V2Base::execute_cmd(ChannelInfo *channel) {
+ uint16 value;
+ int16 offset;
+ uint8 *script_ptr;
+ ChannelInfo * current_channel;
+ ChannelInfo * dest_channel;
+
+ current_channel = channel;
+
+ if (channel->d.next_cmd == 0)
+ goto check_stopped;
+ script_ptr = &_current_data[channel->d.next_cmd];
+
+ for (;;) {
+ uint8 opcode = *script_ptr++;
+ if (opcode >= 0xf8) {
+ switch (opcode) {
+ case 0xf8: // set hull curve
+ debug(7, "channels[%d]: hull curve %2d",
+ (uint)(channel - _channels), *script_ptr);
+ channel->d.hull_curve = hull_offsets[*script_ptr / 2];
+ script_ptr++;
+ break;
+
+ case 0xf9: // set freqmod curve
+ debug(7, "channels[%d]: freqmod curve %2d",
+ (uint)(channel - _channels), *script_ptr);
+ channel->d.freqmod_table = freqmod_offsets[*script_ptr / 4];
+ channel->d.freqmod_modulo = freqmod_lengths[*script_ptr / 4];
+ script_ptr++;
+ break;
+
+ case 0xfd: // clear other channel
+ value = READ_LE_UINT16 (script_ptr) / sizeof (ChannelInfo);
+ debug(7, "clear channel %d", value);
+ script_ptr += 2;
+ // In Indy3, when traveling to Venice a command is
+ // issued to clear channel 4. So we introduce a 4th
+ // channel, which is never used. All OOB accesses are
+ // mapped to this channel.
+ //
+ // The original game had room for 8 channels, but only
+ // channels 0-3 are read, changes to other channels
+ // had no effect.
+ if (value >= ARRAYSIZE (_channels))
+ value = 4;
+ channel = &_channels[value];
+ // fall through
+
+ case 0xfa: // clear current channel
+ if (opcode == 0xfa)
+ debug(7, "clear channel");
+ channel->d.next_cmd = 0;
+ channel->d.base_freq = 0;
+ channel->d.freq_delta = 0;
+ channel->d.freq = 0;
+ channel->d.volume = 0;
+ channel->d.volume_delta = 0;
+ channel->d.inter_note_pause = 0;
+ channel->d.transpose = 0;
+ channel->d.hull_curve = 0;
+ channel->d.hull_offset = 0;
+ channel->d.hull_counter = 0;
+ channel->d.freqmod_table = 0;
+ channel->d.freqmod_offset = 0;
+ channel->d.freqmod_incr = 0;
+ channel->d.freqmod_multiplier = 0;
+ channel->d.freqmod_modulo = 0;
+ break;
+
+ case 0xfb: // ret from subroutine
+ debug(7, "ret from sub");
+ script_ptr = _retaddr;
+ break;
+
+ case 0xfc: // call subroutine
+ offset = READ_LE_UINT16 (script_ptr);
+ debug(7, "subroutine %d", offset);
+ script_ptr += 2;
+ _retaddr = script_ptr;
+ script_ptr = _current_data + offset;
+ break;
+
+ case 0xfe: // loop music
+ opcode = *script_ptr++;
+ offset = READ_LE_UINT16 (script_ptr);
+ script_ptr += 2;
+ debug(7, "loop if %d to %d", opcode, offset);
+ if (!channel->array[opcode / 2] || --channel->array[opcode/2])
+ script_ptr += offset;
+ break;
+
+ case 0xff: // set parameter
+ opcode = *script_ptr++;
+ value = READ_LE_UINT16 (script_ptr);
+ channel->array[opcode / 2] = value;
+ debug(7, "channels[%d]: set param %2d = %5d",
+ (uint)(channel - _channels), opcode, value);
+ script_ptr += 2;
+ if (opcode == 14) {
+ /* tempo var */
+ _ticks_per_music_timer = 125;
+ }
+ if (opcode == 0)
+ goto end;
+ break;
+ }
+ } else { // opcode < 0xf8
+ for (;;) {
+ int16 note, octave;
+ int is_last_note;
+ dest_channel = &_channels[(opcode >> 5) & 3];
+
+ if (!(opcode & 0x80)) {
+
+ int tempo = channel->d.tempo;
+ if (!tempo)
+ tempo = 1;
+ channel->d.time_left = tempo * note_lengths[opcode & 0x1f];
+
+ note = *script_ptr++;
+ is_last_note = note & 0x80;
+ note &= 0x7f;
+ if (note == 0x7f) {
+ debug(8, "channels[%d]: pause %d",
+ (uint)(channel - _channels), channel->d.time_left);
+ goto end;
+ }
+ } else {
+
+ channel->d.time_left = ((opcode & 7) << 8) | *script_ptr++;
+
+ if ((opcode & 0x10)) {
+ debug(8, "channels[%d]: pause %d",
+ (uint)(channel - _channels), channel->d.time_left);
+ goto end;
+ }
+
+ is_last_note = 0;
+ note = (*script_ptr++) & 0x7f;
+ }
+
+ debug(8, "channels[%d]: @%04x note: %3d+%d len: %2d hull: %d mod: %d/%d/%d %s",
+ (uint)(dest_channel - channel), script_ptr ? (uint)(script_ptr - _current_data - 2) : 0,
+ note, (signed short) dest_channel->d.transpose, channel->d.time_left,
+ dest_channel->d.hull_curve, dest_channel->d.freqmod_table,
+ dest_channel->d.freqmod_incr,dest_channel->d.freqmod_multiplier,
+ is_last_note ? "last":"");
+
+ uint16 myfreq;
+ dest_channel->d.time_left = channel->d.time_left;
+ dest_channel->d.note_length =
+ channel->d.time_left - dest_channel->d.inter_note_pause;
+ note += dest_channel->d.transpose;
+ while (note < 0)
+ note += 12;
+ octave = note / 12;
+ note = note % 12;
+ dest_channel->d.hull_offset = 0;
+ dest_channel->d.hull_counter = 1;
+ if (_pcjr && dest_channel == &_channels[3]) {
+ dest_channel->d.hull_curve = 196 + note * 12;
+ myfreq = 384 - 64 * octave;
+ } else {
+ myfreq = _freqs_table[note] >> octave;
+ }
+ dest_channel->d.freq = dest_channel->d.base_freq = myfreq;
+ if (is_last_note)
+ goto end;
+ opcode = *script_ptr++;
+ }
+ }
+ }
+
+end:
+ channel = current_channel;
+ if (channel->d.time_left) {
+ channel->d.next_cmd = script_ptr - _current_data;
+ return;
+ }
+
+ channel->d.next_cmd = 0;
+
+check_stopped:
+ int i;
+ for (i = 0; i < 4; i++) {
+ if (_channels[i].d.time_left)
+ return;
+ }
+
+ _current_nr = 0;
+ _current_data = 0;
+ chainNextSound();
+}
+
+void Player_V2Base::next_freqs(ChannelInfo *channel) {
+ channel->d.volume += channel->d.volume_delta;
+ channel->d.base_freq += channel->d.freq_delta;
+
+ channel->d.freqmod_offset += channel->d.freqmod_incr;
+ if (channel->d.freqmod_offset > channel->d.freqmod_modulo)
+ channel->d.freqmod_offset -= channel->d.freqmod_modulo;
+
+ channel->d.freq =
+ (int) (freqmod_table[channel->d.freqmod_table + (channel->d.freqmod_offset >> 4)])
+ * (int) channel->d.freqmod_multiplier / 256
+ + channel->d.base_freq;
+
+ debug(9, "Freq: %d/%d, %d/%d/%d*%d %d",
+ channel->d.base_freq, (int16)channel->d.freq_delta,
+ channel->d.freqmod_table, channel->d.freqmod_offset,
+ channel->d.freqmod_incr, channel->d.freqmod_multiplier,
+ channel->d.freq);
+
+ if (channel->d.note_length && !--channel->d.note_length) {
+ channel->d.hull_offset = 16;
+ channel->d.hull_counter = 1;
+ }
+
+ if (!--channel->d.time_left) {
+ execute_cmd(channel);
+ }
+
+ if (channel->d.hull_counter && !--channel->d.hull_counter) {
+ for (;;) {
+ const int16 *hull_ptr = hulls
+ + channel->d.hull_curve + channel->d.hull_offset / 2;
+ if (hull_ptr[1] == -1) {
+ channel->d.volume = hull_ptr[0];
+ if (hull_ptr[0] == 0)
+ channel->d.volume_delta = 0;
+ channel->d.hull_offset += 4;
+ } else {
+ channel->d.volume_delta = hull_ptr[0];
+ channel->d.hull_counter = hull_ptr[1];
+ channel->d.hull_offset += 4;
+ break;
+ }
+ }
+ }
+}
+
+void Player_V2Base::nextTick() {
+ for (int i = 0; i < 4; i++) {
+ if (!_channels[i].d.time_left)
+ continue;
+ next_freqs(&_channels[i]);
+ }
+ if (_music_timer_ctr++ >= _ticks_per_music_timer) {
+ _music_timer_ctr = 0;
+ _music_timer++;
+ }
+}
+
+
+} // End of namespace Scumm
diff --git a/engines/scumm/player_v2base.h b/engines/scumm/player_v2base.h
new file mode 100644
index 0000000000..7b90ae98cf
--- /dev/null
+++ b/engines/scumm/player_v2base.h
@@ -0,0 +1,148 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SCUMM_PLAYER_V2BASE_H
+#define SCUMM_PLAYER_V2BASE_H
+
+#include "common/scummsys.h"
+#include "common/mutex.h"
+#include "scumm/music.h"
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+
+namespace Scumm {
+
+class ScummEngine;
+
+
+#include "common/pack-start.h" // START STRUCT PACKING
+
+struct channel_data {
+ uint16 time_left; // 00
+ uint16 next_cmd; // 02
+ uint16 base_freq; // 04
+ uint16 freq_delta; // 06
+ uint16 freq; // 08
+ uint16 volume; // 10
+ uint16 volume_delta; // 12
+ uint16 tempo; // 14
+ uint16 inter_note_pause; // 16
+ uint16 transpose; // 18
+ uint16 note_length; // 20
+ uint16 hull_curve; // 22
+ uint16 hull_offset; // 24
+ uint16 hull_counter; // 26
+ uint16 freqmod_table; // 28
+ uint16 freqmod_offset; // 30
+ uint16 freqmod_incr; // 32
+ uint16 freqmod_multiplier; // 34
+ uint16 freqmod_modulo; // 36
+ uint16 unknown[4]; // 38 - 44
+ uint16 music_timer; // 46
+ uint16 music_script_nr; // 48
+} PACKED_STRUCT;
+
+#include "common/pack-end.h" // END STRUCT PACKING
+
+/**
+ * Common base class for Player_V2 and Player_V2CMS.
+ */
+class Player_V2Base : public Audio::AudioStream, public MusicEngine {
+public:
+ Player_V2Base(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr);
+ virtual ~Player_V2Base();
+
+ // MusicEngine API
+// virtual void setMusicVolume(int vol);
+// virtual void startSound(int sound);
+// virtual void stopSound(int sound);
+// virtual void stopAllSounds();
+ virtual int getMusicTimer();
+// virtual int getSoundStatus(int sound) const;
+
+ // AudioStream API
+/*
+ int readBuffer(int16 *buffer, const int numSamples) {
+ do_mix(buffer, numSamples / 2);
+ return numSamples;
+ }
+*/
+ bool isStereo() const { return true; }
+ bool endOfData() const { return false; }
+ int getRate() const { return _sampleRate; }
+
+protected:
+ enum {
+ FIXP_SHIFT = 16
+ };
+
+ bool _isV3Game;
+ Audio::Mixer *_mixer;
+ Audio::SoundHandle _soundHandle;
+ ScummEngine *_vm;
+
+ bool _pcjr;
+ int _header_len;
+
+ const uint32 _sampleRate;
+ uint32 _next_tick;
+ uint32 _tick_len;
+
+ int _current_nr;
+ byte *_current_data;
+ int _next_nr;
+ byte *_next_data;
+ byte *_retaddr;
+
+ Common::Mutex _mutex;
+
+ union ChannelInfo {
+ channel_data d;
+ uint16 array[sizeof(channel_data)/2];
+ };
+
+ ChannelInfo _channels[5];
+
+private:
+ int _music_timer;
+ int _music_timer_ctr;
+ int _ticks_per_music_timer;
+
+ const uint16 *_freqs_table;
+
+protected:
+ virtual void nextTick();
+ virtual void clear_channel(int i);
+ virtual void chainSound(int nr, byte *data);
+ virtual void chainNextSound();
+
+ void execute_cmd(ChannelInfo *channel);
+ void next_freqs(ChannelInfo *channel);
+};
+
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/player_v2cms.cpp b/engines/scumm/player_v2cms.cpp
index ba60a31061..7bec171173 100644
--- a/engines/scumm/player_v2cms.cpp
+++ b/engines/scumm/player_v2cms.cpp
@@ -23,8 +23,7 @@
*
*/
-#include "engines/engine.h"
-#include "scumm/player_v2.h"
+#include "scumm/player_v2cms.h"
#include "scumm/scumm.h"
#include "sound/mididrv.h"
#include "sound/mixer.h"
@@ -32,15 +31,6 @@
namespace Scumm {
-#define FREQ_HZ 236 // Don't change!
-
-#define FIXP_SHIFT 16
-#define MAX_OUTPUT 0x7fff
-
-#define NG_PRESET 0x0f35 /* noise generator preset */
-#define FB_WNOISE 0x12000 /* feedback for white noise */
-#define FB_PNOISE 0x08000 /* feedback for periodic noise */
-
#define PROCESS_ATTACK 1
#define PROCESS_RELEASE 2
#define PROCESS_SUSTAIN 3
@@ -49,283 +39,6 @@ namespace Scumm {
#define CMS_RATE 22050
-const uint8 note_lengths[] = {
- 0,
- 0, 0, 2,
- 0, 3, 4,
- 5, 6, 8,
- 9, 12, 16,
- 18, 24, 32,
- 36, 48, 64,
- 72, 96
-};
-
-static const uint16 hull_offsets[] = {
- 0, 12, 24, 36, 48, 60,
- 72, 88, 104, 120, 136, 256,
- 152, 164, 180
-};
-
-static const int16 hulls[] = {
- // hull 0
- 3, -1, 0, 0, 0, 0, 0, 0,
- 0, -1, 0, 0,
- // hull 1 (staccato)
- 3, -1, 0, 32, 0, -1, 0, 0,
- 0, -1, 0, 0,
- // hull 2 (legato)
- 3, -1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- // hull 3 (staccatissimo)
- 3, -1, 0, 2, 0, -1, 0, 0,
- 0, -1, 0, 0,
- // hull 4
- 3, -1, 0, 6, 0, -1, 0, 0,
- 0, -1, 0, 0,
- // hull 5
- 3, -1, 0, 16, 0, -1, 0, 0,
- 0, -1, 0, 0,
- // hull 6
- (int16) 60000, -1, -1000, 20, 0, 0, 0, 0,
- (int16) 40000, -1, -5000, 5, 0, -1, 0, 0,
- // hull 7
- (int16) 50000, -1, 0, 8, 30000, -1, 0, 0,
- 28000, -1, -5000, 5, 0, -1, 0, 0,
- // hull 8
- (int16) 60000, -1, -2000, 16, 0, 0, 0, 0,
- 28000, -1, -6000, 5, 0, -1, 0, 0,
- // hull 9
- (int16) 55000, -1, 0, 8, (int16) 35000, -1, 0, 0,
- (int16) 40000, -1, -2000, 10, 0, -1, 0, 0,
- // hull 10
- (int16) 60000, -1, 0, 4, -2000, 8, 0, 0,
- (int16) 40000, -1, -6000, 5, 0, -1, 0, 0,
- // hull 12
- 0, -1, 150, 340, -150, 340, 0, -1,
- 0, -1, 0, 0,
- // hull 13 == 164
- 20000, -1, 4000, 7, 1000, 15, 0, 0,
- (int16) 35000, -1, -2000, 15, 0, -1, 0, 0,
-
- // hull 14 == 180
- (int16) 35000, -1, 500, 20, 0, 0, 0, 0,
- (int16) 45000, -1, -500, 60, 0, -1, 0, 0,
-
- // hull misc = 196
- (int16) 44000, -1, -4400, 10, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 53000, -1, -5300, 10, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 63000, -1, -6300, 10, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 44000, -1, -1375, 32, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 53000, -1, -1656, 32, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- // hull 11 == 256
- (int16) 63000, -1, -1968, 32, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 44000, -1, - 733, 60, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 53000, -1, - 883, 60, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 63000, -1, -1050, 60, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 44000, -1, - 488, 90, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 53000, -1, - 588, 90, 0, -1, 0, 0,
- 0, -1, 0, 0,
-
- (int16) 63000, -1, - 700, 90, 0, -1, 0, 0,
- 0, -1, 0, 0
-};
-
-static const uint16 freqmod_lengths[] = {
- 0x1000, 0x1000, 0x20, 0x2000, 0x1000
-};
-
-static const uint16 freqmod_offsets[] = {
- 0, 0x100, 0x200, 0x302, 0x202
-};
-
-static const int8 freqmod_table[0x502] = {
- 0, 3, 6, 9, 12, 15, 18, 21,
- 24, 27, 30, 33, 36, 39, 42, 45,
- 48, 51, 54, 57, 59, 62, 65, 67,
- 70, 73, 75, 78, 80, 82, 85, 87,
- 89, 91, 94, 96, 98, 100, 102, 103,
- 105, 107, 108, 110, 112, 113, 114, 116,
- 117, 118, 119, 120, 121, 122, 123, 123,
- 124, 125, 125, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 125, 125,
- 124, 123, 123, 122, 121, 120, 119, 118,
- 117, 116, 114, 113, 112, 110, 108, 107,
- 105, 103, 102, 100, 98, 96, 94, 91,
- 89, 87, 85, 82, 80, 78, 75, 73,
- 70, 67, 65, 62, 59, 57, 54, 51,
- 48, 45, 42, 39, 36, 33, 30, 27,
- 24, 21, 18, 15, 12, 9, 6, 3,
- 0, -3, -6, -9, -12, -15, -18, -21,
- -24, -27, -30, -33, -36, -39, -42, -45,
- -48, -51, -54, -57, -59, -62, -65, -67,
- -70, -73, -75, -78, -80, -82, -85, -87,
- -89, -91, -94, -96, -98,-100,-102,-103,
- -105,-107,-108,-110,-112,-113,-114,-116,
- -117,-118,-119,-120,-121,-122,-123,-123,
- -124,-125,-125,-126,-126,-126,-126,-126,
- -126,-126,-126,-126,-126,-126,-125,-125,
- -124,-123,-123,-122,-121,-120,-119,-118,
- -117,-116,-114,-113,-112,-110,-108,-107,
- -105,-103,-102,-100, -98, -96, -94, -91,
- -89, -87, -85, -82, -80, -78, -75, -73,
- -70, -67, -65, -62, -59, -57, -54, -51,
- -48, -45, -42, -39, -36, -33, -30, -27,
- -24, -21, -18, -15, -12, -9, -6, -3,
-
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127,
- -128,-127,-126,-125,-124,-123,-122,-121,
- -120,-119,-118,-117,-116,-115,-114,-113,
- -112,-111,-110,-109,-108,-107,-106,-105,
- -104,-103,-102,-101,-100, -99, -98, -97,
- -96, -95, -94, -93, -92, -91, -90, -89,
- -88, -87, -86, -85, -84, -83, -82, -81,
- -80, -79, -78, -77, -76, -75, -74, -73,
- -72, -71, -70, -69, -68, -67, -66, -65,
- -64, -63, -62, -61, -60, -59, -58, -57,
- -56, -55, -54, -53, -52, -51, -50, -49,
- -48, -47, -46, -45, -44, -43, -42, -41,
- -40, -39, -38, -37, -36, -35, -34, -33,
- -32, -31, -30, -29, -28, -27, -26, -25,
- -24, -23, -22, -21, -20, -19, -18, -17,
- -16, -15, -14, -13, -12, -11, -10, -9,
- -8, -7, -6, -5, -4, -3, -2, -1,
-
- -120, 120,
-
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- -120,-120,-120,-120,-120,-120,-120,-120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120,
-
- 41, 35, -66,-124, -31, 108, -42, -82,
- 82,-112, 73, -15, -15, -69, -23, -21,
- -77, -90, -37, 60,-121, 12, 62,-103,
- 36, 94, 13, 28, 6, -73, 71, -34,
- -77, 18, 77, -56, 67, -69,-117, -90,
- 31, 3, 90, 125, 9, 56, 37, 31,
- 93, -44, -53, -4,-106, -11, 69, 59,
- 19, 13,-119, 10, 28, -37, -82, 50,
- 32,-102, 80, -18, 64, 120, 54, -3,
- 18, 73, 50, -10, -98, 125, 73, -36,
- -83, 79, 20, -14, 68, 64, 102, -48,
- 107, -60, 48, -73, 50, 59, -95, 34,
- -10, 34,-111, -99, -31,-117, 31, -38,
- -80, -54,-103, 2, -71, 114, -99, 73,
- 44,-128, 126, -59,-103, -43, -23,-128,
- -78, -22, -55, -52, 83, -65, 103, -42,
- -65, 20, -42, 126, 45, -36,-114, 102,
- -125, -17, 87, 73, 97, -1, 105,-113,
- 97, -51, -47, 30, -99,-100, 22, 114,
- 114, -26, 29, -16,-124, 79, 74, 119,
- 2, -41, -24, 57, 44, 83, -53, -55,
- 18, 30, 51, 116, -98, 12, -12, -43,
- -44, -97, -44, -92, 89, 126, 53, -49,
- 50, 34, -12, -52, -49, -45,-112, 45,
- 72, -45,-113, 117, -26, -39, 29, 42,
- -27, -64, -9, 43, 120,-127,-121, 68,
- 14, 95, 80, 0, -44, 97,-115, -66,
- 123, 5, 21, 7, 59, 51,-126, 31,
- 24, 112,-110, -38, 100, 84, -50, -79,
- -123, 62, 105, 21, -8, 70, 106, 4,
- -106, 115, 14, -39, 22, 47, 103, 104,
- -44, -9, 74, 74, -48, 87, 104, 118,
- -6, 22, -69, 17, -83, -82, 36,-120,
- 121, -2, 82, -37, 37, 67, -27, 60,
- -12, 69, -45, -40, 40, -50, 11, -11,
- -59, 96, 89, 61,-105, 39,-118, 89,
- 118, 45, -48, -62, -55, -51, 104, -44,
- 73, 106, 121, 37, 8, 97, 64, 20,
- -79, 59, 106, -91, 17, 40, -63,-116,
- -42, -87, 11,-121,-105,-116, 47, -15,
- 21, 29,-102,-107, -63,-101, -31, -64,
- 126, -23, -88,-102, -89,-122, -62, -75,
- 84, -65,-102, -25, -39, 35, -47, 85,
- -112, 56, 40, -47, -39, 108, -95, 102,
- 94, 78, -31, 48,-100, -2, -39, 113,
- -97, -30, -91, -30, 12,-101, -76, 71,
- 101, 56, 42, 70,-119, -87,-126, 121,
- 122, 118, 120, -62, 99, -79, 38, -33,
- -38, 41, 109, 62, 98, -32,-106, 18,
- 52, -65, 57, -90, 63,-119, 94, -15,
- 109, 14, -29, 108, 40, -95, 30, 32,
- 29, -53, -62, 3, 63, 65, 7,-124,
- 15, 20, 5, 101, 27, 40, 97, -55,
- -59, -25, 44,-114, 70, 54, 8, -36,
- -13, -88,-115, -2, -66, -14, -21, 113,
- -1, -96, -48, 59, 117, 6,-116, 126,
- -121, 120, 115, 77, -48, -66,-126, -66,
- -37, -62, 70, 65, 43,-116, -6, 48,
- 127, 112, -16, -89, 84,-122, 50,-107,
- -86, 91, 104, 19, 11, -26, -4, -11,
- -54, -66, 125, -97,-119,-118, 65, 27,
- -3, -72, 79, 104, -10, 114, 123, 20,
- -103, -51, -45, 13, -16, 68, 58, -76,
- -90, 102, 83, 51, 11, -53, -95, 16
-};
-
static const byte freqTable[] = {
3, 10, 17, 24, 31, 38, 45, 51,
58, 65, 71, 77, 83, 90, 96, 102,
@@ -416,50 +129,17 @@ static const byte releaseRate[] = {
36, 56, 80, 100, 120, 140, 160, 255
};
-static const uint16 pcjr_freq_table[12] = {
- 65472, 61760, 58304, 55040, 52032, 49024,
- 46272, 43648, 41216, 38912, 36736, 34624
-};
-
static const byte volumeTable[] = {
0x00, 0x10, 0x10, 0x11, 0x11, 0x21, 0x22, 0x22,
0x33, 0x44, 0x55, 0x66, 0x88, 0xAA, 0xCC, 0xFF
};
-static CMSEmulator *g_cmsEmu = 0;
-
-Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) {
+Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer)
+ : Player_V2Base(scumm, mixer, true) {
int i;
- _isV3Game = (scumm->_game.version >= 3);
- _vm = scumm;
- _mixer = mixer;
-// debug("mixer rate: %d", _mixer->getOutputRate());
- _sampleRate = CMS_RATE;
-
- _header_len = (scumm->_game.features & GF_OLD_BUNDLE) ? 4 : 6;
-
- // Initialize sound queue
- _current_nr = _next_nr = 0;
- _current_data = _next_data = 0;
-
- // Initialize channel code
- for (i = 0; i < 4; ++i)
- clear_channel(i);
-
- _next_tick = 0;
- _tick_len = (_sampleRate << FIXP_SHIFT) / FREQ_HZ;
-
- // Initialize V3 music timer
- _music_timer_ctr = _music_timer = 0;
- _ticks_per_music_timer = 65535;
-
setMusicVolume(255);
- _timer_output = 0;
- for (i = 0; i < 4; i++)
- _timer_count[i] = 0;
-
memset(_cmsVoicesBase, 0, sizeof(Voice)*16);
memset(_cmsVoices, 0, sizeof(Voice2)*8);
memset(_cmsChips, 0, sizeof(MusicChip)*2);
@@ -495,7 +175,7 @@ Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) {
_cmsVoices[7].octaveOutput = &(_cmsChips[1].octave[1]);
// inits the CMS Emulator like in the original
- g_cmsEmu = new CMSEmulator(_sampleRate);
+ _cmsEmu = new CMSEmulator(_sampleRate);
static const byte cmsInitData[13*2] = {
0x1C, 0x02,
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00,
@@ -505,8 +185,8 @@ Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) {
i = 0;
for (int cmsPort = 0x220; i < 2; cmsPort += 2, ++i) {
for (int off = 0; off < 13; ++off) {
- g_cmsEmu->portWrite(cmsPort+1, cmsInitData[off*2]);
- g_cmsEmu->portWrite(cmsPort, cmsInitData[off*2+1]);
+ _cmsEmu->portWrite(cmsPort+1, cmsInitData[off*2]);
+ _cmsEmu->portWrite(cmsPort, cmsInitData[off*2+1]);
}
}
@@ -517,40 +197,12 @@ Player_V2CMS::~Player_V2CMS() {
Common::StackLock lock(_mutex);
_mixer->stopHandle(_soundHandle);
- delete g_cmsEmu;
+ delete _cmsEmu;
}
void Player_V2CMS::setMusicVolume(int vol) {
}
-void Player_V2CMS::chainSound(int nr, byte *data) {
- int offset = _header_len + 10;
-
- _current_nr = nr;
- _current_data = data;
-
- for (int i = 0; i < 4; i++) {
- clear_channel(i);
-
- _channels[i].d.music_script_nr = nr;
- if (data) {
- _channels[i].d.next_cmd = READ_LE_UINT16(data + offset + 2 * i);
- if (_channels[i].d.next_cmd) {
- _channels[i].d.time_left = 1;
- }
- }
- }
- _music_timer = 0;
-}
-
-void Player_V2CMS::chainNextSound() {
- if (_next_nr) {
- chainSound(_next_nr, _next_data);
- _next_nr = 0;
- _next_data = 0;
- }
-}
-
void Player_V2CMS::stopAllSounds() {
Common::StackLock lock(_mutex);
@@ -702,275 +354,6 @@ int Player_V2CMS::getSoundStatus(int nr) const {
return _current_nr == nr || _next_nr == nr || _loadedMidiSong == nr;
}
-
-void Player_V2CMS::clear_channel(int i) {
- ChannelInfo *channel = &_channels[i];
- memset(channel, 0, sizeof(ChannelInfo));
-}
-
-int Player_V2CMS::getMusicTimer() {
- if (_isV3Game)
- return _music_timer;
- else
- return _channels[0].d.music_timer;
-}
-
-void Player_V2CMS::execute_cmd(ChannelInfo *channel) {
- uint16 value;
- int16 offset;
- uint8 *script_ptr;
- ChannelInfo * current_channel;
- ChannelInfo * dest_channel;
-
- current_channel = channel;
-
- if (channel->d.next_cmd == 0)
- goto check_stopped;
- script_ptr = &_current_data[channel->d.next_cmd];
-
- for (;;) {
- uint8 opcode = *script_ptr++;
- if (opcode >= 0xf8) {
- switch (opcode) {
- case 0xf8: // set hull curve
- debug(7, "channels[%d]: hull curve %2d",
- (uint)(channel - _channels), *script_ptr);
- channel->d.hull_curve = hull_offsets[*script_ptr / 2];
- script_ptr++;
- break;
-
- case 0xf9: // set freqmod curve
- debug(7, "channels[%d]: freqmod curve %2d",
- (uint)(channel - _channels), *script_ptr);
- channel->d.freqmod_table = freqmod_offsets[*script_ptr / 4];
- channel->d.freqmod_modulo = freqmod_lengths[*script_ptr / 4];
- script_ptr++;
- break;
-
- case 0xfd: // clear other channel
- value = READ_LE_UINT16 (script_ptr) / sizeof (ChannelInfo);
- debug(7, "clear channel %d", value);
- script_ptr += 2;
- // In Indy3, when traveling to Venice a command is
- // issued to clear channel 4. So we introduce a 4th
- // channel, which is never used. All OOB accesses are
- // mapped to this channel.
- //
- // The original game had room for 8 channels, but only
- // channels 0-3 are read, changes to other channels
- // had no effect.
- if (value >= ARRAYSIZE (_channels))
- value = 4;
- channel = &_channels[value];
- // fall through
-
- case 0xfa: // clear current channel
- if (opcode == 0xfa)
- debug(7, "clear channel");
- channel->d.next_cmd = 0;
- channel->d.base_freq = 0;
- channel->d.freq_delta = 0;
- channel->d.freq = 0;
- channel->d.volume = 0;
- channel->d.volume_delta = 0;
- channel->d.inter_note_pause = 0;
- channel->d.transpose = 0;
- channel->d.hull_curve = 0;
- channel->d.hull_offset = 0;
- channel->d.hull_counter = 0;
- channel->d.freqmod_table = 0;
- channel->d.freqmod_offset = 0;
- channel->d.freqmod_incr = 0;
- channel->d.freqmod_multiplier = 0;
- channel->d.freqmod_modulo = 0;
- break;
-
- case 0xfb: // ret from subroutine
- debug(7, "ret from sub");
- script_ptr = _retaddr;
- break;
-
- case 0xfc: // call subroutine
- offset = READ_LE_UINT16 (script_ptr);
- debug(7, "subroutine %d", offset);
- script_ptr += 2;
- _retaddr = script_ptr;
- script_ptr = _current_data + offset;
- break;
-
- case 0xfe: // loop music
- opcode = *script_ptr++;
- offset = READ_LE_UINT16 (script_ptr);
- script_ptr += 2;
- debug(7, "loop if %d to %d", opcode, offset);
- if (!channel->array[opcode / 2] || --channel->array[opcode/2])
- script_ptr += offset;
- break;
-
- case 0xff: // set parameter
- opcode = *script_ptr++;
- value = READ_LE_UINT16 (script_ptr);
- channel->array[opcode / 2] = value;
- debug(7, "channels[%d]: set param %2d = %5d",
- (uint)(channel - _channels), opcode, value);
- script_ptr += 2;
- if (opcode == 14) {
- /* tempo var */
- _ticks_per_music_timer = 125;
- }
- if (opcode == 0)
- goto end;
- break;
- }
- } else { // opcode < 0xf8
- for (;;) {
- int16 note, octave;
- int is_last_note;
- dest_channel = &_channels[(opcode >> 5) & 3];
-
- if (!(opcode & 0x80)) {
-
- int tempo = channel->d.tempo;
- if (!tempo)
- tempo = 1;
- channel->d.time_left = tempo * note_lengths[opcode & 0x1f];
-
- note = *script_ptr++;
- is_last_note = note & 0x80;
- note &= 0x7f;
- if (note == 0x7f) {
- debug(8, "channels[%d]: pause %d",
- (uint)(channel - _channels), channel->d.time_left);
- goto end;
- }
- } else {
-
- channel->d.time_left = ((opcode & 7) << 8) | *script_ptr++;
-
- if ((opcode & 0x10)) {
- debug(8, "channels[%d]: pause %d",
- (uint)(channel - _channels), channel->d.time_left);
- goto end;
- }
-
- is_last_note = 0;
- note = (*script_ptr++) & 0x7f;
- }
-
- debug(8, "channels[%d]: @%04x note: %3d+%d len: %2d hull: %d mod: %d/%d/%d %s",
- (uint)(dest_channel - channel), script_ptr ? (uint)(script_ptr - _current_data - 2) : 0,
- note, (signed short) dest_channel->d.transpose, channel->d.time_left,
- dest_channel->d.hull_curve, dest_channel->d.freqmod_table,
- dest_channel->d.freqmod_incr,dest_channel->d.freqmod_multiplier,
- is_last_note ? "last":"");
-
- uint16 myfreq;
- dest_channel->d.time_left = channel->d.time_left;
- dest_channel->d.note_length =
- channel->d.time_left - dest_channel->d.inter_note_pause;
- note += dest_channel->d.transpose;
- while (note < 0)
- note += 12;
- octave = note / 12;
- note = note % 12;
- dest_channel->d.hull_offset = 0;
- dest_channel->d.hull_counter = 1;
- if (dest_channel == &_channels[3]) {
- dest_channel->d.hull_curve = 196 + note * 12;
- myfreq = 384 - 64 * octave;
- } else {
- myfreq = pcjr_freq_table[note] >> octave;
- }
- dest_channel->d.freq = dest_channel->d.base_freq = myfreq;
- if (is_last_note)
- goto end;
- opcode = *script_ptr++;
- }
- }
- }
-
-end:
- channel = current_channel;
- if (channel->d.time_left) {
- channel->d.next_cmd = script_ptr - _current_data;
- return;
- }
-
- channel->d.next_cmd = 0;
-
-check_stopped:
- int i;
- for (i = 0; i < 4; i++) {
- if (_channels[i].d.time_left)
- return;
- }
-
- _current_nr = 0;
- _current_data = 0;
- chainNextSound();
- return;
-}
-
-void Player_V2CMS::next_freqs(ChannelInfo *channel) {
- channel->d.volume += channel->d.volume_delta;
- channel->d.base_freq += channel->d.freq_delta;
-
- channel->d.freqmod_offset += channel->d.freqmod_incr;
- if (channel->d.freqmod_offset != 0)
- if (channel->d.freqmod_offset > channel->d.freqmod_modulo)
- channel->d.freqmod_offset -= channel->d.freqmod_modulo;
-
- channel->d.freq =
- (int) (freqmod_table[channel->d.freqmod_table + (channel->d.freqmod_offset >> 4)])
- * (int) channel->d.freqmod_multiplier / 256
- + channel->d.base_freq;
-
- debug(9, "Freq: %d/%d, %d/%d/%d*%d %d",
- channel->d.base_freq, (int16)channel->d.freq_delta,
- channel->d.freqmod_table, channel->d.freqmod_offset,
- channel->d.freqmod_incr, channel->d.freqmod_multiplier,
- channel->d.freq);
-
- if (channel->d.note_length && !--channel->d.note_length) {
- channel->d.hull_offset = 16;
- channel->d.hull_counter = 1;
- }
-
- if (!--channel->d.time_left) {
- execute_cmd(channel);
- }
-
- if (channel->d.hull_counter && !--channel->d.hull_counter) {
- for (;;) {
- const int16 *hull_ptr = hulls
- + channel->d.hull_curve + channel->d.hull_offset / 2;
- if (hull_ptr[1] == -1) {
- channel->d.volume = hull_ptr[0];
- if (hull_ptr[0] == 0)
- channel->d.volume_delta = 0;
- channel->d.hull_offset += 4;
- } else {
- channel->d.volume_delta = hull_ptr[0];
- channel->d.hull_counter = hull_ptr[1];
- channel->d.hull_offset += 4;
- break;
- }
- }
- }
-}
-
-void Player_V2CMS::nextTick() {
- for (int i = 0; i < 4; i++) {
- if (!_channels[i].d.time_left)
- continue;
- next_freqs(&_channels[i]);
- }
- if (_music_timer_ctr++ >= _ticks_per_music_timer) {
- _music_timer_ctr = 0;
- _music_timer++;
- }
-}
-
void Player_V2CMS::processMidiData(uint ticks) {
byte *currentData = _midiData;
byte command = 0x00;
@@ -1031,7 +414,7 @@ int Player_V2CMS::readBuffer(int16 *buffer, const int numSamples) {
Common::StackLock lock(_mutex);
uint step = 1;
- int len = numSamples/2;
+ int len = numSamples / 2;
// maybe this needs a complete rewrite
do {
@@ -1061,7 +444,7 @@ int Player_V2CMS::readBuffer(int16 *buffer, const int numSamples) {
step = len;
if (step > (_next_tick >> FIXP_SHIFT))
step = (_next_tick >> FIXP_SHIFT);
- g_cmsEmu->readBuffer(buffer, step);
+ _cmsEmu->readBuffer(buffer, step);
buffer += 2 * step;
_next_tick -= step << FIXP_SHIFT;
} while (len -= step);
@@ -1105,27 +488,27 @@ void Player_V2CMS::playVoice() {
void Player_V2CMS::processChannel(Voice2 *channel) {
++_outputTableReady;
switch (channel->nextProcessState) {
- case PROCESS_RELEASE:
- processRelease(channel);
+ case PROCESS_RELEASE:
+ processRelease(channel);
break;
- case PROCESS_ATTACK:
- processAttack(channel);
+ case PROCESS_ATTACK:
+ processAttack(channel);
break;
- case PROCESS_DECAY:
- processDecay(channel);
+ case PROCESS_DECAY:
+ processDecay(channel);
break;
- case PROCESS_SUSTAIN:
- processSustain(channel);
+ case PROCESS_SUSTAIN:
+ processSustain(channel);
break;
- case PROCESS_VIBRATO:
- processVibrato(channel);
+ case PROCESS_VIBRATO:
+ processVibrato(channel);
break;
- default:
+ default:
break;
}
}
@@ -1207,8 +590,8 @@ void Player_V2CMS::offAllChannels() {
for (int cmsPort = 0x220, i = 0; i < 2; cmsPort += 2, ++i) {
for (int off = 0; off < 10; ++off) {
- g_cmsEmu->portWrite(cmsPort+1, cmsOffData[off*2]);
- g_cmsEmu->portWrite(cmsPort, cmsOffData[off*2+1]);
+ _cmsEmu->portWrite(cmsPort+1, cmsOffData[off*2]);
+ _cmsEmu->portWrite(cmsPort, cmsOffData[off*2+1]);
}
}*/
}
@@ -1397,32 +780,32 @@ void Player_V2CMS::play() {
// with the high nibble of the volumeReg value
// the right channels amplitude is set
// with the low value the left channels amplitude
- g_cmsEmu->portWrite(0x221, 0);
- g_cmsEmu->portWrite(0x220, volumeReg[0]);
- g_cmsEmu->portWrite(0x221, 1);
- g_cmsEmu->portWrite(0x220, volumeReg[1]);
- g_cmsEmu->portWrite(0x221, 2);
- g_cmsEmu->portWrite(0x220, volumeReg[2]);
- g_cmsEmu->portWrite(0x221, 3);
- g_cmsEmu->portWrite(0x220, volumeReg[3]);
- g_cmsEmu->portWrite(0x221, 8);
- g_cmsEmu->portWrite(0x220, freqReg[0]);
- g_cmsEmu->portWrite(0x221, 9);
- g_cmsEmu->portWrite(0x220, freqReg[1]);
- g_cmsEmu->portWrite(0x221, 10);
- g_cmsEmu->portWrite(0x220, freqReg[2]);
- g_cmsEmu->portWrite(0x221, 11);
- g_cmsEmu->portWrite(0x220, freqReg[3]);
- g_cmsEmu->portWrite(0x221, 0x10);
- g_cmsEmu->portWrite(0x220, octaveReg[0]);
- g_cmsEmu->portWrite(0x221, 0x11);
- g_cmsEmu->portWrite(0x220, octaveReg[1]);
- g_cmsEmu->portWrite(0x221, 0x14);
- g_cmsEmu->portWrite(0x220, freqEnable);
- g_cmsEmu->portWrite(0x221, 0x15);
- g_cmsEmu->portWrite(0x220, noiseEnable);
- g_cmsEmu->portWrite(0x221, 0x16);
- g_cmsEmu->portWrite(0x220, noiseGen);
+ _cmsEmu->portWrite(0x221, 0);
+ _cmsEmu->portWrite(0x220, volumeReg[0]);
+ _cmsEmu->portWrite(0x221, 1);
+ _cmsEmu->portWrite(0x220, volumeReg[1]);
+ _cmsEmu->portWrite(0x221, 2);
+ _cmsEmu->portWrite(0x220, volumeReg[2]);
+ _cmsEmu->portWrite(0x221, 3);
+ _cmsEmu->portWrite(0x220, volumeReg[3]);
+ _cmsEmu->portWrite(0x221, 8);
+ _cmsEmu->portWrite(0x220, freqReg[0]);
+ _cmsEmu->portWrite(0x221, 9);
+ _cmsEmu->portWrite(0x220, freqReg[1]);
+ _cmsEmu->portWrite(0x221, 10);
+ _cmsEmu->portWrite(0x220, freqReg[2]);
+ _cmsEmu->portWrite(0x221, 11);
+ _cmsEmu->portWrite(0x220, freqReg[3]);
+ _cmsEmu->portWrite(0x221, 0x10);
+ _cmsEmu->portWrite(0x220, octaveReg[0]);
+ _cmsEmu->portWrite(0x221, 0x11);
+ _cmsEmu->portWrite(0x220, octaveReg[1]);
+ _cmsEmu->portWrite(0x221, 0x14);
+ _cmsEmu->portWrite(0x220, freqEnable);
+ _cmsEmu->portWrite(0x221, 0x15);
+ _cmsEmu->portWrite(0x220, noiseEnable);
+ _cmsEmu->portWrite(0x221, 0x16);
+ _cmsEmu->portWrite(0x220, noiseGen);
}
void Player_V2CMS::playMusicChips(const MusicChip *table) {
@@ -1430,30 +813,30 @@ void Player_V2CMS::playMusicChips(const MusicChip *table) {
do {
cmsPort += 2;
- g_cmsEmu->portWrite(cmsPort+1, 0);
- g_cmsEmu->portWrite(cmsPort, table->ampl[0]);
- g_cmsEmu->portWrite(cmsPort+1, 1);
- g_cmsEmu->portWrite(cmsPort, table->ampl[1]);
- g_cmsEmu->portWrite(cmsPort+1, 2);
- g_cmsEmu->portWrite(cmsPort, table->ampl[2]);
- g_cmsEmu->portWrite(cmsPort+1, 3);
- g_cmsEmu->portWrite(cmsPort, table->ampl[3]);
- g_cmsEmu->portWrite(cmsPort+1, 8);
- g_cmsEmu->portWrite(cmsPort, table->freq[0]);
- g_cmsEmu->portWrite(cmsPort+1, 9);
- g_cmsEmu->portWrite(cmsPort, table->freq[1]);
- g_cmsEmu->portWrite(cmsPort+1, 10);
- g_cmsEmu->portWrite(cmsPort, table->freq[2]);
- g_cmsEmu->portWrite(cmsPort+1, 11);
- g_cmsEmu->portWrite(cmsPort, table->freq[3]);
- g_cmsEmu->portWrite(cmsPort+1, 0x10);
- g_cmsEmu->portWrite(cmsPort, table->octave[0]);
- g_cmsEmu->portWrite(cmsPort+1, 0x11);
- g_cmsEmu->portWrite(cmsPort, table->octave[1]);
- g_cmsEmu->portWrite(cmsPort+1, 0x14);
- g_cmsEmu->portWrite(cmsPort, 0x3F);
- g_cmsEmu->portWrite(cmsPort+1, 0x15);
- g_cmsEmu->portWrite(cmsPort, 0x00);
+ _cmsEmu->portWrite(cmsPort+1, 0);
+ _cmsEmu->portWrite(cmsPort, table->ampl[0]);
+ _cmsEmu->portWrite(cmsPort+1, 1);
+ _cmsEmu->portWrite(cmsPort, table->ampl[1]);
+ _cmsEmu->portWrite(cmsPort+1, 2);
+ _cmsEmu->portWrite(cmsPort, table->ampl[2]);
+ _cmsEmu->portWrite(cmsPort+1, 3);
+ _cmsEmu->portWrite(cmsPort, table->ampl[3]);
+ _cmsEmu->portWrite(cmsPort+1, 8);
+ _cmsEmu->portWrite(cmsPort, table->freq[0]);
+ _cmsEmu->portWrite(cmsPort+1, 9);
+ _cmsEmu->portWrite(cmsPort, table->freq[1]);
+ _cmsEmu->portWrite(cmsPort+1, 10);
+ _cmsEmu->portWrite(cmsPort, table->freq[2]);
+ _cmsEmu->portWrite(cmsPort+1, 11);
+ _cmsEmu->portWrite(cmsPort, table->freq[3]);
+ _cmsEmu->portWrite(cmsPort+1, 0x10);
+ _cmsEmu->portWrite(cmsPort, table->octave[0]);
+ _cmsEmu->portWrite(cmsPort+1, 0x11);
+ _cmsEmu->portWrite(cmsPort, table->octave[1]);
+ _cmsEmu->portWrite(cmsPort+1, 0x14);
+ _cmsEmu->portWrite(cmsPort, 0x3F);
+ _cmsEmu->portWrite(cmsPort+1, 0x15);
+ _cmsEmu->portWrite(cmsPort, 0x00);
++table;
} while ((cmsPort & 2) == 0);
}
diff --git a/engines/scumm/player_v2cms.h b/engines/scumm/player_v2cms.h
new file mode 100644
index 0000000000..fd939d8505
--- /dev/null
+++ b/engines/scumm/player_v2cms.h
@@ -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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SCUMM_PLAYER_V2CMS_H
+#define SCUMM_PLAYER_V2CMS_H
+
+#include "scumm/player_v2base.h" // for channel_data
+
+class CMSEmulator;
+
+namespace Scumm {
+
+/**
+ * Scumm V2 CMS/Gameblaster MIDI driver.
+ */
+class Player_V2CMS : public Player_V2Base {
+public:
+ Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer);
+ virtual ~Player_V2CMS();
+
+ // MusicEngine API
+ virtual void setMusicVolume(int vol);
+ virtual void startSound(int sound);
+ virtual void stopSound(int sound);
+ virtual void stopAllSounds();
+// virtual int getMusicTimer();
+ virtual int getSoundStatus(int sound) const;
+
+ // AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples);
+ bool isStereo() const { return true; }
+ bool endOfData() const { return false; }
+ int getRate() const { return _sampleRate; }
+
+protected:
+
+#include "common/pack-start.h" // START STRUCT PACKING
+ struct Voice {
+ byte attack;
+ byte decay;
+ byte sustain;
+ byte release;
+ byte octadd;
+ int16 vibrato;
+ int16 vibrato2;
+ int16 noise;
+ } PACKED_STRUCT;
+
+ struct Voice2 {
+ byte *amplitudeOutput;
+ byte *freqOutput;
+ byte *octaveOutput;
+
+ uint8 channel;
+ int8 sustainLevel;
+ int8 attackRate;
+ uint8 maxAmpl;
+ int8 decayRate;
+ int8 sustainRate;
+ int8 releaseRate;
+ int8 releaseTime;
+ int8 vibratoRate;
+ int8 vibratoDepth;
+
+ int8 curVibratoRate;
+ int8 curVibratoUnk;
+
+ int8 unkVibratoRate;
+ int8 unkVibratoDepth;
+
+ int8 unkRate;
+ int8 unkCount;
+
+ int nextProcessState;
+ int8 curVolume;
+ int8 curOctave;
+ int8 curFreq;
+
+ int8 octaveAdd;
+
+ int8 playingNote;
+ Voice2 *nextVoice;
+
+ byte chanNumber;
+ } PACKED_STRUCT;
+
+ struct MusicChip {
+ byte ampl[4];
+ byte freq[4];
+ byte octave[2];
+ } PACKED_STRUCT;
+#include "common/pack-end.h" // END STRUCT PACKING
+
+ Voice _cmsVoicesBase[16];
+ Voice2 _cmsVoices[8];
+ MusicChip _cmsChips[2];
+
+ int8 _tempo;
+ int8 _tempoSum;
+ byte _looping;
+ byte _octaveMask;
+ int16 _midiDelay;
+ Voice2 *_midiChannel[16];
+ byte _midiChannelUse[16];
+ byte *_midiData;
+ byte *_midiSongBegin;
+
+ int _loadedMidiSong;
+
+ byte _lastMidiCommand;
+ uint _outputTableReady;
+ byte _clkFrequenz;
+ byte _restart;
+ byte _curSno;
+
+ void loadMidiData(byte *data, int sound);
+ void play();
+
+ void processChannel(Voice2 *channel);
+ void processRelease(Voice2 *channel);
+ void processAttack(Voice2 *channel);
+ void processDecay(Voice2 *channel);
+ void processSustain(Voice2 *channel);
+ void processVibrato(Voice2 *channel);
+
+ void playMusicChips(const MusicChip *table);
+ void playNote(byte *&data);
+ void clearNote(byte *&data);
+ void offAllChannels();
+ void playVoice();
+ void processMidiData(uint ticks);
+
+ Voice2 *getFreeVoice();
+ Voice2 *getPlayVoice(byte param);
+
+ // from Player_V2
+protected:
+ CMSEmulator *_cmsEmu;
+
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp
index d9a5e3414c..5aae59d987 100644
--- a/engines/scumm/resource.cpp
+++ b/engines/scumm/resource.cpp
@@ -1012,7 +1012,7 @@ void ResourceManager::freeResources() {
void ScummEngine::loadPtrToResource(int type, int resindex, const byte *source) {
byte *alloced;
- int i, len;
+ int len;
_res->nukeResource(type, resindex);
@@ -1024,12 +1024,13 @@ void ScummEngine::loadPtrToResource(int type, int resindex, const byte *source)
alloced = _res->createResource(type, resindex, len);
if (!source) {
- alloced[0] = fetchScriptByte();
- for (i = 1; i < len; i++)
- alloced[i] = *_scriptPointer++;
+ // Need to refresh the script pointer, since createResource may
+ // have caused the script resource to expire.
+ refreshScriptPointer();
+ memcpy(alloced, _scriptPointer, len);
+ _scriptPointer += len;
} else {
- for (i = 0; i < len; i++)
- alloced[i] = source[i];
+ memcpy(alloced, source, len);
}
}
diff --git a/engines/scumm/resource_v2.cpp b/engines/scumm/resource_v2.cpp
index e469c721b1..3dc3b4d14e 100644
--- a/engines/scumm/resource_v2.cpp
+++ b/engines/scumm/resource_v2.cpp
@@ -23,8 +23,6 @@
*
*/
-
-
#include "scumm/file.h"
#include "scumm/scumm_v2.h"
#include "scumm/resource.h"
@@ -175,24 +173,24 @@ void ScummEngine_v2::readIndexFile() {
switch (magic) {
case 0x0100:
- printf("Enhanced V2 game detected\n");
+ debug("Enhanced V2 game detected");
assert(_game.version == 2);
readEnhancedIndexFile();
break;
case 0x0A31:
- printf("Classic V1 game detected\n");
+ debug("Classic V1 game detected");
assert(_game.version == 1);
readClassicIndexFile();
break;
case 0x4643:
if (!(_game.platform == Common::kPlatformNES))
error("Use maniac target");
- printf("NES V1 game detected\n");
+ debug("NES V1 game detected");
assert(_game.version == 1);
readClassicIndexFile();
break;
case 0x132:
- printf("C64 V1 game detected\n");
+ debug("C64 V1 game detected");
if (_game.id == GID_MANIAC) {
assert(_game.version == 0);
} else {
@@ -201,7 +199,7 @@ void ScummEngine_v2::readIndexFile() {
readClassicIndexFile();
break;
case 0x032:
- printf("Apple II V1 game detected\n");
+ debug("Apple II V1 game detected");
assert(_game.version == 0);
readClassicIndexFile();
break;
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index b100e15604..58bb817292 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -377,10 +377,10 @@ bool ScummEngine::loadState(int slot, bool compat) {
return false;
}
- _engineStartTime = _system->getMillis() / 1000 - infos.playtime;
+ setTotalPlayTime(infos.playtime * 1000);
} else {
// start time counting
- _engineStartTime = _system->getMillis() / 1000;
+ setTotalPlayTime();
}
// Due to a bug in scummvm up to and including 0.3.0, save games could be saved
@@ -796,7 +796,7 @@ void ScummEngine::saveInfos(Common::WriteStream* file) {
// still save old format for older versions
section.timeTValue = 0;
- section.playtime = _system->getMillis() / 1000 - _engineStartTime;
+ section.playtime = getTotalPlayTime() / 1000;
TimeDate curTime;
_system->getTimeAndDate(curTime);
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
index d33ece7f6a..91e780bcd1 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -50,7 +50,7 @@ namespace Scumm {
* only saves/loads those which are valid for the version of the savegame
* which is being loaded/saved currently.
*/
-#define CURRENT_VER 83
+#define CURRENT_VER 84
/**
* An auxillary macro, used to specify savegame versions. We use this instead
diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp
index 223e9822e2..eac2061560 100644
--- a/engines/scumm/script.cpp
+++ b/engines/scumm/script.cpp
@@ -339,7 +339,7 @@ void ScummEngine::runScriptNested(int script) {
_currentScript = script;
getScriptBaseAddress();
- getScriptEntryPoint();
+ resetScriptPointer();
executeScript();
if (vm.numNestedScripts != 0)
@@ -354,7 +354,7 @@ void ScummEngine::runScriptNested(int script) {
slot->status != ssDead && slot->freezeCount == 0) {
_currentScript = nest->slot;
getScriptBaseAddress();
- getScriptEntryPoint();
+ resetScriptPointer();
return;
}
}
@@ -440,24 +440,38 @@ void ScummEngine::getScriptBaseAddress() {
}
}
-
-void ScummEngine::getScriptEntryPoint() {
+void ScummEngine::resetScriptPointer() {
if (_currentScript == 0xFF)
return;
_scriptPointer = _scriptOrgPointer + vm.slot[_currentScript].offs;
}
+/**
+ * This method checks whether the resource that contains the active script
+ * moved, and if so, updates the script pointer accordingly.
+ *
+ * The script resource may have moved because it might have been garbage
+ * collected by ResourceManager::expireResources.
+ */
+void ScummEngine::refreshScriptPointer() {
+ if (*_lastCodePtr + sizeof(MemBlkHeader) != _scriptOrgPointer) {
+ long oldoffs = _scriptPointer - _scriptOrgPointer;
+ getScriptBaseAddress();
+ _scriptPointer = _scriptOrgPointer + oldoffs;
+ }
+}
+
/** Execute a script - Read opcode, and execute it from the table */
void ScummEngine::executeScript() {
int c;
while (_currentScript != 0xFF) {
if (_showStack == 1) {
- printf("Stack:");
+ debugN("Stack:");
for (c = 0; c < _scummStackPos; c++) {
- printf(" %d", _vmStack[c]);
+ debugN(" %d", _vmStack[c]);
}
- printf("\n");
+ debugN("\n");
}
_opcode = fetchScriptByte();
if (_game.version > 2) // V0-V2 games didn't use the didexec flag
@@ -469,9 +483,9 @@ void ScummEngine::executeScript() {
getOpcodeDesc(_opcode));
if (_hexdumpScripts == true) {
for (c = -1; c < 15; c++) {
- printf(" %02x", *(_scriptPointer + c));
+ debugN(" %02x", *(_scriptPointer + c));
}
- printf("\n");
+ debugN("\n");
}
executeOpcode(_opcode);
@@ -492,20 +506,12 @@ const char *ScummEngine::getOpcodeDesc(byte i) {
}
byte ScummEngine::fetchScriptByte() {
- if (*_lastCodePtr + sizeof(MemBlkHeader) != _scriptOrgPointer) {
- long oldoffs = _scriptPointer - _scriptOrgPointer;
- getScriptBaseAddress();
- _scriptPointer = _scriptOrgPointer + oldoffs;
- }
+ refreshScriptPointer();
return *_scriptPointer++;
}
uint ScummEngine::fetchScriptWord() {
- if (*_lastCodePtr + sizeof(MemBlkHeader) != _scriptOrgPointer) {
- long oldoffs = _scriptPointer - _scriptOrgPointer;
- getScriptBaseAddress();
- _scriptPointer = _scriptOrgPointer + oldoffs;
- }
+ refreshScriptPointer();
uint a = READ_LE_UINT16(_scriptPointer);
_scriptPointer += 2;
return a;
@@ -516,11 +522,7 @@ int ScummEngine::fetchScriptWordSigned() {
}
uint ScummEngine::fetchScriptDWord() {
- if (*_lastCodePtr + sizeof(MemBlkHeader) != _scriptOrgPointer) {
- long oldoffs = _scriptPointer - _scriptOrgPointer;
- getScriptBaseAddress();
- _scriptPointer = _scriptOrgPointer + oldoffs;
- }
+ refreshScriptPointer();
uint a = READ_LE_UINT32(_scriptPointer);
_scriptPointer += 4;
return a;
@@ -898,7 +900,7 @@ void ScummEngine::runAllScripts() {
if (vm.slot[i].cycle == cycle && vm.slot[i].status == ssRunning && !vm.slot[i].didexec) {
_currentScript = (byte)i;
getScriptBaseAddress();
- getScriptEntryPoint();
+ resetScriptPointer();
executeScript();
}
}
@@ -1231,22 +1233,26 @@ bool ScummEngine::isRoomScriptRunning(int script) const {
void ScummEngine::copyScriptString(byte *dst) {
int len = resStrLen(_scriptPointer) + 1;
- while (len--)
- *dst++ = fetchScriptByte();
+ memcpy(dst, _scriptPointer, len);
+ _scriptPointer += len;
+ dst += len;
*dst = 0;
}
-//
-// Given a pointer to a Scumm string, this function returns the total byte length
-// of the string data in that resource. To do so it has to understand certain
-// special characters embedded into the string. The reason for this function is that
-// sometimes this embedded data contains zero bytes, thus we can't just use strlen.
-//
-int ScummEngine::resStrLen(const byte *src) const {
+/**
+ * Given a pointer to a Scumm string, this function returns the total
+ * byte length of the string data in that resource. To do so it has to
+ * understand certain special characters embedded into the string. The
+ * reason for this function is that sometimes this embedded data
+ * contains zero bytes, thus we can't just use strlen.
+ */
+int ScummEngine::resStrLen(const byte *src) {
int num = 0;
byte chr;
- if (src == NULL)
+ if (src == NULL) {
+ refreshScriptPointer();
src = _scriptPointer;
+ }
while ((chr = *src++) != 0) {
num++;
if (_game.heversion <= 71 && chr == 0xFF) {
diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp
index cf44ee195e..d3f256c951 100644
--- a/engines/scumm/script_v0.cpp
+++ b/engines/scumm/script_v0.cpp
@@ -829,6 +829,8 @@ void ScummEngine_v0::o_setActorBitVar() {
// This flag causes the actor to stop moving (used by script #158, Green Tentacle 'Oomph!')
if (a->_miscflags & 0x40)
a->stopActorMoving();
+ if (a->_miscflags & 0x80)
+ a->setActorCostume(0);
debug(0, "o_setActorBitVar(%d, %d, %d)", act, mask, mod);
}
@@ -987,7 +989,10 @@ void ScummEngine_v0::o_setOwnerOf() {
void ScummEngine_v0::resetSentence(bool walking) {
_activeVerb = 13;
- if (!walking) {
+ // If the actor is walking, or the screen is a keypad (no sentence verbs/objects are drawn)
+ // Then reset all active objects (stops the radio crash, bug #3077966)
+ if (!walking || !(_userState & 32)) {
+ _v0ObjectFlag = 0;
_activeInventory = 0;
_activeObject = 0;
_activeObject2 = 0;
diff --git a/engines/scumm/script_v2.cpp b/engines/scumm/script_v2.cpp
index bc8446d16f..d3a2272a39 100644
--- a/engines/scumm/script_v2.cpp
+++ b/engines/scumm/script_v2.cpp
@@ -1174,6 +1174,8 @@ void ScummEngine_v2::o2_walkActorToObject() {
int obj;
Actor *a;
+ _v0ObjectFlag = 0;
+
a = derefActor(getVarOrDirectByte(PARAM_1), "o2_walkActorToObject");
obj = getVarOrDirectWord(PARAM_2);
if (whereIsObject(obj) != WIO_NOT_FOUND) {
@@ -1182,6 +1184,7 @@ void ScummEngine_v2::o2_walkActorToObject() {
AdjustBoxResult r = a->adjustXYToBeInBox(x, y);
x = r.x;
y = r.y;
+
a->startWalkActor(x, y, dir);
}
}
diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index ea903fc108..d3e1ba43ef 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -1840,17 +1840,12 @@ void ScummEngine_v5::o5_roomOps() {
Common::InSaveFile *file = _saveFileMan->openForLoading(filename);
if (file != NULL) {
byte *ptr;
- int len = 256, cnt = 0;
- ptr = (byte *)malloc(len);
- while (ptr) {
- int r = file->read(ptr + cnt, len - cnt);
- cnt += r;
- if (cnt < len)
- break;
- len *= 2;
- ptr = (byte *)realloc(ptr, len);
- }
- ptr[cnt] = '\0';
+ const int len = file->size();
+ ptr = (byte *)malloc(len + 1);
+ assert(ptr);
+ int r = file->read(ptr, len);
+ assert(r == len);
+ ptr[len] = '\0';
loadPtrToResource(rtString, a, ptr);
free(ptr);
delete file;
@@ -2156,6 +2151,7 @@ void ScummEngine_v5::o5_stringOps() {
case 2: /* copystring */
a = getVarOrDirectByte(PARAM_1);
b = getVarOrDirectByte(PARAM_2);
+ assert(a != b);
_res->nukeResource(rtString, a);
ptr = getResourceAddress(rtString, b);
if (ptr)
diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp
index c5841dfaf4..0226343df5 100644
--- a/engines/scumm/script_v6.cpp
+++ b/engines/scumm/script_v6.cpp
@@ -536,7 +536,18 @@ void ScummEngine_v6::o6_not() {
}
void ScummEngine_v6::o6_eq() {
- push(pop() == pop());
+ int a = pop();
+ int b = pop();
+
+ // WORKAROUND: Forces the game version string set via script 1 to be used in both Macintosh and Windows versions,
+ // when checking for save game compatibility. Allows saved games to be shared between Macintosh and Windows versions.
+ // The scripts check VAR_PLATFORM (b) against the value (2) of the Macintosh platform (a).
+ if (_game.id == GID_BASEBALL2001 && (vm.slot[_currentScript].number == 291 || vm.slot[_currentScript].number == 292) &&
+ a == 2 && b == 1) {
+ push(1);
+ } else {
+ push(a == b);
+ }
}
void ScummEngine_v6::o6_neq() {
@@ -1285,7 +1296,7 @@ void ScummEngine_v6::o6_loadRoomWithEgo() {
void ScummEngine_v6::o6_getRandomNumber() {
int rnd;
- rnd = _rnd.getRandomNumber(pop());
+ rnd = _rnd.getRandomNumber(ABS(pop()));
if (VAR_RANDOM_NR != 0xFF)
VAR(VAR_RANDOM_NR) = rnd;
push(rnd);
diff --git a/engines/scumm/script_v8.cpp b/engines/scumm/script_v8.cpp
index 4d552a9429..f2addff19f 100644
--- a/engines/scumm/script_v8.cpp
+++ b/engines/scumm/script_v8.cpp
@@ -766,7 +766,6 @@ void ScummEngine_v8::o8_actorOps() {
if (subOp == 0x7A) {
_curActor = pop();
- //printf("Setting current actor to %d\n", _curActor);
return;
}
@@ -937,7 +936,6 @@ void ScummEngine_v8::o8_verbOps() {
_curVerb = pop();
_curVerbSlot = getVerbSlot(_curVerb, 0);
assertRange(0, _curVerbSlot, _numVerbs - 1, "new verb slot");
- //printf("Setting current actor to %d\n", _curActor);
return;
}
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index b141b2d758..40eeba3663 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 Sat Oct 02 14:51:12 2010
+ This file was generated by the md5table tool on Mon Oct 18 00:42:16 2010
DO NOT EDIT MANUALLY!
*/
@@ -132,7 +132,7 @@ static const MD5Table md5table[] = {
{ "2d4acbdcfd8e374c9da8c2e7303a5cd0", "BluesBirthday", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "2d624d1b214f7faf0094daea65c6d1a6", "maniac", "Apple II", "", -1, Common::EN_ANY, Common::kPlatformApple2GS },
{ "2d9d46f23cb07bbc90b8ad464d3e4ff8", "atlantis", "", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh },
- { "2e85f7aa054930c692a5b1bed1dfc295", "football2002", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown },
+ { "2e85f7aa054930c692a5b1bed1dfc295", "football2002", "", "Patched", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "2e8a1f76ea33bc5e04347646feee173d", "pajama3", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "2fe369ad70f52a8cf7ad6077ee64f81a", "loom", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformAmiga },
{ "305d3dd57c96c65b017bc70c8c7cfb5e", "monkey", "CD", "CD", 8955, Common::DE_DEU, Common::kPlatformPC },
@@ -609,7 +609,7 @@ static const MD5Table md5table[] = {
{ "f237bf8a5ef9af78b2a6a4f3901da341", "pajama", "", "Demo", 18354, Common::EN_ANY, Common::kPlatformUnknown },
{ "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC },
{ "f3d55aea441e260e9e9c7d2a187097e0", "puttzoo", "", "Demo", 14337, Common::EN_ANY, Common::kPlatformWindows },
- { "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "Demo", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh },
+ { "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "HE 60", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh },
{ "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "f73883f13b5a302749a5bad31d909780", "tentacle", "", "CD", -1, Common::DE_DEU, Common::kPlatformMacintosh },
{ "f7711f9264d4d43c2a1518ec7c10a607", "pajama3", "", "", 79382, Common::EN_USA, Common::kPlatformUnknown },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 2f25aeefba..392b3ca3c4 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -61,6 +61,7 @@
#include "scumm/player_pce.h"
#include "scumm/player_v1.h"
#include "scumm/player_v2.h"
+#include "scumm/player_v2cms.h"
#include "scumm/player_v2a.h"
#include "scumm/player_v3a.h"
#include "scumm/player_v4a.h"
@@ -136,7 +137,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
uint tmpVal;
tmpStr[0] = dr.md5[2*i];
tmpStr[1] = dr.md5[2*i+1];
- sscanf(tmpStr, "%x", &tmpVal);
+ int res = sscanf(tmpStr, "%x", &tmpVal);
+ assert(res == 1);
_gameMD5[i] = (byte)tmpVal;
}
@@ -145,6 +147,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
// Init all vars
_v0ObjectIndex = false;
_v0ObjectInInventory = false;
+ _v0ObjectFlag = 0;
_imuse = NULL;
_imuseDigital = NULL;
_musicEngine = NULL;
@@ -209,7 +212,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_saveLoadSlot = 0;
_lastSaveTime = 0;
_saveTemporaryState = false;
- memset(_saveLoadFileName, 0, sizeof(_saveLoadFileName));
memset(_saveLoadName, 0, sizeof(_saveLoadName));
memset(_localScriptOffsets, 0, sizeof(_localScriptOffsets));
_scriptPointer = NULL;
@@ -281,6 +283,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
_townsScreen = 0;
#endif
+ _cjkFont = 0;
+ _cjkChar = 0;
_shadowPalette = NULL;
_shadowPaletteSize = 0;
memset(_currentPalette, 0, sizeof(_currentPalette));
@@ -481,7 +485,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
if (ConfMan.getBool("demo_mode"))
_game.features |= GF_DEMO;
if (ConfMan.hasKey("nosubtitles")) {
- printf("Configuration key 'nosubtitles' is deprecated. Use 'subtitles' instead\n");
+ // We replaced nosubtitles *ages* ago. Just convert it silently
+ debug("Configuration key 'nosubtitles' is deprecated. Converting to 'subtitles'");
if (!ConfMan.hasKey("subtitles"))
ConfMan.setBool("subtitles", !ConfMan.getBool("nosubtitles"));
}
@@ -631,6 +636,7 @@ ScummEngine::~ScummEngine() {
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
delete _townsScreen;
#endif
+ delete _cjkFont;
delete _debugger;
@@ -1642,6 +1648,10 @@ void ScummEngine_v90he::resetScumm() {
_logicHE = new LogicHEsoccer(this);
break;
+ case GID_BASEBALL2001:
+ _logicHE = new LogicHEbaseball2001(this);
+ break;
+
case GID_BASKETBALL:
_logicHE = new LogicHEbasketball(this);
break;
@@ -1918,7 +1928,7 @@ int ScummEngine::getTalkSpeed() {
#pragma mark -
Common::Error ScummEngine::go() {
- _engineStartTime = _system->getMillis() / 1000;
+ setTotalPlayTime();
// If requested, load a save game instead of running the boot script
if (_saveLoadFlag != 2 || !loadState(_saveLoadSlot, _saveTemporaryState)) {
@@ -2496,10 +2506,6 @@ void ScummEngine::startManiac() {
void ScummEngine::pauseEngineIntern(bool pause) {
if (pause) {
- // Record start of the pause, so that we can later
- // adjust _engineStartTime accordingly.
- _pauseStartTime = _system->getMillis();
-
// Pause sound & video
_oldSoundsPaused = _sound->_soundsPaused;
_sound->pauseSounds(true);
@@ -2517,10 +2523,6 @@ void ScummEngine::pauseEngineIntern(bool pause) {
// Resume sound & video
_sound->pauseSounds(_oldSoundsPaused);
-
- // Adjust engine start time
- _engineStartTime += (_system->getMillis() - _pauseStartTime) / 1000;
- _pauseStartTime = 0;
}
}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index aef5cfbec7..0a513b6068 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -36,6 +36,7 @@
#include "common/rect.h"
#include "common/str.h"
#include "graphics/surface.h"
+#include "graphics/sjis.h"
#include "scumm/gfx.h"
#include "scumm/detection.h"
@@ -66,10 +67,14 @@ namespace Common {
/**
* This is the namespace of the SCUMM engine.
*
- * Status of this engine: ???
+ * Status of this engine:
+ * Complete support for all SCUMM based LucasArts adventures.
+ * Complete support for many Humongous Entertainment games,
+ * but for some of the newer ones, this is still work in progress.
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Classic 2D LucasArts adventures
+ * - numerous Humongous Entertainment games
*/
namespace Scumm {
@@ -248,6 +253,7 @@ enum ScummGameId {
GID_FUNSHOP, // Used for all three funshops
GID_FOOTBALL,
GID_SOCCER,
+ GID_BASEBALL2001,
GID_BASKETBALL,
GID_MOONBASE,
GID_HECUP // CUP demos
@@ -587,6 +593,7 @@ protected:
bool _v0ObjectIndex; // V0 Use object index, instead of object number
bool _v0ObjectInInventory; // V0 Use object number from inventory
+ byte _v0ObjectFlag;
/* Global resource tables */
int _numVariables, _numBitVariables, _numLocalObjects;
@@ -654,7 +661,7 @@ protected:
byte _saveLoadFlag, _saveLoadSlot;
uint32 _lastSaveTime;
bool _saveTemporaryState;
- char _saveLoadFileName[32];
+ Common::String _saveLoadFileName;
char _saveLoadName[32];
bool saveState(Common::OutSaveFile *out, bool writeHeader = true);
@@ -693,9 +700,6 @@ protected:
void saveInfos(Common::WriteStream* file);
static bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff);
- int32 _engineStartTime;
- int32 _pauseStartTime;
-
protected:
/* Script VM - should be in Script class */
uint32 _localScriptOffsets[1024];
@@ -748,9 +752,10 @@ protected:
void stopObjectScript(int script);
void getScriptBaseAddress();
- void getScriptEntryPoint();
+ void resetScriptPointer();
int getVerbEntrypoint(int obj, int entry);
+ void refreshScriptPointer();
byte fetchScriptByte();
virtual uint fetchScriptWord();
virtual int fetchScriptWordSigned();
@@ -770,7 +775,7 @@ protected:
void endOverride();
void copyScriptString(byte *dst);
- int resStrLen(const byte *src) const;
+ int resStrLen(const byte *src);
void doSentence(int c, int b, int a);
/* Should be in Resource class */
@@ -1417,6 +1422,8 @@ public:
bool towns_isRectInStringBox(int x1, int y1, int x2, int y2);
byte _townsPaletteFlags;
byte _townsCharsetColorMap[16];
+ Graphics::FontSJIS *_cjkFont;
+ uint16 _cjkChar;
protected:
void towns_drawStripToScreen(VirtScreen *vs, int dstX, int dstY, int srcX, int srcY, int w, int h);
diff --git a/engines/scumm/smush/codec47.cpp b/engines/scumm/smush/codec47.cpp
index 62bc0bb098..333fdabccf 100644
--- a/engines/scumm/smush/codec47.cpp
+++ b/engines/scumm/smush/codec47.cpp
@@ -301,9 +301,11 @@ void Codec47Decoder::makeTables47(int width) {
int32 a, c, d;
int16 tmp;
- for (int l = 0; l < 512; l += 2) {
+ for (int l = 0; l < ARRAYSIZE(codec47_table); l += 2) {
_table[l / 2] = (int16)(codec47_table[l + 1] * width + codec47_table[l]);
}
+ // Note: _table[255] is never inited; but since only the first 0xF8
+ // entries of it are used anyway, this doesn't matter.
a = 0;
c = 0;
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index 5eb2b9d159..4b09547c8c 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -601,7 +601,12 @@ void ScummEngine::CHARSET_1() {
} else if (!(_game.platform == Common::kPlatformFMTowns) && _string[0].height) {
_nextTop += _string[0].height;
} else {
+ bool useCJK = _useCJKMode;
+ // SCUMM5 FM-Towns doesn't use the height of the ROM font here.
+ if (_game.platform == Common::kPlatformFMTowns && _game.version == 5)
+ _useCJKMode = false;
_nextTop += _charset->getFontHeight();
+ _useCJKMode = useCJK;
}
if (_game.version > 3) {
// FIXME: is this really needed?
@@ -634,9 +639,7 @@ void ScummEngine::CHARSET_1() {
#endif
} else {
if (c & 0x80 && _useCJKMode) {
- if (_language == Common::JA_JPN && !checkSJISCode(c)) {
- c = 0x20; //not in S-JIS
- } else {
+ if (checkSJISCode(c)) {
byte *buffer = _charsetBuffer + _charsetBufPos;
c += *buffer++ * 256; //LE
_charsetBufPos = buffer - _charsetBuffer;
@@ -993,11 +996,8 @@ void ScummEngine::drawString(int a, const byte *msg) {
}
}
if (c & 0x80 && _useCJKMode) {
- if (_language == Common::JA_JPN && !checkSJISCode(c)) {
- c = 0x20; //not in S-JIS
- } else {
+ if (checkSJISCode(c))
c += buf[i++] * 256;
- }
}
_charset->printChar(c, true);
_charset->_blitAlso = false;
@@ -1021,6 +1021,7 @@ int ScummEngine::convertMessageToString(const byte *msg, byte *dst, int dstSize)
uint num = 0;
uint32 val;
byte chr;
+ byte lastChr = 0;
const byte *src;
byte *end;
byte transBuf[384];
@@ -1128,11 +1129,12 @@ int ScummEngine::convertMessageToString(const byte *msg, byte *dst, int dstSize)
} else if (_game.id == GID_DIG && (chr == 1 || chr == 2 || chr == 3 || chr == 8)) {
// Skip these characters
} else {
- if (!(chr == '@') || (_game.id == GID_CMI && _language == Common::ZH_TWN) ||
- (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine && _language == Common::JA_JPN))
- {
+ if ((chr != '@') || (_game.id == GID_CMI && _language == Common::ZH_TWN) ||
+ (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine && _language == Common::JA_JPN) ||
+ (_game.platform == Common::kPlatformFMTowns && _language == Common::JA_JPN && checkSJISCode(lastChr))) {
*dst++ = chr;
}
+ lastChr = chr;
}
// Check for a buffer overflow
diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp
index 77181c0b55..c443f98bc6 100644
--- a/engines/scumm/verbs.cpp
+++ b/engines/scumm/verbs.cpp
@@ -167,11 +167,6 @@ void ScummEngine_v0::switchActor(int slot) {
if (_currentMode == 0 || _currentMode == 1 || _currentMode == 2)
return;
- // verbs disabled for the current actor
- ActorC64 *a = (ActorC64 *)derefActor(VAR(VAR_EGO), "switchActor");
- if (a->_miscflags & 0x40)
- return;
-
VAR(VAR_EGO) = VAR(97 + slot);
resetVerbs();
actorFollowCamera(VAR(VAR_EGO));
@@ -323,7 +318,7 @@ void ScummEngine_v2::checkV2MouseOver(Common::Point pos) {
}
}
- if (new_box != _mouseOverBoxV2) {
+ if ((new_box != _mouseOverBoxV2) || (_game.version == 0)) {
if (_mouseOverBoxV2 != -1) {
rect = _mouseOverBoxesV2[_mouseOverBoxV2].rect;
@@ -524,9 +519,8 @@ void ScummEngine_v2::handleMouseOver(bool updateInventory) {
}
void ScummEngine_v0::handleMouseOver(bool updateInventory) {
- ScummEngine_v2::handleMouseOver(updateInventory);
-
drawSentence();
+ ScummEngine_v2::handleMouseOver(updateInventory);
}
#ifdef ENABLE_HE
@@ -727,7 +721,7 @@ void ScummEngine_v2::checkExecVerbs() {
}
void ScummEngine_v0::runObject(int obj, int entry) {
- int prev = _v0ObjectInInventory;
+ bool prev = _v0ObjectInInventory;
if (getVerbEntrypoint(obj, entry) == 0) {
// If nothing was found, attempt to find the 'WHAT-IS' verb script
@@ -978,6 +972,7 @@ bool ScummEngine_v0::verbExec() {
// We acted on an inventory item
if (_activeInventory && verbExecutes(_activeInventory, true) && _activeVerb != 3) {
_v0ObjectInInventory = true;
+ _activeObject = _activeInventory;
runObject(_activeInventory, _activeVerb);
_verbExecuting = false;
@@ -1036,7 +1031,7 @@ bool ScummEngine_v0::verbExec() {
}
void ScummEngine_v0::checkExecVerbs() {
- Actor *a = derefActor(VAR(VAR_EGO), "checkExecVerbs");
+ ActorC64 *a = (ActorC64 *)derefActor(VAR(VAR_EGO), "checkExecVerbs");
VirtScreen *zone = findVirtScreen(_mouse.y);
// Is a verb currently executing
@@ -1151,27 +1146,28 @@ void ScummEngine_v0::checkExecVerbs() {
obj = 0;
objIdx = 0;
}
+
+ if (a->_miscflags & 0x80) {
+ if (_activeVerb != 7 && over != 7) {
+ _activeVerb = 0;
+ over = 0;
+ }
+ }
// Handle New Kid verb options
if (_activeVerb == 7 || over == 7) {
// Disable New-Kid (in the secret lab)
if (_currentMode == 2 || _currentMode == 0)
return;
-
- if (!(((ActorC64 *)a)->_miscflags & 0x80)) {
- if (_activeVerb != 7) {
- _activeVerb = over;
- over = 0;
- }
- }
- if (over) {
+ if (_activeVerb == 7 && over) {
_activeVerb = 13;
switchActor(_verbs[over].verbid - 1);
return;
}
setNewKidVerbs();
+ _activeVerb = 7;
return;
}
@@ -1187,7 +1183,7 @@ void ScummEngine_v0::checkExecVerbs() {
if (zone->number == kMainVirtScreen) {
// Ignore verbs?
- if (((ActorC64 *)a)->_miscflags & 0x40) {
+ if (a->_miscflags & 0x40) {
resetSentence(false);
return;
}
diff --git a/engines/sky/disk.cpp b/engines/sky/disk.cpp
index 90b55133ed..5ad0c3eb19 100644
--- a/engines/sky/disk.cpp
+++ b/engines/sky/disk.cpp
@@ -59,7 +59,7 @@ Disk::Disk() {
if (!_dataDiskHandle->isOpen())
error("Error opening %s", dataFilename);
- printf("Found BASS version v0.0%d (%d dnr entries)\n", determineGameVersion(), _dinnerTableEntries);
+ debug("Found BASS version v0.0%d (%d dnr entries)", determineGameVersion(), _dinnerTableEntries);
memset(_buildList, 0, 60 * 2);
memset(_loadedFilesList, 0, 60 * 4);
diff --git a/engines/sky/logic.cpp b/engines/sky/logic.cpp
index e19cbb27e8..1c1e2c9682 100644
--- a/engines/sky/logic.cpp
+++ b/engines/sky/logic.cpp
@@ -2510,7 +2510,7 @@ bool Logic::fnUnPauseFx(uint32 a, uint32 b, uint32 c) {
}
bool Logic::fnPrintf(uint32 a, uint32 b, uint32 c) {
- printf("fnPrintf: %d\n", a);
+ debug("fnPrintf(%d, %d, %d)", a, b, c);
return true;
}
diff --git a/engines/sky/sky.h b/engines/sky/sky.h
index 7eff8c662a..58c9d1de11 100644
--- a/engines/sky/sky.h
+++ b/engines/sky/sky.h
@@ -35,8 +35,8 @@
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Beneath a Steel Sky
*/
namespace Sky {
diff --git a/engines/sword1/console.cpp b/engines/sword1/console.cpp
new file mode 100644
index 0000000000..7a1c087dd5
--- /dev/null
+++ b/engines/sword1/console.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "sword1/console.h"
+#include "sword1/sword1.h"
+
+namespace Sword1 {
+
+SwordConsole::SwordConsole(SwordEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
+
+SwordConsole::~SwordConsole() {
+}
+
+void SwordConsole::preEnter() {
+}
+
+void SwordConsole::postEnter() {
+}
+
+} // End of namespace Sword
diff --git a/engines/sword1/console.h b/engines/sword1/console.h
new file mode 100644
index 0000000000..09d197363e
--- /dev/null
+++ b/engines/sword1/console.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SWORD1_CONSOLE_H
+#define SWORD1_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Sword1 {
+
+class SwordEngine;
+
+class SwordConsole : public GUI::Debugger {
+public:
+ SwordConsole(SwordEngine *vm);
+ virtual ~SwordConsole(void);
+
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+private:
+ SwordEngine *_vm;
+};
+
+} // End of namespace Sword1
+
+#endif
diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp
index 8d9ca85829..aee49c4b60 100644
--- a/engines/sword1/control.cpp
+++ b/engines/sword1/control.cpp
@@ -1118,8 +1118,7 @@ void Control::saveGameToFile(uint8 slot) {
outf->writeUint32BE(saveDate);
outf->writeUint16BE(saveTime);
- uint32 currentTime = _system->getMillis() / 1000;
- outf->writeUint32BE(currentTime - SwordEngine::_systemVars.engineStartTime);
+ outf->writeUint32BE(g_engine->getTotalPlayTime() / 1000);
_objMan->saveLiveList(liveBuf);
for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
@@ -1181,10 +1180,9 @@ bool Control::restoreGameFromFile(uint8 slot) {
inf->readUint16BE(); // save time
if (saveVersion < 2) { // Before version 2 we didn't had play time feature
- SwordEngine::_systemVars.engineStartTime = _system->getMillis() / 1000; // Start counting
+ g_engine->setTotalPlayTime(0);
} else {
- uint32 currentTime = _system->getMillis() / 1000;
- SwordEngine::_systemVars.engineStartTime = currentTime - inf->readUint32BE(); // Engine start time
+ g_engine->setTotalPlayTime(inf->readUint32BE() * 1000);
}
_restoreBuf = (uint8*)malloc(
diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp
index e51a3d6a8d..9fc24e75e8 100644
--- a/engines/sword1/detection.cpp
+++ b/engines/sword1/detection.cpp
@@ -309,12 +309,9 @@ SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int
desc.setSaveTime(hour, minutes);
if (versionSave > 1) {
- minutes = playTime / 60;
- hour = minutes / 60;
- minutes %= 60;
- desc.setPlayTime(hour, minutes);
+ desc.setPlayTime(playTime * 1000);
} else { //We have no playtime data
- desc.setPlayTime(0, 0);
+ desc.setPlayTime(0);
}
delete in;
diff --git a/engines/sword1/module.mk b/engines/sword1/module.mk
index 1dbff19464..a19fcbfab9 100644
--- a/engines/sword1/module.mk
+++ b/engines/sword1/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/sword1
MODULE_OBJS := \
animation.o \
+ console.o \
control.o \
debug.o \
detection.o \
diff --git a/engines/sword1/resman.cpp b/engines/sword1/resman.cpp
index 41f952c3f4..228cd28bb7 100644
--- a/engines/sword1/resman.cpp
+++ b/engines/sword1/resman.cpp
@@ -332,10 +332,13 @@ Common::File *ResMan::resFile(uint32 id) {
Clu *closeClu = _openCluStart;
_openCluStart = _openCluStart->nextOpen;
- closeClu->file->close();
- delete closeClu->file;
- closeClu->file = NULL;
- closeClu->nextOpen = NULL;
+ if (closeClu) {
+ if (closeClu->file)
+ closeClu->file->close();
+ delete closeClu->file;
+ closeClu->file = NULL;
+ closeClu->nextOpen = NULL;
+ }
_openClus--;
}
}
diff --git a/engines/sword1/screen.cpp b/engines/sword1/screen.cpp
index b07acf9a0b..9fa808d561 100644
--- a/engines/sword1/screen.cpp
+++ b/engines/sword1/screen.cpp
@@ -886,8 +886,8 @@ uint8* Screen::psxBackgroundToIndexed(uint8 *psxBackground, uint32 bakXres, uint
// needed because some psx backgrounds are half width and half height
uint8* Screen::psxShrinkedBackgroundToIndexed(uint8 *psxBackground, uint32 bakXres, uint32 bakYres) {
- uint32 xresInTiles = (bakXres / 2) % 16 ? (bakXres / 32) + 1 : (bakXres / 32);
- uint32 yresInTiles = (bakYres / 2) % 16 ? (bakYres / 32) + 1 : (bakYres / 32);
+ uint32 xresInTiles = ((bakXres / 2) % 16) ? (bakXres / 32) + 1 : (bakXres / 32);
+ uint32 yresInTiles = ((bakYres / 2) % 16) ? (bakYres / 32) + 1 : (bakYres / 32);
uint32 totTiles = xresInTiles * yresInTiles;
uint32 tileYpos = 0; //tile position in a virtual xresInTiles * yresInTiles grid
uint32 tileXpos = 0;
diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp
index 0d4f5b7445..0dcadeca2a 100644
--- a/engines/sword1/sword1.cpp
+++ b/engines/sword1/sword1.cpp
@@ -66,6 +66,8 @@ SwordEngine::SwordEngine(OSystem *syst)
SearchMan.addSubDirectoryMatching(gameDataDir, "smackshi");
SearchMan.addSubDirectoryMatching(gameDataDir, "english");//PSX Demo
SearchMan.addSubDirectoryMatching(gameDataDir, "italian");//PSX Demo
+
+ _console = new SwordConsole(this);
}
SwordEngine::~SwordEngine() {
@@ -78,6 +80,7 @@ SwordEngine::~SwordEngine() {
delete _mouse;
delete _objectMan;
delete _resMan;
+ delete _console;
}
Common::Error SwordEngine::init() {
@@ -563,7 +566,7 @@ void SwordEngine::checkCdFiles() { // check if we're running from cd, hdd or wha
Common::Error SwordEngine::go() {
_control->checkForOldSaveGames();
- SwordEngine::_systemVars.engineStartTime = _system->getMillis() / 1000;
+ setTotalPlayTime(0);
uint16 startPos = ConfMan.getInt("boot_param");
_control->readSavegameDescriptions();
@@ -678,6 +681,13 @@ uint8 SwordEngine::mainLoop() {
if (retCode == CONTROL_NOTHING_DONE)
_screen->fullRefresh();
}
+
+ // Check for Debugger Activation
+ if (_keyPressed.hasFlags(Common::KBD_CTRL) && _keyPressed.keycode == Common::KEYCODE_d) {
+ this->getDebugger()->attach();
+ this->getDebugger()->onFrame();
+ }
+
_mouseState = 0;
_keyPressed.reset();
} while ((Logic::_scriptVars[SCREEN] == Logic::_scriptVars[NEW_SCREEN]) && (retCode == 0) && (!shouldQuit()));
diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h
index a0497847d5..592d2da6f4 100644
--- a/engines/sword1/sword1.h
+++ b/engines/sword1/sword1.h
@@ -30,14 +30,15 @@
#include "common/events.h"
#include "common/util.h"
#include "sword1/sworddefs.h"
+#include "sword1/console.h"
/**
* This is the namespace of the Sword1 engine.
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Broken Sword: The Shadow of the Templars
*/
namespace Sword1 {
@@ -74,7 +75,6 @@ struct SystemVars {
uint8 showText;
uint8 language;
bool isDemo;
- uint32 engineStartTime; // Used for playtime
Common::Platform platform;
};
@@ -107,6 +107,8 @@ protected:
virtual bool hasFeature(EngineFeature f) const;
virtual void syncSoundSettings();
+ GUI::Debugger *getDebugger() { return _console; }
+
Common::Error loadGameState(int slot);
bool canLoadGameStateCurrently();
Common::Error saveGameState(int slot, const char *desc);
@@ -122,6 +124,8 @@ private:
void reinitRes(); //Reinits the resources after a GMM load
+ SwordConsole *_console;
+
uint8 mainLoop();
Common::Point _mouseCoord;
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 10895b2ec1..f664e784d5 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -398,10 +398,4 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *s
return NULL;
}
-void MoviePlayer::pauseMovie(bool pause) {
- if (_bgSoundHandle) {
- _snd->pauseHandle(*_bgSoundHandle, pause);
- }
-}
-
} // End of namespace Sword2
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index ee32b1d5f2..4796d39097 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -76,7 +76,6 @@ public:
bool load(const char *name);
void play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut);
- void pauseMovie(bool pause);
protected:
Sword2Engine *_vm;
diff --git a/engines/sword2/console.cpp b/engines/sword2/console.cpp
index 4bf7c0da19..20fd79bc38 100644
--- a/engines/sword2/console.cpp
+++ b/engines/sword2/console.cpp
@@ -237,13 +237,15 @@ bool Debugger::Cmd_Mem(int argc, const char **argv) {
break;
}
- DebugPrintf("%9ld %-3d %-4d %-20s %s\n", blocks[i]->size, blocks[i]->id, blocks[i]->uid, type, _vm->_resman->fetchName(blocks[i]->ptr));
+ DebugPrintf("%9d %-3d %-4d %-20s %s\n",
+ blocks[i]->size, blocks[i]->id, blocks[i]->uid,
+ type, _vm->_resman->fetchName(blocks[i]->ptr));
}
free(blocks);
DebugPrintf("---------------------------------------------------------------------------\n");
- DebugPrintf("%9ld\n", _vm->_memory->getTotAlloc());
+ DebugPrintf("%9d\n", _vm->_memory->getTotAlloc());
return true;
}
diff --git a/engines/sword2/controls.cpp b/engines/sword2/controls.cpp
index 7428cbb534..c55cc72493 100644
--- a/engines/sword2/controls.cpp
+++ b/engines/sword2/controls.cpp
@@ -180,12 +180,12 @@ void FontRendererGui::fetchText(uint32 textId, byte *buf) {
byte *data = _vm->fetchTextLine(_vm->_resman->openResource(textId / SIZE), textId & 0xffff);
int i;
- for (i = 0; data[i + 2]; i++) {
- if (buf)
+ if (buf) {
+ for (i = 0; data[i + 2]; i++)
buf[i] = data[i + 2];
+ buf[i] = 0;
}
- buf[i] = 0;
_vm->_resman->closeResource(textId / SIZE);
}
diff --git a/engines/sword2/debug.cpp b/engines/sword2/debug.cpp
index 8f9f54ad5c..cb3c3b6a30 100644
--- a/engines/sword2/debug.cpp
+++ b/engines/sword2/debug.cpp
@@ -120,15 +120,6 @@ void Debugger::buildDebugText() {
makeDebugTextBlock(buf, 0, 105);
}
-#ifdef SWORD2_DEBUG
- // speed-up indicator
-
- if (_vm->_renderSkip) { // see sword2.cpp
- sprintf(buf, "SKIPPING FRAMES FOR SPEED-UP!");
- makeDebugTextBlock(buf, 0, 120);
- }
-#endif
-
// debug info at top of screen - enabled/disabled as one complete unit
if (_displayTime) {
diff --git a/engines/sword2/logic.cpp b/engines/sword2/logic.cpp
index 394bf7ddc8..511561c55a 100644
--- a/engines/sword2/logic.cpp
+++ b/engines/sword2/logic.cpp
@@ -278,16 +278,6 @@ void Logic::resetKillList() {
}
/**
- * Pause or unpause the currently playing cutscene movie, if any.
- * @param pause true if pausing, false if unpausing
- */
-
-void Logic::pauseMovie(bool pause) {
- if (_moviePlayer)
- _moviePlayer->pauseMovie(pause);
-}
-
-/**
* Read current location number from script vars
*/
diff --git a/engines/sword2/logic.h b/engines/sword2/logic.h
index 8c49225df2..793f87d037 100644
--- a/engines/sword2/logic.h
+++ b/engines/sword2/logic.h
@@ -317,8 +317,6 @@ public:
void logicOne(uint32 new_script);
void resetKillList();
- void pauseMovie(bool pause);
-
// Read location number from script vars
uint32 getLocationNum();
};
diff --git a/engines/sword2/music.cpp b/engines/sword2/music.cpp
index c052aa6b46..89073fef8e 100644
--- a/engines/sword2/music.cpp
+++ b/engines/sword2/music.cpp
@@ -496,9 +496,16 @@ int Sound::readBuffer(int16 *buffer, const int numSamples) {
memset(buffer, 0, 2 * numSamples);
if (!_mixBuffer || numSamples > _mixBufferLen) {
- if (_mixBuffer)
- _mixBuffer = (int16 *)realloc(_mixBuffer, 2 * numSamples);
- else
+ if (_mixBuffer) {
+ int16 *newBuffer = (int16 *)realloc(_mixBuffer, 2 * numSamples);
+ if (newBuffer) {
+ _mixBuffer = newBuffer;
+ } else {
+ // We can't use the old buffer any more. It's too small.
+ free(_mixBuffer);
+ _mixBuffer = 0;
+ }
+ } else
_mixBuffer = (int16 *)malloc(2 * numSamples);
_mixBufferLen = numSamples;
diff --git a/engines/sword2/palette.cpp b/engines/sword2/palette.cpp
index 84ebd142ca..dd1a2ba877 100644
--- a/engines/sword2/palette.cpp
+++ b/engines/sword2/palette.cpp
@@ -171,6 +171,9 @@ void Screen::setPalette(int16 startEntry, int16 noEntries, byte *colourTable, ui
}
void Screen::dimPalette(bool dim) {
+ if (getFadeStatus() != RDFADE_NONE)
+ return;
+
if (dim != _dimPalette) {
_dimPalette = dim;
setSystemPalette(_palette, 0, 256);
diff --git a/engines/sword2/protocol.cpp b/engines/sword2/protocol.cpp
index 03b021f04c..6c47c07401 100644
--- a/engines/sword2/protocol.cpp
+++ b/engines/sword2/protocol.cpp
@@ -412,8 +412,8 @@ byte *Sword2Engine::fetchPsxParallax(uint32 location, uint8 level) {
debug(2, "fetchPsxParallax() -> %s parallax, xRes: %u, yRes: %u", (level == 0) ? "Background" : "Foreground", plxXres, plxYres);
// Calculate the number of tiles which compose the parallax grid.
- horTiles = plxXres % 64 ? (plxXres / 64) + 1 : plxXres / 64;
- verTiles = plxYres % 16 ? (plxYres / 16) + 1 : plxYres / 16;
+ horTiles = (plxXres % 64) ? (plxXres / 64) + 1 : plxXres / 64;
+ verTiles = (plxYres % 16) ? (plxYres / 16) + 1 : plxYres / 16;
totSize = plxSize + horTiles * verTiles * 4 + 8;
diff --git a/engines/sword2/render.cpp b/engines/sword2/render.cpp
index 1a8dcdab16..99295be571 100644
--- a/engines/sword2/render.cpp
+++ b/engines/sword2/render.cpp
@@ -731,8 +731,8 @@ int32 Screen::initialisePsxParallaxLayer(byte *parallax) {
data = parallax + xTiles * yTiles * 4;
_xBlocks[_layer] = xTiles;
- _yBlocks[_layer] = (yTiles / 2) + (yTiles % 2 ? 1 : 0);
- bool oddTiles = (yTiles % 2 ? true : false);
+ _yBlocks[_layer] = (yTiles / 2) + ((yTiles % 2) ? 1 : 0);
+ bool oddTiles = ((yTiles % 2) ? true : false);
_blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *));
if (!_blockSurfaces[_layer])
diff --git a/engines/sword2/resman.cpp b/engines/sword2/resman.cpp
index 81d74f355b..fa9c396ef3 100644
--- a/engines/sword2/resman.cpp
+++ b/engines/sword2/resman.cpp
@@ -302,6 +302,8 @@ byte *ResourceManager::openResource(uint32 res, bool dump) {
readCluIndex(cluFileNum, file);
}
+ assert(_resFiles[cluFileNum].entryTab);
+
uint32 pos = _resFiles[cluFileNum].entryTab[actual_res * 2 + 0];
uint32 len = _resFiles[cluFileNum].entryTab[actual_res * 2 + 1];
@@ -474,15 +476,18 @@ void ResourceManager::readCluIndex(uint16 fileNum, Common::File *file) {
file->seek(table_offset);
assert((tableSize % 8) == 0);
- _resFiles[fileNum].entryTab = (uint32*)malloc(tableSize);
+ _resFiles[fileNum].entryTab = (uint32 *)malloc(tableSize);
_resFiles[fileNum].numEntries = tableSize / 8;
+
+ assert(_resFiles[fileNum].entryTab);
+
file->read(_resFiles[fileNum].entryTab, tableSize);
if (file->eos() || file->err())
error("unable to read index table from file %s", _resFiles[fileNum].fileName);
#ifdef SCUMM_BIG_ENDIAN
for (int tabCnt = 0; tabCnt < _resFiles[fileNum].numEntries * 2; tabCnt++)
- _resFiles[fileNum].entryTab[tabCnt] = FROM_LE_32(_resFiles[fileNum].entryTab[tabCnt]);
+ _resFiles[fileNum].entryTab[tabCnt] = FROM_LE_32(_resFiles[fileNum].entryTab[tabCnt]);
#endif
}
diff --git a/engines/sword2/sound.cpp b/engines/sword2/sound.cpp
index e36c946eba..b1d0dee81b 100644
--- a/engines/sword2/sound.cpp
+++ b/engines/sword2/sound.cpp
@@ -393,18 +393,6 @@ int32 Sound::stopFx(int32 i) {
return RD_OK;
}
-void Sound::pauseAllSound() {
- pauseMusic();
- pauseSpeech();
- pauseFx();
-}
-
-void Sound::unpauseAllSound() {
- unpauseMusic();
- unpauseSpeech();
- unpauseFx();
-}
-
void Sound::printFxQueue() {
int freeSlots = 0;
diff --git a/engines/sword2/sound.h b/engines/sword2/sound.h
index 29bbdf22ca..5acc39179f 100644
--- a/engines/sword2/sound.h
+++ b/engines/sword2/sound.h
@@ -262,9 +262,6 @@ public:
void pauseMusic();
void unpauseMusic();
- void pauseAllSound();
- void unpauseAllSound();
-
void playMovieSound(int32 res, int type);
void stopMovieSounds();
diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp
index b3b688771a..9c67fcdf25 100644
--- a/engines/sword2/sword2.cpp
+++ b/engines/sword2/sword2.cpp
@@ -290,13 +290,6 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) {
_wantSfxDebug = false;
-#ifdef SWORD2_DEBUG
- _stepOneCycle = false;
- _renderSkip = false;
-#endif
-
- _gamePaused = false;
-
_gameCycle = 0;
_gameSpeed = 1;
@@ -481,13 +474,6 @@ Common::Error Sword2Engine::run() {
while (1) {
_debugger->onFrame();
-#ifdef SWORD2_DEBUG
- if (_stepOneCycle) {
- pauseEngine(true);
- _stepOneCycle = false;
- }
-#endif
-
// Handle GMM Loading
if (_gmmLoadSlot != -1) {
@@ -516,10 +502,13 @@ Common::Error Sword2Engine::run() {
} else if (ke->kbd.hasFlags(0) || ke->kbd.hasFlags(Common::KBD_SHIFT)) {
switch (ke->kbd.keycode) {
case Common::KEYCODE_p:
- if (_gamePaused)
+ if (isPaused()) {
+ _screen->dimPalette(false);
pauseEngine(false);
- else
+ } else {
pauseEngine(true);
+ _screen->dimPalette(true);
+ }
break;
#if 0
// Disabled because of strange rumors about the
@@ -533,17 +522,6 @@ Common::Error Sword2Engine::run() {
}
break;
#endif
-#ifdef SWORD2_DEBUG
- case Common::KEYCODE_SPACE:
- if (_gamePaused) {
- _stepOneCycle = true;
- pauseEngine(false);
- }
- break;
- case Common::KEYCODE_s:
- _renderSkip = !_renderSkip;
- break;
-#endif
default:
break;
}
@@ -551,7 +529,7 @@ Common::Error Sword2Engine::run() {
}
// skip GameCycle if we're paused
- if (!_gamePaused) {
+ if (!isPaused()) {
_gameCycle++;
gameCycle();
}
@@ -566,15 +544,7 @@ Common::Error Sword2Engine::run() {
// creates the debug text blocks
_debugger->buildDebugText();
-#ifdef SWORD2_DEBUG
- // if not in console & '_renderSkip' is set, only render
- // display once every 4 game-cycles
-
- if (!_renderSkip || (_gameCycle % 4) == 0)
- _screen->buildDisplay();
-#else
_screen->buildDisplay();
-#endif
}
return Common::kNoError;
@@ -798,49 +768,13 @@ void Sword2Engine::sleepUntil(uint32 time) {
}
}
-void Sword2Engine::pauseEngine(bool pause) {
- if (pause == _gamePaused)
- return;
-
- // We don't need to hide the cursor for outside pausing. Not as long
- // as it replaces the cursor with the GUI cursor, at least.
-
- _mouse->pauseEngine(pause);
- pauseEngineIntern(pause);
-
- if (pause) {
-#ifdef SWORD2_DEBUG
- // Don't dim it if we're single-stepping through frames
- // dim the palette during the pause
-
- if (!_stepOneCycle)
- _screen->dimPalette(true);
-#else
- _screen->dimPalette(true);
-#endif
- } else {
- _screen->dimPalette(false);
-
- // If mouse is about or we're in a chooser menu
- if (!_mouse->getMouseStatus() || _mouse->isChoosing())
- _mouse->setMouse(NORMAL_MOUSE_ID);
- }
-}
-
void Sword2Engine::pauseEngineIntern(bool pause) {
- if (pause == _gamePaused)
- return;
+ Engine::pauseEngineIntern(pause);
if (pause) {
- _sound->pauseAllSound();
- _logic->pauseMovie(true);
_screen->pauseScreen(true);
- _gamePaused = true;
} else {
- _logic->pauseMovie(false);
_screen->pauseScreen(false);
- _sound->unpauseAllSound();
- _gamePaused = false;
}
}
diff --git a/engines/sword2/sword2.h b/engines/sword2/sword2.h
index 201ce5e836..302627b635 100644
--- a/engines/sword2/sword2.h
+++ b/engines/sword2/sword2.h
@@ -53,8 +53,8 @@ class OSystem;
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Broken Sword II: The Smoking Mirror
*/
namespace Sword2 {
@@ -155,8 +155,6 @@ public:
Sword2Engine(OSystem *syst);
~Sword2Engine();
- void pauseEngine(bool pause);
-
int getFramesPerSecond();
void registerDefaultSettings();
@@ -204,11 +202,6 @@ public:
int32 _gameCycle;
-#ifdef SWORD2_DEBUG
- bool _renderSkip;
- bool _stepOneCycle;
-#endif
-
#if RIGHT_CLICK_CLEARS_LUGGAGE
bool heldIsInInventory();
#endif
@@ -237,8 +230,6 @@ public:
char *getSaveFileName(uint16 slotNo);
uint32 findBufferSize();
- bool _gamePaused;
-
void startGame();
void gameCycle();
void restartGame();
diff --git a/engines/sword25/detection.cpp b/engines/sword25/detection.cpp
index e210f4d27c..3900df2fcf 100644
--- a/engines/sword25/detection.cpp
+++ b/engines/sword25/detection.cpp
@@ -24,10 +24,12 @@
*/
#include "base/plugins.h"
-
+#include "common/savefile.h"
+#include "common/system.h"
#include "engines/advancedDetector.h"
#include "sword25/sword25.h"
+#include "sword25/kernel/persistenceservice.h"
namespace Sword25 {
uint32 Sword25Engine::getGameFlags() const { return _gameDescription->flags; }
@@ -68,7 +70,7 @@ static const ADGameDescription gameDescriptions[] = {
AD_TABLE_END_MARKER
};
-} // end of namespace Sword25
+} // End of namespace Sword25
static const char *directoryGlobs[] = {
"system", // Used by extracted dats
@@ -113,6 +115,9 @@ public:
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual int getMaximumSaveSlot() const { return Sword25::PersistenceService::getSlotCount(); }
+ virtual SaveStateList listSaves(const char *target) const;
};
bool Sword25MetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
@@ -122,6 +127,31 @@ bool Sword25MetaEngine::createInstance(OSystem *syst, Engine **engine, const ADG
return desc != 0;
}
+bool Sword25MetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves);
+}
+
+SaveStateList Sword25MetaEngine::listSaves(const char *target) const {
+ Common::String pattern = target;
+ pattern = pattern + ".???";
+ SaveStateList saveList;
+
+ Sword25::PersistenceService ps;
+ Sword25::setGameTarget(target);
+
+ ps.reloadSlots();
+
+ for (uint i = 0; i < ps.getSlotCount(); ++i) {
+ if (ps.isSlotOccupied(i)) {
+ Common::String desc = ps.getSavegameDescription(i);
+ saveList.push_back(SaveStateDescriptor(i, desc));
+ }
+ }
+
+ return saveList;
+}
+
#if PLUGIN_ENABLED_DYNAMIC(SWORD25)
REGISTER_PLUGIN_DYNAMIC(SWORD25, PLUGIN_TYPE_ENGINE, Sword25MetaEngine);
#else
diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp
index f6757b9a8e..4193e02b2e 100644
--- a/engines/sword25/fmv/movieplayer.cpp
+++ b/engines/sword25/fmv/movieplayer.cpp
@@ -39,16 +39,15 @@
#include "sword25/package/packagemanager.h"
#include "sword25/sfx/soundengine.h"
+#define INDIRECTRENDERING 1
+
namespace Sword25 {
#define BS_LOG_PREFIX "MOVIEPLAYER"
#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */
-Service *OggTheora_CreateObject(Kernel *pKernel) {
- return new MoviePlayer(pKernel);
-}
-
+#ifdef USE_THEORADEC
MoviePlayer::MoviePlayer(Kernel *pKernel) : Service(pKernel), _decoder(g_system->getMixer()) {
if (!registerScriptBindings())
BS_LOG_ERRORLN("Script bindings could not be registered.");
@@ -62,20 +61,22 @@ MoviePlayer::~MoviePlayer() {
bool MoviePlayer::loadMovie(const Common::String &filename, uint z) {
// Get the file and load it into the decoder
- Common::SeekableReadStream *in = Kernel::GetInstance()->GetPackage()->getStream(filename);
+ Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(filename);
_decoder.load(in);
// Ausgabebitmap erstellen
- GraphicEngine *pGfx = Kernel::GetInstance()->GetGfx();
- _outputBitmap = pGfx->GetMainPanel()->addDynamicBitmap(_decoder.getWidth(), _decoder.getHeight());
+ GraphicEngine *pGfx = Kernel::getInstance()->getGfx();
+
+#if INDIRECTRENDERING
+ _outputBitmap = pGfx->getMainPanel()->addDynamicBitmap(_decoder.getWidth(), _decoder.getHeight());
if (!_outputBitmap.isValid()) {
BS_LOG_ERRORLN("Output bitmap for movie playback could not be created.");
return false;
}
// Skalierung des Ausgabebitmaps berechnen, so dass es möglichst viel Bildschirmfläche einnimmt.
- float screenToVideoWidth = (float)pGfx->GetDisplayWidth() / (float)_outputBitmap->getWidth();
- float screenToVideoHeight = (float)pGfx->GetDisplayHeight() / (float)_outputBitmap->getHeight();
+ float screenToVideoWidth = (float)pGfx->getDisplayWidth() / (float)_outputBitmap->getWidth();
+ float screenToVideoHeight = (float)pGfx->getDisplayHeight() / (float)_outputBitmap->getHeight();
float scaleFactor = MIN(screenToVideoWidth, screenToVideoHeight);
if (abs((int)(scaleFactor - 1.0f)) < FLT_EPSILON)
@@ -87,8 +88,19 @@ bool MoviePlayer::loadMovie(const Common::String &filename, uint z) {
_outputBitmap->setZ(z);
// Ausgabebitmap auf dem Bildschirm zentrieren
- _outputBitmap->setX((pGfx->GetDisplayWidth() - _outputBitmap->getWidth()) / 2);
- _outputBitmap->setY((pGfx->GetDisplayHeight() - _outputBitmap->getHeight()) / 2);
+ _outputBitmap->setX((pGfx->getDisplayWidth() - _outputBitmap->getWidth()) / 2);
+ _outputBitmap->setY((pGfx->getDisplayHeight() - _outputBitmap->getHeight()) / 2);
+#else
+ _backSurface = pGfx->getSurface();
+
+ _outX = (pGfx->getDisplayWidth() - _decoder.getWidth()) / 2;
+ _outY = (pGfx->getDisplayHeight() - _decoder.getHeight()) / 2;
+
+ if (_outX < 0)
+ _outX = 0;
+ if (_outY < 0)
+ _outY = 0;
+#endif
return true;
}
@@ -113,11 +125,21 @@ bool MoviePlayer::pause() {
void MoviePlayer::update() {
if (_decoder.isVideoLoaded()) {
Graphics::Surface *s = _decoder.decodeNextFrame();
-
- // Transfer the next frame
- assert(s->bytesPerPixel == 4);
- byte *frameData = (byte *)s->getBasePtr(0, 0);
- _outputBitmap->setContent(frameData, s->pitch * s->h, 0, s->pitch);
+ if (s) {
+ // Transfer the next frame
+ assert(s->bytesPerPixel == 4);
+
+#if INDIRECTRENDERING
+ byte *frameData = (byte *)s->getBasePtr(0, 0);
+ _outputBitmap->setContent(frameData, s->pitch * s->h, 0, s->pitch);
+#else
+ g_system->copyRectToScreen((byte *)s->getBasePtr(0, 0), s->pitch, _outX, _outY, MIN(s->w, _backSurface->w), MIN(s->h, _backSurface->h));
+ g_system->updateScreen();
+#endif
+ } else {
+ // Movie complete, so unload the movie
+ unloadMovie();
+ }
}
}
@@ -141,9 +163,9 @@ void MoviePlayer::setScaleFactor(float scaleFactor) {
_outputBitmap->setScaleFactor(scaleFactor);
// Ausgabebitmap auf dem Bildschirm zentrieren
- GraphicEngine *gfxPtr = Kernel::GetInstance()->GetGfx();
- _outputBitmap->setX((gfxPtr->GetDisplayWidth() - _outputBitmap->getWidth()) / 2);
- _outputBitmap->setY((gfxPtr->GetDisplayHeight() - _outputBitmap->getHeight()) / 2);
+ GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
+ _outputBitmap->setX((gfxPtr->getDisplayWidth() - _outputBitmap->getWidth()) / 2);
+ _outputBitmap->setY((gfxPtr->getDisplayHeight() - _outputBitmap->getHeight()) / 2);
}
}
@@ -151,4 +173,56 @@ double MoviePlayer::getTime() {
return _decoder.getElapsedTime() / 1000.0;
}
+#else // USE_THEORADEC
+
+MoviePlayer::MoviePlayer(Kernel *pKernel) : Service(pKernel) {
+ if (!registerScriptBindings())
+ BS_LOG_ERRORLN("Script bindings could not be registered.");
+ else
+ BS_LOGLN("Script bindings registered.");
+}
+
+MoviePlayer::~MoviePlayer() {
+}
+
+bool MoviePlayer::loadMovie(const Common::String &Filename, unsigned int Z) {
+ return true;
+}
+
+bool MoviePlayer::unloadMovie() {
+ return true;
+}
+
+bool MoviePlayer::play() {
+ return true;
+}
+
+bool MoviePlayer::pause() {
+ return true;
+}
+
+void MoviePlayer::update() {
+}
+
+bool MoviePlayer::isMovieLoaded() {
+ return true;
+}
+
+bool MoviePlayer::isPaused() {
+ return true;
+}
+
+float MoviePlayer::getScaleFactor() {
+ return 1.0f;
+}
+
+void MoviePlayer::setScaleFactor(float ScaleFactor) {
+}
+
+double MoviePlayer::getTime() {
+ return 1.0;
+}
+
+#endif // USE_THEORADEC
+
} // End of namespace Sword25
diff --git a/engines/sword25/fmv/movieplayer.h b/engines/sword25/fmv/movieplayer.h
index 96beb648c0..350407cea5 100644
--- a/engines/sword25/fmv/movieplayer.h
+++ b/engines/sword25/fmv/movieplayer.h
@@ -35,11 +35,16 @@
#ifndef SWORD25_MOVIEPLAYER_H
#define SWORD25_MOVIEPLAYER_H
+#include "common/scummsys.h" // for USE_THEORADEC
+
#include "sword25/kernel/common.h"
#include "sword25/kernel/service.h"
-#include "sword25/fmv/theora_decoder.h"
#include "sword25/gfx/bitmap.h"
+#ifdef USE_THEORADEC
+#include "sword25/fmv/theora_decoder.h"
+#endif
+
namespace Sword25 {
class MoviePlayer : public Service {
@@ -135,9 +140,15 @@ public:
private:
bool registerScriptBindings();
+
+#ifdef USE_THEORADEC
TheoraDecoder _decoder;
+ Graphics::Surface *_backSurface;
+ int _outX, _outY;
+
RenderObjectPtr<Bitmap> _outputBitmap;
+#endif
};
} // End of namespace Sword25
diff --git a/engines/sword25/fmv/movieplayer_script.cpp b/engines/sword25/fmv/movieplayer_script.cpp
index 13bb149672..aa854448ff 100644
--- a/engines/sword25/fmv/movieplayer_script.cpp
+++ b/engines/sword25/fmv/movieplayer_script.cpp
@@ -32,6 +32,8 @@
*
*/
+#include "common/scummsys.h" // for USE_THEORADEC
+
#include "sword25/kernel/common.h"
#include "sword25/kernel/kernel.h"
#include "sword25/script/script.h"
@@ -42,7 +44,7 @@
namespace Sword25 {
int loadMovie(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
lua_pushbooleancpp(L, FMVPtr->loadMovie(luaL_checkstring(L, 1), lua_gettop(L) == 2 ? static_cast<uint>(luaL_checknumber(L, 2)) : 10));
@@ -51,7 +53,7 @@ int loadMovie(lua_State *L) {
}
int unloadMovie(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
lua_pushbooleancpp(L, FMVPtr->unloadMovie());
@@ -60,7 +62,7 @@ int unloadMovie(lua_State *L) {
}
int play(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
lua_pushbooleancpp(L, FMVPtr->play());
@@ -69,7 +71,7 @@ int play(lua_State *L) {
}
int pause(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
lua_pushbooleancpp(L, FMVPtr->pause());
@@ -78,7 +80,7 @@ int pause(lua_State *L) {
}
int update(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
FMVPtr->update();
@@ -87,7 +89,7 @@ int update(lua_State *L) {
}
int isMovieLoaded(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
lua_pushbooleancpp(L, FMVPtr->isMovieLoaded());
@@ -96,7 +98,7 @@ int isMovieLoaded(lua_State *L) {
}
int isPaused(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
lua_pushbooleancpp(L, FMVPtr->isPaused());
@@ -105,7 +107,7 @@ int isPaused(lua_State *L) {
}
int getScaleFactor(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
lua_pushnumber(L, FMVPtr->getScaleFactor());
@@ -114,7 +116,7 @@ int getScaleFactor(lua_State *L) {
}
int setScaleFactor(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
FMVPtr->setScaleFactor(static_cast<float>(luaL_checknumber(L, 1)));
@@ -123,7 +125,7 @@ int setScaleFactor(lua_State *L) {
}
int getTime(lua_State *L) {
- MoviePlayer *FMVPtr = Kernel::GetInstance()->GetFMV();
+ MoviePlayer *FMVPtr = Kernel::getInstance()->getFMV();
BS_ASSERT(FMVPtr);
lua_pushnumber(L, FMVPtr->getTime());
@@ -148,9 +150,7 @@ const luaL_reg LIBRARY_FUNCTIONS[] = {
};
bool MoviePlayer::registerScriptBindings() {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- ScriptEngine *pScript = static_cast<ScriptEngine *>(pKernel->GetService("script"));
+ ScriptEngine *pScript = Kernel::getInstance()->getScript();
BS_ASSERT(pScript);
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
BS_ASSERT(L);
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp
index 9b1951828e..d6c2544fe5 100644
--- a/engines/sword25/fmv/theora_decoder.cpp
+++ b/engines/sword25/fmv/theora_decoder.cpp
@@ -37,6 +37,8 @@
*/
#include "sword25/fmv/theora_decoder.h"
+
+#ifdef USE_THEORADEC
#include "sword25/fmv/yuvtorgba.h"
#include "common/system.h"
#include "sound/decoders/raw.h"
@@ -242,10 +244,12 @@ bool TheoraDecoder::load(Common::SeekableReadStream *stream) {
if (_theoraComment.user_comments[i]) {
int len = _theoraComment.comment_lengths[i];
char *value = (char *)malloc(len + 1);
- memcpy(value, _theoraComment.user_comments[i], len);
- value[len] = '\0';
- debug(1, "\t%s", value);
- free(value);
+ if (value) {
+ memcpy(value, _theoraComment.user_comments[i], len);
+ value[len] = '\0';
+ debug(1, "\t%s", value);
+ free(value);
+ }
}
}
}
@@ -343,7 +347,7 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() {
int maxsamples = (AUDIOFD_FRAGSIZE - _audiobufFill) / 2 / _vorbisInfo.channels;
for (i = 0; i < ret && i < maxsamples; i++)
for (j = 0; j < _vorbisInfo.channels; j++) {
- int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32768);
+ int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767);
_audiobuf[count++] = val;
}
@@ -397,8 +401,7 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() {
}
if (!_videobufReady && !_audiobufReady && _fileStream->eos()) {
- close();
- return _surface;
+ return NULL;
}
if (!_videobufReady || !_audiobufReady) {
@@ -410,11 +413,15 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() {
}
// If playback has begun, top audio buffer off immediately.
-/* FIXME: This is currently crashing
- if (_stateFlag) {
+ if (_stateFlag && _audiobufReady) {
_audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO);
+
+ // The audio mixer is now responsible for the old audio buffer.
+ // We need to create a new one.
+ _audiobuf = (ogg_int16_t *)calloc(AUDIOFD_FRAGSIZE, sizeof(ogg_int16_t));
+ _audiobufFill = 0;
+ _audiobufReady = false;
}
-*/
// are we at or past time for this video frame?
if (_stateFlag && _videobufReady) {
@@ -490,3 +497,5 @@ Audio::QueuingAudioStream *TheoraDecoder::createAudioStream() {
}
} // End of namespace Sword25
+
+#endif
diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h
index 12d8035c0a..f6c622563b 100644
--- a/engines/sword25/fmv/theora_decoder.h
+++ b/engines/sword25/fmv/theora_decoder.h
@@ -26,6 +26,10 @@
#ifndef SWORD25_THEORADECODER_H
#define SWORD25_THEORADECODER_H
+#include "common/scummsys.h" // for USE_THEORADEC
+
+#ifdef USE_THEORADEC
+
#include "graphics/video/video_decoder.h"
#include "sound/audiostream.h"
#include "sound/mixer.h"
@@ -150,3 +154,5 @@ private:
} // End of namespace Sword25
#endif
+
+#endif
diff --git a/engines/sword25/fmv/yuvtorgba.cpp b/engines/sword25/fmv/yuvtorgba.cpp
index 12d11b6784..e9d0189265 100644
--- a/engines/sword25/fmv/yuvtorgba.cpp
+++ b/engines/sword25/fmv/yuvtorgba.cpp
@@ -34,6 +34,8 @@
#include "sword25/fmv/yuvtorgba.h"
+#ifdef USE_THEORADEC
+
namespace Sword25 {
static const int PRECISION = 32768;
@@ -241,3 +243,5 @@ void YUVtoBGRA::translate(th_ycbcr_buffer &YUVBuffer, const th_info &theoraInfo,
}
} // End of namespace Sword25
+
+#endif
diff --git a/engines/sword25/fmv/yuvtorgba.h b/engines/sword25/fmv/yuvtorgba.h
index 15fa85b7e4..675248e6e0 100644
--- a/engines/sword25/fmv/yuvtorgba.h
+++ b/engines/sword25/fmv/yuvtorgba.h
@@ -35,6 +35,9 @@
#ifndef SWORD25_YUVTORGBA_H
#define SWORD25_YUVTORGBA_H
+#include "common/scummsys.h" // for USE_THEORADEC
+
+#ifdef USE_THEORADEC
#include "sword25/kernel/common.h"
#include <theora/theora.h>
#include <theora/codec.h>
@@ -49,3 +52,5 @@ public:
} // End of namespace Sword25
#endif
+
+#endif
diff --git a/engines/sword25/gfx/animation.cpp b/engines/sword25/gfx/animation.cpp
index 7ec445acb8..0d3baae347 100644
--- a/engines/sword25/gfx/animation.cpp
+++ b/engines/sword25/gfx/animation.cpp
@@ -38,7 +38,6 @@
#include "sword25/kernel/resmanager.h"
#include "sword25/kernel/inputpersistenceblock.h"
#include "sword25/kernel/outputpersistenceblock.h"
-#include "sword25/kernel/callbackregistry.h"
#include "sword25/package/packagemanager.h"
#include "sword25/gfx/image/image.h"
#include "sword25/gfx/animationtemplate.h"
@@ -99,8 +98,8 @@ Animation::Animation(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject
void Animation::initializeAnimationResource(const Common::String &fileName) {
// Die Resource wird für die gesamte Lebensdauer des Animations-Objektes gelockt.
- Resource *resourcePtr = Kernel::GetInstance()->GetResourceManager()->RequestResource(fileName);
- if (resourcePtr && resourcePtr->GetType() == Resource::TYPE_ANIMATION)
+ Resource *resourcePtr = Kernel::getInstance()->getResourceManager()->requestResource(fileName);
+ if (resourcePtr && resourcePtr->getType() == Resource::TYPE_ANIMATION)
_animationResourcePtr = static_cast<AnimationResource *>(resourcePtr);
else {
BS_LOG_ERRORLN("The resource \"%s\" could not be requested. The Animation can't be created.", fileName.c_str());
@@ -133,14 +132,14 @@ Animation::~Animation() {
getAnimationDescription()->unlock();
}
- // Delete Callbacks
- Common::Array<ANIMATION_CALLBACK_DATA>::iterator it = _deleteCallbacks.begin();
- for (; it != _deleteCallbacks.end(); it++)((*it).Callback)((*it).Data);
+ // Invoke the "delete" callback
+ if (_deleteCallback)
+ (_deleteCallback)(getHandle());
}
void Animation::play() {
- // Wenn die Animation zuvor komplett durchgelaufen ist, wird sie wieder von Anfang abgespielt
+ // If the animation was completed, then play it again from the start.
if (_finished)
stop();
@@ -182,13 +181,13 @@ bool Animation::doRender() {
BS_ASSERT(_currentFrame < animationDescriptionPtr->getFrameCount());
// Bitmap des aktuellen Frames holen
- Resource *pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(animationDescriptionPtr->getFrame(_currentFrame).fileName);
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(_currentFrame).fileName);
BS_ASSERT(pResource);
- BS_ASSERT(pResource->GetType() == Resource::TYPE_BITMAP);
+ BS_ASSERT(pResource->getType() == Resource::TYPE_BITMAP);
BitmapResource *pBitmapResource = static_cast<BitmapResource *>(pResource);
// Framebufferobjekt holen
- GraphicEngine *pGfx = static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx"));
+ GraphicEngine *pGfx = Kernel::getInstance()->getGfx();
BS_ASSERT(pGfx);
// Bitmap zeichnen
@@ -242,28 +241,20 @@ void Animation::frameNotification(int timeElapsed) {
BS_ASSERT(0);
}
- // Überläufe behandeln
+ // Deal with overflows
if (tmpCurFrame < 0) {
- // Loop-Point Callbacks
- for (uint i = 0; i < _loopPointCallbacks.size();) {
- if ((_loopPointCallbacks[i].Callback)(_loopPointCallbacks[i].Data) == false) {
- _loopPointCallbacks.remove_at(i);
- } else
- i++;
- }
+ // Loop-Point callback
+ if (_loopPointCallback && !(_loopPointCallback)(getHandle()))
+ _loopPointCallback = 0;
- // Ein Unterlauf darf nur auftreten, wenn der Animationstyp JOJO ist.
+ // An underflow may only occur if the animation type is JOJO.
BS_ASSERT(animationDescriptionPtr->getAnimationType() == AT_JOJO);
tmpCurFrame = - tmpCurFrame;
_direction = FORWARD;
} else if (static_cast<uint>(tmpCurFrame) >= animationDescriptionPtr->getFrameCount()) {
- // Loop-Point Callbacks
- for (uint i = 0; i < _loopPointCallbacks.size();) {
- if ((_loopPointCallbacks[i].Callback)(_loopPointCallbacks[i].Data) == false) {
- _loopPointCallbacks.remove_at(i);
- } else
- i++;
- }
+ // Loop-Point callback
+ if (_loopPointCallback && !(_loopPointCallback)(getHandle()))
+ _loopPointCallback = 0;
switch (animationDescriptionPtr->getAnimationType()) {
case AT_ONESHOT:
@@ -290,13 +281,9 @@ void Animation::frameNotification(int timeElapsed) {
forceRefresh();
if (animationDescriptionPtr->getFrame(_currentFrame).action != "") {
- // Action Callbacks
- for (uint i = 0; i < _actionCallbacks.size();) {
- if ((_actionCallbacks[i].Callback)(_actionCallbacks[i].Data) == false) {
- _actionCallbacks.remove_at(i);
- } else
- i++;
- }
+ // action callback
+ if (_actionCallback && !(_actionCallback)(getHandle()))
+ _actionCallback = 0;
}
}
@@ -315,9 +302,9 @@ void Animation::computeCurrentCharacteristics() {
BS_ASSERT(animationDescriptionPtr);
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
- Resource *pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(curFrame.fileName);
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
BS_ASSERT(pResource);
- BS_ASSERT(pResource->GetType() == Resource::TYPE_BITMAP);
+ BS_ASSERT(pResource->getType() == Resource::TYPE_BITMAP);
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
// Größe des Bitmaps auf die Animation übertragen
@@ -338,7 +325,7 @@ bool Animation::lockAllFrames() {
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
BS_ASSERT(animationDescriptionPtr);
for (uint i = 0; i < animationDescriptionPtr->getFrameCount(); ++i) {
- if (!Kernel::GetInstance()->GetResourceManager()->RequestResource(animationDescriptionPtr->getFrame(i).fileName)) {
+ if (!Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(i).fileName)) {
BS_LOG_ERRORLN("Could not lock all animation frames.");
return false;
}
@@ -356,14 +343,14 @@ bool Animation::unlockAllFrames() {
BS_ASSERT(animationDescriptionPtr);
for (uint i = 0; i < animationDescriptionPtr->getFrameCount(); ++i) {
Resource *pResource;
- if (!(pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(animationDescriptionPtr->getFrame(i).fileName))) {
+ if (!(pResource = Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(i).fileName))) {
BS_LOG_ERRORLN("Could not unlock all animation frames.");
return false;
}
// Zwei mal freigeben um den Request von LockAllFrames() und den jetzigen Request aufzuheben
pResource->release();
- if (pResource->GetLockCount())
+ if (pResource->getLockCount())
pResource->release();
}
@@ -524,9 +511,9 @@ int Animation::computeXModifier() const {
BS_ASSERT(animationDescriptionPtr);
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
- Resource *pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(curFrame.fileName);
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
BS_ASSERT(pResource);
- BS_ASSERT(pResource->GetType() == Resource::TYPE_BITMAP);
+ BS_ASSERT(pResource->getType() == Resource::TYPE_BITMAP);
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
int result = curFrame.flipV ? - static_cast<int>((pBitmap->getWidth() - 1 - curFrame.hotspotX) * _scaleFactorX) :
@@ -542,9 +529,9 @@ int Animation::computeYModifier() const {
BS_ASSERT(animationDescriptionPtr);
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
- Resource *pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(curFrame.fileName);
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
BS_ASSERT(pResource);
- BS_ASSERT(pResource->GetType() == Resource::TYPE_BITMAP);
+ BS_ASSERT(pResource->getType() == Resource::TYPE_BITMAP);
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
int result = curFrame.flipH ? - static_cast<int>((pBitmap->getHeight() - 1 - curFrame.hotspotY) * _scaleFactorY) :
@@ -555,63 +542,6 @@ int Animation::computeYModifier() const {
return result;
}
-void Animation::registerActionCallback(ANIMATION_CALLBACK callback, uint data) {
- ANIMATION_CALLBACK_DATA cd;
- cd.Callback = callback;
- cd.Data = data;
- _actionCallbacks.push_back(cd);
-}
-
-void Animation::registerLoopPointCallback(ANIMATION_CALLBACK callback, uint data) {
- ANIMATION_CALLBACK_DATA cd;
- cd.Callback = callback;
- cd.Data = data;
- _loopPointCallbacks.push_back(cd);
-}
-
-void Animation::registerDeleteCallback(ANIMATION_CALLBACK callback, uint data) {
- ANIMATION_CALLBACK_DATA cd;
- cd.Callback = callback;
- cd.Data = data;
- _deleteCallbacks.push_back(cd);
-}
-
-void Animation::persistCallbackVector(OutputPersistenceBlock &writer, const Common::Array<ANIMATION_CALLBACK_DATA> &vector) {
- // Anzahl an Callbacks persistieren.
- writer.write(vector.size());
-
- // Alle Callbacks einzeln persistieren.
- Common::Array<ANIMATION_CALLBACK_DATA>::const_iterator it = vector.begin();
- while (it != vector.end()) {
- writer.write(CallbackRegistry::getInstance().resolveCallbackPointer((void (*)(int))it->Callback));
- writer.write(it->Data);
-
- ++it;
- }
-}
-
-void Animation::unpersistCallbackVector(InputPersistenceBlock &reader, Common::Array<ANIMATION_CALLBACK_DATA> &vector) {
- // Callbackvector leeren.
- vector.resize(0);
-
- // Anzahl an Callbacks einlesen.
- uint callbackCount;
- reader.read(callbackCount);
-
- // Alle Callbacks einzeln wieder herstellen.
- for (uint i = 0; i < callbackCount; ++i) {
- ANIMATION_CALLBACK_DATA callbackData;
-
- Common::String callbackFunctionName;
- reader.read(callbackFunctionName);
- callbackData.Callback = reinterpret_cast<ANIMATION_CALLBACK>(CallbackRegistry::getInstance().resolveCallbackFunction(callbackFunctionName));
-
- reader.read(callbackData.Data);
-
- vector.push_back(callbackData);
- }
-}
-
bool Animation::persist(OutputPersistenceBlock &writer) {
bool result = true;
@@ -632,7 +562,7 @@ bool Animation::persist(OutputPersistenceBlock &writer) {
if (_animationResourcePtr) {
uint marker = 0;
writer.write(marker);
- writer.write(_animationResourcePtr->getFileName());
+ writer.writeString(_animationResourcePtr->getFileName());
} else if (_animationTemplateHandle) {
uint marker = 1;
writer.write(marker);
@@ -644,9 +574,18 @@ bool Animation::persist(OutputPersistenceBlock &writer) {
//writer.write(_AnimationDescriptionPtr);
writer.write(_framesLocked);
- persistCallbackVector(writer, _loopPointCallbacks);
- persistCallbackVector(writer, _actionCallbacks);
- persistCallbackVector(writer, _deleteCallbacks);
+
+ // The following is only there to for compatibility with older saves
+ // resp. the original engine.
+ writer.write((uint)1);
+ writer.writeString("LuaLoopPointCB");
+ writer.write(getHandle());
+ writer.write((uint)1);
+ writer.writeString("LuaActionCB");
+ writer.write(getHandle());
+ writer.write((uint)1);
+ writer.writeString("LuaDeleteCB");
+ writer.write(getHandle());
result &= RenderObject::persistChildren(writer);
@@ -678,7 +617,7 @@ bool Animation::unpersist(InputPersistenceBlock &reader) {
reader.read(marker);
if (marker == 0) {
Common::String resourceFilename;
- reader.read(resourceFilename);
+ reader.readString(resourceFilename);
initializeAnimationResource(resourceFilename);
} else if (marker == 1) {
reader.read(_animationTemplateHandle);
@@ -690,9 +629,39 @@ bool Animation::unpersist(InputPersistenceBlock &reader) {
if (_framesLocked)
lockAllFrames();
- unpersistCallbackVector(reader, _loopPointCallbacks);
- unpersistCallbackVector(reader, _actionCallbacks);
- unpersistCallbackVector(reader, _deleteCallbacks);
+
+ // The following is only there to for compatibility with older saves
+ // resp. the original engine.
+ uint callbackCount;
+ Common::String callbackFunctionName;
+ uint callbackData;
+
+ // loop point callback
+ reader.read(callbackCount);
+ assert(callbackCount == 1);
+ reader.readString(callbackFunctionName);
+ assert(callbackFunctionName == "LuaLoopPointCB");
+ reader.read(callbackData);
+ assert(callbackData == getHandle());
+
+ // loop point callback
+ reader.read(callbackCount);
+ assert(callbackCount == 1);
+ reader.readString(callbackFunctionName);
+ assert(callbackFunctionName == "LuaActionCB");
+ reader.read(callbackData);
+ assert(callbackData == getHandle());
+
+ // loop point callback
+ reader.read(callbackCount);
+ assert(callbackCount == 1);
+ reader.readString(callbackFunctionName);
+ assert(callbackFunctionName == "LuaDeleteCB");
+ reader.read(callbackData);
+ assert(callbackData == getHandle());
+
+ // Set the callbacks
+ setCallbacks();
result &= RenderObject::unpersistChildren(reader);
@@ -705,7 +674,7 @@ AnimationDescription *Animation::getAnimationDescription() const {
if (_animationResourcePtr)
return _animationResourcePtr;
else
- return AnimationTemplateRegistry::getInstance().resolveHandle(_animationTemplateHandle);
+ return AnimationTemplateRegistry::instance().resolveHandle(_animationTemplateHandle);
}
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/animation.h b/engines/sword25/gfx/animation.h
index 0676c0c116..72fe7e2de8 100644
--- a/engines/sword25/gfx/animation.h
+++ b/engines/sword25/gfx/animation.h
@@ -151,9 +151,7 @@ public:
typedef bool (*ANIMATION_CALLBACK)(uint);
- void registerLoopPointCallback(ANIMATION_CALLBACK callback, uint data = 0);
- void registerActionCallback(ANIMATION_CALLBACK callback, uint data = 0);
- void registerDeleteCallback(ANIMATION_CALLBACK Callback, uint Data = 0);
+ void setCallbacks();
protected:
virtual bool doRender();
@@ -178,13 +176,9 @@ private:
uint _animationTemplateHandle;
bool _framesLocked;
- struct ANIMATION_CALLBACK_DATA {
- ANIMATION_CALLBACK Callback;
- uint Data;
- };
- Common::Array<ANIMATION_CALLBACK_DATA> _loopPointCallbacks;
- Common::Array<ANIMATION_CALLBACK_DATA> _actionCallbacks;
- Common::Array<ANIMATION_CALLBACK_DATA> _deleteCallbacks;
+ ANIMATION_CALLBACK _loopPointCallback;
+ ANIMATION_CALLBACK _actionCallback;
+ ANIMATION_CALLBACK _deleteCallback;
/**
@brief Lockt alle Frames.
@@ -216,8 +210,6 @@ private:
int computeYModifier() const;
void initMembers();
- void persistCallbackVector(OutputPersistenceBlock &writer, const Common::Array<ANIMATION_CALLBACK_DATA> &vector);
- void unpersistCallbackVector(InputPersistenceBlock &reader, Common::Array<ANIMATION_CALLBACK_DATA> &vector);
AnimationDescription *getAnimationDescription() const;
void initializeAnimationResource(const Common::String &fileName);
};
diff --git a/engines/sword25/gfx/animationdescription.h b/engines/sword25/gfx/animationdescription.h
index a52f5d3f68..88cbb23503 100644
--- a/engines/sword25/gfx/animationdescription.h
+++ b/engines/sword25/gfx/animationdescription.h
@@ -50,7 +50,7 @@ protected:
_scalingAllowed(true),
_alphaAllowed(true),
_colorModulationAllowed(true)
- {};
+ {}
public:
struct Frame {
diff --git a/engines/sword25/gfx/animationresource.cpp b/engines/sword25/gfx/animationresource.cpp
index 93b5934041..6e5f683a2e 100644
--- a/engines/sword25/gfx/animationresource.cpp
+++ b/engines/sword25/gfx/animationresource.cpp
@@ -35,7 +35,6 @@
#include "sword25/gfx/animationresource.h"
#include "sword25/kernel/kernel.h"
-#include "sword25/kernel/string.h"
#include "sword25/package/packagemanager.h"
#include "sword25/gfx/bitmapresource.h"
@@ -54,8 +53,7 @@ AnimationResource::AnimationResource(const Common::String &filename) :
Common::XMLParser(),
_valid(false) {
// Get a pointer to the package manager
- Kernel *pKernel = Kernel::GetInstance();
- _pPackage = static_cast<PackageManager *>(pKernel->GetService("package"));
+ _pPackage = Kernel::getInstance()->getPackage();
BS_ASSERT(_pPackage);
// Switch to the folder the specified Xml fiile is in
@@ -117,7 +115,7 @@ bool AnimationResource::parseBooleanKey(Common::String s, bool &result) {
}
bool AnimationResource::parserCallback_animation(ParserNode *node) {
- if (!parseIntegerKey(node->values["fps"].c_str(), 1, &_FPS) || (_FPS < MIN_FPS) || (_FPS > MAX_FPS)) {
+ if (!parseIntegerKey(node->values["fps"], 1, &_FPS) || (_FPS < MIN_FPS) || (_FPS > MAX_FPS)) {
return parserError("Illegal or missing fps attribute in <animation> tag in \"%s\". Assuming default (\"%d\").",
getFileName().c_str(), DEFAULT_FPS);
}
@@ -212,7 +210,7 @@ AnimationResource::~AnimationResource() {
bool AnimationResource::precacheAllFrames() const {
Common::Array<Frame>::const_iterator iter = _frames.begin();
for (; iter != _frames.end(); ++iter) {
- if (!Kernel::GetInstance()->GetResourceManager()->PrecacheResource((*iter).fileName)) {
+ if (!Kernel::getInstance()->getResourceManager()->precacheResource((*iter).fileName)) {
BS_LOG_ERRORLN("Could not precache \"%s\".", (*iter).fileName.c_str());
return false;
}
@@ -233,7 +231,7 @@ bool AnimationResource::computeFeatures() {
Common::Array<Frame>::const_iterator iter = _frames.begin();
for (; iter != _frames.end(); ++iter) {
BitmapResource *pBitmap;
- if (!(pBitmap = static_cast<BitmapResource *>(Kernel::GetInstance()->GetResourceManager()->RequestResource((*iter).fileName)))) {
+ if (!(pBitmap = static_cast<BitmapResource *>(Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName)))) {
BS_LOG_ERRORLN("Could not request \"%s\".", (*iter).fileName.c_str());
return false;
}
diff --git a/engines/sword25/gfx/animationtemplate.cpp b/engines/sword25/gfx/animationtemplate.cpp
index 2019d19565..4a060dbad9 100644
--- a/engines/sword25/gfx/animationtemplate.cpp
+++ b/engines/sword25/gfx/animationtemplate.cpp
@@ -49,7 +49,7 @@ uint AnimationTemplate::create(const Common::String &sourceAnimation) {
AnimationTemplate *animationTemplatePtr = new AnimationTemplate(sourceAnimation);
if (animationTemplatePtr->isValid()) {
- return AnimationTemplateRegistry::getInstance().resolvePtr(animationTemplatePtr);
+ return AnimationTemplateRegistry::instance().resolvePtr(animationTemplatePtr);
} else {
delete animationTemplatePtr;
return 0;
@@ -60,7 +60,7 @@ uint AnimationTemplate::create(const AnimationTemplate &other) {
AnimationTemplate *animationTemplatePtr = new AnimationTemplate(other);
if (animationTemplatePtr->isValid()) {
- return AnimationTemplateRegistry::getInstance().resolvePtr(animationTemplatePtr);
+ return AnimationTemplateRegistry::instance().resolvePtr(animationTemplatePtr);
} else {
delete animationTemplatePtr;
return 0;
@@ -71,7 +71,7 @@ uint AnimationTemplate::create(InputPersistenceBlock &reader, uint handle) {
AnimationTemplate *animationTemplatePtr = new AnimationTemplate(reader, handle);
if (animationTemplatePtr->isValid()) {
- return AnimationTemplateRegistry::getInstance().resolvePtr(animationTemplatePtr);
+ return AnimationTemplateRegistry::instance().resolvePtr(animationTemplatePtr);
} else {
delete animationTemplatePtr;
return 0;
@@ -80,7 +80,7 @@ uint AnimationTemplate::create(InputPersistenceBlock &reader, uint handle) {
AnimationTemplate::AnimationTemplate(const Common::String &sourceAnimation) {
// Objekt registrieren.
- AnimationTemplateRegistry::getInstance().registerObject(this);
+ AnimationTemplateRegistry::instance().registerObject(this);
_valid = false;
@@ -93,7 +93,7 @@ AnimationTemplate::AnimationTemplate(const Common::String &sourceAnimation) {
AnimationTemplate::AnimationTemplate(const AnimationTemplate &other) : AnimationDescription() {
// Objekt registrieren.
- AnimationTemplateRegistry::getInstance().registerObject(this);
+ AnimationTemplateRegistry::instance().registerObject(this);
_valid = false;
@@ -118,16 +118,16 @@ AnimationTemplate::AnimationTemplate(const AnimationTemplate &other) : Animation
AnimationTemplate::AnimationTemplate(InputPersistenceBlock &reader, uint handle) {
// Objekt registrieren.
- AnimationTemplateRegistry::getInstance().registerObject(this, handle);
+ AnimationTemplateRegistry::instance().registerObject(this, handle);
// Objekt laden.
_valid = unpersist(reader);
}
AnimationResource *AnimationTemplate::requestSourceAnimation(const Common::String &sourceAnimation) const {
- ResourceManager *RMPtr = Kernel::GetInstance()->GetResourceManager();
+ ResourceManager *RMPtr = Kernel::getInstance()->getResourceManager();
Resource *resourcePtr;
- if (NULL == (resourcePtr = RMPtr->RequestResource(sourceAnimation)) || resourcePtr->GetType() != Resource::TYPE_ANIMATION) {
+ if (NULL == (resourcePtr = RMPtr->requestResource(sourceAnimation)) || resourcePtr->getType() != Resource::TYPE_ANIMATION) {
BS_LOG_ERRORLN("The resource \"%s\" could not be requested or is has an invalid type. The animation template can't be created.", sourceAnimation.c_str());
return 0;
}
@@ -141,7 +141,7 @@ AnimationTemplate::~AnimationTemplate() {
}
// Objekt deregistrieren
- AnimationTemplateRegistry::getInstance().deregisterObject(this);
+ AnimationTemplateRegistry::instance().deregisterObject(this);
}
void AnimationTemplate::addFrame(int index) {
@@ -195,13 +195,13 @@ bool AnimationTemplate::persist(OutputPersistenceBlock &writer) {
writer.write(Iter->hotspotY);
writer.write(Iter->flipV);
writer.write(Iter->flipH);
- writer.write(Iter->fileName);
- writer.write(Iter->action);
+ writer.writeString(Iter->fileName);
+ writer.writeString(Iter->action);
++Iter;
}
// Restliche Member persistieren.
- writer.write(_sourceAnimationPtr->getFileName());
+ writer.writeString(_sourceAnimationPtr->getFileName());
writer.write(_valid);
return Result;
@@ -224,15 +224,15 @@ bool AnimationTemplate::unpersist(InputPersistenceBlock &reader) {
reader.read(frame.hotspotY);
reader.read(frame.flipV);
reader.read(frame.flipH);
- reader.read(frame.fileName);
- reader.read(frame.action);
+ reader.readString(frame.fileName);
+ reader.readString(frame.action);
_frames.push_back(frame);
}
// Die Animations-Resource wird für die gesamte Lebensdauer des Objektes gelockt
Common::String sourceAnimation;
- reader.read(sourceAnimation);
+ reader.readString(sourceAnimation);
_sourceAnimationPtr = requestSourceAnimation(sourceAnimation);
reader.read(_valid);
diff --git a/engines/sword25/gfx/animationtemplateregistry.cpp b/engines/sword25/gfx/animationtemplateregistry.cpp
index 6f4af690c6..ac1d6096f4 100644
--- a/engines/sword25/gfx/animationtemplateregistry.cpp
+++ b/engines/sword25/gfx/animationtemplateregistry.cpp
@@ -39,9 +39,9 @@
#include "sword25/gfx/animationtemplateregistry.h"
#include "sword25/gfx/animationtemplate.h"
-namespace Sword25 {
+DECLARE_SINGLETON(Sword25::AnimationTemplateRegistry)
-Common::ScopedPtr<AnimationTemplateRegistry> AnimationTemplateRegistry::_instancePtr;
+namespace Sword25 {
void AnimationTemplateRegistry::logErrorLn(const char *message) const {
BS_LOG_ERRORLN(message);
diff --git a/engines/sword25/gfx/animationtemplateregistry.h b/engines/sword25/gfx/animationtemplateregistry.h
index 256cbab8cd..c5308bb124 100644
--- a/engines/sword25/gfx/animationtemplateregistry.h
+++ b/engines/sword25/gfx/animationtemplateregistry.h
@@ -39,19 +39,17 @@
#include "sword25/kernel/persistable.h"
#include "sword25/kernel/objectregistry.h"
-#include "common/ptr.h"
+#include "common/singleton.h"
namespace Sword25 {
class AnimationTemplate;
-class AnimationTemplateRegistry : public ObjectRegistry<AnimationTemplate>, public Persistable {
+class AnimationTemplateRegistry :
+ public ObjectRegistry<AnimationTemplate>,
+ public Persistable,
+ public Common::Singleton<AnimationTemplateRegistry> {
public:
- static AnimationTemplateRegistry &getInstance() {
- if (!_instancePtr.get())
- _instancePtr.reset(new AnimationTemplateRegistry);
- return *_instancePtr.get();
- }
virtual bool persist(OutputPersistenceBlock &writer);
virtual bool unpersist(InputPersistenceBlock &reader);
@@ -59,8 +57,6 @@ public:
private:
virtual void logErrorLn(const char *message) const;
virtual void logWarningLn(const char *message) const;
-
- static Common::ScopedPtr<AnimationTemplateRegistry> _instancePtr;
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/bitmap.cpp b/engines/sword25/gfx/bitmap.cpp
index 3a6ffb4a98..b5412c8276 100644
--- a/engines/sword25/gfx/bitmap.cpp
+++ b/engines/sword25/gfx/bitmap.cpp
@@ -32,26 +32,14 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/gfx/bitmap.h"
#include "sword25/kernel/outputpersistenceblock.h"
#include "sword25/kernel/inputpersistenceblock.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Logging
-// -----------------------------------------------------------------------------
-
#define BS_LOG_PREFIX "BITMAP"
-// -----------------------------------------------------------------------------
-// Konstruktion / Destruktion
-// -----------------------------------------------------------------------------
-
Bitmap::Bitmap(RenderObjectPtr<RenderObject> parentPtr, TYPES type, uint handle) :
RenderObject(parentPtr, type, handle),
_modulationColor(0xffffffff),
@@ -61,15 +49,9 @@ Bitmap::Bitmap(RenderObjectPtr<RenderObject> parentPtr, TYPES type, uint handle)
_flipV(false) {
}
-// -----------------------------------------------------------------------------
-
Bitmap::~Bitmap() {
}
-// -----------------------------------------------------------------------------
-// Darstellungsart festlegen
-// -----------------------------------------------------------------------------
-
void Bitmap::setAlpha(int alpha) {
if (!isAlphaAllowed()) {
BS_LOG_WARNINGLN("Tried to set alpha value on a bitmap that does not support alpha blending. Call was ignored.");
@@ -94,8 +76,6 @@ void Bitmap::setAlpha(int alpha) {
}
}
-// -----------------------------------------------------------------------------
-
void Bitmap::setModulationColor(uint modulationColor) {
if (!isColorModulationAllowed()) {
BS_LOG_WARNINGLN("Tried to set modulation color of a bitmap that does not support color modulation. Call was ignored.");
@@ -109,15 +89,11 @@ void Bitmap::setModulationColor(uint modulationColor) {
}
}
-// -----------------------------------------------------------------------------
-
void Bitmap::setScaleFactor(float scaleFactor) {
setScaleFactorX(scaleFactor);
setScaleFactorY(scaleFactor);
}
-// -----------------------------------------------------------------------------
-
void Bitmap::setScaleFactorX(float scaleFactorX) {
if (!isScalingAllowed()) {
BS_LOG_WARNINGLN("Tried to set scale factor of a bitmap that does not support scaling. Call was ignored.");
@@ -134,12 +110,12 @@ void Bitmap::setScaleFactorX(float scaleFactorX) {
_width = static_cast<int>(_originalWidth * _scaleFactorX);
if (_scaleFactorX <= 0.0f)
_scaleFactorX = 0.001f;
+ if (_width <= 0)
+ _width = 1;
forceRefresh();
}
}
-// -----------------------------------------------------------------------------
-
void Bitmap::setScaleFactorY(float scaleFactorY) {
if (!isScalingAllowed()) {
BS_LOG_WARNINGLN("Tried to set scale factor of a bitmap that does not support scaling. Call was ignored.");
@@ -156,28 +132,22 @@ void Bitmap::setScaleFactorY(float scaleFactorY) {
_height = static_cast<int>(_originalHeight * scaleFactorY);
if (_scaleFactorY <= 0.0f)
_scaleFactorY = 0.001f;
+ if (_height <= 0)
+ _height = 1;
forceRefresh();
}
}
-// -----------------------------------------------------------------------------
-
void Bitmap::setFlipH(bool flipH) {
_flipH = flipH;
forceRefresh();
}
-// -----------------------------------------------------------------------------
-
void Bitmap::setFlipV(bool flipV) {
_flipV = flipV;
forceRefresh();
}
-// -----------------------------------------------------------------------------
-// Persistenz
-// -----------------------------------------------------------------------------
-
bool Bitmap::persist(OutputPersistenceBlock &writer) {
bool result = true;
@@ -193,8 +163,6 @@ bool Bitmap::persist(OutputPersistenceBlock &writer) {
return result;
}
-// -----------------------------------------------------------------------------
-
bool Bitmap::unpersist(InputPersistenceBlock &reader) {
bool result = true;
diff --git a/engines/sword25/gfx/bitmap.h b/engines/sword25/gfx/bitmap.h
index a00baf37a4..741269c423 100644
--- a/engines/sword25/gfx/bitmap.h
+++ b/engines/sword25/gfx/bitmap.h
@@ -35,19 +35,11 @@
#ifndef SWORD25_BITMAP_H
#define SWORD25_BITMAP_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/gfx/renderobject.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Klassendeklaration
-// -----------------------------------------------------------------------------
-
class Bitmap : public RenderObject {
protected:
Bitmap(RenderObjectPtr<RenderObject> parentPtr, TYPES type, uint handle = 0);
diff --git a/engines/sword25/gfx/bitmapresource.cpp b/engines/sword25/gfx/bitmapresource.cpp
index 46e6ca77ce..cf3c85e3ac 100644
--- a/engines/sword25/gfx/bitmapresource.cpp
+++ b/engines/sword25/gfx/bitmapresource.cpp
@@ -35,16 +35,12 @@
#include "sword25/gfx/bitmapresource.h"
#include "sword25/kernel/kernel.h"
#include "sword25/gfx/graphicengine.h"
-#include "sword25/gfx/image/imageloader.h"
#include "sword25/package/packagemanager.h"
namespace Sword25 {
#define BS_LOG_PREFIX "BITMAP"
-// Konstruktion / Destruktion
-// --------------------------
-
BitmapResource::BitmapResource(const Common::String &filename, Image *pImage) :
_valid(false),
_pImage(pImage),
@@ -56,8 +52,6 @@ BitmapResource::~BitmapResource() {
delete _pImage;
}
-// -----------------------------------------------------------------------------
-
uint BitmapResource::getPixel(int x, int y) const {
BS_ASSERT(x >= 0 && x < _pImage->getWidth());
BS_ASSERT(y >= 0 && y < _pImage->getHeight());
diff --git a/engines/sword25/gfx/bitmapresource.h b/engines/sword25/gfx/bitmapresource.h
index 1054770e79..37849f918e 100644
--- a/engines/sword25/gfx/bitmapresource.h
+++ b/engines/sword25/gfx/bitmapresource.h
@@ -35,7 +35,6 @@
#ifndef SWORD25_BITMAP_RESOURCE_H
#define SWORD25_BITMAP_RESOURCE_H
-// Includes
#include "sword25/kernel/common.h"
#include "sword25/kernel/resource.h"
#include "sword25/gfx/image/image.h"
@@ -204,8 +203,8 @@ public:
}
private:
- Image *_pImage;
- bool _valid;
+ Image *_pImage;
+ bool _valid;
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/dynamicbitmap.cpp b/engines/sword25/gfx/dynamicbitmap.cpp
index 91d46e99f4..612e370712 100644
--- a/engines/sword25/gfx/dynamicbitmap.cpp
+++ b/engines/sword25/gfx/dynamicbitmap.cpp
@@ -32,10 +32,6 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/gfx/dynamicbitmap.h"
#include "sword25/gfx/bitmapresource.h"
#include "sword25/package/packagemanager.h"
@@ -43,16 +39,8 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Logging
-// -----------------------------------------------------------------------------
-
#define BS_LOG_PREFIX "DYNAMICBITMAP"
-// -----------------------------------------------------------------------------
-// Konstruktion / Destruktion
-// -----------------------------------------------------------------------------
-
DynamicBitmap::DynamicBitmap(RenderObjectPtr<RenderObject> parentPtr, uint width, uint height) :
Bitmap(parentPtr, TYPE_DYNAMICBITMAP) {
// Das BS_Bitmap konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
@@ -61,15 +49,11 @@ DynamicBitmap::DynamicBitmap(RenderObjectPtr<RenderObject> parentPtr, uint width
_initSuccess = createRenderedImage(width, height);
}
-// -----------------------------------------------------------------------------
-
DynamicBitmap::DynamicBitmap(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
Bitmap(parentPtr, TYPE_DYNAMICBITMAP, handle) {
_initSuccess = unpersist(reader);
}
-// -----------------------------------------------------------------------------
-
bool DynamicBitmap::createRenderedImage(uint width, uint height) {
// RenderedImage mit den gewünschten Maßen erstellen
bool result = false;
@@ -81,13 +65,9 @@ bool DynamicBitmap::createRenderedImage(uint width, uint height) {
return result;
}
-// -----------------------------------------------------------------------------
-
DynamicBitmap::~DynamicBitmap() {
}
-// -----------------------------------------------------------------------------
-
uint DynamicBitmap::getPixel(int x, int y) const {
BS_ASSERT(x >= 0 && x < _width);
BS_ASSERT(y >= 0 && y < _height);
@@ -95,11 +75,9 @@ uint DynamicBitmap::getPixel(int x, int y) const {
return _image->getPixel(x, y);
}
-// -----------------------------------------------------------------------------
-
bool DynamicBitmap::doRender() {
// Framebufferobjekt holen
- GraphicEngine *pGfx = static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx"));
+ GraphicEngine *pGfx = Kernel::getInstance()->getGfx();
BS_ASSERT(pGfx);
// Bitmap zeichnen
@@ -119,42 +97,26 @@ bool DynamicBitmap::doRender() {
return result;
}
-// -----------------------------------------------------------------------------
-
bool DynamicBitmap::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
return _image->setContent(pixeldata, size, offset, stride);
}
-// -----------------------------------------------------------------------------
-// Auskunftsmethoden
-// -----------------------------------------------------------------------------
-
bool DynamicBitmap::isScalingAllowed() const {
return _image->isScalingAllowed();
}
-// -----------------------------------------------------------------------------
-
bool DynamicBitmap::isAlphaAllowed() const {
return _image->isAlphaAllowed();
}
-// -----------------------------------------------------------------------------
-
bool DynamicBitmap::isColorModulationAllowed() const {
return _image->isColorModulationAllowed();
}
-// -----------------------------------------------------------------------------
-
bool DynamicBitmap::isSetContentAllowed() const {
return true;
}
-// -----------------------------------------------------------------------------
-// Persistenz
-// -----------------------------------------------------------------------------
-
bool DynamicBitmap::persist(OutputPersistenceBlock &writer) {
bool result = true;
diff --git a/engines/sword25/gfx/dynamicbitmap.h b/engines/sword25/gfx/dynamicbitmap.h
index a02769fb57..1737bdf5fc 100644
--- a/engines/sword25/gfx/dynamicbitmap.h
+++ b/engines/sword25/gfx/dynamicbitmap.h
@@ -35,11 +35,6 @@
#ifndef SWORD25_DYNAMIC_BITMAP_H
#define SWORD25_DYNAMIC_BITMAP_H
-
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/gfx/bitmap.h"
#include "sword25/gfx/image/renderedimage.h"
@@ -48,10 +43,6 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Klassendeklaration
-// -----------------------------------------------------------------------------
-
class DynamicBitmap : public Bitmap {
friend class RenderObject;
@@ -60,18 +51,18 @@ public:
virtual uint getPixel(int x, int y) const;
- virtual bool setContent(const byte *pixeldata, uint size, uint offset, uint stride);
+ virtual bool setContent(const byte *pixeldata, uint size, uint offset, uint stride);
- virtual bool isScalingAllowed() const;
- virtual bool isAlphaAllowed() const;
- virtual bool isColorModulationAllowed() const;
- virtual bool isSetContentAllowed() const;
+ virtual bool isScalingAllowed() const;
+ virtual bool isAlphaAllowed() const;
+ virtual bool isColorModulationAllowed() const;
+ virtual bool isSetContentAllowed() const;
- virtual bool persist(OutputPersistenceBlock &writer);
- virtual bool unpersist(InputPersistenceBlock &reader);
+ virtual bool persist(OutputPersistenceBlock &writer);
+ virtual bool unpersist(InputPersistenceBlock &reader);
protected:
- virtual bool doRender();
+ virtual bool doRender();
private:
DynamicBitmap(RenderObjectPtr<RenderObject> parentPtr, uint width, uint height);
diff --git a/engines/sword25/gfx/fontresource.cpp b/engines/sword25/gfx/fontresource.cpp
index 9f23133a71..dbb9c67fe5 100644
--- a/engines/sword25/gfx/fontresource.cpp
+++ b/engines/sword25/gfx/fontresource.cpp
@@ -34,38 +34,27 @@
#define BS_LOG_PREFIX "FONTRESOURCE"
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/kernel.h"
-#include "sword25/kernel/string.h"
#include "sword25/package/packagemanager.h"
#include "sword25/gfx/fontresource.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Konstanten
-// -----------------------------------------------------------------------------
-
-static const uint DEFAULT_LINEHEIGHT = 20;
-static const uint DEFAULT_GAPWIDTH = 1;
-
-// -----------------------------------------------------------------------------
-// Konstruktion / Destruktion
-// -----------------------------------------------------------------------------
+enum {
+ DEFAULT_LINEHEIGHT = 20,
+ DEFAULT_GAPWIDTH = 1
+};
-FontResource::FontResource(Kernel *pKernel, const Common::String &FileName) :
+FontResource::FontResource(Kernel *pKernel, const Common::String &fileName) :
_pKernel(pKernel),
- _Valid(false),
- Resource(FileName, Resource::TYPE_FONT),
+ _valid(false),
+ Resource(fileName, Resource::TYPE_FONT),
Common::XMLParser() {
// Get a pointer to the package manager
BS_ASSERT(_pKernel);
- PackageManager *pPackage = static_cast<PackageManager *>(_pKernel->GetService("package"));
+ PackageManager *pPackage = _pKernel->getPackage();
BS_ASSERT(pPackage);
// Load the contents of the file
@@ -80,73 +69,69 @@ FontResource::FontResource(Kernel *pKernel, const Common::String &FileName) :
if (!loadBuffer((const byte *)xmlData, fileSize))
return;
- _Valid = parse();
+ _valid = parse();
close();
free(xmlData);
}
-// -----------------------------------------------------------------------------
-
bool FontResource::parserCallback_font(ParserNode *node) {
// Get the attributes of the font
Common::String bitmapFilename = node->values["bitmap"];
- if (!parseIntegerKey(node->values["lineheight"].c_str(), 1, &_LineHeight)) {
+ if (!parseIntegerKey(node->values["lineheight"], 1, &_lineHeight)) {
BS_LOG_WARNINGLN("Illegal or missing lineheight attribute in <font> tag in \"%s\". Assuming default (\"%d\").",
getFileName().c_str(), DEFAULT_LINEHEIGHT);
- _LineHeight = DEFAULT_LINEHEIGHT;
+ _lineHeight = DEFAULT_LINEHEIGHT;
}
- if (!parseIntegerKey(node->values["gap"].c_str(), 1, &_GapWidth)) {
+ if (!parseIntegerKey(node->values["gap"], 1, &_gapWidth)) {
BS_LOG_WARNINGLN("Illegal or missing gap attribute in <font> tag in \"%s\". Assuming default (\"%d\").",
getFileName().c_str(), DEFAULT_GAPWIDTH);
- _GapWidth = DEFAULT_GAPWIDTH;
+ _gapWidth = DEFAULT_GAPWIDTH;
}
// Get a reference to the package manager
BS_ASSERT(_pKernel);
- PackageManager *pPackage = static_cast<PackageManager *>(_pKernel->GetService("package"));
+ PackageManager *pPackage = _pKernel->getPackage();
BS_ASSERT(pPackage);
// Get the full path and filename for the bitmap resource
- _BitmapFileName = pPackage->getAbsolutePath(bitmapFilename);
- if (_BitmapFileName == "") {
+ _bitmapFileName = pPackage->getAbsolutePath(bitmapFilename);
+ if (_bitmapFileName == "") {
BS_LOG_ERRORLN("Image file \"%s\" was specified in <font> tag of \"%s\" but could not be found.",
- _BitmapFileName.c_str(), getFileName().c_str());
+ _bitmapFileName.c_str(), getFileName().c_str());
}
// Pre-cache the resource
- if (!_pKernel->GetResourceManager()->PrecacheResource(_BitmapFileName)) {
- BS_LOG_ERRORLN("Could not precache \"%s\".", _BitmapFileName.c_str());
+ if (!_pKernel->getResourceManager()->precacheResource(_bitmapFileName)) {
+ BS_LOG_ERRORLN("Could not precache \"%s\".", _bitmapFileName.c_str());
}
return true;
}
-// -----------------------------------------------------------------------------
-
bool FontResource::parserCallback_character(ParserNode *node) {
// Get the attributes of the character
int charCode, top, left, right, bottom;
- if (!parseIntegerKey(node->values["code"].c_str(), 1, &charCode) || (charCode < 0) || (charCode >= 256)) {
+ if (!parseIntegerKey(node->values["code"], 1, &charCode) || (charCode < 0) || (charCode >= 256)) {
return parserError("Illegal or missing code attribute in <character> tag in \"%s\".", getFileName().c_str());
}
- if (!parseIntegerKey(node->values["top"].c_str(), 1, &top) || (top < 0)) {
+ if (!parseIntegerKey(node->values["top"], 1, &top) || (top < 0)) {
return parserError("Illegal or missing top attribute in <character> tag in \"%s\".", getFileName().c_str());
}
- if (!parseIntegerKey(node->values["left"].c_str(), 1, &left) || (left < 0)) {
+ if (!parseIntegerKey(node->values["left"], 1, &left) || (left < 0)) {
return parserError("Illegal or missing left attribute in <character> tag in \"%s\".", getFileName().c_str());
}
- if (!parseIntegerKey(node->values["right"].c_str(), 1, &right) || (right < 0)) {
+ if (!parseIntegerKey(node->values["right"], 1, &right) || (right < 0)) {
return parserError("Illegal or missing right attribute in <character> tag in \"%s\".", getFileName().c_str());
}
- if (!parseIntegerKey(node->values["bottom"].c_str(), 1, &bottom) || (bottom < 0)) {
+ if (!parseIntegerKey(node->values["bottom"], 1, &bottom) || (bottom < 0)) {
return parserError("Illegal or missing bottom attribute in <character> tag in \"%s\".", getFileName().c_str());
}
- this->_CharacterRects[charCode] = Common::Rect(left, top, right, bottom);
+ this->_characterRects[charCode] = Common::Rect(left, top, right, bottom);
return true;
}
diff --git a/engines/sword25/gfx/fontresource.h b/engines/sword25/gfx/fontresource.h
index cfb0251084..19c44d0ade 100644
--- a/engines/sword25/gfx/fontresource.h
+++ b/engines/sword25/gfx/fontresource.h
@@ -35,10 +35,6 @@
#ifndef SWORD25_FONTRESOURCE_H
#define SWORD25_FONTRESOURCE_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/xmlparser.h"
@@ -47,16 +43,8 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Forward declarations
-// -----------------------------------------------------------------------------
-
class Kernel;
-// -----------------------------------------------------------------------------
-// Klassendefinition
-// -----------------------------------------------------------------------------
-
class FontResource : public Resource, Common::XMLParser {
public:
/**
@@ -65,15 +53,15 @@ public:
@param FileName der Dateiname der zu ladenen Resource
@remark Wenn der Konstruktor erfolgreich ausgeführt werden konnte gibt die Methode IsValid true zurück.
*/
- FontResource(Kernel *pKernel, const Common::String &FileName);
+ FontResource(Kernel *pKernel, const Common::String &fileName);
/**
@brief Gibt true zurück, wenn das Objekt korrekt initialisiert wurde.
Diese Methode kann dazu benutzt werden um festzustellen, ob der Konstruktor erfolgreich ausgeführt wurde.
*/
- bool IsValid() const {
- return _Valid;
+ bool isValid() const {
+ return _valid;
}
/**
@@ -81,8 +69,8 @@ public:
Die Zeilenhöhe ist der Wert, der zur Y-Koordinate addiert wird, wenn ein Zeilenumbruch auftritt.
*/
- int GetLineHeight() const {
- return _LineHeight;
+ int getLineHeight() const {
+ return _lineHeight;
}
/**
@@ -90,8 +78,8 @@ public:
Der Buchstabenabstand ist der Wert, der zwischen zwei Buchstaben freigelassen wird.
*/
- int GetGapWidth() const {
- return _GapWidth;
+ int getGapWidth() const {
+ return _gapWidth;
}
/**
@@ -99,25 +87,25 @@ public:
@param Character der ASCII-Code des Zeichens
@return Das Bounding-Rect des übergebenen Zeichens auf der Charactermap.
*/
- const Common::Rect &GetCharacterRect(int Character) const {
- BS_ASSERT(Character >= 0 && Character < 256);
- return _CharacterRects[Character];
+ const Common::Rect &getCharacterRect(int character) const {
+ BS_ASSERT(character >= 0 && character < 256);
+ return _characterRects[character];
}
/**
@brief Gibt den Dateinamen der Charactermap zurück.
*/
- const Common::String &GetCharactermapFileName() const {
- return _BitmapFileName;
+ const Common::String &getCharactermapFileName() const {
+ return _bitmapFileName;
}
private:
Kernel *_pKernel;
- bool _Valid;
- Common::String _BitmapFileName;
- int _LineHeight;
- int _GapWidth;
- Common::Rect _CharacterRects[256];
+ bool _valid;
+ Common::String _bitmapFileName;
+ int _lineHeight;
+ int _gapWidth;
+ Common::Rect _characterRects[256];
// Parser
CUSTOM_XML_PARSER(FontResource) {
@@ -139,14 +127,6 @@ private:
// Parser callback methods
bool parserCallback_font(ParserNode *node);
bool parserCallback_character(ParserNode *node);
-
- // -----------------------------------------------------------------------------
- // Hilfsmethoden
- // -----------------------------------------------------------------------------
-
-// bool _ParseXMLDocument(const Common::String &FileName, TiXmlDocument &Doc) const;
-// bool _ParseFontTag(TiXmlElement &Tag, Common::String &BitmapFileName, int &LineHeight, int &GapWidth) const;
-// bool _ParseCharacterTag(TiXmlElement &Tag, int &Code, Common::Rect &Rect) const;
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/framecounter.cpp b/engines/sword25/gfx/framecounter.cpp
index 15bc7d00ea..07415cc2dc 100644
--- a/engines/sword25/gfx/framecounter.cpp
+++ b/engines/sword25/gfx/framecounter.cpp
@@ -37,30 +37,30 @@
namespace Sword25 {
-Framecounter::Framecounter(int UpdateFrequency) :
- m_FPS(0),
- m_FPSCount(0),
- m_LastUpdateTime(-1) {
- SetUpdateFrequency(UpdateFrequency);
+Framecounter::Framecounter(int updateFrequency) :
+ _FPS(0),
+ _FPSCount(0),
+ _lastUpdateTime(-1) {
+ setUpdateFrequency(updateFrequency);
}
-void Framecounter::Update() {
+void Framecounter::update() {
// Aktuellen Systemtimerstand auslesen
- uint64_t Timer = g_system->getMillis() * 1000;
+ uint64 timer = g_system->getMillis() * 1000;
// Falls m_LastUpdateTime == -1 ist, wird der Frame-Counter zum ersten Mal aufgerufen und der aktuelle Systemtimer als erster
// Messzeitpunkt genommen.
- if (m_LastUpdateTime == -1)
- m_LastUpdateTime = Timer;
+ if (_lastUpdateTime == -1)
+ _lastUpdateTime = timer;
else {
// Die Anzahl der Frames im aktuellen Messzeitraum wird erhöht.
- m_FPSCount++;
+ _FPSCount++;
// Falls der Messzeitraum verstrichen ist, wird die durchschnittliche Framerate berechnet und ein neuer Messzeitraum begonnen.
- if (Timer - m_LastUpdateTime >= m_UpdateDelay) {
- m_FPS = static_cast<int>((1000000 * (uint64_t)m_FPSCount) / (Timer - m_LastUpdateTime));
- m_LastUpdateTime = Timer;
- m_FPSCount = 0;
+ if (timer - _lastUpdateTime >= _updateDelay) {
+ _FPS = static_cast<int>((1000000 * (uint64)_FPSCount) / (timer - _lastUpdateTime));
+ _lastUpdateTime = timer;
+ _FPSCount = 0;
}
}
}
diff --git a/engines/sword25/gfx/framecounter.h b/engines/sword25/gfx/framecounter.h
index 8a8402a3bb..994950573f 100644
--- a/engines/sword25/gfx/framecounter.h
+++ b/engines/sword25/gfx/framecounter.h
@@ -37,7 +37,6 @@
// Includes
#include "sword25/kernel/common.h"
-#include "sword25/kernel/bs_stdint.h"
namespace Sword25 {
@@ -46,6 +45,12 @@ namespace Sword25 {
*/
class Framecounter {
private:
+
+ // TODO: This class should be rewritten based on Audio::Timestamp,
+ // which provides higher accuracy and avoids using 64 bit data types.
+ typedef unsigned long long uint64;
+ typedef signed long long int64;
+
enum {
DEFAULT_UPDATE_FREQUENCY = 10
};
@@ -56,37 +61,37 @@ public:
* @param UpdateFrequency Specifies how often the frame counter should be updated in a sceond.
* The default value is 10.
*/
- Framecounter(int UpdateFrequency = DEFAULT_UPDATE_FREQUENCY);
+ Framecounter(int updateFrequency = DEFAULT_UPDATE_FREQUENCY);
/**
* Determines how often the frame counter should be updated in a second.
* @param UpdateFrequency Specifies how often the frame counter should be updated in a second.
*/
- inline void SetUpdateFrequency(int UpdateFrequency);
+ inline void setUpdateFrequency(int updateFrequency);
/**
* This method must be called once per frame.
*/
- void Update();
+ void update();
/**
* Returns the current FPS value.
*/
- int GetFPS() const {
- return m_FPS;
+ int getFPS() const {
+ return _FPS;
}
private:
- int m_FPS;
- int m_FPSCount;
- int64_t m_LastUpdateTime;
- uint64_t m_UpdateDelay;
+ int _FPS;
+ int _FPSCount;
+ int64 _lastUpdateTime;
+ uint64 _updateDelay;
};
// Inlines
-void Framecounter::SetUpdateFrequency(int UpdateFrequency) {
+void Framecounter::setUpdateFrequency(int updateFrequency) {
// Frequency in time (converted to microseconds)
- m_UpdateDelay = 1000000 / UpdateFrequency;
+ _updateDelay = 1000000 / updateFrequency;
}
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp
index ea0c8c82c5..44b9932de1 100644
--- a/engines/sword25/gfx/graphicengine.cpp
+++ b/engines/sword25/gfx/graphicengine.cpp
@@ -52,108 +52,90 @@
#include "sword25/gfx/graphicengine.h"
-namespace Lua {
-extern "C"
-{
#include "sword25/util/lua/lua.h"
#include "sword25/util/lua/lauxlib.h"
-}
-}
-
-namespace {
-const int BIT_DEPTH = 32;
-const int BACKBUFFER_COUNT = 1;
-const Common::String PNG_EXTENSION(".png");
-const Common::String PNG_S_EXTENSION("_s.png");
-const Common::String ANI_EXTENSION("_ani.xml");
-const Common::String FNT_EXTENSION("_fnt.xml");
-const Common::String SWF_EXTENSION(".swf");
-const Common::String B25S_EXTENSION(".b25s");
-}
+enum {
+ BIT_DEPTH = 32,
+ BACKBUFFER_COUNT = 1
+};
namespace Sword25 {
-using namespace Lua;
-
static const uint FRAMETIME_SAMPLE_COUNT = 5; // Anzahl der Framezeiten über die, die Framezeit gemittelt wird
GraphicEngine::GraphicEngine(Kernel *pKernel) :
- m_Width(0),
- m_Height(0),
- m_BitDepth(0),
- m_Windowed(0),
- m_LastTimeStamp((uint64) - 1), // max. BS_INT64 um beim ersten Aufruf von _UpdateLastFrameDuration() einen Reset zu erzwingen
- m_LastFrameDuration(0),
- m_TimerActive(true),
- m_FrameTimeSampleSlot(0),
- m_RepaintedPixels(0),
+ _width(0),
+ _height(0),
+ _bitDepth(0),
+ _windowed(0),
+ _lastTimeStamp((uint) -1), // max. BS_INT64 um beim ersten Aufruf von _UpdateLastFrameDuration() einen Reset zu erzwingen
+ _lastFrameDuration(0),
+ _timerActive(true),
+ _frameTimeSampleSlot(0),
+ _repaintedPixels(0),
_thumbnail(NULL),
ResourceService(pKernel) {
- m_FrameTimeSamples.resize(FRAMETIME_SAMPLE_COUNT);
+ _frameTimeSamples.resize(FRAMETIME_SAMPLE_COUNT);
- if (!RegisterScriptBindings())
+ if (!registerScriptBindings())
BS_LOG_ERRORLN("Script bindings could not be registered.");
else
BS_LOGLN("Script bindings registered.");
}
GraphicEngine::~GraphicEngine() {
+ unregisterScriptBindings();
_backSurface.free();
_frameBuffer.free();
delete _thumbnail;
}
-Service *GraphicEngine_CreateObject(Kernel *pKernel) {
- return new GraphicEngine(pKernel);
-}
-
-bool GraphicEngine::Init(int Width, int Height, int BitDepth, int BackbufferCount, bool Windowed) {
+bool GraphicEngine::init(int width, int height, int bitDepth, int backbufferCount, bool isWindowed_) {
// Warnung ausgeben, wenn eine nicht unterstützte Bittiefe gewählt wurde.
- if (BitDepth != BIT_DEPTH) {
- BS_LOG_WARNINGLN("Can't use a bit depth of %d (not supported). Falling back to %d.", BitDepth, BIT_DEPTH);
- m_BitDepth = BIT_DEPTH;
+ if (bitDepth != BIT_DEPTH) {
+ BS_LOG_WARNINGLN("Can't use a bit depth of %d (not supported). Falling back to %d.", bitDepth, BIT_DEPTH);
+ _bitDepth = BIT_DEPTH;
}
// Warnung ausgeben, wenn nicht genau ein Backbuffer gewählt wurde.
- if (BackbufferCount != BACKBUFFER_COUNT) {
- BS_LOG_WARNINGLN("Can't use %d backbuffers (not supported). Falling back to %d.", BackbufferCount, BACKBUFFER_COUNT);
- BackbufferCount = BACKBUFFER_COUNT;
+ if (backbufferCount != BACKBUFFER_COUNT) {
+ BS_LOG_WARNINGLN("Can't use %d backbuffers (not supported). Falling back to %d.", backbufferCount, BACKBUFFER_COUNT);
+ backbufferCount = BACKBUFFER_COUNT;
}
// Parameter in lokale Variablen kopieren
- m_Width = Width;
- m_Height = Height;
- m_BitDepth = BitDepth;
- m_Windowed = Windowed;
- m_ScreenRect.left = 0;
- m_ScreenRect.top = 0;
- m_ScreenRect.right = m_Width;
- m_ScreenRect.bottom = m_Height;
-
- _backSurface.create(Width, Height, 4);
- _frameBuffer.create(Width, Height, 4);
+ _width = width;
+ _height = height;
+ _bitDepth = bitDepth;
+ _windowed = isWindowed_;
+ _screenRect.left = 0;
+ _screenRect.top = 0;
+ _screenRect.right = _width;
+ _screenRect.bottom = _height;
+
+ _backSurface.create(width, height, 4);
+ _frameBuffer.create(width, height, 4);
// Standardmäßig ist Vsync an.
- SetVsync(true);
+ setVsync(true);
// Layer-Manager initialisieren.
- _renderObjectManagerPtr.reset(new RenderObjectManager(Width, Height, BackbufferCount + 1));
+ _renderObjectManagerPtr.reset(new RenderObjectManager(width, height, backbufferCount + 1));
// Hauptpanel erstellen
- m_MainPanelPtr = _renderObjectManagerPtr->getTreeRoot()->addPanel(Width, Height, BS_ARGB(0, 0, 0, 0));
- if (!m_MainPanelPtr.isValid()) return false;
- m_MainPanelPtr->setVisible(true);
+ _mainPanelPtr = _renderObjectManagerPtr->getTreeRoot()->addPanel(width, height, BS_ARGB(0, 0, 0, 0));
+ if (!_mainPanelPtr.isValid())
+ return false;
+ _mainPanelPtr->setVisible(true);
return true;
}
-// -----------------------------------------------------------------------------
-
-bool GraphicEngine::StartFrame(bool UpdateAll) {
+bool GraphicEngine::startFrame(bool updateAll) {
// Berechnen, wie viel Zeit seit dem letzten Frame vergangen ist.
// Dieser Wert kann über GetLastFrameDuration() von Modulen abgefragt werden, die zeitabhängig arbeiten.
- UpdateLastFrameDuration();
+ updateLastFrameDuration();
// Den Layer-Manager auf den nächsten Frame vorbereiten
_renderObjectManagerPtr->startFrame();
@@ -161,9 +143,7 @@ bool GraphicEngine::StartFrame(bool UpdateAll) {
return true;
}
-// -----------------------------------------------------------------------------
-
-bool GraphicEngine::EndFrame() {
+bool GraphicEngine::endFrame() {
// Scene zeichnen
_renderObjectManagerPtr->render();
@@ -179,7 +159,7 @@ bool GraphicEngine::EndFrame() {
g_system->updateScreen();
// Debug-Lines zeichnen
- if (!m_DebugLines.empty()) {
+ if (!_debugLines.empty()) {
#if 0
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINES);
@@ -201,55 +181,76 @@ bool GraphicEngine::EndFrame() {
warning("STUB: Drawing debug lines");
- m_DebugLines.clear();
+ _debugLines.clear();
}
// Framecounter aktualisieren
- m_FPSCounter.Update();
+ _FPSCounter.update();
return true;
}
-// -----------------------------------------------------------------------------
-
-RenderObjectPtr<Panel> GraphicEngine::GetMainPanel() {
- return m_MainPanelPtr;
+RenderObjectPtr<Panel> GraphicEngine::getMainPanel() {
+ return _mainPanelPtr;
}
-// -----------------------------------------------------------------------------
-
-void GraphicEngine::SetVsync(bool Vsync) {
- warning("STUB: SetVsync(%d)", Vsync);
+void GraphicEngine::setVsync(bool vsync) {
+ warning("STUB: SetVsync(%d)", vsync);
}
-// -----------------------------------------------------------------------------
-
-bool GraphicEngine::GetVsync() const {
- warning("STUB: GetVsync()");
+bool GraphicEngine::getVsync() const {
+ warning("STUB: getVsync()");
return true;
}
-// -----------------------------------------------------------------------------
-
bool GraphicEngine::fill(const Common::Rect *fillRectPtr, uint color) {
- Common::Rect rect(m_Width - 1, m_Height - 1);
+ Common::Rect rect(_width - 1, _height - 1);
+
+ int ca = (color >> 24) & 0xff;
+
+ if (ca == 0)
+ return true;
+
+ int cr = (color >> 16) & 0xff;
+ int cg = (color >> 8) & 0xff;
+ int cb = (color >> 0) & 0xff;
if (fillRectPtr) {
rect = *fillRectPtr;
}
- if (fillRectPtr->width() > 0 && fillRectPtr->height() > 0) {
- _backSurface.fillRect(rect, color);
- g_system->copyRectToScreen((byte *)_backSurface.getBasePtr(fillRectPtr->left, fillRectPtr->top), _backSurface.pitch, fillRectPtr->left, fillRectPtr->top, fillRectPtr->width(), fillRectPtr->height());
+ if (rect.width() > 0 && rect.height() > 0) {
+ if (ca == 0xff) {
+ _backSurface.fillRect(rect, color);
+ } else {
+ byte *outo = (byte *)_backSurface.getBasePtr(rect.left, rect.top);
+ byte *out;
+
+ for (int i = rect.top; i < rect.bottom; i++) {
+ out = outo;
+ for (int j = rect.left; j < rect.right; j++) {
+ *out += (byte)(((cb - *out) * ca) >> 8);
+ out++;
+ *out += (byte)(((cg - *out) * ca) >> 8);
+ out++;
+ *out += (byte)(((cr - *out) * ca) >> 8);
+ out++;
+ *out = 255;
+ out++;
+ }
+
+ outo += _backSurface.pitch;
+ }
+ }
+
+ g_system->copyRectToScreen((byte *)_backSurface.getBasePtr(rect.left, rect.top), _backSurface.pitch, rect.left, rect.top, rect.width(), rect.height());
}
return true;
}
-// -----------------------------------------------------------------------------
-
-Graphics::Surface *GraphicEngine::GetScreenshot() {
+Graphics::Surface *GraphicEngine::getScreenshot() {
return &_frameBuffer;
}
@@ -257,19 +258,19 @@ Graphics::Surface *GraphicEngine::GetScreenshot() {
// RESOURCE MANAGING
// -----------------------------------------------------------------------------
-Resource *GraphicEngine::loadResource(const Common::String &FileName) {
- BS_ASSERT(canLoadResource(FileName));
+Resource *GraphicEngine::loadResource(const Common::String &filename) {
+ BS_ASSERT(canLoadResource(filename));
- // Bild für den Softwarebuffer laden
- if (FileName.hasSuffix(PNG_S_EXTENSION)) {
- bool Result = false;
- SWImage *pImage = new SWImage(FileName, Result);
- if (!Result) {
+ // Load image for "software buffer" (FIXME: Whatever that means?)
+ if (filename.hasSuffix("_s.png")) {
+ bool result = false;
+ SWImage *pImage = new SWImage(filename, result);
+ if (!result) {
delete pImage;
return 0;
}
- BitmapResource *pResource = new BitmapResource(FileName, pImage);
+ BitmapResource *pResource = new BitmapResource(filename, pImage);
if (!pResource->isValid()) {
delete pResource;
return 0;
@@ -278,16 +279,16 @@ Resource *GraphicEngine::loadResource(const Common::String &FileName) {
return pResource;
}
- // Sprite-Bild laden
- if (FileName.hasSuffix(PNG_EXTENSION) || FileName.hasSuffix(B25S_EXTENSION)) {
- bool Result = false;
- RenderedImage *pImage = new RenderedImage(FileName, Result);
- if (!Result) {
+ // Load sprite image
+ if (filename.hasSuffix(".png") || filename.hasSuffix(".b25s")) {
+ bool result = false;
+ RenderedImage *pImage = new RenderedImage(filename, result);
+ if (!result) {
delete pImage;
return 0;
}
- BitmapResource *pResource = new BitmapResource(FileName, pImage);
+ BitmapResource *pResource = new BitmapResource(filename, pImage);
if (!pResource->isValid()) {
delete pResource;
return 0;
@@ -297,31 +298,32 @@ Resource *GraphicEngine::loadResource(const Common::String &FileName) {
}
- // Vectorgraphik laden
- if (FileName.hasSuffix(SWF_EXTENSION)) {
- debug(2, "VectorImage: %s", FileName.c_str());
+ // Load vector graphics
+ if (filename.hasSuffix(".swf")) {
+ debug(2, "VectorImage: %s", filename.c_str());
// Pointer auf Package-Manager holen
- PackageManager *pPackage = Kernel::GetInstance()->GetPackage();
+ PackageManager *pPackage = Kernel::getInstance()->getPackage();
BS_ASSERT(pPackage);
// Datei laden
byte *pFileData;
- uint FileSize;
- if (!(pFileData = static_cast<byte *>(pPackage->getFile(FileName, &FileSize)))) {
- BS_LOG_ERRORLN("File \"%s\" could not be loaded.", FileName.c_str());
+ uint fileSize;
+ pFileData = pPackage->getFile(filename, &fileSize);
+ if (!pFileData) {
+ BS_LOG_ERRORLN("File \"%s\" could not be loaded.", filename.c_str());
return 0;
}
- bool Result = false;
- VectorImage *pImage = new VectorImage(pFileData, FileSize, Result, FileName);
- if (!Result) {
+ bool result = false;
+ VectorImage *pImage = new VectorImage(pFileData, fileSize, result, filename);
+ if (!result) {
delete pImage;
- delete [] pFileData;
+ delete[] pFileData;
return 0;
}
- BitmapResource *pResource = new BitmapResource(FileName, pImage);
+ BitmapResource *pResource = new BitmapResource(filename, pImage);
if (!pResource->isValid()) {
delete pResource;
delete[] pFileData;
@@ -332,9 +334,9 @@ Resource *GraphicEngine::loadResource(const Common::String &FileName) {
return pResource;
}
- // Animation laden
- if (FileName.hasSuffix(ANI_EXTENSION)) {
- AnimationResource *pResource = new AnimationResource(FileName);
+ // Load animation
+ if (filename.hasSuffix("_ani.xml")) {
+ AnimationResource *pResource = new AnimationResource(filename);
if (pResource->isValid())
return pResource;
else {
@@ -343,10 +345,10 @@ Resource *GraphicEngine::loadResource(const Common::String &FileName) {
}
}
- // Font laden
- if (FileName.hasSuffix(FNT_EXTENSION)) {
- FontResource *pResource = new FontResource(Kernel::GetInstance(), FileName);
- if (pResource->IsValid())
+ // Load font
+ if (filename.hasSuffix("_fnt.xml")) {
+ FontResource *pResource = new FontResource(Kernel::getInstance(), filename);
+ if (pResource->isValid())
return pResource;
else {
delete pResource;
@@ -354,18 +356,18 @@ Resource *GraphicEngine::loadResource(const Common::String &FileName) {
}
}
- BS_LOG_ERRORLN("Service cannot load \"%s\".", FileName.c_str());
+ BS_LOG_ERRORLN("Service cannot load \"%s\".", filename.c_str());
return 0;
}
// -----------------------------------------------------------------------------
-bool GraphicEngine::canLoadResource(const Common::String &FileName) {
- return FileName.hasSuffix(PNG_EXTENSION) ||
- FileName.hasSuffix(ANI_EXTENSION) ||
- FileName.hasSuffix(FNT_EXTENSION) ||
- FileName.hasSuffix(SWF_EXTENSION) ||
- FileName.hasSuffix(B25S_EXTENSION);
+bool GraphicEngine::canLoadResource(const Common::String &filename) {
+ return filename.hasSuffix(".png") ||
+ filename.hasSuffix("_ani.xml") ||
+ filename.hasSuffix("_fnt.xml") ||
+ filename.hasSuffix(".swf") ||
+ filename.hasSuffix(".b25s");
}
@@ -373,57 +375,33 @@ bool GraphicEngine::canLoadResource(const Common::String &FileName) {
// DEBUGGING
// -----------------------------------------------------------------------------
-void GraphicEngine::DrawDebugLine(const Vertex &Start, const Vertex &End, uint Color) {
- m_DebugLines.push_back(DebugLine(Start, End, Color));
+void GraphicEngine::drawDebugLine(const Vertex &start, const Vertex &end, uint color) {
+ _debugLines.push_back(DebugLine(start, end, color));
}
-void GraphicEngine::UpdateLastFrameDuration() {
- // Aktuelle Zeit holen
- uint64_t CurrentTime = Kernel::GetInstance()->GetMicroTicks();
-
- // Verstrichene Zeit seit letztem Frame berechnen und zu große Zeitsprünge ( > 250 msek.) unterbinden
- // (kann vorkommen bei geladenen Spielständen, während des Debuggings oder Hardwareungenauigkeiten)
- m_FrameTimeSamples[m_FrameTimeSampleSlot] = static_cast<uint>(CurrentTime - m_LastTimeStamp);
- if (m_FrameTimeSamples[m_FrameTimeSampleSlot] > 250000) m_FrameTimeSamples[m_FrameTimeSampleSlot] = 250000;
- m_FrameTimeSampleSlot = (m_FrameTimeSampleSlot + 1) % FRAMETIME_SAMPLE_COUNT;
-
- // Die Framezeit wird über mehrere Frames gemittelt um Ausreisser zu eliminieren
- Common::Array<uint>::const_iterator it = m_FrameTimeSamples.begin();
- uint Sum = *it;
- for (it++; it != m_FrameTimeSamples.end(); it++) Sum += *it;
- m_LastFrameDuration = Sum / FRAMETIME_SAMPLE_COUNT;
-
- // _LastTimeStamp auf die Zeit des aktuellen Frames setzen
- m_LastTimeStamp = CurrentTime;
+void GraphicEngine::updateLastFrameDuration() {
+ // Record current time
+ const uint currentTime = Kernel::getInstance()->getMilliTicks();
+
+ // Compute the elapsed time since the last frame and prevent too big ( > 250 msecs) time jumps.
+ // These can occur when loading save states, during debugging or due to hardware inaccuracies.
+ _frameTimeSamples[_frameTimeSampleSlot] = static_cast<uint>(currentTime - _lastTimeStamp);
+ if (_frameTimeSamples[_frameTimeSampleSlot] > 250000)
+ _frameTimeSamples[_frameTimeSampleSlot] = 250000;
+ _frameTimeSampleSlot = (_frameTimeSampleSlot + 1) % FRAMETIME_SAMPLE_COUNT;
+
+ // Compute the average frame duration over multiple frames to eliminate outliers.
+ Common::Array<uint>::const_iterator it = _frameTimeSamples.begin();
+ uint sum = *it;
+ for (it++; it != _frameTimeSamples.end(); it++)
+ sum += *it;
+ _lastFrameDuration = sum * 1000 / FRAMETIME_SAMPLE_COUNT;
+
+ // Update m_LastTimeStamp with the current frame's timestamp
+ _lastTimeStamp = currentTime;
}
-namespace {
-bool DoSaveScreenshot(GraphicEngine &GraphicEngine, const Common::String &Filename) {
- Graphics::Surface *data = GraphicEngine.GetScreenshot();
- if (!data) {
- BS_LOG_ERRORLN("Call to GetScreenshot() failed. Cannot save screenshot.");
- return false;
- }
-
- Common::FSNode f(Filename);
- Common::WriteStream *stream = f.createWriteStream();
- if (!stream) {
- BS_LOG_ERRORLN("Call to GetScreenshot() failed. Cannot save screenshot.");
- return false;
- }
-
- bool result = Screenshot::SaveToFile(data, stream);
- delete stream;
-
- return result;
-}
-}
-
-bool GraphicEngine::SaveScreenshot(const Common::String &Filename) {
- return DoSaveScreenshot(*this, Filename);
-}
-
-bool GraphicEngine::SaveThumbnailScreenshot(const Common::String &Filename) {
+bool GraphicEngine::saveThumbnailScreenshot(const Common::String &filename) {
// Note: In ScumMVM, rather than saivng the thumbnail to a file, we store it in memory
// until needed when creating savegame files
delete _thumbnail;
@@ -431,59 +409,64 @@ bool GraphicEngine::SaveThumbnailScreenshot(const Common::String &Filename) {
return true;
}
-void GraphicEngine::ARGBColorToLuaColor(lua_State *L, uint Color) {
- lua_Number Components[4] = {
- (Color >> 16) & 0xff, // Rot
- (Color >> 8) & 0xff, // Grün
- Color & 0xff, // Blau
- Color >> 24, // Alpha
+void GraphicEngine::ARGBColorToLuaColor(lua_State *L, uint color) {
+ lua_Number components[4] = {
+ (color >> 16) & 0xff, // Rot
+ (color >> 8) & 0xff, // Grün
+ color & 0xff, // Blau
+ color >> 24, // Alpha
};
lua_newtable(L);
for (uint i = 1; i <= 4; i++) {
lua_pushnumber(L, i);
- lua_pushnumber(L, Components[i - 1]);
+ lua_pushnumber(L, components[i - 1]);
lua_settable(L, -3);
}
}
-uint GraphicEngine::LuaColorToARGBColor(lua_State *L, int StackIndex) {
+uint GraphicEngine::luaColorToARGBColor(lua_State *L, int stackIndex) {
#ifdef DEBUG
int __startStackDepth = lua_gettop(L);
#endif
// Sicherstellen, dass wir wirklich eine Tabelle betrachten
- luaL_checktype(L, StackIndex, LUA_TTABLE);
+ luaL_checktype(L, stackIndex, LUA_TTABLE);
// Größe der Tabelle auslesen
- uint n = luaL_getn(L, StackIndex);
+ uint n = luaL_getn(L, stackIndex);
// RGB oder RGBA Farben werden unterstützt und sonst keine
- if (n != 3 && n != 4) luaL_argcheck(L, 0, StackIndex, "at least 3 of the 4 color components have to be specified");
-
- // Rote Farbkomponente auslesen
- lua_rawgeti(L, StackIndex, 1);
- uint Red = static_cast<uint>(lua_tonumber(L, -1));
- if (!lua_isnumber(L, -1) || Red >= 256) luaL_argcheck(L, 0, StackIndex, "red color component must be an integer between 0 and 255");
+ if (n != 3 && n != 4)
+ luaL_argcheck(L, 0, stackIndex, "at least 3 of the 4 color components have to be specified");
+
+ // Red color component reading
+ lua_rawgeti(L, stackIndex, 1);
+ uint red = static_cast<uint>(lua_tonumber(L, -1));
+ if (!lua_isnumber(L, -1) || red >= 256)
+ luaL_argcheck(L, 0, stackIndex, "red color component must be an integer between 0 and 255");
lua_pop(L, 1);
- // Grüne Farbkomponente auslesen
- lua_rawgeti(L, StackIndex, 2);
- uint Green = static_cast<uint>(lua_tonumber(L, -1));
- if (!lua_isnumber(L, -1) || Green >= 256) luaL_argcheck(L, 0, StackIndex, "green color component must be an integer between 0 and 255");
+ // Green color component reading
+ lua_rawgeti(L, stackIndex, 2);
+ uint green = static_cast<uint>(lua_tonumber(L, -1));
+ if (!lua_isnumber(L, -1) || green >= 256)
+ luaL_argcheck(L, 0, stackIndex, "green color component must be an integer between 0 and 255");
lua_pop(L, 1);
- // Blaue Farbkomponente auslesen
- lua_rawgeti(L, StackIndex, 3);
- uint Blue = static_cast<uint>(lua_tonumber(L, -1));
- if (!lua_isnumber(L, -1) || Blue >= 256) luaL_argcheck(L, 0, StackIndex, "blue color component must be an integer between 0 and 255");
+ // Blue color component reading
+ lua_rawgeti(L, stackIndex, 3);
+ uint blue = static_cast<uint>(lua_tonumber(L, -1));
+ if (!lua_isnumber(L, -1) || blue >= 256)
+ luaL_argcheck(L, 0, stackIndex, "blue color component must be an integer between 0 and 255");
lua_pop(L, 1);
- // Alpha Farbkomponente auslesen
- uint Alpha = 0xff;
+ // Alpha color component reading
+ uint alpha = 0xff;
if (n == 4) {
- lua_rawgeti(L, StackIndex, 4);
- Alpha = static_cast<uint>(lua_tonumber(L, -1));
- if (!lua_isnumber(L, -1) || Alpha >= 256) luaL_argcheck(L, 0, StackIndex, "alpha color component must be an integer between 0 and 255");
+ lua_rawgeti(L, stackIndex, 4);
+ alpha = static_cast<uint>(lua_tonumber(L, -1));
+ if (!lua_isnumber(L, -1) || alpha >= 256)
+ luaL_argcheck(L, 0, stackIndex, "alpha color component must be an integer between 0 and 255");
lua_pop(L, 1);
}
@@ -491,11 +474,11 @@ uint GraphicEngine::LuaColorToARGBColor(lua_State *L, int StackIndex) {
BS_ASSERT(__startStackDepth == lua_gettop(L));
#endif
- return (Alpha << 24) | (Red << 16) | (Green << 8) | Blue;
+ return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
bool GraphicEngine::persist(OutputPersistenceBlock &writer) {
- writer.write(m_TimerActive);
+ writer.write(_timerActive);
bool result = _renderObjectManagerPtr->persist(writer);
@@ -503,7 +486,7 @@ bool GraphicEngine::persist(OutputPersistenceBlock &writer) {
}
bool GraphicEngine::unpersist(InputPersistenceBlock &reader) {
- reader.read(m_TimerActive);
+ reader.read(_timerActive);
_renderObjectManagerPtr->unpersist(reader);
return reader.isGood();
diff --git a/engines/sword25/gfx/graphicengine.h b/engines/sword25/gfx/graphicengine.h
index 019f5eec4c..e1ae0d2d62 100644
--- a/engines/sword25/gfx/graphicengine.h
+++ b/engines/sword25/gfx/graphicengine.h
@@ -33,7 +33,7 @@
*/
/*
- * BS_GraphicEngine
+ * GraphicEngine
* ----------------
* This the graphics engine interface.
*
@@ -46,10 +46,10 @@
// Includes
#include "common/array.h"
#include "common/rect.h"
+#include "common/ptr.h"
#include "common/str.h"
#include "graphics/surface.h"
#include "sword25/kernel/common.h"
-#include "sword25/kernel/bs_stdint.h"
#include "sword25/kernel/resservice.h"
#include "sword25/kernel/persistable.h"
#include "sword25/gfx/framecounter.h"
@@ -64,21 +64,16 @@ class Panel;
class Screenshot;
class RenderObjectManager;
-// Typen
typedef uint BS_COLOR;
-// Makros
#define BS_RGB(R,G,B) (0xFF000000 | ((R) << 16) | ((G) << 8) | (B))
#define BS_ARGB(A,R,G,B) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B))
/**
- @brief Dies ist das Graphik-Engine Interface, dass alle Methoden und Klassen enthält, die eine Graphik-Engine implementieren muss.
-
- Hier sind nur wenige Rumpffunktionen realisiert, wie z.B. das Abfragen der Parameter des Ausgabepuffers.
- Die Hauptfunktionen muss eine Implementation dieses Inferfaces stellen.<br>
- Die bisher einzige Implementation ist BS_DDrawGfx.
-*/
-
+ * This is the graphics engine. Unlike the original code, this is not
+ * an interface that needs to be subclassed, but rather already contains
+ * all required functionality.
+ */
class GraphicEngine : public ResourceService, public Persistable {
public:
// Enums
@@ -115,15 +110,17 @@ public:
// ---------
/**
- * Initialises the graphics engine and sets the screen mode. Returns true if initialisation failed.
- * Notes: This method should be called immediately after the initialisation of all services.
+ * Initialises the graphics engine and sets the screen mode. Returns
+ * true if initialisation failed.
+ * @note This method should be called immediately after the
+ * initialisation of all services.
*
* @param Height The height of the output buffer in pixels. The default value is 600
* @param BitDepth The bit depth of the desired output buffer in bits. The default value is 16
* @param BackbufferCount The number of back buffers to be created. The default value is 2
* @param Windowed Indicates whether the engine is to run in windowed mode.
*/
- bool Init(int Width = 800, int Height = 600, int BitDepth = 16, int BackbufferCount = 2, bool Windowed = false);
+ bool init(int width = 800, int height = 600, int bitDepth = 16, int backbufferCount = 2, bool windowed = false);
/**
* Begins rendering a new frame.
@@ -132,7 +129,7 @@ public:
* @param UpdateAll Specifies whether the renderer should redraw everything on the next frame.
* This feature can be useful if the renderer with Dirty Rectangles works, but sometimes the client may
*/
- bool StartFrame(bool UpdateAll = false);
+ bool startFrame(bool updateAll = false);
/**
* Ends the rendering of a frame and draws it on the screen.
@@ -140,7 +137,7 @@ public:
* This method must be at the end of the main loop. After this call, no further Render method may be called.
* This should only be called once for a given previous call to #StartFrame.
*/
- bool EndFrame();
+ bool endFrame();
// Debug methods
@@ -154,15 +151,7 @@ public:
* @param End The ending point of the line
* @param Color The colour of the line. The default is BS_RGB (255,255,255) (White)
*/
- void DrawDebugLine(const Vertex &Start, const Vertex &End, uint Color = BS_RGB(255, 255, 255));
-
- /**
- * Creates a screenshot of the current frame buffer and writes it to a graphic file in PNG format.
- * Returns true if the screenshot was saved successfully.
- * Notes: This method should only be called after a call to EndFrame(), and before the next call to StartFrame().
- * @param Filename The filename for the screenshot
- */
- bool SaveScreenshot(const Common::String &Filename);
+ void drawDebugLine(const Vertex &start, const Vertex &end, uint color = BS_RGB(255, 255, 255));
/**
* Creates a thumbnail with the dimensions of 200x125. This will not include the top and bottom of the screen..
@@ -171,7 +160,7 @@ public:
* The frame buffer must have a resolution of 800x600.
* @param Filename The filename for the screenshot
*/
- bool SaveThumbnailScreenshot(const Common::String &Filename);
+ bool saveThumbnailScreenshot(const Common::String &filename);
/**
* Reads the current contents of the frame buffer
@@ -181,35 +170,39 @@ public:
* @param Height Returns the height of the frame buffer
* @param Data Returns the raw data of the frame buffer as an array of 32-bit colour values.
*/
- Graphics::Surface *GetScreenshot();
+ Graphics::Surface *getScreenshot();
- RenderObjectPtr<Panel> GetMainPanel();
+ RenderObjectPtr<Panel> getMainPanel();
/**
* Specifies the time (in microseconds) since the last frame has passed
*/
- int GetLastFrameDurationMicro() {
- if (m_TimerActive) return m_LastFrameDuration;
- else return 0;
+ int getLastFrameDurationMicro() const {
+ if (!_timerActive)
+ return 0;
+ return _lastFrameDuration;
}
/**
* Specifies the time (in microseconds) the previous frame took
*/
- float GetLastFrameDuration() {
- if (m_TimerActive) return static_cast<float>(m_LastFrameDuration) / 1000000.0f;
- else return 0;
+ float getLastFrameDuration() const {
+ if (!_timerActive)
+ return 0;
+ return static_cast<float>(_lastFrameDuration) / 1000000.0f;
}
- void StopMainTimer() {
- m_TimerActive = false;
+ void stopMainTimer() {
+ _timerActive = false;
}
- void ResumeMainTimer() {
- m_TimerActive = true;
+
+ void resumeMainTimer() {
+ _timerActive = true;
}
- float GetSecondaryFrameDuration() {
- return static_cast<float>(m_LastFrameDuration) / 1000000.0f;
+
+ float getSecondaryFrameDuration() const {
+ return static_cast<float>(_lastFrameDuration) / 1000000.0f;
}
// Accessor methods
@@ -217,29 +210,29 @@ public:
/**
* Returns the width of the output buffer in pixels
*/
- int GetDisplayWidth() {
- return m_Width;
+ int getDisplayWidth() const {
+ return _width;
}
/**
* Returns the height of the output buffer in pixels
*/
- int GetDisplayHeight() {
- return m_Height;
+ int getDisplayHeight() const {
+ return _height;
}
/**
* Returns the bounding box of the output buffer: (0, 0, Width, Height)
*/
- Common::Rect &GetDisplayRect() {
- return m_ScreenRect;
+ Common::Rect &getDisplayRect() {
+ return _screenRect;
}
/**
* Returns the bit depth of the output buffer
*/
- int GetBitDepth() {
- return m_BitDepth;
+ int getBitDepth() {
+ return _bitDepth;
}
/**
@@ -247,19 +240,19 @@ public:
* Notes: In windowed mode, this setting has no effect.
* @param Vsync Indicates whether the frame buffer changes are to be synchronised with Vsync.
*/
- void SetVsync(bool Vsync);
+ void setVsync(bool vsync);
/**
* Returns true if V-Sync is on.
* Notes: In windowed mode, this setting has no effect.
*/
- bool GetVsync() const;
+ bool getVsync() const;
/**
* Returns true if the engine is running in Windowed mode.
*/
- bool IsWindowed() {
- return m_Windowed;
+ bool isWindowed() {
+ return _windowed;
}
/**
@@ -269,17 +262,17 @@ public:
* If the rectangle falls partly off-screen, then it is automatically trimmed.
* If a NULL value is passed, then the entire image is to be filled.
* @param Color The 32-bit colour with which the area is to be filled. The default is BS_RGB(0, 0, 0) (black)
- @remark Falls das Rechteck nicht völlig innerhalb des Bildschirms ist, wird es automatisch zurechtgestutzt.
+ * @note FIf the rectangle is not completely inside the screen, it is automatically clipped.
*/
- bool fill(const Common::Rect *FillRectPtr = 0, uint Color = BS_RGB(0, 0, 0));
+ bool fill(const Common::Rect *fillRectPtr = 0, uint color = BS_RGB(0, 0, 0));
// Debugging Methods
- int GetFPSCount() const {
- return m_FPSCounter.GetFPS();
+ int getFPSCount() const {
+ return _FPSCounter.getFPS();
}
- int GetRepaintedPixels() const {
- return m_RepaintedPixels;
+ int getRepaintedPixels() const {
+ return _repaintedPixels;
}
Graphics::Surface _backSurface;
@@ -298,8 +291,8 @@ public:
* @param ColorFormat The desired colour format. The parameter must be of type COLOR_FORMATS
* @return Returns the size of a pixel in bytes. If the colour format is unknown, -1 is returned.
*/
- static int GetPixelSize(GraphicEngine::COLOR_FORMATS ColorFormat) {
- switch (ColorFormat) {
+ static int getPixelSize(GraphicEngine::COLOR_FORMATS colorFormat) {
+ switch (colorFormat) {
case GraphicEngine::CF_ARGB32:
return 4;
default:
@@ -314,10 +307,10 @@ public:
* @return Reflects the length of the line in bytes. If the colour format is
* unknown, -1 is returned
*/
- static int CalcPitch(GraphicEngine::COLOR_FORMATS ColorFormat, int Width) {
- switch (ColorFormat) {
+ static int calcPitch(GraphicEngine::COLOR_FORMATS colorFormat, int width) {
+ switch (colorFormat) {
case GraphicEngine::CF_ARGB32:
- return Width * 4;
+ return width * 4;
default:
BS_ASSERT(false);
@@ -328,69 +321,70 @@ public:
// Resource-Managing Methods
// --------------------------
- virtual Resource *loadResource(const Common::String &fileName);
- virtual bool canLoadResource(const Common::String &fileName);
+ virtual Resource *loadResource(const Common::String &fileName);
+ virtual bool canLoadResource(const Common::String &fileName);
// Persistence Methods
// -------------------
- virtual bool persist(OutputPersistenceBlock &Writer);
- virtual bool unpersist(InputPersistenceBlock &Reader);
+ virtual bool persist(OutputPersistenceBlock &writer);
+ virtual bool unpersist(InputPersistenceBlock &reader);
- static void ARGBColorToLuaColor(lua_State *L, uint Color);
- static uint LuaColorToARGBColor(lua_State *L, int StackIndex);
+ static void ARGBColorToLuaColor(lua_State *L, uint color);
+ static uint luaColorToARGBColor(lua_State *L, int stackIndex);
protected:
// Display Variables
// -----------------
- int m_Width;
- int m_Height;
- Common::Rect m_ScreenRect;
- int m_BitDepth;
- bool m_Windowed;
+ int _width;
+ int _height;
+ Common::Rect _screenRect;
+ int _bitDepth;
+ bool _windowed;
// Debugging Variables
// -------------------
- Framecounter m_FPSCounter;
+ Framecounter _FPSCounter;
- uint m_RepaintedPixels;
+ uint _repaintedPixels;
/**
* Calculates the time since the last frame beginning has passed.
*/
- void UpdateLastFrameDuration();
+ void updateLastFrameDuration();
private:
- bool RegisterScriptBindings();
+ bool registerScriptBindings();
+ void unregisterScriptBindings();
// LastFrameDuration Variables
// ---------------------------
- uint64 m_LastTimeStamp;
- uint m_LastFrameDuration;
- bool m_TimerActive;
- Common::Array<uint> m_FrameTimeSamples;
- uint m_FrameTimeSampleSlot;
+ uint _lastTimeStamp;
+ uint _lastFrameDuration;
+ bool _timerActive;
+ Common::Array<uint> _frameTimeSamples;
+ uint _frameTimeSampleSlot;
private:
byte *_backBuffer;
- RenderObjectPtr<Panel> m_MainPanelPtr;
+ RenderObjectPtr<Panel> _mainPanelPtr;
- Common::ScopedPtr<RenderObjectManager> _renderObjectManagerPtr;
+ Common::ScopedPtr<RenderObjectManager> _renderObjectManagerPtr;
struct DebugLine {
- DebugLine(const Vertex &_Start, const Vertex &_End, uint _Color) :
- Start(_Start),
- End(_End),
- Color(_Color) {}
+ DebugLine(const Vertex &start, const Vertex &end, uint color) :
+ _start(start),
+ _end(end),
+ _color(color) {}
DebugLine() {}
- Vertex Start;
- Vertex End;
- uint Color;
+ Vertex _start;
+ Vertex _end;
+ uint _color;
};
- Common::Array<DebugLine> m_DebugLines;
+ Common::Array<DebugLine> _debugLines;
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/graphicengine_script.cpp b/engines/sword25/gfx/graphicengine_script.cpp
index d443023436..0814a23871 100644
--- a/engines/sword25/gfx/graphicengine_script.cpp
+++ b/engines/sword25/gfx/graphicengine_script.cpp
@@ -32,13 +32,8 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/kernel/kernel.h"
-#include "sword25/kernel/callbackregistry.h"
#include "sword25/script/script.h"
#include "sword25/script/luabindhelper.h"
#include "sword25/script/luacallback.h"
@@ -57,20 +52,14 @@ namespace Sword25 {
#define BS_LOG_PREFIX "GRAPHICENGINE"
-// -----------------------------------------------------------------------------
-// Callback-Objekte
-// -----------------------------------------------------------------------------
-
-static bool AnimationDeleteCallback(uint Data);
-static bool AnimationActionCallback(uint Data);
-static bool AnimationLoopPointCallback(uint Data);
+static bool animationDeleteCallback(uint Data);
+static bool animationActionCallback(uint Data);
+static bool animationLoopPointCallback(uint Data);
namespace {
-// -------------------------------------------------------------------------
-
class ActionCallback : public LuaCallback {
public:
- ActionCallback(lua_State *L) : LuaCallback(L) {};
+ ActionCallback(lua_State *L) : LuaCallback(L) {}
Common::String Action;
@@ -81,25 +70,10 @@ protected:
}
};
-Common::ScopedPtr<LuaCallback> LoopPointCallbackPtr;
-Common::ScopedPtr<ActionCallback> ActionCallbackPtr;
-
-// -------------------------------------------------------------------------
-
-struct CallbackfunctionRegisterer {
- CallbackfunctionRegisterer() {
- CallbackRegistry::getInstance().registerCallbackFunction("LuaLoopPointCB", (void ( *)(int))AnimationLoopPointCallback);
- CallbackRegistry::getInstance().registerCallbackFunction("LuaActionCB", (void ( *)(int))AnimationActionCallback);
- CallbackRegistry::getInstance().registerCallbackFunction("LuaDeleteCB", (void ( *)(int))AnimationDeleteCallback);
- }
-};
-static CallbackfunctionRegisterer Instance;
+static LuaCallback *loopPointCallbackPtr = 0; // FIXME: should be turned into GraphicEngine member var
+static ActionCallback *actionCallbackPtr = 0; // FIXME: should be turned into GraphicEngine member var
}
-// -----------------------------------------------------------------------------
-// Constants
-// -----------------------------------------------------------------------------
-
// Die Strings werden als #defines definiert um Stringkomposition zur Compilezeit zu ermöglichen.
#define RENDEROBJECT_CLASS_NAME "Gfx.RenderObject"
#define BITMAP_CLASS_NAME "Gfx.Bitmap"
@@ -109,8 +83,6 @@ static CallbackfunctionRegisterer Instance;
#define ANIMATION_TEMPLATE_CLASS_NAME "Gfx.AnimationTemplate"
static const char *GFX_LIBRARY_NAME = "Gfx";
-// -----------------------------------------------------------------------------
-
// Wie luaL_checkudata, nur ohne dass kein Fehler erzeugt wird.
static void *my_checkudata(lua_State *L, int ud, const char *tname) {
int top = lua_gettop(L);
@@ -131,23 +103,19 @@ static void *my_checkudata(lua_State *L, int ud, const char *tname) {
return NULL;
}
-// -----------------------------------------------------------------------------
-
-static void NewUintUserData(lua_State *L, uint Value) {
- void *UserData = lua_newuserdata(L, sizeof(Value));
- memcpy(UserData, &Value, sizeof(Value));
+static void newUintUserData(lua_State *L, uint value) {
+ void *userData = lua_newuserdata(L, sizeof(value));
+ memcpy(userData, &value, sizeof(value));
}
-// -----------------------------------------------------------------------------
-
-static AnimationTemplate *CheckAnimationTemplate(lua_State *L, int idx = 1) {
+static AnimationTemplate *checkAnimationTemplate(lua_State *L, int idx = 1) {
// Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.AnimationTemplate
- uint AnimationTemplateHandle;
- if ((AnimationTemplateHandle = *reinterpret_cast<uint *>(my_checkudata(L, idx, ANIMATION_TEMPLATE_CLASS_NAME))) != 0) {
- AnimationTemplate *AnimationTemplatePtr = AnimationTemplateRegistry::getInstance().resolveHandle(AnimationTemplateHandle);
- if (!AnimationTemplatePtr)
- luaL_error(L, "The animation template with the handle %d does no longer exist.", AnimationTemplateHandle);
- return AnimationTemplatePtr;
+ uint animationTemplateHandle;
+ if ((animationTemplateHandle = *reinterpret_cast<uint *>(my_checkudata(L, idx, ANIMATION_TEMPLATE_CLASS_NAME))) != 0) {
+ AnimationTemplate *animationTemplatePtr = AnimationTemplateRegistry::instance().resolveHandle(animationTemplateHandle);
+ if (!animationTemplatePtr)
+ luaL_error(L, "The animation template with the handle %d does no longer exist.", animationTemplateHandle);
+ return animationTemplatePtr;
} else {
luaL_argcheck(L, 0, idx, "'" ANIMATION_TEMPLATE_CLASS_NAME "' expected");
return 0;
@@ -155,13 +123,11 @@ static AnimationTemplate *CheckAnimationTemplate(lua_State *L, int idx = 1) {
}
-// -----------------------------------------------------------------------------
-
-static int NewAnimationTemplate(lua_State *L) {
- uint AnimationTemplateHandle = AnimationTemplate::create(luaL_checkstring(L, 1));
- AnimationTemplate *AnimationTemplatePtr = AnimationTemplateRegistry::getInstance().resolveHandle(AnimationTemplateHandle);
- if (AnimationTemplatePtr && AnimationTemplatePtr->isValid()) {
- NewUintUserData(L, AnimationTemplateHandle);
+static int newAnimationTemplate(lua_State *L) {
+ uint animationTemplateHandle = AnimationTemplate::create(luaL_checkstring(L, 1));
+ AnimationTemplate *animationTemplatePtr = AnimationTemplateRegistry::instance().resolveHandle(animationTemplateHandle);
+ if (animationTemplatePtr && animationTemplatePtr->isValid()) {
+ newUintUserData(L, animationTemplateHandle);
//luaL_getmetatable(L, ANIMATION_TEMPLATE_CLASS_NAME);
LuaBindhelper::getMetatable(L, ANIMATION_TEMPLATE_CLASS_NAME);
BS_ASSERT(!lua_isnil(L, -1));
@@ -173,45 +139,37 @@ static int NewAnimationTemplate(lua_State *L) {
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int AT_AddFrame(lua_State *L) {
- AnimationTemplate *pAT = CheckAnimationTemplate(L);
+static int at_addFrame(lua_State *L) {
+ AnimationTemplate *pAT = checkAnimationTemplate(L);
pAT->addFrame(static_cast<int>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int AT_SetFrame(lua_State *L) {
- AnimationTemplate *pAT = CheckAnimationTemplate(L);
+static int at_setFrame(lua_State *L) {
+ AnimationTemplate *pAT = checkAnimationTemplate(L);
pAT->setFrame(static_cast<int>(luaL_checknumber(L, 2)), static_cast<int>(luaL_checknumber(L, 3)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static bool AnimationTypeStringToNumber(const char *TypeString, Animation::ANIMATION_TYPES &Result) {
- if (strcmp(TypeString, "jojo") == 0) {
- Result = Animation::AT_JOJO;
+static bool animationTypeStringToNumber(const char *typeString, Animation::ANIMATION_TYPES &result) {
+ if (strcmp(typeString, "jojo") == 0) {
+ result = Animation::AT_JOJO;
return true;
- } else if (strcmp(TypeString, "loop") == 0) {
- Result = Animation::AT_LOOP;
+ } else if (strcmp(typeString, "loop") == 0) {
+ result = Animation::AT_LOOP;
return true;
- } else if (strcmp(TypeString, "oneshot") == 0) {
- Result = Animation::AT_ONESHOT;
+ } else if (strcmp(typeString, "oneshot") == 0) {
+ result = Animation::AT_ONESHOT;
return true;
} else
return false;
}
-// -----------------------------------------------------------------------------
-
-static int AT_SetAnimationType(lua_State *L) {
- AnimationTemplate *pAT = CheckAnimationTemplate(L);
- Animation::ANIMATION_TYPES AnimationType;
- if (AnimationTypeStringToNumber(luaL_checkstring(L, 2), AnimationType)) {
- pAT->setAnimationType(AnimationType);
+static int at_setAnimationType(lua_State *L) {
+ AnimationTemplate *pAT = checkAnimationTemplate(L);
+ Animation::ANIMATION_TYPES animationType;
+ if (animationTypeStringToNumber(luaL_checkstring(L, 2), animationType)) {
+ pAT->setAnimationType(animationType);
} else {
luaL_argcheck(L, 0, 2, "Invalid animation type");
}
@@ -219,68 +177,58 @@ static int AT_SetAnimationType(lua_State *L) {
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int AT_SetFPS(lua_State *L) {
- AnimationTemplate *pAT = CheckAnimationTemplate(L);
+static int at_setFPS(lua_State *L) {
+ AnimationTemplate *pAT = checkAnimationTemplate(L);
pAT->setFPS(static_cast<int>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int AT_Finalize(lua_State *L) {
- AnimationTemplate *pAT = CheckAnimationTemplate(L);
+static int at_finalize(lua_State *L) {
+ AnimationTemplate *pAT = checkAnimationTemplate(L);
delete pAT;
return 0;
}
-// -----------------------------------------------------------------------------
-
static const luaL_reg ANIMATION_TEMPLATE_METHODS[] = {
- {"AddFrame", AT_AddFrame},
- {"SetFrame", AT_SetFrame},
- {"SetAnimationType", AT_SetAnimationType},
- {"SetFPS", AT_SetFPS},
- {"__gc", AT_Finalize},
+ {"AddFrame", at_addFrame},
+ {"SetFrame", at_setFrame},
+ {"SetAnimationType", at_setAnimationType},
+ {"SetFPS", at_setFPS},
+ {"__gc", at_finalize},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static GraphicEngine *GetGE() {
- Kernel *pKernel = Kernel::GetInstance();
+static GraphicEngine *getGE() {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- GraphicEngine *pGE = static_cast<GraphicEngine *>(pKernel->GetService("gfx"));
+ GraphicEngine *pGE = pKernel->getGfx();
BS_ASSERT(pGE);
return pGE;
}
-// -----------------------------------------------------------------------------
-
-static int Init(lua_State *L) {
- GraphicEngine *pGE = GetGE();
+static int init(lua_State *L) {
+ GraphicEngine *pGE = getGE();
switch (lua_gettop(L)) {
case 0:
- lua_pushbooleancpp(L, pGE->Init());
+ lua_pushbooleancpp(L, pGE->init());
break;
case 1:
- lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L, 1))));
+ lua_pushbooleancpp(L, pGE->init(static_cast<int>(luaL_checknumber(L, 1))));
break;
case 2:
- lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L, 1)), static_cast<int>(luaL_checknumber(L, 2))));
+ lua_pushbooleancpp(L, pGE->init(static_cast<int>(luaL_checknumber(L, 1)), static_cast<int>(luaL_checknumber(L, 2))));
break;
case 3:
- lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L, 1)), static_cast<int>(luaL_checknumber(L, 2)),
+ lua_pushbooleancpp(L, pGE->init(static_cast<int>(luaL_checknumber(L, 1)), static_cast<int>(luaL_checknumber(L, 2)),
static_cast<int>(luaL_checknumber(L, 3))));
break;
case 4:
- lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L, 1)), static_cast<int>(luaL_checknumber(L, 2)),
+ lua_pushbooleancpp(L, pGE->init(static_cast<int>(luaL_checknumber(L, 1)), static_cast<int>(luaL_checknumber(L, 2)),
static_cast<int>(luaL_checknumber(L, 3)), static_cast<int>(luaL_checknumber(L, 4))));
break;
default:
- lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L, 1)), static_cast<int>(luaL_checknumber(L, 2)),
+ lua_pushbooleancpp(L, pGE->init(static_cast<int>(luaL_checknumber(L, 1)), static_cast<int>(luaL_checknumber(L, 2)),
static_cast<int>(luaL_checknumber(L, 3)), static_cast<int>(luaL_checknumber(L, 4)),
lua_tobooleancpp(L, 5)));
}
@@ -291,14 +239,14 @@ static int Init(lua_State *L) {
#endif
// Main-Panel zum Gfx-Modul hinzufügen
- RenderObjectPtr<Panel> MainPanelPtr(GetGE()->GetMainPanel());
- BS_ASSERT(MainPanelPtr.isValid());
+ RenderObjectPtr<Panel> mainPanelPtr(getGE()->getMainPanel());
+ BS_ASSERT(mainPanelPtr.isValid());
lua_pushstring(L, GFX_LIBRARY_NAME);
lua_gettable(L, LUA_GLOBALSINDEX);
BS_ASSERT(!lua_isnil(L, -1));
- NewUintUserData(L, MainPanelPtr->getHandle());
+ newUintUserData(L, mainPanelPtr->getHandle());
BS_ASSERT(!lua_isnil(L, -1));
// luaL_getmetatable(L, PANEL_CLASS_NAME);
LuaBindhelper::getMetatable(L, PANEL_CLASS_NAME);
@@ -318,213 +266,177 @@ static int Init(lua_State *L) {
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int StartFrame(lua_State *L) {
- GraphicEngine *pGE = GetGE();
+static int startFrame(lua_State *L) {
+ GraphicEngine *pGE = getGE();
if (lua_gettop(L) == 0)
- lua_pushbooleancpp(L, pGE->StartFrame());
+ lua_pushbooleancpp(L, pGE->startFrame());
else
- lua_pushbooleancpp(L, pGE->StartFrame(lua_tobooleancpp(L, 1)));
+ lua_pushbooleancpp(L, pGE->startFrame(lua_tobooleancpp(L, 1)));
return 1;
}
-// -----------------------------------------------------------------------------
+static int endFrame(lua_State *L) {
+ GraphicEngine *pGE = getGE();
-static int EndFrame(lua_State *L) {
- GraphicEngine *pGE = GetGE();
-
- lua_pushbooleancpp(L, pGE->EndFrame());
+ lua_pushbooleancpp(L, pGE->endFrame());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int DrawDebugLine(lua_State *L) {
- GraphicEngine *pGE = GetGE();
+static int drawDebugLine(lua_State *L) {
+ GraphicEngine *pGE = getGE();
- Vertex Start;
- Vertex End;
- Vertex::luaVertexToVertex(L, 1, Start);
- Vertex::luaVertexToVertex(L, 2, End);
- pGE->DrawDebugLine(Start, End, GraphicEngine::LuaColorToARGBColor(L, 3));
+ Vertex start;
+ Vertex end;
+ Vertex::luaVertexToVertex(L, 1, start);
+ Vertex::luaVertexToVertex(L, 2, end);
+ pGE->drawDebugLine(start, end, GraphicEngine::luaColorToARGBColor(L, 3));
return 0;
}
-// -----------------------------------------------------------------------------
+static int getDisplayWidth(lua_State *L) {
+ GraphicEngine *pGE = getGE();
-static int GetDisplayWidth(lua_State *L) {
- GraphicEngine *pGE = GetGE();
-
- lua_pushnumber(L, pGE->GetDisplayWidth());
+ lua_pushnumber(L, pGE->getDisplayWidth());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetDisplayHeight(lua_State *L) {
- GraphicEngine *pGE = GetGE();
+static int getDisplayHeight(lua_State *L) {
+ GraphicEngine *pGE = getGE();
- lua_pushnumber(L, pGE->GetDisplayHeight());
+ lua_pushnumber(L, pGE->getDisplayHeight());
return 1;
}
-// -----------------------------------------------------------------------------
+static int getBitDepth(lua_State *L) {
+ GraphicEngine *pGE = getGE();
-static int GetBitDepth(lua_State *L) {
- GraphicEngine *pGE = GetGE();
-
- lua_pushnumber(L, pGE->GetBitDepth());
+ lua_pushnumber(L, pGE->getBitDepth());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SetVsync(lua_State *L) {
- GraphicEngine *pGE = GetGE();
+static int setVsync(lua_State *L) {
+ GraphicEngine *pGE = getGE();
- pGE->SetVsync(lua_tobooleancpp(L, 1));
+ pGE->setVsync(lua_tobooleancpp(L, 1));
return 0;
}
-// -----------------------------------------------------------------------------
+static int isVsync(lua_State *L) {
+ GraphicEngine *pGE = getGE();
-static int IsVsync(lua_State *L) {
- GraphicEngine *pGE = GetGE();
-
- lua_pushbooleancpp(L, pGE->GetVsync());
+ lua_pushbooleancpp(L, pGE->getVsync());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int IsWindowed(lua_State *L) {
- GraphicEngine *pGE = GetGE();
+static int isWindowed(lua_State *L) {
+ GraphicEngine *pGE = getGE();
- lua_pushbooleancpp(L, pGE->IsWindowed());
+ lua_pushbooleancpp(L, pGE->isWindowed());
return 1;
}
-// -----------------------------------------------------------------------------
+static int getFPSCount(lua_State *L) {
+ GraphicEngine *pGE = getGE();
-static int GetFPSCount(lua_State *L) {
- GraphicEngine *pGE = GetGE();
-
- lua_pushnumber(L, pGE->GetFPSCount());
+ lua_pushnumber(L, pGE->getFPSCount());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetLastFrameDuration(lua_State *L) {
- GraphicEngine *pGE = GetGE();
+static int getLastFrameDuration(lua_State *L) {
+ GraphicEngine *pGE = getGE();
- lua_pushnumber(L, pGE->GetLastFrameDuration());
+ lua_pushnumber(L, pGE->getLastFrameDuration());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int StopMainTimer(lua_State *L) {
- GraphicEngine *pGE = GetGE();
- pGE->StopMainTimer();
+static int stopMainTimer(lua_State *L) {
+ GraphicEngine *pGE = getGE();
+ pGE->stopMainTimer();
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int ResumeMainTimer(lua_State *L) {
- GraphicEngine *pGE = GetGE();
- pGE->ResumeMainTimer();
+static int resumeMainTimer(lua_State *L) {
+ GraphicEngine *pGE = getGE();
+ pGE->resumeMainTimer();
return 0;
}
-// -----------------------------------------------------------------------------
+static int getSecondaryFrameDuration(lua_State *L) {
+ GraphicEngine *pGE = getGE();
-static int GetSecondaryFrameDuration(lua_State *L) {
- GraphicEngine *pGE = GetGE();
-
- lua_pushnumber(L, pGE->GetSecondaryFrameDuration());
+ lua_pushnumber(L, pGE->getSecondaryFrameDuration());
return 1;
}
-// -----------------------------------------------------------------------------
+static int saveScreenshot(lua_State *L) {
+ // This is used by system/debug.lua only. We do not implement this; support
+ // for taking screenshots is a backend feature.
+ lua_pushbooleancpp(L, false);
-static int SaveScreenshot(lua_State *L) {
- GraphicEngine *pGE = GetGE();
- lua_pushbooleancpp(L, pGE->SaveScreenshot(luaL_checkstring(L, 1)));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SaveThumbnailScreenshot(lua_State *L) {
- GraphicEngine *pGE = GetGE();
- lua_pushbooleancpp(L, pGE->SaveThumbnailScreenshot(luaL_checkstring(L, 1)));
+static int saveThumbnailScreenshot(lua_State *L) {
+ GraphicEngine *pGE = getGE();
+ lua_pushbooleancpp(L, pGE->saveThumbnailScreenshot(luaL_checkstring(L, 1)));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetRepaintedPixels(lua_State *L) {
- GraphicEngine *pGE = GetGE();
- lua_pushnumber(L, static_cast<lua_Number>(pGE->GetRepaintedPixels()));
+static int getRepaintedPixels(lua_State *L) {
+ GraphicEngine *pGE = getGE();
+ lua_pushnumber(L, static_cast<lua_Number>(pGE->getRepaintedPixels()));
return 1;
}
-// -----------------------------------------------------------------------------
-
static const luaL_reg GFX_FUNCTIONS[] = {
- {"Init", Init},
- {"StartFrame", StartFrame},
- {"EndFrame", EndFrame},
- {"DrawDebugLine", DrawDebugLine},
- {"SetVsync", SetVsync},
- {"GetDisplayWidth", GetDisplayWidth},
- {"GetDisplayHeight", GetDisplayHeight},
- {"GetBitDepth", GetBitDepth},
- {"IsVsync", IsVsync},
- {"IsWindowed", IsWindowed},
- {"GetFPSCount", GetFPSCount},
- {"GetLastFrameDuration", GetLastFrameDuration},
- {"StopMainTimer", StopMainTimer},
- {"ResumeMainTimer", ResumeMainTimer},
- {"GetSecondaryFrameDuration", GetSecondaryFrameDuration},
- {"SaveScreenshot", SaveScreenshot},
- {"NewAnimationTemplate", NewAnimationTemplate},
- {"GetRepaintedPixels", GetRepaintedPixels},
- {"SaveThumbnailScreenshot", SaveThumbnailScreenshot},
+ {"Init", init},
+ {"StartFrame", startFrame},
+ {"EndFrame", endFrame},
+ {"DrawDebugLine", drawDebugLine},
+ {"SetVsync", setVsync},
+ {"GetDisplayWidth", getDisplayWidth},
+ {"GetDisplayHeight", getDisplayHeight},
+ {"GetBitDepth", getBitDepth},
+ {"IsVsync", isVsync},
+ {"IsWindowed", isWindowed},
+ {"GetFPSCount", getFPSCount},
+ {"GetLastFrameDuration", getLastFrameDuration},
+ {"StopMainTimer", stopMainTimer},
+ {"ResumeMainTimer", resumeMainTimer},
+ {"GetSecondaryFrameDuration", getSecondaryFrameDuration},
+ {"SaveScreenshot", saveScreenshot},
+ {"NewAnimationTemplate", newAnimationTemplate},
+ {"GetRepaintedPixels", getRepaintedPixels},
+ {"SaveThumbnailScreenshot", saveThumbnailScreenshot},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static RenderObjectPtr<RenderObject> CheckRenderObject(lua_State *L, bool ErrorIfRemoved = true) {
+static RenderObjectPtr<RenderObject> checkRenderObject(lua_State *L, bool errorIfRemoved = true) {
// Der erste Parameter muss vom Typ userdata sein und die Metatable einer Klasse haben, die von Gfx.RenderObject "erbt".
- uint *UserDataPtr;
- if ((UserDataPtr = (uint *) my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0 ||
- (UserDataPtr = (uint *) my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0 ||
- (UserDataPtr = (uint *) my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0 ||
- (UserDataPtr = (uint *) my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0) {
- RenderObjectPtr<RenderObject> ROPtr(* UserDataPtr);
- if (ROPtr.isValid())
- return ROPtr;
+ uint *userDataPtr;
+ if ((userDataPtr = (uint *) my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0 ||
+ (userDataPtr = (uint *) my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0 ||
+ (userDataPtr = (uint *) my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0 ||
+ (userDataPtr = (uint *) my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0) {
+ RenderObjectPtr<RenderObject> roPtr(*userDataPtr);
+ if (roPtr.isValid())
+ return roPtr;
else {
- if (ErrorIfRemoved)
- luaL_error(L, "The renderobject with the handle %d does no longer exist.", * UserDataPtr);
+ if (errorIfRemoved)
+ luaL_error(L, "The renderobject with the handle %d does no longer exist.", *userDataPtr);
}
} else {
luaL_argcheck(L, 0, 1, "'" RENDEROBJECT_CLASS_NAME "' expected");
@@ -533,143 +445,115 @@ static RenderObjectPtr<RenderObject> CheckRenderObject(lua_State *L, bool ErrorI
return RenderObjectPtr<RenderObject>();
}
-// -----------------------------------------------------------------------------
-
-static int RO_SetPos(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- Vertex Pos;
- Vertex::luaVertexToVertex(L, 2, Pos);
- ROPtr->setPos(Pos.x, Pos.y);
+static int ro_setPos(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ Vertex pos;
+ Vertex::luaVertexToVertex(L, 2, pos);
+ roPtr->setPos(pos.x, pos.y);
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int RO_SetX(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- ROPtr->setX(static_cast<int>(luaL_checknumber(L, 2)));
+static int ro_setX(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ roPtr->setX(static_cast<int>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int RO_SetY(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- ROPtr->setY(static_cast<int>(luaL_checknumber(L, 2)));
+static int ro_setY(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ roPtr->setY(static_cast<int>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int RO_SetZ(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- ROPtr->setZ(static_cast<int>(luaL_checknumber(L, 2)));
+static int ro_setZ(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ roPtr->setZ(static_cast<int>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int RO_SetVisible(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- ROPtr->setVisible(lua_tobooleancpp(L, 2));
+static int ro_setVisible(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ roPtr->setVisible(lua_tobooleancpp(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int RO_GetX(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- lua_pushnumber(L, ROPtr->getX());
+static int ro_getX(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ lua_pushnumber(L, roPtr->getX());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_GetY(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- lua_pushnumber(L, ROPtr->getY());
+static int ro_getY(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ lua_pushnumber(L, roPtr->getY());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_GetZ(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- lua_pushnumber(L, ROPtr->getZ());
+static int ro_getZ(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ lua_pushnumber(L, roPtr->getZ());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_GetAbsoluteX(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- lua_pushnumber(L, ROPtr->getAbsoluteX());
+static int ro_getAbsoluteX(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ lua_pushnumber(L, roPtr->getAbsoluteX());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_GetAbsoluteY(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- lua_pushnumber(L, ROPtr->getAbsoluteY());
+static int ro_getAbsoluteY(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ lua_pushnumber(L, roPtr->getAbsoluteY());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_GetWidth(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- lua_pushnumber(L, ROPtr->getWidth());
+static int ro_getWidth(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ lua_pushnumber(L, roPtr->getWidth());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_GetHeight(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- lua_pushnumber(L, ROPtr->getHeight());
+static int ro_getHeight(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ lua_pushnumber(L, roPtr->getHeight());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_IsVisible(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- lua_pushbooleancpp(L, ROPtr->isVisible());
+static int ro_isVisible(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ lua_pushbooleancpp(L, roPtr->isVisible());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_AddPanel(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- RenderObjectPtr<Panel> PanelPtr = ROPtr->addPanel(static_cast<int>(luaL_checknumber(L, 2)),
+static int ro_addPanel(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ RenderObjectPtr<Panel> panelPtr = roPtr->addPanel(static_cast<int>(luaL_checknumber(L, 2)),
static_cast<int>(luaL_checknumber(L, 3)),
- GraphicEngine::LuaColorToARGBColor(L, 4));
- if (PanelPtr.isValid()) {
- NewUintUserData(L, PanelPtr->getHandle());
+ GraphicEngine::luaColorToARGBColor(L, 4));
+ if (panelPtr.isValid()) {
+ newUintUserData(L, panelPtr->getHandle());
// luaL_getmetatable(L, PANEL_CLASS_NAME);
LuaBindhelper::getMetatable(L, PANEL_CLASS_NAME);
BS_ASSERT(!lua_isnil(L, -1));
@@ -680,14 +564,12 @@ static int RO_AddPanel(lua_State *L) {
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_AddBitmap(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- RenderObjectPtr<Bitmap> BitmaPtr = ROPtr->addBitmap(luaL_checkstring(L, 2));
- if (BitmaPtr.isValid()) {
- NewUintUserData(L, BitmaPtr->getHandle());
+static int ro_addBitmap(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ RenderObjectPtr<Bitmap> bitmaPtr = roPtr->addBitmap(luaL_checkstring(L, 2));
+ if (bitmaPtr.isValid()) {
+ newUintUserData(L, bitmaPtr->getHandle());
// luaL_getmetatable(L, BITMAP_CLASS_NAME);
LuaBindhelper::getMetatable(L, BITMAP_CLASS_NAME);
BS_ASSERT(!lua_isnil(L, -1));
@@ -698,18 +580,18 @@ static int RO_AddBitmap(lua_State *L) {
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_AddText(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
+static int ro_addText(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
- RenderObjectPtr<Text> TextPtr;
- if (lua_gettop(L) >= 3) TextPtr = ROPtr->addText(luaL_checkstring(L, 2), luaL_checkstring(L, 3));
- else TextPtr = ROPtr->addText(luaL_checkstring(L, 2));
+ RenderObjectPtr<Text> textPtr;
+ if (lua_gettop(L) >= 3)
+ textPtr = roPtr->addText(luaL_checkstring(L, 2), luaL_checkstring(L, 3));
+ else
+ textPtr = roPtr->addText(luaL_checkstring(L, 2));
- if (TextPtr.isValid()) {
- NewUintUserData(L, TextPtr->getHandle());
+ if (textPtr.isValid()) {
+ newUintUserData(L, textPtr->getHandle());
// luaL_getmetatable(L, TEXT_CLASS_NAME);
LuaBindhelper::getMetatable(L, TEXT_CLASS_NAME);
BS_ASSERT(!lua_isnil(L, -1));
@@ -720,69 +602,67 @@ static int RO_AddText(lua_State *L) {
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int RO_AddAnimation(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
+static int ro_addAnimation(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
- RenderObjectPtr<Animation> AnimationPtr;
+ RenderObjectPtr<Animation> animationPtr;
if (lua_type(L, 2) == LUA_TUSERDATA)
- AnimationPtr = ROPtr->addAnimation(*CheckAnimationTemplate(L, 2));
+ animationPtr = roPtr->addAnimation(*checkAnimationTemplate(L, 2));
else
- AnimationPtr = ROPtr->addAnimation(luaL_checkstring(L, 2));
+ animationPtr = roPtr->addAnimation(luaL_checkstring(L, 2));
- if (AnimationPtr.isValid()) {
- NewUintUserData(L, AnimationPtr->getHandle());
+ if (animationPtr.isValid()) {
+ newUintUserData(L, animationPtr->getHandle());
// luaL_getmetatable(L, ANIMATION_CLASS_NAME);
LuaBindhelper::getMetatable(L, ANIMATION_CLASS_NAME);
BS_ASSERT(!lua_isnil(L, -1));
lua_setmetatable(L, -2);
// Alle Animationscallbacks registrieren.
- AnimationPtr->registerDeleteCallback(AnimationDeleteCallback, AnimationPtr->getHandle());
- AnimationPtr->registerLoopPointCallback(AnimationLoopPointCallback, AnimationPtr->getHandle());
- AnimationPtr->registerActionCallback(AnimationActionCallback, AnimationPtr->getHandle());
+ animationPtr->setCallbacks();
} else
lua_pushnil(L);
return 1;
}
-// -----------------------------------------------------------------------------
+void Animation::setCallbacks() {
+ _actionCallback = animationActionCallback;
+ _loopPointCallback = animationLoopPointCallback;
+ _deleteCallback = animationDeleteCallback;
+}
static const luaL_reg RENDEROBJECT_METHODS[] = {
- {"AddAnimation", RO_AddAnimation},
- {"AddText", RO_AddText},
- {"AddBitmap", RO_AddBitmap},
- {"AddPanel", RO_AddPanel},
- {"SetPos", RO_SetPos},
- {"SetX", RO_SetX},
- {"SetY", RO_SetY},
- {"SetZ", RO_SetZ},
- {"SetVisible", RO_SetVisible},
- {"GetX", RO_GetX},
- {"GetY", RO_GetY},
- {"GetZ", RO_GetZ},
- {"GetAbsoluteX", RO_GetAbsoluteX},
- {"GetAbsoluteY", RO_GetAbsoluteY},
- {"GetWidth", RO_GetWidth},
- {"GetHeight", RO_GetHeight},
- {"IsVisible", RO_IsVisible},
+ {"AddAnimation", ro_addAnimation},
+ {"AddText", ro_addText},
+ {"AddBitmap", ro_addBitmap},
+ {"AddPanel", ro_addPanel},
+ {"SetPos", ro_setPos},
+ {"SetX", ro_setX},
+ {"SetY", ro_setY},
+ {"SetZ", ro_setZ},
+ {"SetVisible", ro_setVisible},
+ {"GetX", ro_getX},
+ {"GetY", ro_getY},
+ {"GetZ", ro_getZ},
+ {"GetAbsoluteX", ro_getAbsoluteX},
+ {"GetAbsoluteY", ro_getAbsoluteY},
+ {"GetWidth", ro_getWidth},
+ {"GetHeight", ro_getHeight},
+ {"IsVisible", ro_isVisible},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static RenderObjectPtr<Panel> CheckPanel(lua_State *L) {
+static RenderObjectPtr<Panel> checkPanel(lua_State *L) {
// Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Panel
- uint *UserDataPtr;
- if ((UserDataPtr = (uint *) my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0) {
- RenderObjectPtr<RenderObject> ROPtr(*UserDataPtr);
- if (ROPtr.isValid()) {
- return ROPtr->toPanel();
+ uint *userDataPtr;
+ if ((userDataPtr = (uint *)my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0) {
+ RenderObjectPtr<RenderObject> roPtr(*userDataPtr);
+ if (roPtr.isValid()) {
+ return roPtr->toPanel();
} else
- luaL_error(L, "The panel with the handle %d does no longer exist.", *UserDataPtr);
+ luaL_error(L, "The panel with the handle %d does no longer exist.", *userDataPtr);
} else {
luaL_argcheck(L, 0, 1, "'" PANEL_CLASS_NAME "' expected");
}
@@ -790,54 +670,44 @@ static RenderObjectPtr<Panel> CheckPanel(lua_State *L) {
return RenderObjectPtr<Panel>();
}
-// -----------------------------------------------------------------------------
-
-static int P_GetColor(lua_State *L) {
- RenderObjectPtr<Panel> PanelPtr = CheckPanel(L);
+static int p_getColor(lua_State *L) {
+ RenderObjectPtr<Panel> PanelPtr = checkPanel(L);
BS_ASSERT(PanelPtr.isValid());
GraphicEngine::ARGBColorToLuaColor(L, PanelPtr->getColor());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int P_SetColor(lua_State *L) {
- RenderObjectPtr<Panel> PanelPtr = CheckPanel(L);
+static int p_setColor(lua_State *L) {
+ RenderObjectPtr<Panel> PanelPtr = checkPanel(L);
BS_ASSERT(PanelPtr.isValid());
- PanelPtr->setColor(GraphicEngine::LuaColorToARGBColor(L, 2));
+ PanelPtr->setColor(GraphicEngine::luaColorToARGBColor(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int P_Remove(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- ROPtr.erase();
+static int p_remove(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ roPtr.erase();
return 0;
}
-// -----------------------------------------------------------------------------
-
static const luaL_reg PANEL_METHODS[] = {
- {"GetColor", P_GetColor},
- {"SetColor", P_SetColor},
- {"Remove", P_Remove},
+ {"GetColor", p_getColor},
+ {"SetColor", p_setColor},
+ {"Remove", p_remove},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static RenderObjectPtr<Bitmap> CheckBitmap(lua_State *L) {
+static RenderObjectPtr<Bitmap> checkBitmap(lua_State *L) {
// Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Bitmap
- uint *UserDataPtr;
- if ((UserDataPtr = (uint *) my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0) {
- RenderObjectPtr<RenderObject> ROPtr(*UserDataPtr);
- if (ROPtr.isValid()) {
- return ROPtr->toBitmap();
+ uint *userDataPtr;
+ if ((userDataPtr = (uint *)my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0) {
+ RenderObjectPtr<RenderObject> roPtr(*userDataPtr);
+ if (roPtr.isValid()) {
+ return roPtr->toBitmap();
} else
- luaL_error(L, "The bitmap with the handle %d does no longer exist.", *UserDataPtr);
+ luaL_error(L, "The bitmap with the handle %d does no longer exist.", *userDataPtr);
} else {
luaL_argcheck(L, 0, 1, "'" BITMAP_CLASS_NAME "' expected");
}
@@ -845,204 +715,165 @@ static RenderObjectPtr<Bitmap> CheckBitmap(lua_State *L) {
return RenderObjectPtr<Bitmap>();
}
-// -----------------------------------------------------------------------------
-
-static int B_SetAlpha(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- BitmapPtr->setAlpha(static_cast<uint>(luaL_checknumber(L, 2)));
+static int b_setAlpha(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ bitmapPtr->setAlpha(static_cast<uint>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int B_SetTintColor(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- BitmapPtr->setModulationColor(GraphicEngine::LuaColorToARGBColor(L, 2));
+static int b_setTintColor(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ bitmapPtr->setModulationColor(GraphicEngine::luaColorToARGBColor(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int B_SetScaleFactor(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- BitmapPtr->setScaleFactor(static_cast<float>(luaL_checknumber(L, 2)));
+static int b_setScaleFactor(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ bitmapPtr->setScaleFactor(static_cast<float>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int B_SetScaleFactorX(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- BitmapPtr->setScaleFactorX(static_cast<float>(luaL_checknumber(L, 2)));
+static int b_setScaleFactorX(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ bitmapPtr->setScaleFactorX(static_cast<float>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int B_SetScaleFactorY(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- BitmapPtr->setScaleFactorY(static_cast<float>(luaL_checknumber(L, 2)));
+static int b_setScaleFactorY(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ bitmapPtr->setScaleFactorY(static_cast<float>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int B_SetFlipH(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- BitmapPtr->setFlipH(lua_tobooleancpp(L, 2));
+static int b_setFlipH(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ bitmapPtr->setFlipH(lua_tobooleancpp(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int B_SetFlipV(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- BitmapPtr->setFlipV(lua_tobooleancpp(L, 2));
+static int b_setFlipV(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ bitmapPtr->setFlipV(lua_tobooleancpp(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int B_GetAlpha(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- lua_pushnumber(L, BitmapPtr->getAlpha());
+static int b_getAlpha(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ lua_pushnumber(L, bitmapPtr->getAlpha());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_GetTintColor(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- GraphicEngine::ARGBColorToLuaColor(L, BitmapPtr->getModulationColor());
+static int b_getTintColor(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ GraphicEngine::ARGBColorToLuaColor(L, bitmapPtr->getModulationColor());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_GetScaleFactorX(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- lua_pushnumber(L, BitmapPtr->getScaleFactorX());
+static int b_getScaleFactorX(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ lua_pushnumber(L, bitmapPtr->getScaleFactorX());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_GetScaleFactorY(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- lua_pushnumber(L, BitmapPtr->getScaleFactorY());
+static int b_getScaleFactorY(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ lua_pushnumber(L, bitmapPtr->getScaleFactorY());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_IsFlipH(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- lua_pushbooleancpp(L, BitmapPtr->isFlipH());
+static int b_isFlipH(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ lua_pushbooleancpp(L, bitmapPtr->isFlipH());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_IsFlipV(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- lua_pushbooleancpp(L, BitmapPtr->isFlipV());
+static int b_isFlipV(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ lua_pushbooleancpp(L, bitmapPtr->isFlipV());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_GetPixel(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
+static int b_getPixel(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
Vertex Pos;
Vertex::luaVertexToVertex(L, 2, Pos);
- GraphicEngine::ARGBColorToLuaColor(L, BitmapPtr->getPixel(Pos.x, Pos.y));
+ GraphicEngine::ARGBColorToLuaColor(L, bitmapPtr->getPixel(Pos.x, Pos.y));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_IsScalingAllowed(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- lua_pushbooleancpp(L, BitmapPtr->isScalingAllowed());
+static int b_isScalingAllowed(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ lua_pushbooleancpp(L, bitmapPtr->isScalingAllowed());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_IsAlphaAllowed(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- lua_pushbooleancpp(L, BitmapPtr->isAlphaAllowed());
+static int b_isAlphaAllowed(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ lua_pushbooleancpp(L, bitmapPtr->isAlphaAllowed());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int B_IsTintingAllowed(lua_State *L) {
- RenderObjectPtr<Bitmap> BitmapPtr = CheckBitmap(L);
- BS_ASSERT(BitmapPtr.isValid());
- lua_pushbooleancpp(L, BitmapPtr->isColorModulationAllowed());
+static int b_isTintingAllowed(lua_State *L) {
+ RenderObjectPtr<Bitmap> bitmapPtr = checkBitmap(L);
+ BS_ASSERT(bitmapPtr.isValid());
+ lua_pushbooleancpp(L, bitmapPtr->isColorModulationAllowed());
return 1;
}
-// -----------------------------------------------------------------------------
-static int B_Remove(lua_State *L) {
- RenderObjectPtr<RenderObject> ROPtr = CheckRenderObject(L);
- BS_ASSERT(ROPtr.isValid());
- ROPtr.erase();
+static int b_remove(lua_State *L) {
+ RenderObjectPtr<RenderObject> roPtr = checkRenderObject(L);
+ BS_ASSERT(roPtr.isValid());
+ roPtr.erase();
return 0;
}
-// -----------------------------------------------------------------------------
-
static const luaL_reg BITMAP_METHODS[] = {
- {"SetAlpha", B_SetAlpha},
- {"SetTintColor", B_SetTintColor},
- {"SetScaleFactor", B_SetScaleFactor},
- {"SetScaleFactorX", B_SetScaleFactorX},
- {"SetScaleFactorY", B_SetScaleFactorY},
- {"SetFlipH", B_SetFlipH},
- {"SetFlipV", B_SetFlipV},
- {"GetAlpha", B_GetAlpha},
- {"GetTintColor", B_GetTintColor},
- {"GetScaleFactorX", B_GetScaleFactorX},
- {"GetScaleFactorY", B_GetScaleFactorY},
- {"IsFlipH", B_IsFlipH},
- {"IsFlipV", B_IsFlipV},
- {"GetPixel", B_GetPixel},
- {"IsScalingAllowed", B_IsScalingAllowed},
- {"IsAlphaAllowed", B_IsAlphaAllowed},
- {"IsTintingAllowed", B_IsTintingAllowed},
- {"Remove", B_Remove},
+ {"SetAlpha", b_setAlpha},
+ {"SetTintColor", b_setTintColor},
+ {"SetScaleFactor", b_setScaleFactor},
+ {"SetScaleFactorX", b_setScaleFactorX},
+ {"SetScaleFactorY", b_setScaleFactorY},
+ {"SetFlipH", b_setFlipH},
+ {"SetFlipV", b_setFlipV},
+ {"GetAlpha", b_getAlpha},
+ {"GetTintColor", b_getTintColor},
+ {"GetScaleFactorX", b_getScaleFactorX},
+ {"GetScaleFactorY", b_getScaleFactorY},
+ {"IsFlipH", b_isFlipH},
+ {"IsFlipV", b_isFlipV},
+ {"GetPixel", b_getPixel},
+ {"IsScalingAllowed", b_isScalingAllowed},
+ {"IsAlphaAllowed", b_isAlphaAllowed},
+ {"IsTintingAllowed", b_isTintingAllowed},
+ {"Remove", b_remove},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static RenderObjectPtr<Animation> CheckAnimation(lua_State *L) {
+static RenderObjectPtr<Animation> checkAnimation(lua_State *L) {
// Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Animation
- uint *UserDataPtr;
- if ((UserDataPtr = (uint *) my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0) {
- RenderObjectPtr<RenderObject> ROPtr(*UserDataPtr);
- if (ROPtr.isValid())
- return ROPtr->toAnimation();
+ uint *userDataPtr;
+ if ((userDataPtr = (uint *)my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0) {
+ RenderObjectPtr<RenderObject> roPtr(*userDataPtr);
+ if (roPtr.isValid())
+ return roPtr->toAnimation();
else {
- luaL_error(L, "The animation with the handle %d does no longer exist.", *UserDataPtr);
+ luaL_error(L, "The animation with the handle %d does no longer exist.", *userDataPtr);
}
} else {
luaL_argcheck(L, 0, 1, "'" ANIMATION_CLASS_NAME "' expected");
@@ -1051,110 +882,87 @@ static RenderObjectPtr<Animation> CheckAnimation(lua_State *L) {
return RenderObjectPtr<Animation>();
}
-// -----------------------------------------------------------------------------
-
-static int A_Play(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->play();
+static int a_play(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->play();
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_Pause(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->pause();
+static int a_pause(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->pause();
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_Stop(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->stop();
+static int a_stop(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->stop();
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_SetFrame(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->setFrame(static_cast<uint>(luaL_checknumber(L, 2)));
+static int a_setFrame(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->setFrame(static_cast<uint>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_SetAlpha(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->setAlpha(static_cast<int>(luaL_checknumber(L, 2)));
+static int a_setAlpha(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->setAlpha(static_cast<int>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-static int A_SetTintColor(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->setModulationColor(GraphicEngine::LuaColorToARGBColor(L, 2));
+static int a_setTintColor(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->setModulationColor(GraphicEngine::luaColorToARGBColor(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_SetScaleFactor(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->setScaleFactor(static_cast<float>(luaL_checknumber(L, 2)));
+static int a_setScaleFactor(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->setScaleFactor(static_cast<float>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_SetScaleFactorX(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->setScaleFactorX(static_cast<float>(luaL_checknumber(L, 2)));
+static int a_setScaleFactorX(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->setScaleFactorX(static_cast<float>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_SetScaleFactorY(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr->setScaleFactorY(static_cast<float>(luaL_checknumber(L, 2)));
+static int a_setScaleFactorY(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr->setScaleFactorY(static_cast<float>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_GetScaleFactorX(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushnumber(L, AnimationPtr->getScaleFactorX());
+static int a_getScaleFactorX(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushnumber(L, animationPtr->getScaleFactorX());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_GetScaleFactorY(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushnumber(L, AnimationPtr->getScaleFactorY());
+static int a_getScaleFactorY(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushnumber(L, animationPtr->getScaleFactorY());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_GetAnimationType(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- switch (AnimationPtr->getAnimationType()) {
+static int a_getAnimationType(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ switch (animationPtr->getAnimationType()) {
case Animation::AT_JOJO:
lua_pushstring(L, "jojo");
break;
@@ -1170,213 +978,176 @@ static int A_GetAnimationType(lua_State *L) {
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_GetFPS(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushnumber(L, AnimationPtr->getFPS());
+static int a_getFPS(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushnumber(L, animationPtr->getFPS());
return 1;
}
-
-// -----------------------------------------------------------------------------
-
-static int A_GetFrameCount(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushnumber(L, AnimationPtr->getFrameCount());
+static int a_getFrameCount(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushnumber(L, animationPtr->getFrameCount());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_IsScalingAllowed(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushbooleancpp(L, AnimationPtr->isScalingAllowed());
+static int a_isScalingAllowed(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushbooleancpp(L, animationPtr->isScalingAllowed());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_IsAlphaAllowed(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushbooleancpp(L, AnimationPtr->isAlphaAllowed());
+static int a_isAlphaAllowed(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushbooleancpp(L, animationPtr->isAlphaAllowed());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_IsTintingAllowed(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushbooleancpp(L, AnimationPtr->isColorModulationAllowed());
+static int a_isTintingAllowed(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushbooleancpp(L, animationPtr->isColorModulationAllowed());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_GetCurrentFrame(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushnumber(L, AnimationPtr->getCurrentFrame());
+static int a_getCurrentFrame(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushnumber(L, animationPtr->getCurrentFrame());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_GetCurrentAction(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushstring(L, AnimationPtr->getCurrentAction().c_str());
+static int a_getCurrentAction(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushstring(L, animationPtr->getCurrentAction().c_str());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int A_IsPlaying(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- lua_pushbooleancpp(L, AnimationPtr->isRunning());
+static int a_isPlaying(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ lua_pushbooleancpp(L, animationPtr->isRunning());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static bool AnimationLoopPointCallback(uint Handle) {
- lua_State *L = static_cast<lua_State *>(Kernel::GetInstance()->GetScript()->getScriptObject());
- LoopPointCallbackPtr->invokeCallbackFunctions(L, Handle);
+static bool animationLoopPointCallback(uint handle) {
+ lua_State *L = static_cast<lua_State *>(Kernel::getInstance()->getScript()->getScriptObject());
+ loopPointCallbackPtr->invokeCallbackFunctions(L, handle);
return true;
}
-// -----------------------------------------------------------------------------
-
-static int A_RegisterLoopPointCallback(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
+static int a_registerLoopPointCallback(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_pushvalue(L, 2);
- LoopPointCallbackPtr->registerCallbackFunction(L, AnimationPtr->getHandle());
+ loopPointCallbackPtr->registerCallbackFunction(L, animationPtr->getHandle());
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_UnregisterLoopPointCallback(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
+static int a_unregisterLoopPointCallback(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_pushvalue(L, 2);
- LoopPointCallbackPtr->unregisterCallbackFunction(L, AnimationPtr->getHandle());
+ loopPointCallbackPtr->unregisterCallbackFunction(L, animationPtr->getHandle());
return 0;
}
-// -----------------------------------------------------------------------------
-
-static bool AnimationActionCallback(uint Handle) {
- RenderObjectPtr<Animation> AnimationPtr(Handle);
- if (AnimationPtr.isValid()) {
- ActionCallbackPtr->Action = AnimationPtr->getCurrentAction();
- lua_State *L = static_cast<lua_State *>(Kernel::GetInstance()->GetScript()->getScriptObject());
- ActionCallbackPtr->invokeCallbackFunctions(L, AnimationPtr->getHandle());
+static bool animationActionCallback(uint Handle) {
+ RenderObjectPtr<Animation> animationPtr(Handle);
+ if (animationPtr.isValid()) {
+ actionCallbackPtr->Action = animationPtr->getCurrentAction();
+ lua_State *L = static_cast<lua_State *>(Kernel::getInstance()->getScript()->getScriptObject());
+ actionCallbackPtr->invokeCallbackFunctions(L, animationPtr->getHandle());
}
return true;
}
-// -----------------------------------------------------------------------------
-
-static int A_RegisterActionCallback(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
+static int a_registerActionCallback(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_pushvalue(L, 2);
- ActionCallbackPtr->registerCallbackFunction(L, AnimationPtr->getHandle());
+ actionCallbackPtr->registerCallbackFunction(L, animationPtr->getHandle());
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int A_UnregisterActionCallback(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
+static int a_unregisterActionCallback(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_pushvalue(L, 2);
- ActionCallbackPtr->unregisterCallbackFunction(L, AnimationPtr->getHandle());
+ actionCallbackPtr->unregisterCallbackFunction(L, animationPtr->getHandle());
return 0;
}
-// -----------------------------------------------------------------------------
-
-static bool AnimationDeleteCallback(uint Handle) {
- lua_State *L = static_cast<lua_State *>(Kernel::GetInstance()->GetScript()->getScriptObject());
- LoopPointCallbackPtr->removeAllObjectCallbacks(L, Handle);
+static bool animationDeleteCallback(uint Handle) {
+ lua_State *L = static_cast<lua_State *>(Kernel::getInstance()->getScript()->getScriptObject());
+ loopPointCallbackPtr->removeAllObjectCallbacks(L, Handle);
return true;
}
-// -----------------------------------------------------------------------------
-
-static int A_Remove(lua_State *L) {
- RenderObjectPtr<Animation> AnimationPtr = CheckAnimation(L);
- BS_ASSERT(AnimationPtr.isValid());
- AnimationPtr.erase();
+static int a_remove(lua_State *L) {
+ RenderObjectPtr<Animation> animationPtr = checkAnimation(L);
+ BS_ASSERT(animationPtr.isValid());
+ animationPtr.erase();
return 0;
}
-// -----------------------------------------------------------------------------
-
static const luaL_reg ANIMATION_METHODS[] = {
- {"Play", A_Play},
- {"Pause", A_Pause},
- {"Stop", A_Stop},
- {"SetFrame", A_SetFrame},
- {"SetAlpha", A_SetAlpha},
- {"SetTintColor", A_SetTintColor},
- {"SetScaleFactor", A_SetScaleFactor},
- {"SetScaleFactorX", A_SetScaleFactorX},
- {"SetScaleFactorY", A_SetScaleFactorY},
- {"GetScaleFactorX", A_GetScaleFactorX},
- {"GetScaleFactorY", A_GetScaleFactorY},
- {"GetAnimationType", A_GetAnimationType},
- {"GetFPS", A_GetFPS},
- {"GetFrameCount", A_GetFrameCount},
- {"IsScalingAllowed", A_IsScalingAllowed},
- {"IsAlphaAllowed", A_IsAlphaAllowed},
- {"IsTintingAllowed", A_IsTintingAllowed},
- {"GetCurrentFrame", A_GetCurrentFrame},
- {"GetCurrentAction", A_GetCurrentAction},
- {"IsPlaying", A_IsPlaying},
- {"RegisterLoopPointCallback", A_RegisterLoopPointCallback},
- {"UnregisterLoopPointCallback", A_UnregisterLoopPointCallback},
- {"RegisterActionCallback", A_RegisterActionCallback},
- {"UnregisterActionCallback", A_UnregisterActionCallback},
- {"Remove", A_Remove},
+ {"Play", a_play},
+ {"Pause", a_pause},
+ {"Stop", a_stop},
+ {"SetFrame", a_setFrame},
+ {"SetAlpha", a_setAlpha},
+ {"SetTintColor", a_setTintColor},
+ {"SetScaleFactor", a_setScaleFactor},
+ {"SetScaleFactorX", a_setScaleFactorX},
+ {"SetScaleFactorY", a_setScaleFactorY},
+ {"GetScaleFactorX", a_getScaleFactorX},
+ {"GetScaleFactorY", a_getScaleFactorY},
+ {"GetAnimationType", a_getAnimationType},
+ {"GetFPS", a_getFPS},
+ {"GetFrameCount", a_getFrameCount},
+ {"IsScalingAllowed", a_isScalingAllowed},
+ {"IsAlphaAllowed", a_isAlphaAllowed},
+ {"IsTintingAllowed", a_isTintingAllowed},
+ {"GetCurrentFrame", a_getCurrentFrame},
+ {"GetCurrentAction", a_getCurrentAction},
+ {"IsPlaying", a_isPlaying},
+ {"RegisterLoopPointCallback", a_registerLoopPointCallback},
+ {"UnregisterLoopPointCallback", a_unregisterLoopPointCallback},
+ {"RegisterActionCallback", a_registerActionCallback},
+ {"UnregisterActionCallback", a_unregisterActionCallback},
+ {"Remove", a_remove},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static RenderObjectPtr<Text> CheckText(lua_State *L) {
+static RenderObjectPtr<Text> checkText(lua_State *L) {
// Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Text
- uint *UserDataPtr;
- if ((UserDataPtr = (uint *) my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0) {
- RenderObjectPtr<RenderObject> ROPtr(*UserDataPtr);
- if (ROPtr.isValid())
- return ROPtr->toText();
+ uint *userDataPtr;
+ if ((userDataPtr = (uint *)my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0) {
+ RenderObjectPtr<RenderObject> roPtr(*userDataPtr);
+ if (roPtr.isValid())
+ return roPtr->toText();
else
- luaL_error(L, "The text with the handle %d does no longer exist.", *UserDataPtr);
+ luaL_error(L, "The text with the handle %d does no longer exist.", *userDataPtr);
} else {
luaL_argcheck(L, 0, 1, "'" TEXT_CLASS_NAME "' expected");
}
@@ -1384,148 +1155,118 @@ static RenderObjectPtr<Text> CheckText(lua_State *L) {
return RenderObjectPtr<Text>();
}
-// -----------------------------------------------------------------------------
-
-static int T_SetFont(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- TextPtr->SetFont(luaL_checkstring(L, 2));
+static int t_setFont(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ textPtr->setFont(luaL_checkstring(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int T_SetText(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- TextPtr->SetText(luaL_checkstring(L, 2));
+static int t_setText(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ textPtr->setText(luaL_checkstring(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int T_SetAlpha(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- TextPtr->setAlpha(static_cast<int>(luaL_checknumber(L, 2)));
+static int t_setAlpha(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ textPtr->setAlpha(static_cast<int>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int T_SetColor(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- TextPtr->setColor(GraphicEngine::LuaColorToARGBColor(L, 2));
+static int t_setColor(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ textPtr->setColor(GraphicEngine::luaColorToARGBColor(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int T_SetAutoWrap(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- TextPtr->SetAutoWrap(lua_tobooleancpp(L, 2));
+static int t_setAutoWrap(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ textPtr->setAutoWrap(lua_tobooleancpp(L, 2));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int T_SetAutoWrapThreshold(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- TextPtr->SetAutoWrapThreshold(static_cast<uint>(luaL_checknumber(L, 2)));
+static int t_setAutoWrapThreshold(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ textPtr->setAutoWrapThreshold(static_cast<uint>(luaL_checknumber(L, 2)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int T_GetText(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- lua_pushstring(L, TextPtr->GetText().c_str());
+static int t_getText(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ lua_pushstring(L, textPtr->getText().c_str());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int T_GetFont(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- lua_pushstring(L, TextPtr->GetFont().c_str());
+static int t_getFont(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ lua_pushstring(L, textPtr->getFont().c_str());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int T_GetAlpha(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- lua_pushnumber(L, TextPtr->getAlpha());
+static int t_getAlpha(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ lua_pushnumber(L, textPtr->getAlpha());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int T_GetColor(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- lua_pushnumber(L, TextPtr->getColor());
+static int t_getColor(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ lua_pushnumber(L, textPtr->getColor());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int T_IsAutoWrap(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- lua_pushbooleancpp(L, TextPtr->IsAutoWrapActive());
+static int t_isAutoWrap(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ lua_pushbooleancpp(L, textPtr->isAutoWrapActive());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int T_GetAutoWrapThreshold(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- lua_pushnumber(L, TextPtr->GetAutoWrapThreshold());
+static int t_getAutoWrapThreshold(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ lua_pushnumber(L, textPtr->getAutoWrapThreshold());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int T_Remove(lua_State *L) {
- RenderObjectPtr<Text> TextPtr = CheckText(L);
- BS_ASSERT(TextPtr.isValid());
- TextPtr.erase();
+static int t_remove(lua_State *L) {
+ RenderObjectPtr<Text> textPtr = checkText(L);
+ BS_ASSERT(textPtr.isValid());
+ textPtr.erase();
return 0;
}
-// -----------------------------------------------------------------------------
-
static const luaL_reg TEXT_METHODS[] = {
- {"SetFont", T_SetFont},
- {"SetText", T_SetText},
- {"SetAlpha", T_SetAlpha},
- {"SetColor", T_SetColor},
- {"SetAutoWrap", T_SetAutoWrap},
- {"SetAutoWrapThreshold", T_SetAutoWrapThreshold},
- {"GetText", T_GetText},
- {"GetFont", T_GetFont},
- {"GetAlpha", T_GetAlpha},
- {"GetColor", T_GetColor},
- {"IsAutoWrap", T_IsAutoWrap},
- {"GetAutoWrapThreshold", T_GetAutoWrapThreshold},
- {"Remove", T_Remove},
+ {"SetFont", t_setFont},
+ {"SetText", t_setText},
+ {"SetAlpha", t_setAlpha},
+ {"SetColor", t_setColor},
+ {"SetAutoWrap", t_setAutoWrap},
+ {"SetAutoWrapThreshold", t_setAutoWrapThreshold},
+ {"GetText", t_getText},
+ {"GetFont", t_getFont},
+ {"GetAlpha", t_getAlpha},
+ {"GetColor", t_getColor},
+ {"IsAutoWrap", t_isAutoWrap},
+ {"GetAutoWrapThreshold", t_getAutoWrapThreshold},
+ {"Remove", t_remove},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-bool GraphicEngine::RegisterScriptBindings() {
- Kernel *pKernel = Kernel::GetInstance();
+bool GraphicEngine::registerScriptBindings() {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ScriptEngine *pScript = static_cast<ScriptEngine *>(pKernel->GetService("script"));
+ ScriptEngine *pScript = pKernel->getScript();
BS_ASSERT(pScript);
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
BS_ASSERT(L);
@@ -1544,10 +1285,21 @@ bool GraphicEngine::RegisterScriptBindings() {
if (!LuaBindhelper::addFunctionsToLib(L, GFX_LIBRARY_NAME, GFX_FUNCTIONS)) return false;
- LoopPointCallbackPtr.reset(new LuaCallback(L));
- ActionCallbackPtr.reset(new ActionCallback(L));
+ assert(loopPointCallbackPtr == 0);
+ loopPointCallbackPtr = new LuaCallback(L);
+
+ assert(actionCallbackPtr == 0);
+ actionCallbackPtr = new ActionCallback(L);
return true;
}
+void GraphicEngine::unregisterScriptBindings() {
+ delete loopPointCallbackPtr;
+ loopPointCallbackPtr = 0;
+
+ delete actionCallbackPtr;
+ actionCallbackPtr = 0;
+}
+
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/art.cpp b/engines/sword25/gfx/image/art.cpp
index e9aacbcf24..d30460901d 100644
--- a/engines/sword25/gfx/image/art.cpp
+++ b/engines/sword25/gfx/image/art.cpp
@@ -34,40 +34,13 @@
/* Various utility functions RLL finds useful. */
+#include "common/textconsole.h"
+
#include "sword25/gfx/image/art.h"
namespace Sword25 {
/**
- * art_die: Print the error message to stderr and exit with a return code of 1.
- * @fmt: The printf-style format for the error message.
- *
- * Used for dealing with severe errors.
- **/
-void art_die(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- exit(1);
-}
-
-/**
- * art_warn: Print the warning message to stderr.
- * @fmt: The printf-style format for the warning message.
- *
- * Used for generating warnings.
- **/
-void art_warn(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-}
-
-/**
* art_svp_free: Free an #ArtSVP structure.
* @svp: #ArtSVP to free.
*
@@ -551,11 +524,11 @@ static void art_svp_vpath_stroke_arc(ArtVpath **p_vpath, int *pn, int *pn_max,
if (radius > 0) {
/* curve to the left */
if (th_0 < th_1) th_0 += M_PI * 2;
- n_pts = ceil((th_0 - th_1) / theta);
+ n_pts = (int)ceil((th_0 - th_1) / theta);
} else {
/* curve to the right */
if (th_1 < th_0) th_1 += M_PI * 2;
- n_pts = ceil((th_1 - th_0) / theta);
+ n_pts = (int)ceil((th_1 - th_0) / theta);
}
art_vpath_add_point(p_vpath, pn, pn_max,
ART_LINETO, xc + x0, yc + y0);
@@ -769,7 +742,7 @@ static void render_cap(ArtVpath **p_result, int *pn_result, int *pn_result_max,
ART_LINETO, vpath[i1].x + dlx0, vpath[i1].y + dly0);
break;
case ART_PATH_STROKE_CAP_ROUND:
- n_pts = ceil(M_PI / (2.0 * M_SQRT2 * sqrt(flatness / line_width)));
+ n_pts = (int)ceil(M_PI / (2.0 * M_SQRT2 * sqrt(flatness / line_width)));
art_vpath_add_point(p_result, pn_result, pn_result_max,
ART_LINETO, vpath[i1].x - dlx0, vpath[i1].y - dly0);
for (i = 1; i < n_pts; i++) {
@@ -1149,7 +1122,7 @@ static int art_svp_writer_rewind_add_segment(ArtSvpWriter *self, int wind_left,
ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
ArtSVP *svp;
ArtSVPSeg *seg;
- art_boolean left_filled, right_filled;
+ art_boolean left_filled = 0, right_filled = 0;
int wind_right = wind_left + delta_wind;
int seg_num;
const int init_n_points_max = 4;
@@ -1172,7 +1145,7 @@ static int art_svp_writer_rewind_add_segment(ArtSvpWriter *self, int wind_left,
right_filled = (wind_right > 0);
break;
default:
- art_die("Unknown wind rule %d\n", swr->rule);
+ error("Unknown wind rule %d", swr->rule);
}
if (left_filled == right_filled) {
/* discard segment now */
@@ -1386,7 +1359,7 @@ static void art_svp_intersect_add_horiz(ArtIntersectCtx *ctx, ArtActiveSeg *seg)
ArtActiveSeg *place_right = NULL;
if (seg->flags & ART_ACTIVE_FLAGS_IN_HORIZ) {
- art_warn("*** attempt to put segment in horiz list twice\n");
+ warning("attempt to put segment in horiz list twice");
return;
}
seg->flags |= ART_ACTIVE_FLAGS_IN_HORIZ;
@@ -1563,7 +1536,7 @@ static ArtActiveSeg *art_svp_intersect_add_point(ArtIntersectCtx *ctx, double x,
break;
new_x = x_test;
if (new_x < x_test) {
- art_warn("art_svp_intersect_add_point: non-ascending x\n");
+ warning("art_svp_intersect_add_point: non-ascending x");
}
x_test = new_x;
}
@@ -2281,7 +2254,8 @@ static void art_svp_render_insert_active(int i, int *active_segs, int n_active_s
/* this is a cheap hack to get ^'s sorted correctly */
x = seg_x[i] + 0.001 * seg_dx[i];
- for (j = 0; j < n_active_segs && seg_x[active_segs[j]] < x; j++);
+ for (j = 0; j < n_active_segs && seg_x[active_segs[j]] < x; j++)
+ ;
tmp1 = i;
while (j < n_active_segs) {
@@ -2438,7 +2412,8 @@ void art_svp_render_aa_iter_step(ArtSVPRenderAAIter *iter, int *p_start,
svp->segs[i].bbox.x0 < x1) {
seg = &svp->segs[i];
/* move cursor to topmost vector which overlaps [y,y+1) */
- for (curs = 0; seg->points[curs + 1].y < y; curs++);
+ for (curs = 0; seg->points[curs + 1].y < y; curs++)
+ ;
cursor[i] = curs;
dy = seg->points[curs + 1].y - seg->points[curs].y;
if (fabs(dy) >= EPSILON_6)
@@ -2491,12 +2466,12 @@ void art_svp_render_aa_iter_step(ArtSVPRenderAAIter *iter, int *p_start,
start += (int)delta;
else if (ix_min == ix_max) {
/* case 1, antialias a single pixel */
- xdelta = (ix_min + 1 - (x_min + x_max) * 0.5) * delta;
+ xdelta = (int)((ix_min + 1 - (x_min + x_max) * 0.5) * delta);
ADD_STEP(ix_min, xdelta)
if (ix_min + 1 < x1) {
- xdelta = delta - xdelta;
+ xdelta = (int)(delta - xdelta);
ADD_STEP(ix_min + 1, xdelta)
}
@@ -2505,8 +2480,8 @@ void art_svp_render_aa_iter_step(ArtSVPRenderAAIter *iter, int *p_start,
rslope = 1.0 / fabs(seg_dx[seg_index]);
drslope = delta * rslope;
last =
- drslope * 0.5 *
- (ix_min + 1 - x_min) * (ix_min + 1 - x_min);
+ (int)(drslope * 0.5 *
+ (ix_min + 1 - x_min) * (ix_min + 1 - x_min));
xdelta = last;
if (ix_min >= x0) {
ADD_STEP(ix_min, xdelta)
@@ -2519,25 +2494,25 @@ void art_svp_render_aa_iter_step(ArtSVPRenderAAIter *iter, int *p_start,
if (ix_max > x1)
ix_max = x1;
for (; x < ix_max; x++) {
- this_ = (seg->dir ? 16711680.0 : -16711680.0) * rslope *
- (x + 0.5 - x_min);
+ this_ = (int)((seg->dir ? 16711680.0 : -16711680.0) * rslope *
+ (x + 0.5 - x_min));
xdelta = this_ - last;
last = this_;
ADD_STEP(x, xdelta)
}
if (x < x1) {
- this_ =
- delta * (1 - 0.5 *
+ this_ =
+ (int)(delta * (1 - 0.5 *
(x_max - ix_max) * (x_max - ix_max) *
- rslope);
+ rslope));
xdelta = this_ - last;
last = this_;
ADD_STEP(x, xdelta)
if (x + 1 < x1) {
- xdelta = delta - last;
+ xdelta = (int)(delta - last);
ADD_STEP(x + 1, xdelta)
}
diff --git a/engines/sword25/gfx/image/b25sloader.cpp b/engines/sword25/gfx/image/b25sloader.cpp
deleted file mode 100644
index 513e74ccea..0000000000
--- a/engines/sword25/gfx/image/b25sloader.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
-#include "sword25/gfx/image/b25sloader.h"
-#include "sword25/gfx/image/pngloader.h"
-
-namespace Sword25 {
-
-#define BS_LOG_PREFIX "B25SLOADER"
-
-// -----------------------------------------------------------------------------
-
-namespace {
-static Common::String LoadString(Common::ReadStream &In, uint MaxSize = 999) {
- Common::String Result;
-
- char ch = (char)In.readByte();
- while ((ch != '\0') && (ch != ' ')) {
- Result += ch;
- if (Result.size() >= MaxSize) break;
- ch = (char)In.readByte();
- }
-
- return Result;
-}
-
-uint FindEmbeddedPNG(const byte *FileDataPtr, uint FileSize) {
- if (memcmp(FileDataPtr, "BS25SAVEGAME", 12))
- return 0;
-
- // Read in the header
- Common::MemoryReadStream stream(FileDataPtr, FileSize);
-
- // Headerinformationen der Spielstandes einlesen.
- uint compressedGamedataSize;
- LoadString(stream);
- LoadString(stream);
- Common::String gameSize = LoadString(stream);
- compressedGamedataSize = atoi(gameSize.c_str());
- LoadString(stream);
-
- // Return the offset of where the thumbnail starts
- return static_cast<uint>(stream.pos() + compressedGamedataSize);
-}
-}
-
-// -----------------------------------------------------------------------------
-
-bool B25SLoader::IsCorrectImageFormat(const byte *FileDataPtr, uint FileSize) {
- // PNG innerhalb des Spielstandes finden und den Methodenaufruf zu BS_PNGLoader weiterreichen.
- uint PNGOffset = FindEmbeddedPNG(FileDataPtr, FileSize);
- if (PNGOffset > 0) {
- return PNGLoader::DoIsCorrectImageFormat(FileDataPtr + PNGOffset, FileSize - PNGOffset);
- }
-
- return false;
-}
-
-// -----------------------------------------------------------------------------
-
-bool B25SLoader::DecodeImage(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS ColorFormat, byte *&UncompressedDataPtr,
- int &Width, int &Height, int &Pitch) {
- // PNG innerhalb des Spielstandes finden und den Methodenaufruf zu BS_PNGLoader weiterreichen.
- uint PNGOffset = FindEmbeddedPNG(FileDataPtr, FileSize);
- if (PNGOffset > 0) {
- return PNGLoader::DoDecodeImage(FileDataPtr + PNGOffset, FileSize - PNGOffset, ColorFormat, UncompressedDataPtr, Width, Height, Pitch);
- }
-
- return false;
-}
-
-// -----------------------------------------------------------------------------
-
-bool B25SLoader::ImageProperties(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS &ColorFormat, int &Width, int &Height) {
- // PNG innerhalb des Spielstandes finden und den Methodenaufruf zu BS_PNGLoader weiterreichen.
- uint PNGOffset = FindEmbeddedPNG(FileDataPtr, FileSize);
- if (PNGOffset > 0) {
- return PNGLoader::DoImageProperties(FileDataPtr + PNGOffset, FileSize - PNGOffset, ColorFormat, Width, Height);
- }
-
- return false;
-}
-
-} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/b25sloader.h b/engines/sword25/gfx/image/b25sloader.h
deleted file mode 100644
index fbfaf87194..0000000000
--- a/engines/sword25/gfx/image/b25sloader.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-#ifndef SWORD25_B25SLOADER_H
-#define SWORD25_B25SLOADER_H
-
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
-#include "sword25/kernel/common.h"
-#include "sword25/gfx/image/imageloader.h"
-
-namespace Sword25 {
-
-// -----------------------------------------------------------------------------
-// Klassendeklaration
-// -----------------------------------------------------------------------------
-
-class B25SLoader : public ImageLoader {
-public:
- static ImageLoader *CreateInstance() {
- return static_cast<ImageLoader *>(new B25SLoader());
- }
-
-protected:
- virtual bool IsCorrectImageFormat(const byte *FileDataPtr, uint FileSize);
- virtual bool DecodeImage(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS ColorFormat, byte *&UncompressedDataPtr,
- int &Width, int &Height, int &Pitch);
- virtual bool ImageProperties(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS &ColorFormat, int &Width, int &Height);
-
-};
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/sword25/gfx/image/image.h b/engines/sword25/gfx/image/image.h
index bc0ff20d77..5ac6d1ac25 100644
--- a/engines/sword25/gfx/image/image.h
+++ b/engines/sword25/gfx/image/image.h
@@ -51,7 +51,7 @@ namespace Sword25 {
class Image {
public:
- virtual ~Image() {};
+ virtual ~Image() {}
// Enums
/**
diff --git a/engines/sword25/gfx/image/imageloader.cpp b/engines/sword25/gfx/image/imageloader.cpp
deleted file mode 100644
index 55ce833cc9..0000000000
--- a/engines/sword25/gfx/image/imageloader.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-#include "sword25/gfx/image/imageloader.h"
-#include "sword25/gfx/image/imageloader_ids.h"
-
-namespace Sword25 {
-
-#define BS_LOG_PREFIX "IMAGELOADER"
-
-// Statische Elemente der Klasse BS_ImageLoader intialisieren.
-Common::List<ImageLoader *> ImageLoader::_ImageLoaderList;
-bool ImageLoader::_ImageLoaderListInitialized = false;
-
-// Lade Methode
-// ------------
-
-bool ImageLoader::LoadImage(const byte *pFileData, uint FileSize,
- GraphicEngine::COLOR_FORMATS ColorFormat,
- byte *&pUncompressedData,
- int &Width, int &Height,
- int &Pitch) {
- // Falls die Liste der BS_ImageLoader noch nicht initialisiert wurde, wird dies getan.
- if (!_ImageLoaderListInitialized)
- _InitializeLoaderList();
-
- // Passenden BS_ImageLoader finden und Bild dekodieren
- ImageLoader *pLoader = _FindSuitableImageLoader(pFileData, FileSize);
- if (pLoader) {
- return pLoader->DecodeImage(pFileData, FileSize,
- ColorFormat,
- pUncompressedData,
- Width, Height,
- Pitch);
- }
-
- return false;
-}
-
-// Info Methode
-// ------------
-
-bool ImageLoader::ExtractImageProperties(const byte *pFileData, uint FileSize,
- GraphicEngine::COLOR_FORMATS &ColorFormat,
- int &Width, int &Height) {
- // Falls die Liste der BS_ImageLoader noch nicht initialisiert wurde, wird dies getan.
- if (!_ImageLoaderListInitialized)
- _InitializeLoaderList();
-
- // Passenden BS_ImageLoader finden und Bildeigenschaften auslesen.
- ImageLoader *pLoader = _FindSuitableImageLoader(pFileData, FileSize);
- if (pLoader) {
- return pLoader->ImageProperties(pFileData, FileSize,
- ColorFormat,
- Width, Height);
- }
-
- return false;
-}
-
-// Verwaltungs Methoden
-// --------------------
-
-void ImageLoader::_InitializeLoaderList() {
- // Von jedem BS_ImageLoader wird eine Instanz erzeugt, diese fügen sich selbständig in die BS_ImageLoader-Liste ein.
- for (int i = 0; i < BS_IMAGELOADER_COUNT; i++)
- BS_IMAGELOADER_IDS[i]();
-
- // Die Liste als gefüllt markieren.
- _ImageLoaderListInitialized = true;
-
- // Sicherstellen, dass beim Beenden alle BS_ImageLoader Instanzen zerstört werden.
- atexit(ImageLoader::_DeinitializeLoaderList);
-}
-
-void ImageLoader::_DeinitializeLoaderList() {
- while (!_ImageLoaderList.empty()) {
- delete _ImageLoaderList.back();
- _ImageLoaderList.pop_back();
- }
-}
-
-ImageLoader *ImageLoader::_FindSuitableImageLoader(const byte *pFileData, uint FileSize) {
- // Alle BS_ImageLoader-Objekte durchgehen, bis eins gefunden wurde, dass das Bild laden kann
- Common::List<ImageLoader *>::iterator Iter = _ImageLoaderList.begin();
- for (; Iter != _ImageLoaderList.end(); ++Iter) {
- // Falls ein geeigneter BS-ImageLoader gefunden wurde, wird er zurückgegeben.
- if ((*Iter)->IsCorrectImageFormat(pFileData, FileSize)) {
- return (*Iter);
- }
- }
-
- // Es konnte kein passender BS_ImageLoader gefunden werden.
- BS_LOG_ERRORLN("Could not find suitable image loader for image data.");
- return NULL;
-}
-
-} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/imageloader.h b/engines/sword25/gfx/image/imageloader.h
deleted file mode 100644
index aae48a083c..0000000000
--- a/engines/sword25/gfx/image/imageloader.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-/*
- BS_ImageLoader
- --------------
-
- Autor: Malte Thiesen
-*/
-
-#ifndef SWORD25_IMAGELOADER_H
-#define SWORD25_IMAGELOADER_H
-
-// Includes
-#include "sword25/kernel/bs_stdint.h"
-#include "sword25/kernel/common.h"
-#include "sword25/gfx/graphicengine.h"
-
-namespace Sword25 {
-
-/**
- @brief Über die statischen Methoden dieser Klasse werden alle unterstützten Bildformate geladen.
-
- Zum Laden von Bildern wird die #LoadImage-Methode benutzt.
-
- Außerdem stellt diese Klasse das Interface da, das alle Klassen implementieren müssen, die Bildformate einlesen.<br>
- Zur Unterstützung eines neuen Bildformates muss folgendermaßen vorgegangen werden:
- - Erzeugen einer neuen von #BS_ImageLoader abgeleiteten Klasse, die die Methoden #IsCorrectImageFormat und #DecodeImage impelementiert.
- - Die Klasse muss eine statische Methode haben, die eine Instanz von ihr erzeugt und einen Pointer darauf zurückgibt.
- - Diese Methode muss in der Liste in der Datei imageloader_ids.h eingetragen werden.
- - Die Klasse muss JEDES Eingabebild seines Bildformates in die folgenden Farbformate konvertieren können:
- - BS_GraphicEngine::CF_ARGB32
- - Zum Konvertieren der Bilddaten können die Hilfsmethoden dieser Klasse benutzt werden, die ARGB Bilddaten in alle benötigten
- Farbformate konvertieren.
-*/
-class ImageLoader {
-public:
-
- //@{
- /** @name Lade Methoden */
-
- /**
- @brief Lädt eine Bilddatei.
-
- Diese Methode kann sämtliche unterstütztem Bildformate lesen. Die Methode erkennt selbstständing um welches Dateiformat es sich
- bei der vorliegenden Datei handelt.<br>
- Bisher wird nur PNG unterstützt.
-
- @param pFileData ein Pointer auf die Bilddaten.
- @param FileSize die Größe der Bilddaten in Byte.
- @param ColorFormat gibt das gewünschte Farbformat an, in das die Bilddaten konvertiert werden sollen.<br>
- Folgende Farbformate werden unterstützt:
- - BS_GraphicEngine::CF_ARGB32
- @param pUncompressedData nach erfolgreichen Laden zeigt dieser Pointer auf die enpackten und konvertierten Bilddaten.
- @param Width gibt nach erfolgreichen Laden die Breite des geladenen Bildes an.
- @param Height gibt nach erfolgreichen Laden die Höhe des geladenen Bildes an.
- @param Pitch gibt nach erfolgreichen Laden die Länge einer Bildzeile in Byte an.
- @return Gibt false zurück, falls das Laden fehlgeschlagen ist.
- @remark Die Größe der Ausgabedaten in Bytes kann wie folgt berechnet werden: Pitch * Height.
- @remark Es darf nicht vergessen werden, die Ausgabedaten nach erfolgter Benutzung mit delete freizugeben.
- */
- static bool LoadImage(const byte *pFileData, uint FileSize,
- GraphicEngine::COLOR_FORMATS ColorFormat,
- byte *&pUncompressedData,
- int &Width, int &Height,
- int &Pitch);
-
- /**
- @brief Liest die Bildeigenschaften eines Bildes aus.
-
- @param pFileData ein Pointer auf die Bilddaten.
- @param FileSize die Größe des Bilddaten in Byte.
- @param ColorFormat enthält nach einem erfolgreichem Aufruf das Farbformat des Bildes.
- @param Width enthält nach einem erfolgreichem Aufruf die Breite des Bildes in Pixeln.
- @param Height enthält nach einem erfolgreichem Aufruf die Höhe des Bildes in Pixeln.
- @return Gibt false zurück, wenn die Bildeigenschaften nicht ausgelesen werden konnten.
- @remark Es darf nicht vergessen werden, die Ausgabedaten nach erfolgter Benutzung mit delete freizugeben.
- */
- static bool ExtractImageProperties(const byte *pFileData, uint FileSize,
- GraphicEngine::COLOR_FORMATS &ColorFormat,
- int &Width, int &Height);
- //@}
-
-protected:
-
- // Protected Konstruktor, damit Instanzen dieser Klasse nur von BS_ImageLoader-Objekten erstellt werden können
- /**
- @brief Der Standardkonstruktor.
-
- Dieser Konstruktor registriert alle Instanzen von #BS_ImageLoader-Klassen in einer Liste.<br>
- Diese Liste enthält jeweils eine Instanz jedes #BS_ImageLoader und wird benutzt um beliebige Bilddateien einem Loader zuzuordnen.
- @remark Dieser Konstruktor ist protected damit nur #BS_ImageLoader-Objekte diese Klasse instanziieren können.
- */
- ImageLoader() {
- // Klasse registrieren
- _ImageLoaderList.push_front(this);
- }
-
- virtual ~ImageLoader() {}
-
- //@{
- /** @name Abstrakte Methoden */
-
- /**
- @brief Gibt an, ob der #BS_ImageLoader ein Bild lesen kann.
- @param pFileData ein Pointer auf die kompletten Daten des Bildes.
- @param FileSize die Größe der Daten in Byte.
- @return Gibt true zurück, wenn der #BS_ImageLoader das Bild lesen kann, ansonsten false.
- @remark Diese Methode muss von allen BS_ImageLoader Klassen implementiert werden.
- */
- virtual bool IsCorrectImageFormat(const byte *pFileData, uint FileSize) = 0;
-
- /**
- @brief Lädt eine Bilddatei.
- @param pFileData ein Pointer auf die Bilddaten.
- @param FileSize die Größe der Bilddaten in Byte.
- @param ColorFormat gibt das gewünschte Farbformat an, in das die Bilddaten konvertiert werden sollen.<br>
- Folgende Farbformate werden unterstützt:
- - BS_GraphicEngine::CF_ARGB32
- @param pUncompressedData nach erfolgreichen Laden zeigt dieser Pointer auf die enpackten und konvertierten Bilddaten.
- @param Width gibt nach erfolgreichen Laden die Breite des geladenen Bildes an.
- @param Height gibt nach erfolgreichen Laden die Höhe des geladenen Bildes an.
- @param Pitch gibt nach erfolgreichen Laden die Länge einer Bildzeile in Byte an.
- @return Gibt false zurück, falls das Laden fehlgeschlagen ist.
- @remark Die Größe der Ausgabedaten in Bytes kann wie folgt berechnet werden: Pitch * Height.
- @remark Es darf nicht vergessen werden, die Ausgabedaten nach erfolgter Benutzung mit delete freizugeben.
- @remark Diese Methode muss von allen BS_ImageLoader Klassen implementiert werden.
- */
- virtual bool DecodeImage(const byte *pFileData, uint FileSize,
- GraphicEngine::COLOR_FORMATS ColorFormat,
- byte *&pUncompressedData,
- int &Width, int &Height,
- int &Pitch) = 0;
-
- /**
- @brief Liest die Bildeigenschaften aus.
- @param pFileData ein Pointer auf die Bilddaten.
- @param FileSize die Größe des Bilddaten in Byte.
- @param ColorFormat enthält nach einem erfolgreichem Aufruf das Farbformat des Bildes.
- @param Width enthält nach einem erfolgreichem Aufruf die Breite des Bildes in Pixeln.
- @param Height enthält nach einem erfolgreichem Aufruf die Höhe des Bildes in Pixeln.
- @return Gibt false zurück, wenn die Bildeigenschaften nicht ausgelesen werden konnten.
- @remark Es darf nicht vergessen werden, die Ausgabedaten nach erfolgter Benutzung mit delete freizugeben.
- @remark Diese Methode muss von allen BS_ImageLoader Klassen implementiert werden.
- */
- virtual bool ImageProperties(const byte *pFileData, uint FileSize,
- GraphicEngine::COLOR_FORMATS &ColorFormat,
- int &Width, int &Height) = 0;
-
- //@}
-
-private:
-
- /**
- @brief Erzeugt je eine Instanz aller BS_ImageLoader Klassen und fügt diese in eine interne Liste ein. Diese werden dann beim
- Laden von Bildern benutzt.
- @remark Die Klassen müssen in der Datei imageloader_ids.h eingetragen sein, damit sie an dieser Stelle berücksichtigt werden.
- */
- static void _InitializeLoaderList();
-
- /**
- @brief Zerstört alle Instanzen von BS_ImageLoader Klassen, die in dieser Klasse registriert sind.
- */
- static void _DeinitializeLoaderList();
-
- /**
- @brief Sucht zu Bilddaten ein BS_ImageLoader Objekt, dass die Bilddaten dekodieren kann.
- @return Gibt einen Pointer auf ein passendes BS_ImageLoader Objekt zurück, oder NULL, wenn kein passendes Objekt gefunden wurde.
- */
- static ImageLoader *_FindSuitableImageLoader(const byte *pFileData, uint FileSize);
-
- static Common::List<ImageLoader *> _ImageLoaderList; // Die Liste aller BS_ImageLoader-Objekte
- static bool _ImageLoaderListInitialized; // Gibt an, ob die Liste schon intialisiert wurde
-};
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/sword25/gfx/image/imageloader_ids.h b/engines/sword25/gfx/image/imageloader_ids.h
deleted file mode 100644
index 8fb6872ad7..0000000000
--- a/engines/sword25/gfx/image/imageloader_ids.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-/*
- imageloader_ids.h
- -----------------
- In dieser Datei sind alle ImageLoader verzeichnet.
- JEDER neuer ImageLoader muss hier eingetragen werden, ansonsten wird er beim Laden eines Bildes nicht berücksichtigt.
-
- Autor: Malte Thiesen
-*/
-
-#include "sword25/gfx/image/imageloader.h"
-
-// Die Headerdateien der ImageLoader müssen hier eingebunden werden
-#include "sword25/gfx/image/pngloader.h"
-#include "sword25/gfx/image/b25sloader.h"
-
-namespace Sword25 {
-
-// Die Tabelle enthält Pointer auf statische Member-Funktionen innerhalb der Klassen, die eine Instanz der Klasse
-// erzeugen
-typedef ImageLoader*(*BS_IMAGELOADER_NEW)();
-const BS_IMAGELOADER_NEW BS_IMAGELOADER_IDS[] = {
- PNGLoader::CreateInstance,
- B25SLoader::CreateInstance,
-};
-const int BS_IMAGELOADER_COUNT = sizeof(BS_IMAGELOADER_IDS) / sizeof(BS_IMAGELOADER_NEW);
-
-
-} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/pngloader.cpp b/engines/sword25/gfx/image/pngloader.cpp
index c59d68724d..1b72595a8f 100644
--- a/engines/sword25/gfx/image/pngloader.cpp
+++ b/engines/sword25/gfx/image/pngloader.cpp
@@ -32,9 +32,8 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
+// Disable symbol overrides so that we can use png.h
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "sword25/gfx/image/image.h"
#include "sword25/gfx/image/pngloader.h"
@@ -44,44 +43,74 @@ namespace Sword25 {
#define BS_LOG_PREFIX "PNGLOADER"
-// -----------------------------------------------------------------------------
-// Konstruktor / Destruktor
-// -----------------------------------------------------------------------------
-PNGLoader::PNGLoader() {
+/**
+ * Load a NULL-terminated string from the given stream.
+ */
+static Common::String loadString(Common::ReadStream &in, uint maxSize = 999) {
+ Common::String result;
+
+ while (!in.eos() && (result.size() < maxSize)) {
+ char ch = (char)in.readByte();
+ if (ch == '\0')
+ break;
+
+ result += ch;
+ }
+
+ return result;
}
-// -----------------------------------------------------------------------------
-// Laden
-// -----------------------------------------------------------------------------
+/**
+ * Check if the given data is a savegame, and if so, locate the
+ * offset to the image data.
+ * @return offset to image data if fileDataPtr contains a savegame; 0 otherwise
+ */
+static uint findEmbeddedPNG(const byte *fileDataPtr, uint fileSize) {
+ if (fileSize < 100)
+ return 0;
+ if (memcmp(fileDataPtr, "BS25SAVEGAME", 12))
+ return 0;
+
+ // Read in the header
+ Common::MemoryReadStream stream(fileDataPtr, fileSize);
+ stream.seek(0, SEEK_SET);
+
+ // Headerinformationen der Spielstandes einlesen.
+ uint compressedGamedataSize;
+ loadString(stream); // Marker
+ loadString(stream); // Version
+ loadString(stream); // Description
+ Common::String gameSize = loadString(stream);
+ compressedGamedataSize = atoi(gameSize.c_str());
+ loadString(stream);
+
+ // Return the offset of where the thumbnail starts
+ return static_cast<uint>(stream.pos() + compressedGamedataSize);
+}
static void png_user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
- memcpy(data, (char *)png_ptr->io_ptr, length);
- png_ptr->io_ptr = (void *)((png_size_t)png_ptr->io_ptr + length);
+ const byte **ref = (const byte **)png_get_io_ptr(png_ptr);
+ memcpy(data, *ref, length);
+ *ref += length;
+}
+
+static bool doIsCorrectImageFormat(const byte *fileDataPtr, uint fileSize) {
+ return (fileSize > 8) && png_check_sig(const_cast<byte *>(fileDataPtr), 8);
}
-// -----------------------------------------------------------------------------
-bool PNGLoader::DoDecodeImage(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS ColorFormat, byte *&UncompressedDataPtr,
- int &Width, int &Height, int &Pitch) {
+bool PNGLoader::doDecodeImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) {
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
- png_bytep RawDataBuffer = NULL;
- png_bytep *pRowPtr = NULL;
- int BitDepth;
- int ColorType;
- int InterlaceType;
+ int bitDepth;
+ int colorType;
+ int interlaceType;
int i;
- // Zielfarbformat überprüfen
- if (ColorFormat != GraphicEngine::CF_ARGB32) {
- BS_LOG_ERRORLN("Illegal or unsupported color format.");
- return false;
- }
-
- // PNG Signatur überprüfen
- if (!png_check_sig(reinterpret_cast<png_bytep>(const_cast<byte *>(FileDataPtr)), 8)) {
+ // Check for valid PNG signature
+ if (!doIsCorrectImageFormat(fileDataPtr, fileSize)) {
error("png_check_sig failed");
}
@@ -97,127 +126,92 @@ bool PNGLoader::DoDecodeImage(const byte *FileDataPtr, uint FileSize, GraphicEn
}
// Alternative Lesefunktion benutzen
- png_set_read_fn(png_ptr, (void *)FileDataPtr, png_user_read_data);
+ const byte **ref = &fileDataPtr;
+ png_set_read_fn(png_ptr, (void *)ref, png_user_read_data);
// PNG Header einlesen
png_read_info(png_ptr, info_ptr);
// PNG Informationen auslesen
- png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&Width, (png_uint_32 *)&Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL);
+ png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&width, (png_uint_32 *)&height, &bitDepth, &colorType, &interlaceType, NULL, NULL);
// Pitch des Ausgabebildes berechnen
- Pitch = GraphicEngine::CalcPitch(ColorFormat, Width);
+ pitch = GraphicEngine::calcPitch(GraphicEngine::CF_ARGB32, width);
// Speicher für die endgültigen Bilddaten reservieren
// Dieses geschieht vor dem reservieren von Speicher für temporäre Bilddaten um die Fragmentierung des Speichers gering zu halten
- UncompressedDataPtr = new byte[Pitch * Height];
- if (!UncompressedDataPtr) {
+ uncompressedDataPtr = new byte[pitch * height];
+ if (!uncompressedDataPtr) {
error("Could not allocate memory for output image.");
}
// Bilder jeglicher Farbformate werden zunächst in ARGB Bilder umgewandelt
- if (BitDepth == 16)
+ if (bitDepth == 16)
png_set_strip_16(png_ptr);
- if (ColorType == PNG_COLOR_TYPE_PALETTE)
+ if (colorType == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
- if (BitDepth < 8)
+ if (bitDepth < 8)
png_set_expand(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr);
- if (ColorType == PNG_COLOR_TYPE_GRAY ||
- ColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
+ if (colorType == PNG_COLOR_TYPE_GRAY ||
+ colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
png_set_bgr(png_ptr);
- if (ColorType != PNG_COLOR_TYPE_RGB_ALPHA)
+ if (colorType != PNG_COLOR_TYPE_RGB_ALPHA)
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
// Nachdem die Transformationen registriert wurden, werden die Bilddaten erneut eingelesen
png_read_update_info(png_ptr, info_ptr);
- png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&Width, (png_uint_32 *)&Height, &BitDepth, &ColorType, NULL, NULL, NULL);
-
- // PNGs ohne Interlacing werden Zeilenweise eingelesen
- if (InterlaceType == PNG_INTERLACE_NONE) {
- // Speicher für eine Bildzeile reservieren
- RawDataBuffer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
- if (!RawDataBuffer) {
- error("Could not allocate memory for row buffer.");
- }
+ png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&width, (png_uint_32 *)&height, &bitDepth, &colorType, NULL, NULL, NULL);
- // Bilddaten zeilenweise einlesen und in das gewünschte Zielformat konvertieren
- for (i = 0; i < Height; i++) {
- // Zeile einlesen
- png_read_row(png_ptr, RawDataBuffer, NULL);
-
- // Zeile konvertieren
- switch (ColorFormat) {
- case GraphicEngine::CF_ARGB32:
- memcpy(&UncompressedDataPtr[i * Pitch], RawDataBuffer, Pitch);
- break;
- default:
- assert(0);
- }
+ if (interlaceType == PNG_INTERLACE_NONE) {
+ // PNGs without interlacing can simply be read row by row.
+ for (i = 0; i < height; i++) {
+ png_read_row(png_ptr, uncompressedDataPtr + i * pitch, NULL);
}
} else {
- // PNGs mit Interlacing werden an einem Stück eingelesen
- // Speicher für das komplette Bild reservieren
- RawDataBuffer = new png_byte[png_get_rowbytes(png_ptr, info_ptr) * Height];
- if (!RawDataBuffer) {
- error("Could not allocate memory for raw image buffer.");
- }
+ // PNGs with interlacing require us to allocate an auxillary
+ // buffer with pointers to all row starts.
- // Speicher für die Rowpointer reservieren
- pRowPtr = new png_bytep[Height];
+ // Allocate row pointer buffer
+ png_bytep *pRowPtr = new png_bytep[height];
if (!pRowPtr) {
error("Could not allocate memory for row pointers.");
}
- // Alle Rowpointer mit den richtigen Offsets initialisieren
- for (i = 0; i < Height; i++)
- pRowPtr[i] = RawDataBuffer + i * png_get_rowbytes(png_ptr, info_ptr);
+ // Initialize row pointers
+ for (i = 0; i < height; i++)
+ pRowPtr[i] = uncompressedDataPtr + i * pitch;
- // Bild einlesen
+ // Read image data
png_read_image(png_ptr, pRowPtr);
- // Bilddaten zeilenweise in das gewünschte Ausgabeformat konvertieren
- switch (ColorFormat) {
- case GraphicEngine::CF_ARGB32:
- for (i = 0; i < Height; i++)
- memcpy(&UncompressedDataPtr[i * Pitch], &RawDataBuffer[i * png_get_rowbytes(png_ptr, info_ptr)], Pitch);
- break;
- default:
- error("Unhandled case in DoDecodeImage");
- break;
- }
+ // Free row pointer buffer
+ delete[] pRowPtr;
}
- // Die zusätzlichen Daten am Ende des Bildes lesen
+ // Read additional data at the end.
png_read_end(png_ptr, NULL);
- // Die Strukturen freigeben
+ // Destroy libpng structures
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- // Temporäre Buffer freigeben
- delete[] pRowPtr;
- delete[] RawDataBuffer;
-
- // Der Funktionsaufruf war erfolgreich
+ // Signal success
return true;
}
-// -----------------------------------------------------------------------------
-
-bool PNGLoader::DecodeImage(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS ColorFormat, byte *&UncompressedDataPtr,
- int &Width, int &Height, int &Pitch) {
- return DoDecodeImage(FileDataPtr, FileSize, ColorFormat, UncompressedDataPtr, Width, Height, Pitch);
+bool PNGLoader::decodeImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) {
+ uint pngOffset = findEmbeddedPNG(fileDataPtr, fileSize);
+ return doDecodeImage(fileDataPtr + pngOffset, fileSize - pngOffset, uncompressedDataPtr, width, height, pitch);
}
-// -----------------------------------------------------------------------------
-
-bool PNGLoader::DoImageProperties(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS &ColorFormat, int &Width, int &Height) {
- // PNG Signatur überprüfen
- if (!DoIsCorrectImageFormat(FileDataPtr, FileSize)) return false;
+bool PNGLoader::doImageProperties(const byte *fileDataPtr, uint fileSize, int &width, int &height) {
+ // Check for valid PNG signature
+ if (!doIsCorrectImageFormat(fileDataPtr, fileSize))
+ return false;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
@@ -234,21 +228,16 @@ bool PNGLoader::DoImageProperties(const byte *FileDataPtr, uint FileSize, Graphi
}
// Alternative Lesefunktion benutzen
- png_set_read_fn(png_ptr, (void *)FileDataPtr, png_user_read_data);
+ const byte **ref = &fileDataPtr;
+ png_set_read_fn(png_ptr, (void *)ref, png_user_read_data);
// PNG Header einlesen
png_read_info(png_ptr, info_ptr);
// PNG Informationen auslesen
- int BitDepth;
- int ColorType;
- png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&Width, (png_uint_32 *)&Height, &BitDepth, &ColorType, NULL, NULL, NULL);
-
- // PNG-ColorType in BS ColorFormat konvertieren.
- if (ColorType & PNG_COLOR_MASK_ALPHA || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
- ColorFormat = GraphicEngine::CF_ARGB32;
- else
- ColorFormat = GraphicEngine::CF_RGB24;
+ int bitDepth;
+ int colorType;
+ png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&width, (png_uint_32 *)&height, &bitDepth, &colorType, NULL, NULL, NULL);
// Die Strukturen freigeben
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
@@ -257,27 +246,10 @@ bool PNGLoader::DoImageProperties(const byte *FileDataPtr, uint FileSize, Graphi
}
-// -----------------------------------------------------------------------------
-
-bool PNGLoader::ImageProperties(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS &ColorFormat, int &Width, int &Height) {
- return DoImageProperties(FileDataPtr, FileSize, ColorFormat, Width, Height);
+bool PNGLoader::imageProperties(const byte *fileDataPtr, uint fileSize, int &width, int &height) {
+ uint pngOffset = findEmbeddedPNG(fileDataPtr, fileSize);
+ return doImageProperties(fileDataPtr + pngOffset, fileSize - pngOffset, width, height);
}
-// -----------------------------------------------------------------------------
-// Header überprüfen
-// -----------------------------------------------------------------------------
-
-bool PNGLoader::DoIsCorrectImageFormat(const byte *FileDataPtr, uint FileSize) {
- if (FileSize > 8)
- return png_check_sig(const_cast<byte *>(FileDataPtr), 8) ? true : false;
- else
- return false;
-}
-
-// -----------------------------------------------------------------------------
-
-bool PNGLoader::IsCorrectImageFormat(const byte *FileDataPtr, uint FileSize) {
- return DoIsCorrectImageFormat(FileDataPtr, FileSize);
-}
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/pngloader.h b/engines/sword25/gfx/image/pngloader.h
index 44c31b267c..e0d68ff8b9 100644
--- a/engines/sword25/gfx/image/pngloader.h
+++ b/engines/sword25/gfx/image/pngloader.h
@@ -32,46 +32,60 @@
*
*/
-/*
- BS_PNGLoader
- ------------
- BS_ImageLoader-Klasse zum Laden von PNG-Dateien
-
- Autor: Malte Thiesen
-*/
-
#ifndef SWORD25_PNGLOADER2_H
#define SWORD25_PNGLOADER2_H
-// Includes
#include "sword25/kernel/common.h"
-#include "sword25/gfx/image/imageloader.h"
+#include "sword25/gfx/graphicengine.h"
namespace Sword25 {
-// Klassendefinition
-class PNGLoader : public ImageLoader {
-public:
- static ImageLoader *CreateInstance() {
- return (ImageLoader *) new PNGLoader();
- }
+/**
+ * Class for loading PNG files, and PNG data embedded into savegames.
+ *
+ * Originally written by Malte Thiesen.
+ */
+class PNGLoader {
+protected:
+ PNGLoader() {} // Protected constructor to prevent instances
- // Alle virtuellen Methoden von BS_ImageLoader sind hier als static-Methode implementiert, damit sie von BS_B25SLoader aufgerufen werden können.
- // Die virtuellen Methoden rufen diese Methoden auf.
- static bool DoIsCorrectImageFormat(const byte *FileDataPtr, uint FileSize);
- static bool DoDecodeImage(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS ColorFormat, byte *&UncompressedDataPtr,
- int &Width, int &Height, int &Pitch);
- static bool DoImageProperties(const byte *FileDataPtr, uint FileSize, GraphicEngine::COLOR_FORMATS &ColorFormat, int &Width, int &Height);
+ static bool doDecodeImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch);
+ static bool doImageProperties(const byte *fileDataPtr, uint fileSize, int &width, int &height);
-protected:
- PNGLoader();
- bool DecodeImage(const byte *pFileData, uint FileSize,
- GraphicEngine::COLOR_FORMATS ColorFormat,
- byte *&pUncompressedData,
- int &Width, int &Height,
- int &Pitch);
- bool IsCorrectImageFormat(const byte *FileDataPtr, uint FileSize);
- bool ImageProperties(const byte *FileDatePtr, uint FileSize, GraphicEngine::COLOR_FORMATS &ColorFormat, int &Width, int &Height);
+public:
+
+ /**
+ * Decode an image.
+ * @param[in] fileDatePtr pointer to the image data
+ * @param[in] fileSize size of the image data in bytes
+ * @param[out] pUncompressedData if successful, this is set to a pointer containing the decoded image data
+ * @param[out] width if successful, this is set to the width of the image
+ * @param[out] height if successful, this is set to the height of the image
+ * @param[out] pitch if successful, this is set to the number of bytes per scanline in the image
+ * @return false in case of an error
+ *
+ * @remark The size of the output data equals pitch * height.
+ * @remark This function does not free the image buffer passed to it,
+ * it is the callers responsibility to do so.
+ */
+ static bool decodeImage(const byte *pFileData, uint fileSize,
+ byte *&pUncompressedData,
+ int &width, int &height,
+ int &pitch);
+ /**
+ * Extract the properties of an image.
+ * @param[in] fileDatePtr pointer to the image data
+ * @param[in] fileSize size of the image data in bytes
+ * @param[out] width if successful, this is set to the width of the image
+ * @param[out] height if successful, this is set to the height of the image
+ * @return returns true if extraction of the properties was successful, false in case of an error
+ *
+ * @remark This function does not free the image buffer passed to it,
+ * it is the callers responsibility to do so.
+ */
+ static bool imageProperties(const byte *fileDatePtr, uint fileSize,
+ int &width,
+ int &height);
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp
index 96b6139a59..fb82f893c6 100644
--- a/engines/sword25/gfx/image/renderedimage.cpp
+++ b/engines/sword25/gfx/image/renderedimage.cpp
@@ -37,7 +37,7 @@
// -----------------------------------------------------------------------------
#include "sword25/package/packagemanager.h"
-#include "sword25/gfx/image/imageloader.h"
+#include "sword25/gfx/image/pngloader.h"
#include "sword25/gfx/image/renderedimage.h"
#include "common/system.h"
@@ -56,30 +56,30 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
_height(0) {
result = false;
- PackageManager *pPackage = static_cast<PackageManager *>(Kernel::GetInstance()->GetService("package"));
+ PackageManager *pPackage = Kernel::getInstance()->getPackage();
BS_ASSERT(pPackage);
- _backSurface = (static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx")))->getSurface();
+ _backSurface = Kernel::getInstance()->getGfx()->getSurface();
// Datei laden
byte *pFileData;
uint fileSize;
- if (!(pFileData = (byte *)pPackage->getFile(filename, &fileSize))) {
+ pFileData = pPackage->getFile(filename, &fileSize);
+ if (!pFileData) {
BS_LOG_ERRORLN("File \"%s\" could not be loaded.", filename.c_str());
return;
}
// Bildeigenschaften bestimmen
- GraphicEngine::COLOR_FORMATS colorFormat;
int pitch;
- if (!ImageLoader::ExtractImageProperties(pFileData, fileSize, colorFormat, _width, _height)) {
+ if (!PNGLoader::imageProperties(pFileData, fileSize, _width, _height)) {
BS_LOG_ERRORLN("Could not read image properties.");
delete[] pFileData;
return;
}
// Das Bild dekomprimieren
- if (!ImageLoader::LoadImage(pFileData, fileSize, GraphicEngine::CF_ARGB32, _data, _width, _height, pitch)) {
+ if (!PNGLoader::decodeImage(pFileData, fileSize, _data, _width, _height, pitch)) {
BS_LOG_ERRORLN("Could not decode image.");
delete[] pFileData;
return;
@@ -103,7 +103,7 @@ RenderedImage::RenderedImage(uint width, uint height, bool &result) :
_data = new byte[width * height * 4];
Common::set_to(_data, &_data[width * height * 4], 0);
- _backSurface = (static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx")))->getSurface();
+ _backSurface = Kernel::getInstance()->getGfx()->getSurface();
_doCleanup = true;
@@ -112,7 +112,7 @@ RenderedImage::RenderedImage(uint width, uint height, bool &result) :
}
RenderedImage::RenderedImage() : _width(0), _height(0), _data(0) {
- _backSurface = (static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx")))->getSurface();
+ _backSurface = Kernel::getInstance()->getGfx()->getSurface();
_doCleanup = false;
diff --git a/engines/sword25/gfx/image/swimage.cpp b/engines/sword25/gfx/image/swimage.cpp
index ac4463ea16..84aa35b0f4 100644
--- a/engines/sword25/gfx/image/swimage.cpp
+++ b/engines/sword25/gfx/image/swimage.cpp
@@ -32,12 +32,8 @@
*
*/
-// -----------------------------------------------------------------------------
-// INCLUDES
-// -----------------------------------------------------------------------------
-
#include "sword25/package/packagemanager.h"
-#include "sword25/gfx/image/imageloader.h"
+#include "sword25/gfx/image/pngloader.h"
#include "sword25/gfx/image/swimage.h"
namespace Sword25 {
@@ -45,38 +41,34 @@ namespace Sword25 {
#define BS_LOG_PREFIX "SWIMAGE"
-// -----------------------------------------------------------------------------
-// CONSTRUCTION / DESTRUCTION
-// -----------------------------------------------------------------------------
-
SWImage::SWImage(const Common::String &filename, bool &result) :
_imageDataPtr(0),
_width(0),
_height(0) {
result = false;
- PackageManager *pPackage = static_cast<PackageManager *>(Kernel::GetInstance()->GetService("package"));
+ PackageManager *pPackage = Kernel::getInstance()->getPackage();
BS_ASSERT(pPackage);
// Datei laden
byte *pFileData;
uint fileSize;
- if (!(pFileData = (byte *)pPackage->getFile(filename, &fileSize))) {
+ pFileData = pPackage->getFile(filename, &fileSize);
+ if (!pFileData) {
BS_LOG_ERRORLN("File \"%s\" could not be loaded.", filename.c_str());
return;
}
// Bildeigenschaften bestimmen
- GraphicEngine::COLOR_FORMATS colorFormat;
int pitch;
- if (!ImageLoader::ExtractImageProperties(pFileData, fileSize, colorFormat, _width, _height)) {
+ if (!PNGLoader::imageProperties(pFileData, fileSize, _width, _height)) {
BS_LOG_ERRORLN("Could not read image properties.");
return;
}
// Das Bild dekomprimieren
byte *pUncompressedData;
- if (!ImageLoader::LoadImage(pFileData, fileSize, GraphicEngine::CF_ARGB32, pUncompressedData, _width, _height, pitch)) {
+ if (!PNGLoader::decodeImage(pFileData, fileSize, pUncompressedData, _width, _height, pitch)) {
BS_LOG_ERRORLN("Could not decode image.");
return;
}
@@ -90,15 +82,11 @@ SWImage::SWImage(const Common::String &filename, bool &result) :
return;
}
-// -----------------------------------------------------------------------------
-
SWImage::~SWImage() {
delete[] _imageDataPtr;
}
-// -----------------------------------------------------------------------------
-
bool SWImage::blit(int posX, int posY,
int flipping,
Common::Rect *pPartRect,
@@ -108,22 +96,16 @@ bool SWImage::blit(int posX, int posY,
return false;
}
-// -----------------------------------------------------------------------------
-
bool SWImage::fill(const Common::Rect *pFillRect, uint color) {
BS_LOG_ERRORLN("Fill() is not supported.");
return false;
}
-// -----------------------------------------------------------------------------
-
bool SWImage::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
BS_LOG_ERRORLN("SetContent() is not supported.");
return false;
}
-// -----------------------------------------------------------------------------
-
uint SWImage::getPixel(int x, int y) {
BS_ASSERT(x >= 0 && x < _width);
BS_ASSERT(y >= 0 && y < _height);
diff --git a/engines/sword25/gfx/image/swimage.h b/engines/sword25/gfx/image/swimage.h
index caf6bdcc71..a914c4f41f 100644
--- a/engines/sword25/gfx/image/swimage.h
+++ b/engines/sword25/gfx/image/swimage.h
@@ -35,10 +35,6 @@
#ifndef SWORD25_SWIMAGE_H
#define SWORD25_SWIMAGE_H
-// -----------------------------------------------------------------------------
-// INCLUDES
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/gfx/image/image.h"
#include "sword25/gfx/graphicengine.h"
@@ -46,10 +42,6 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// CLASS DEFINITION
-// -----------------------------------------------------------------------------
-
class SWImage : public Image {
public:
SWImage(const Common::String &filename, bool &result);
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
index c2a80cb5f2..5c15c4771a 100644
--- a/engines/sword25/gfx/image/vectorimage.cpp
+++ b/engines/sword25/gfx/image/vectorimage.cpp
@@ -36,7 +36,6 @@
// Includes
// -----------------------------------------------------------------------------
-#include "sword25/kernel/bs_stdint.h"
#include "sword25/gfx/image/art.h"
#include "sword25/gfx/image/vectorimage.h"
#include "sword25/gfx/image/renderedimage.h"
diff --git a/engines/sword25/gfx/image/vectorimagerenderer.cpp b/engines/sword25/gfx/image/vectorimagerenderer.cpp
index 16d1abf9f9..7587aab4e5 100644
--- a/engines/sword25/gfx/image/vectorimagerenderer.cpp
+++ b/engines/sword25/gfx/image/vectorimagerenderer.cpp
@@ -248,9 +248,9 @@ void art_rgb_svp_alpha1(const ArtSVP *svp,
}
static int art_vpath_len(ArtVpath *a) {
- int i;
-
- for (i = 0; a[i].code != ART_END; i++);
+ int i = 0;
+ while (a[i].code != ART_END)
+ i++;
return i;
}
@@ -329,17 +329,17 @@ void drawBez(ArtBpath *bez1, ArtBpath *bez2, art_u8 *buffer, int width, int heig
#if 0
const char *codes[] = {"ART_MOVETO", "ART_MOVETO_OPEN", "ART_CURVETO", "ART_LINETO", "ART_END"};
for (int i = 0;; i++) {
- printf(" bez[%d].code = %s;\n", i, codes[bez[i].code]);
+ debugN(" bez[%d].code = %s;\n", i, codes[bez[i].code]);
if (bez[i].code == ART_END)
break;
if (bez[i].code == ART_CURVETO) {
- printf(" bez[%d].x1 = %f; bez[%d].y1 = %f;\n", i, bez[i].x1, i, bez[i].y1);
- printf(" bez[%d].x2 = %f; bez[%d].y2 = %f;\n", i, bez[i].x2, i, bez[i].y2);
+ debugN(" bez[%d].x1 = %f; bez[%d].y1 = %f;\n", i, bez[i].x1, i, bez[i].y1);
+ debugN(" bez[%d].x2 = %f; bez[%d].y2 = %f;\n", i, bez[i].x2, i, bez[i].y2);
}
- printf(" bez[%d].x3 = %f; bez[%d].y3 = %f;\n", i, bez[i].x3, i, bez[i].y3);
+ debugN(" bez[%d].x3 = %f; bez[%d].y3 = %f;\n", i, bez[i].x3, i, bez[i].y3);
}
- printf(" drawBez(bez, buffer, 1.0, 1.0, %f, 0x%08x);\n", penWidth, color);
+ debugN(" drawBez(bez, buffer, 1.0, 1.0, %f, 0x%08x);\n", penWidth, color);
#endif
// HACK: Some frames have green bounding boxes drawn.
@@ -382,7 +382,7 @@ void drawBez(ArtBpath *bez1, ArtBpath *bez2, art_u8 *buffer, int width, int heig
art_rgb_svp_alpha1(svp, 0, 0, width, height, color, buffer, width * 4);
free(vect);
- free(svp);
+ art_svp_free(svp);
free(vec);
}
diff --git a/engines/sword25/gfx/panel.cpp b/engines/sword25/gfx/panel.cpp
index 3aa0516835..2de1de133a 100644
--- a/engines/sword25/gfx/panel.cpp
+++ b/engines/sword25/gfx/panel.cpp
@@ -32,10 +32,6 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/gfx/panel.h"
#include "sword25/kernel/inputpersistenceblock.h"
@@ -45,14 +41,8 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-
#define BS_LOG_PREFIX "PANEL"
-// -----------------------------------------------------------------------------
-// Construction/Destruction
-// -----------------------------------------------------------------------------
-
Panel::Panel(RenderObjectPtr<RenderObject> parentPtr, int width, int height, uint color) :
RenderObject(parentPtr, RenderObject::TYPE_PANEL),
_color(color) {
@@ -74,37 +64,25 @@ Panel::Panel(RenderObjectPtr<RenderObject> parentPtr, int width, int height, uin
_initSuccess = true;
}
-// -----------------------------------------------------------------------------
-
Panel::Panel(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
RenderObject(parentPtr, RenderObject::TYPE_PANEL, handle) {
_initSuccess = unpersist(reader);
}
-// -----------------------------------------------------------------------------
-
Panel::~Panel() {
}
-// -----------------------------------------------------------------------------
-// Rendern
-// -----------------------------------------------------------------------------
-
bool Panel::doRender() {
// Falls der Alphawert 0 ist, ist das Panel komplett durchsichtig und es muss nichts gezeichnet werden.
if (_color >> 24 == 0)
return true;
- GraphicEngine *gfxPtr = static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx"));
+ GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
BS_ASSERT(gfxPtr);
return gfxPtr->fill(&_bbox, _color);
}
-// -----------------------------------------------------------------------------
-// Persistenz
-// -----------------------------------------------------------------------------
-
bool Panel::persist(OutputPersistenceBlock &writer) {
bool result = true;
@@ -116,8 +94,6 @@ bool Panel::persist(OutputPersistenceBlock &writer) {
return result;
}
-// -----------------------------------------------------------------------------
-
bool Panel::unpersist(InputPersistenceBlock &reader) {
bool result = true;
diff --git a/engines/sword25/gfx/panel.h b/engines/sword25/gfx/panel.h
index 5fbcec5f34..6fe96369a6 100644
--- a/engines/sword25/gfx/panel.h
+++ b/engines/sword25/gfx/panel.h
@@ -35,19 +35,11 @@
#ifndef SWORD25_PANEL_H
#define SWORD25_PANEL_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/gfx/renderobject.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Class Definition
-// -----------------------------------------------------------------------------
-
class Panel : public RenderObject {
friend class RenderObject;
@@ -58,10 +50,10 @@ private:
public:
virtual ~Panel();
- uint getColor() const {
+ uint getColor() const {
return _color;
}
- void setColor(uint color) {
+ void setColor(uint color) {
_color = color;
forceRefresh();
}
diff --git a/engines/sword25/gfx/renderobject.cpp b/engines/sword25/gfx/renderobject.cpp
index 5de6dde79e..77af0bee92 100644
--- a/engines/sword25/gfx/renderobject.cpp
+++ b/engines/sword25/gfx/renderobject.cpp
@@ -53,8 +53,6 @@ namespace Sword25 {
#define BS_LOG_PREFIX "RENDEROBJECT"
-// Konstruktion / Destruktion
-// --------------------------
RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type, uint handle) :
_managerPtr(0),
_parentPtr(parentPtr),
@@ -76,9 +74,9 @@ RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type,
// Renderobject registrieren, abhängig vom Handle-Parameter entweder mit beliebigem oder vorgegebenen Handle.
if (handle == 0)
- _handle = RenderObjectRegistry::getInstance().registerObject(this);
+ _handle = RenderObjectRegistry::instance().registerObject(this);
else
- _handle = RenderObjectRegistry::getInstance().registerObject(this, handle);
+ _handle = RenderObjectRegistry::instance().registerObject(this, handle);
if (_handle == 0)
return;
@@ -110,11 +108,9 @@ RenderObject::~RenderObject() {
deleteAllChildren();
// Objekt deregistrieren.
- RenderObjectRegistry::getInstance().deregisterObject(this);
+ RenderObjectRegistry::instance().deregisterObject(this);
}
-// Rendern
-// -------
bool RenderObject::render() {
// Objektänderungen validieren
validateObject();
@@ -141,9 +137,6 @@ bool RenderObject::render() {
return true;
}
-// Objektverwaltung
-// ----------------
-
void RenderObject::validateObject() {
// Die Veränderungen in den Objektvariablen aufheben
_oldBbox = _bbox;
@@ -222,9 +215,6 @@ int RenderObject::calcAbsoluteY() const {
return _y;
}
-// Baumverwaltung
-// --------------
-
void RenderObject::deleteAllChildren() {
// Es ist nicht notwendig die Liste zu iterieren, da jedes Kind für sich DetatchChildren an diesem Objekt aufruft und sich somit
// selber entfernt. Daher muss immer nur ein beliebiges Element (hier das letzte) gelöscht werden, bis die Liste leer ist.
@@ -275,17 +265,12 @@ void RenderObject::updateAbsolutePos() {
(*it)->updateAbsolutePos();
}
-// Get-Methoden
-// ------------
-
bool RenderObject::getObjectIntersection(RenderObjectPtr<RenderObject> pObject, Common::Rect &result) {
result = pObject->getBbox();
result.clip(_bbox);
return result.isValidRect();
}
-// Set-Methoden
-// ------------
void RenderObject::setPos(int x, int y) {
_x = x;
_y = y;
@@ -313,10 +298,6 @@ void RenderObject::setVisible(bool visible) {
_visible = visible;
}
-// -----------------------------------------------------------------------------
-// Objekterzeuger
-// -----------------------------------------------------------------------------
-
RenderObjectPtr<Animation> RenderObject::addAnimation(const Common::String &filename) {
RenderObjectPtr<Animation> aniPtr((new Animation(this->getHandle(), filename))->getHandle());
if (aniPtr.isValid() && aniPtr->getInitSuccess())
@@ -328,9 +309,6 @@ RenderObjectPtr<Animation> RenderObject::addAnimation(const Common::String &file
}
}
-
-// -----------------------------------------------------------------------------
-
RenderObjectPtr<Animation> RenderObject::addAnimation(const AnimationTemplate &animationTemplate) {
Animation *aniPtr = new Animation(this->getHandle(), animationTemplate);
if (aniPtr && aniPtr->getInitSuccess())
@@ -341,8 +319,6 @@ RenderObjectPtr<Animation> RenderObject::addAnimation(const AnimationTemplate &a
}
}
-// -----------------------------------------------------------------------------
-
RenderObjectPtr<Bitmap> RenderObject::addBitmap(const Common::String &filename) {
RenderObjectPtr<Bitmap> bitmapPtr((new StaticBitmap(this->getHandle(), filename))->getHandle());
if (bitmapPtr.isValid() && bitmapPtr->getInitSuccess())
@@ -354,8 +330,6 @@ RenderObjectPtr<Bitmap> RenderObject::addBitmap(const Common::String &filename)
}
}
-// -----------------------------------------------------------------------------
-
RenderObjectPtr<Bitmap> RenderObject::addDynamicBitmap(uint width, uint height) {
RenderObjectPtr<Bitmap> bitmapPtr((new DynamicBitmap(this->getHandle(), width, height))->getHandle());
if (bitmapPtr.isValid() && bitmapPtr->getInitSuccess())
@@ -367,8 +341,6 @@ RenderObjectPtr<Bitmap> RenderObject::addDynamicBitmap(uint width, uint height)
}
}
-// -----------------------------------------------------------------------------
-
RenderObjectPtr<Panel> RenderObject::addPanel(int width, int height, uint color) {
RenderObjectPtr<Panel> panelPtr((new Panel(this->getHandle(), width, height, color))->getHandle());
if (panelPtr.isValid() && panelPtr->getInitSuccess())
@@ -380,12 +352,10 @@ RenderObjectPtr<Panel> RenderObject::addPanel(int width, int height, uint color)
}
}
-// -----------------------------------------------------------------------------
-
RenderObjectPtr<Text> RenderObject::addText(const Common::String &font, const Common::String &text) {
RenderObjectPtr<Text> textPtr((new Text(this->getHandle()))->getHandle());
- if (textPtr.isValid() && textPtr->getInitSuccess() && textPtr->SetFont(font)) {
- textPtr->SetText(text);
+ if (textPtr.isValid() && textPtr->getInitSuccess() && textPtr->setFont(font)) {
+ textPtr->setText(text);
return textPtr;
} else {
if (textPtr.isValid())
@@ -394,9 +364,6 @@ RenderObjectPtr<Text> RenderObject::addText(const Common::String &font, const Co
}
}
-// Persistenz-Methoden
-// -------------------
-
bool RenderObject::persist(OutputPersistenceBlock &writer) {
// Typ und Handle werden als erstes gespeichert, damit beim Laden ein Objekt vom richtigen Typ mit dem richtigen Handle erzeugt werden kann.
writer.write(static_cast<uint>(_type));
@@ -431,8 +398,6 @@ bool RenderObject::persist(OutputPersistenceBlock &writer) {
return true;
}
-// -----------------------------------------------------------------------------
-
bool RenderObject::unpersist(InputPersistenceBlock &reader) {
// Typ und Handle wurden schon von RecreatePersistedRenderObject() ausgelesen. Jetzt werden die restlichen Objekteigenschaften ausgelesen.
reader.read(_x);
@@ -468,8 +433,6 @@ bool RenderObject::unpersist(InputPersistenceBlock &reader) {
return reader.isGood();
}
-// -----------------------------------------------------------------------------
-
bool RenderObject::persistChildren(OutputPersistenceBlock &writer) {
bool result = true;
@@ -486,8 +449,6 @@ bool RenderObject::persistChildren(OutputPersistenceBlock &writer) {
return result;
}
-// -----------------------------------------------------------------------------
-
bool RenderObject::unpersistChildren(InputPersistenceBlock &reader) {
bool result = true;
@@ -506,8 +467,6 @@ bool RenderObject::unpersistChildren(InputPersistenceBlock &reader) {
return result && reader.isGood();
}
-// -----------------------------------------------------------------------------
-
RenderObjectPtr<RenderObject> RenderObject::recreatePersistedRenderObject(InputPersistenceBlock &reader) {
RenderObjectPtr<RenderObject> result;
@@ -547,8 +506,6 @@ RenderObjectPtr<RenderObject> RenderObject::recreatePersistedRenderObject(InputP
return result;
}
-// Hilfs-Methoden
-// --------------
bool RenderObject::greater(const RenderObjectPtr<RenderObject> lhs, const RenderObjectPtr<RenderObject> rhs) {
// Das Objekt mit dem kleinem Z-Wert müssen zuerst gerendert werden.
if (lhs->_z != rhs->_z)
diff --git a/engines/sword25/gfx/renderobject.h b/engines/sword25/gfx/renderobject.h
index c090ad75c9..7b7b9047f7 100644
--- a/engines/sword25/gfx/renderobject.h
+++ b/engines/sword25/gfx/renderobject.h
@@ -45,7 +45,6 @@
#ifndef SWORD25_RENDEROBJECT_H
#define SWORD25_RENDEROBJECT_H
-// Includes
#include "sword25/kernel/common.h"
#include "sword25/kernel/persistable.h"
#include "common/rect.h"
@@ -55,10 +54,6 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Forward Declarations
-// -----------------------------------------------------------------------------
-
class Kernel;
class RenderObjectManager;
class Bitmap;
@@ -352,7 +347,7 @@ public:
*/
void forceRefresh() {
_refreshForced = true;
- };
+ }
/**
@brief Gibt das Handle des Objekte zurück.
*/
@@ -462,11 +457,11 @@ private:
@param pObject ein Pointer auf das zu entfernende Objekt
@return Gibt false zurück, falls das zu entfernende Objekt nicht in der Liste gefunden werden konnte.
*/
- bool detatchChildren(RenderObjectPtr<RenderObject> pObject);
+ bool detatchChildren(RenderObjectPtr<RenderObject> pObject);
/**
@brief Berechnet die Bounding-Box und registriert das Dirty-Rect beim BS_RenderObjectManager.
*/
- void updateBoxes();
+ void updateBoxes();
/**
@brief Berechnet die Bounding-Box des Objektes.
@return Gibt die Bounding-Box des Objektes in Bildschirmkoordinaten zurück.
@@ -496,7 +491,7 @@ private:
/**
@brief Validiert den Zustand eines Objektes nachdem die durch die Veränderung verursachten Folgen abgearbeitet wurden.
*/
- void validateObject();
+ void validateObject();
/**
@brief Berechnet die absolute Position des Objektes und aller seiner Kinderobjekte neu.
@@ -508,7 +503,7 @@ private:
@brief Teilt dem Objekt mit, dass sich eines seiner Kinderobjekte dahingehend verändert hat, die eine erneute Bestimmung der
Rendereihenfolge verlangt.
*/
- void signalChildChange() {
+ void signalChildChange() {
_childChanged = true;
}
/**
@@ -517,7 +512,7 @@ private:
@param Result das Ergebnisrechteck
@return Gibt false zurück, falls sich die Objekte gar nicht schneiden.
*/
- bool getObjectIntersection(RenderObjectPtr<RenderObject> pObject, Common::Rect &result);
+ bool getObjectIntersection(RenderObjectPtr<RenderObject> pObject, Common::Rect &result);
/**
@brief Vergleichsoperator der auf Objektpointern basiert statt auf Objekten.
@remark Diese Methode wird fürs Sortieren der Kinderliste nach der Rendereihenfolge benutzt.
diff --git a/engines/sword25/gfx/renderobjectmanager.cpp b/engines/sword25/gfx/renderobjectmanager.cpp
index ab4e606270..94f7a04b45 100644
--- a/engines/sword25/gfx/renderobjectmanager.cpp
+++ b/engines/sword25/gfx/renderobjectmanager.cpp
@@ -63,7 +63,7 @@ void RenderObjectManager::startFrame() {
_frameStarted = true;
// Verstrichene Zeit bestimmen
- int timeElapsed = Kernel::GetInstance()->GetGfx()->GetLastFrameDurationMicro();
+ int timeElapsed = Kernel::getInstance()->getGfx()->getLastFrameDurationMicro();
// Alle BS_TimedRenderObject Objekte über den Framestart und die verstrichene Zeit in Kenntnis setzen
RenderObjectList::iterator iter = _timedRenderObjects.begin();
@@ -113,7 +113,7 @@ bool RenderObjectManager::persist(OutputPersistenceBlock &writer) {
}
// Alle BS_AnimationTemplates persistieren.
- result &= AnimationTemplateRegistry::getInstance().persist(writer);
+ result &= AnimationTemplateRegistry::instance().persist(writer);
return result;
}
@@ -143,7 +143,7 @@ bool RenderObjectManager::unpersist(InputPersistenceBlock &reader) {
}
// Alle BS_AnimationTemplates wieder herstellen.
- result &= AnimationTemplateRegistry::getInstance().unpersist(reader);
+ result &= AnimationTemplateRegistry::instance().unpersist(reader);
return result;
}
diff --git a/engines/sword25/gfx/renderobjectmanager.h b/engines/sword25/gfx/renderobjectmanager.h
index 05bba37cd0..8511382d6e 100644
--- a/engines/sword25/gfx/renderobjectmanager.h
+++ b/engines/sword25/gfx/renderobjectmanager.h
@@ -45,7 +45,6 @@
#ifndef SWORD25_RENDEROBJECTMANAGER_H
#define SWORD25_RENDEROBJECTMANAGER_H
-// Includes
#include "common/rect.h"
#include "sword25/kernel/common.h"
#include "sword25/gfx/renderobjectptr.h"
@@ -53,7 +52,6 @@
namespace Sword25 {
-// Klassendefinition
class Kernel;
class RenderObject;
class TimedRenderObject;
diff --git a/engines/sword25/gfx/renderobjectptr.h b/engines/sword25/gfx/renderobjectptr.h
index 894ba877d2..c22c6e83e7 100644
--- a/engines/sword25/gfx/renderobjectptr.h
+++ b/engines/sword25/gfx/renderobjectptr.h
@@ -54,7 +54,7 @@ public:
RenderObjectPtr(uint handle) : _handle(handle) {}
T *operator->() const {
- return static_cast<T *>(RenderObjectRegistry::getInstance().resolveHandle(_handle));
+ return static_cast<T *>(RenderObjectRegistry::instance().resolveHandle(_handle));
}
bool operator==(const RenderObjectPtr<T> & other) {
@@ -62,11 +62,11 @@ public:
}
bool isValid() const {
- return RenderObjectRegistry::getInstance().resolveHandle(_handle) != 0;
+ return RenderObjectRegistry::instance().resolveHandle(_handle) != 0;
}
void erase() {
- delete static_cast<T *>(RenderObjectRegistry::getInstance().resolveHandle(_handle));
+ delete static_cast<T *>(RenderObjectRegistry::instance().resolveHandle(_handle));
_handle = 0;
}
diff --git a/engines/sword25/gfx/renderobjectregistry.cpp b/engines/sword25/gfx/renderobjectregistry.cpp
index edfdbd23a8..c52e2f1a45 100644
--- a/engines/sword25/gfx/renderobjectregistry.cpp
+++ b/engines/sword25/gfx/renderobjectregistry.cpp
@@ -34,14 +34,12 @@
#include "sword25/gfx/renderobjectregistry.h"
-#include "common/ptr.h"
+DECLARE_SINGLETON(Sword25::RenderObjectRegistry)
namespace Sword25 {
#define BS_LOG_PREFIX "RENDEROBJECTREGISTRY"
-Common::ScopedPtr<RenderObjectRegistry> RenderObjectRegistry::_instancePtr;
-
void RenderObjectRegistry::logErrorLn(const char *message) const {
BS_LOG_ERRORLN(message);
}
diff --git a/engines/sword25/gfx/renderobjectregistry.h b/engines/sword25/gfx/renderobjectregistry.h
index b546ee56e1..357d041068 100644
--- a/engines/sword25/gfx/renderobjectregistry.h
+++ b/engines/sword25/gfx/renderobjectregistry.h
@@ -35,42 +35,21 @@
#ifndef SWORD25_RENDEROBJECTREGISTRY_H
#define SWORD25_RENDEROBJECTREGISTRY_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/kernel/objectregistry.h"
-#include "common/ptr.h"
+#include "common/singleton.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Forward Deklarationen
-// -----------------------------------------------------------------------------
-
class RenderObject;
-// -----------------------------------------------------------------------------
-// Klassendeklaration
-// -----------------------------------------------------------------------------
-
-class RenderObjectRegistry : public ObjectRegistry<RenderObject> {
-public:
- static RenderObjectRegistry &getInstance() {
- if (!_instancePtr.get())
- _instancePtr.reset(new RenderObjectRegistry);
- return *_instancePtr.get();
- }
-
- virtual ~RenderObjectRegistry() {}
-
+class RenderObjectRegistry :
+ public ObjectRegistry<RenderObject>,
+ public Common::Singleton<RenderObjectRegistry> {
private:
virtual void logErrorLn(const char *message) const;
virtual void logWarningLn(const char *message) const;
-
- static Common::ScopedPtr<RenderObjectRegistry> _instancePtr;
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/screenshot.cpp b/engines/sword25/gfx/screenshot.cpp
index 9eea2ec422..88417b72c5 100644
--- a/engines/sword25/gfx/screenshot.cpp
+++ b/engines/sword25/gfx/screenshot.cpp
@@ -32,11 +32,10 @@
*
*/
-#define BS_LOG_PREFIX "SCREENSHOT"
+// Disable symbol overrides so that we can use png.h
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
+#define BS_LOG_PREFIX "SCREENSHOT"
#include "common/system.h"
#include "common/savefile.h"
@@ -46,39 +45,36 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-
#include "common/pack-start.h"
struct RGB_PIXEL {
- byte Red;
- byte Green;
- byte Blue;
+ byte red;
+ byte green;
+ byte blue;
} PACKED_STRUCT;
#include "common/pack-end.h"
void userWriteFn(png_structp png_ptr, png_bytep data, png_size_t length) {
- static_cast<Common::WriteStream *>(png_ptr->io_ptr)->write(data, length);
+ static_cast<Common::WriteStream *>(png_get_io_ptr(png_ptr))->write(data, length);
}
void userFlushFn(png_structp png_ptr) {
}
-
-bool Screenshot::SaveToFile(Graphics::Surface *Data, Common::WriteStream *Stream) {
+bool Screenshot::saveToFile(Graphics::Surface *data, Common::WriteStream *stream) {
// Reserve buffer space
- RGB_PIXEL *pixelBuffer = new RGB_PIXEL[Data->w * Data->h];
+ RGB_PIXEL *pixelBuffer = new RGB_PIXEL[data->w * data->h];
// Convert the RGBA data to RGB
- const byte *pSrc = (const byte *)Data->getBasePtr(0, 0);
+ const byte *pSrc = (const byte *)data->getBasePtr(0, 0);
RGB_PIXEL *pDest = pixelBuffer;
- for (uint y = 0; y < Data->h; y++) {
- for (uint x = 0; x < Data->w; x++) {
+ for (uint y = 0; y < data->h; y++) {
+ for (uint x = 0; x < data->w; x++) {
uint32 srcPixel = READ_LE_UINT32(pSrc);
pSrc += sizeof(uint32);
- pDest->Red = (srcPixel >> 16) & 0xff;
- pDest->Green = (srcPixel >> 8) & 0xff;
- pDest->Blue = srcPixel & 0xff;
+ pDest->red = (srcPixel >> 16) & 0xff;
+ pDest->green = (srcPixel >> 8) & 0xff;
+ pDest->blue = srcPixel & 0xff;
++pDest;
}
}
@@ -91,30 +87,30 @@ bool Screenshot::SaveToFile(Graphics::Surface *Data, Common::WriteStream *Stream
if (!info_ptr)
error("Could not create PNG info-struct.");
- // The compression buffer must be large enough to the entire image.
+ // The compression buffer must be large enough to the entire image.
// This ensures that only an IDAT chunk is created.
// When buffer size is used 110% of the raw data size to be sure.
- png_set_compression_buffer_size(png_ptr, (Data->w * Data->h * 3 * 110) / 100);
+ png_set_compression_buffer_size(png_ptr, (data->w * data->h * 3 * 110) / 100);
// Initialise PNG-Info structure
png_set_IHDR(png_ptr, info_ptr,
- Data->w, // Width
- Data->h, // Height
- 8, // Bits depth
+ data->w, // Width
+ data->h, // Height
+ 8, // Bits depth
PNG_COLOR_TYPE_RGB, // Colour type
PNG_INTERLACE_NONE, // No interlacing
PNG_COMPRESSION_TYPE_DEFAULT, // Compression type
PNG_FILTER_TYPE_DEFAULT); // Filter Type
// Rowpointer erstellen
- png_bytep *rowPointers = new png_bytep[Data->h];
- for (uint i = 0; i < Data->h; i++) {
- rowPointers[i] = (png_bytep)&pixelBuffer[Data->w * i];
+ png_bytep *rowPointers = new png_bytep[data->h];
+ for (uint i = 0; i < data->h; i++) {
+ rowPointers[i] = (png_bytep)&pixelBuffer[data->w * i];
}
png_set_rows(png_ptr, info_ptr, &rowPointers[0]);
// Write out the png data to the file
- png_set_write_fn(png_ptr, (void *)Stream, userWriteFn, userFlushFn);
+ png_set_write_fn(png_ptr, (void *)stream, userWriteFn, userFlushFn);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);
@@ -127,14 +123,14 @@ bool Screenshot::SaveToFile(Graphics::Surface *Data, Common::WriteStream *Stream
// -----------------------------------------------------------------------------
-Common::MemoryReadStream *Screenshot::createThumbnail(Graphics::Surface *Data) {
+Common::MemoryReadStream *Screenshot::createThumbnail(Graphics::Surface *data) {
// This method takes a screen image with a dimension of 800x600, and creates a screenshot with a dimension of 200x125.
// First 50 pixels are cut off the top and bottom (the interface boards in the game). The remaining image of 800x500
// will be on a 16th of its size, reduced by being handed out in 4x4 pixel blocks and the average of each block
// generates a pixel of the target image. Finally, the result as a PNG file is stored as a file.
// The source image must be 800x600.
- if (Data->w != 800 || Data->h != 600 || Data->bytesPerPixel != 4) {
+ if (data->w != 800 || data->h != 600 || data->bytesPerPixel != 4) {
BS_LOG_ERRORLN("The sreenshot dimensions have to be 800x600 in order to be saved as a thumbnail.");
return false;
}
@@ -152,7 +148,7 @@ Common::MemoryReadStream *Screenshot::createThumbnail(Graphics::Surface *Data) {
int alpha, red, green, blue;
alpha = red = green = blue = 0;
for (int j = 0; j < 4; ++j) {
- const uint32 *srcP = (const uint32 *)Data->getBasePtr(x * 4, y * 4 + j + 50);
+ const uint32 *srcP = (const uint32 *)data->getBasePtr(x * 4, y * 4 + j + 50);
for (int i = 0; i < 4; ++i) {
uint32 pixel = READ_LE_UINT32(srcP + i);
alpha += (pixel >> 24);
@@ -178,7 +174,7 @@ Common::MemoryReadStream *Screenshot::createThumbnail(Graphics::Surface *Data) {
// Create a PNG representation of the thumbnail data
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
- SaveToFile(&thumbnail, stream);
+ saveToFile(&thumbnail, stream);
// Output a MemoryReadStream that encompasses the written data
Common::MemoryReadStream *result = new Common::MemoryReadStream(stream->getData(), stream->size(),
diff --git a/engines/sword25/gfx/screenshot.h b/engines/sword25/gfx/screenshot.h
index d328130b3f..eefaa1bca6 100644
--- a/engines/sword25/gfx/screenshot.h
+++ b/engines/sword25/gfx/screenshot.h
@@ -35,23 +35,15 @@
#ifndef SWORD25_SCREENSHOT_H
#define SWORD25_SCREENSHOT_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "graphics/surface.h"
#include "sword25/kernel/common.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Class declaration
-// -----------------------------------------------------------------------------
-
class Screenshot {
public:
- static bool SaveToFile(Graphics::Surface *Data, Common::WriteStream *Stream);
- static Common::MemoryReadStream *createThumbnail(Graphics::Surface *Data);
+ static bool saveToFile(Graphics::Surface *data, Common::WriteStream *stream);
+ static Common::MemoryReadStream *createThumbnail(Graphics::Surface *data);
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/staticbitmap.cpp b/engines/sword25/gfx/staticbitmap.cpp
index 7771eb8100..3019fe0ac1 100644
--- a/engines/sword25/gfx/staticbitmap.cpp
+++ b/engines/sword25/gfx/staticbitmap.cpp
@@ -32,10 +32,6 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/gfx/staticbitmap.h"
#include "sword25/gfx/bitmapresource.h"
#include "sword25/package/packagemanager.h"
@@ -44,16 +40,8 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Logging
-// -----------------------------------------------------------------------------
-
#define BS_LOG_PREFIX "STATICBITMAP"
-// -----------------------------------------------------------------------------
-// Konstruktion / Destruktion
-// -----------------------------------------------------------------------------
-
StaticBitmap::StaticBitmap(RenderObjectPtr<RenderObject> parentPtr, const Common::String &filename) :
Bitmap(parentPtr, TYPE_STATICBITMAP) {
// Das BS_Bitmap konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
@@ -63,23 +51,19 @@ StaticBitmap::StaticBitmap(RenderObjectPtr<RenderObject> parentPtr, const Common
_initSuccess = initBitmapResource(filename);
}
-// -----------------------------------------------------------------------------
-
StaticBitmap::StaticBitmap(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
Bitmap(parentPtr, TYPE_STATICBITMAP, handle) {
_initSuccess = unpersist(reader);
}
-// -----------------------------------------------------------------------------
-
bool StaticBitmap::initBitmapResource(const Common::String &filename) {
// Bild-Resource laden
- Resource *resourcePtr = Kernel::GetInstance()->GetResourceManager()->RequestResource(filename);
+ Resource *resourcePtr = Kernel::getInstance()->getResourceManager()->requestResource(filename);
if (!resourcePtr) {
BS_LOG_ERRORLN("Could not request resource \"%s\".", filename.c_str());
return false;
}
- if (resourcePtr->GetType() != Resource::TYPE_BITMAP) {
+ if (resourcePtr->getType() != Resource::TYPE_BITMAP) {
BS_LOG_ERRORLN("Requested resource \"%s\" is not a bitmap.", filename.c_str());
return false;
}
@@ -99,22 +83,18 @@ bool StaticBitmap::initBitmapResource(const Common::String &filename) {
return true;
}
-// -----------------------------------------------------------------------------
-
StaticBitmap::~StaticBitmap() {
}
-// -----------------------------------------------------------------------------
-
bool StaticBitmap::doRender() {
// Bitmap holen
- Resource *resourcePtr = Kernel::GetInstance()->GetResourceManager()->RequestResource(_resourceFilename);
+ Resource *resourcePtr = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
BS_ASSERT(resourcePtr);
- BS_ASSERT(resourcePtr->GetType() == Resource::TYPE_BITMAP);
+ BS_ASSERT(resourcePtr->getType() == Resource::TYPE_BITMAP);
BitmapResource *bitmapResourcePtr = static_cast<BitmapResource *>(resourcePtr);
// Framebufferobjekt holen
- GraphicEngine *gfxPtr = static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx"));
+ GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
BS_ASSERT(gfxPtr);
// Bitmap zeichnen
@@ -137,68 +117,52 @@ bool StaticBitmap::doRender() {
return result;
}
-// -----------------------------------------------------------------------------
-
uint StaticBitmap::getPixel(int x, int y) const {
BS_ASSERT(x >= 0 && x < _width);
BS_ASSERT(y >= 0 && y < _height);
- Resource *pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(_resourceFilename);
- BS_ASSERT(pResource->GetType() == Resource::TYPE_BITMAP);
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
+ BS_ASSERT(pResource->getType() == Resource::TYPE_BITMAP);
BitmapResource *pBitmapResource = static_cast<BitmapResource *>(pResource);
uint result = pBitmapResource->getPixel(x, y);
pResource->release();
return result;
}
-// -----------------------------------------------------------------------------
-
bool StaticBitmap::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
BS_LOG_ERRORLN("SetContent() ist not supported with this object.");
return false;
}
-// -----------------------------------------------------------------------------
-// Auskunftsmethoden
-// -----------------------------------------------------------------------------
-
bool StaticBitmap::isAlphaAllowed() const {
- Resource *pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(_resourceFilename);
- BS_ASSERT(pResource->GetType() == Resource::TYPE_BITMAP);
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
+ BS_ASSERT(pResource->getType() == Resource::TYPE_BITMAP);
bool result = static_cast<BitmapResource *>(pResource)->isAlphaAllowed();
pResource->release();
return result;
}
-// -----------------------------------------------------------------------------
-
bool StaticBitmap::isColorModulationAllowed() const {
- Resource *pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(_resourceFilename);
- BS_ASSERT(pResource->GetType() == Resource::TYPE_BITMAP);
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
+ BS_ASSERT(pResource->getType() == Resource::TYPE_BITMAP);
bool result = static_cast<BitmapResource *>(pResource)->isColorModulationAllowed();
pResource->release();
return result;
}
-// -----------------------------------------------------------------------------
-
bool StaticBitmap::isScalingAllowed() const {
- Resource *pResource = Kernel::GetInstance()->GetResourceManager()->RequestResource(_resourceFilename);
- BS_ASSERT(pResource->GetType() == Resource::TYPE_BITMAP);
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
+ BS_ASSERT(pResource->getType() == Resource::TYPE_BITMAP);
bool result = static_cast<BitmapResource *>(pResource)->isScalingAllowed();
pResource->release();
return result;
}
-// -----------------------------------------------------------------------------
-// Persistenz
-// -----------------------------------------------------------------------------
-
bool StaticBitmap::persist(OutputPersistenceBlock &writer) {
bool result = true;
result &= Bitmap::persist(writer);
- writer.write(_resourceFilename);
+ writer.writeString(_resourceFilename);
result &= RenderObject::persistChildren(writer);
@@ -210,7 +174,7 @@ bool StaticBitmap::unpersist(InputPersistenceBlock &reader) {
result &= Bitmap::unpersist(reader);
Common::String resourceFilename;
- reader.read(resourceFilename);
+ reader.readString(resourceFilename);
result &= initBitmapResource(resourceFilename);
result &= RenderObject::unpersistChildren(reader);
diff --git a/engines/sword25/gfx/staticbitmap.h b/engines/sword25/gfx/staticbitmap.h
index a325487213..b5b4c4f5a2 100644
--- a/engines/sword25/gfx/staticbitmap.h
+++ b/engines/sword25/gfx/staticbitmap.h
@@ -35,19 +35,11 @@
#ifndef SWORD25_STATIC_BITMAP_H
#define SWORD25_STATIC_BITMAP_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/gfx/bitmap.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Klassendeklaration
-// -----------------------------------------------------------------------------
-
class StaticBitmap : public Bitmap {
friend class RenderObject;
@@ -63,20 +55,20 @@ public:
virtual uint getPixel(int x, int y) const;
- virtual bool setContent(const byte *pixeldata, uint size, uint offset, uint stride);
+ virtual bool setContent(const byte *pixeldata, uint size, uint offset, uint stride);
- virtual bool isScalingAllowed() const;
- virtual bool isAlphaAllowed() const;
- virtual bool isColorModulationAllowed() const;
- virtual bool isSetContentAllowed() const {
+ virtual bool isScalingAllowed() const;
+ virtual bool isAlphaAllowed() const;
+ virtual bool isColorModulationAllowed() const;
+ virtual bool isSetContentAllowed() const {
return false;
}
- virtual bool persist(OutputPersistenceBlock &writer);
- virtual bool unpersist(InputPersistenceBlock &reader);
+ virtual bool persist(OutputPersistenceBlock &writer);
+ virtual bool unpersist(InputPersistenceBlock &reader);
protected:
- virtual bool doRender();
+ virtual bool doRender();
private:
Common::String _resourceFilename;
diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp
index 1b0c3a78f0..b8e12ba570 100644
--- a/engines/sword25/gfx/text.cpp
+++ b/engines/sword25/gfx/text.cpp
@@ -36,10 +36,6 @@
// Entweder Fontfile absolut abspeichern, oder Verzeichniswechseln verbieten
// Eine relative Fontfile-Angabe könnte verwandt werden nachdem das Verzeichnis bereits gewechselt wurde und die Datei würde nicht mehr gefunden
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/outputpersistenceblock.h"
#include "sword25/kernel/inputpersistenceblock.h"
@@ -52,59 +48,49 @@ namespace Sword25 {
#define BS_LOG_PREFIX "TEXT"
-// -----------------------------------------------------------------------------
-// Konstanten
-// -----------------------------------------------------------------------------
-
namespace {
const uint AUTO_WRAP_THRESHOLD_DEFAULT = 300;
}
-// -----------------------------------------------------------------------------
-// Konstruktion / Destruktion
-// -----------------------------------------------------------------------------
-
-Text::Text(RenderObjectPtr<RenderObject> ParentPtr) :
- RenderObject(ParentPtr, RenderObject::TYPE_TEXT),
+Text::Text(RenderObjectPtr<RenderObject> parentPtr) :
+ RenderObject(parentPtr, RenderObject::TYPE_TEXT),
_modulationColor(0xffffffff),
- m_AutoWrap(false),
- m_AutoWrapThreshold(AUTO_WRAP_THRESHOLD_DEFAULT) {
+ _autoWrap(false),
+ _autoWrapThreshold(AUTO_WRAP_THRESHOLD_DEFAULT) {
}
-// -----------------------------------------------------------------------------
+Text::Text(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
+ RenderObject(parentPtr, TYPE_TEXT, handle),
+ // Temporarily set fields prior to unpersisting actual values
+ _modulationColor(0xffffffff),
+ _autoWrap(false),
+ _autoWrapThreshold(AUTO_WRAP_THRESHOLD_DEFAULT) {
-Text::Text(InputPersistenceBlock &Reader, RenderObjectPtr<RenderObject> ParentPtr, uint Handle) :
- RenderObject(ParentPtr, TYPE_TEXT, Handle) {
- _initSuccess = unpersist(Reader);
+ // Unpersist the fields
+ _initSuccess = unpersist(reader);
}
-// -----------------------------------------------------------------------------
-
-bool Text::SetFont(const Common::String &Font) {
+bool Text::setFont(const Common::String &font) {
// Font precachen.
- if (GetResourceManager()->PrecacheResource(Font)) {
- m_Font = Font;
- UpdateFormat();
+ if (getResourceManager()->precacheResource(font)) {
+ _font = font;
+ updateFormat();
forceRefresh();
return true;
} else {
- BS_LOG_ERRORLN("Could not precache font \"%s\". Font probably does not exist.", Font.c_str());
+ BS_LOG_ERRORLN("Could not precache font \"%s\". Font probably does not exist.", font.c_str());
return false;
}
}
-// -----------------------------------------------------------------------------
-
-void Text::SetText(const Common::String &text) {
- m_Text = text;
- UpdateFormat();
+void Text::setText(const Common::String &text) {
+ _text = text;
+ updateFormat();
forceRefresh();
}
-// -----------------------------------------------------------------------------
-
void Text::setColor(uint modulationColor) {
uint newModulationColor = (modulationColor & 0x00ffffff) | (_modulationColor & 0xff000000);
if (newModulationColor != _modulationColor) {
@@ -113,8 +99,6 @@ void Text::setColor(uint modulationColor) {
}
}
-// -----------------------------------------------------------------------------
-
void Text::setAlpha(int alpha) {
BS_ASSERT(alpha >= 0 && alpha < 256);
uint newModulationColor = (_modulationColor & 0x00ffffff) | alpha << 24;
@@ -124,225 +108,215 @@ void Text::setAlpha(int alpha) {
}
}
-// -----------------------------------------------------------------------------
-
-void Text::SetAutoWrap(bool AutoWrap) {
- if (AutoWrap != m_AutoWrap) {
- m_AutoWrap = AutoWrap;
- UpdateFormat();
+void Text::setAutoWrap(bool autoWrap) {
+ if (autoWrap != _autoWrap) {
+ _autoWrap = autoWrap;
+ updateFormat();
forceRefresh();
}
}
-// -----------------------------------------------------------------------------
-
-void Text::SetAutoWrapThreshold(uint AutoWrapThreshold) {
- if (AutoWrapThreshold != m_AutoWrapThreshold) {
- m_AutoWrapThreshold = AutoWrapThreshold;
- UpdateFormat();
+void Text::setAutoWrapThreshold(uint autoWrapThreshold) {
+ if (autoWrapThreshold != _autoWrapThreshold) {
+ _autoWrapThreshold = autoWrapThreshold;
+ updateFormat();
forceRefresh();
}
}
-// -----------------------------------------------------------------------------
-
bool Text::doRender() {
// Font-Resource locken.
- FontResource *FontPtr = LockFontResource();
- if (!FontPtr) return false;
+ FontResource *fontPtr = lockFontResource();
+ if (!fontPtr)
+ return false;
// Charactermap-Resource locken.
- ResourceManager *RMPtr = GetResourceManager();
- BitmapResource *CharMapPtr;
+ ResourceManager *rmPtr = getResourceManager();
+ BitmapResource *charMapPtr;
{
- Resource *pResource = RMPtr->RequestResource(FontPtr->GetCharactermapFileName());
+ Resource *pResource = rmPtr->requestResource(fontPtr->getCharactermapFileName());
if (!pResource) {
- BS_LOG_ERRORLN("Could not request resource \"%s\".", FontPtr->GetCharactermapFileName().c_str());
+ BS_LOG_ERRORLN("Could not request resource \"%s\".", fontPtr->getCharactermapFileName().c_str());
return false;
}
- if (pResource->GetType() != Resource::TYPE_BITMAP) {
- BS_LOG_ERRORLN("Requested resource \"%s\" is not a bitmap.", FontPtr->GetCharactermapFileName().c_str());
+ if (pResource->getType() != Resource::TYPE_BITMAP) {
+ BS_LOG_ERRORLN("Requested resource \"%s\" is not a bitmap.", fontPtr->getCharactermapFileName().c_str());
return false;
}
- CharMapPtr = static_cast<BitmapResource *>(pResource);
+ charMapPtr = static_cast<BitmapResource *>(pResource);
}
// Framebufferobjekt holen.
- GraphicEngine *GfxPtr = static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx"));
- BS_ASSERT(GfxPtr);
+ GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
+ BS_ASSERT(gfxPtr);
- bool Result = true;
- Common::Array<LINE>::iterator Iter = m_Lines.begin();
- for (; Iter != m_Lines.end(); ++Iter) {
+ bool result = true;
+ Common::Array<Line>::iterator iter = _lines.begin();
+ for (; iter != _lines.end(); ++iter) {
// Feststellen, ob überhaupt Buchstaben der aktuellen Zeile vom Update betroffen sind.
- Common::Rect CheckRect = (*Iter).BBox;
- CheckRect.translate(_absoluteX, _absoluteY);
+ Common::Rect checkRect = (*iter).bbox;
+ checkRect.translate(_absoluteX, _absoluteY);
// Jeden Buchstaben einzeln Rendern.
- int CurX = _absoluteX + (*Iter).BBox.left;
- int CurY = _absoluteY + (*Iter).BBox.top;
- for (uint i = 0; i < (*Iter).Text.size(); ++i) {
- Common::Rect CurRect = FontPtr->GetCharacterRect((byte)(*Iter).Text[i]);
-
- Common::Rect RenderRect(CurX, CurY, CurX + CurRect.width(), CurY + CurRect.height());
- int RenderX = CurX + (RenderRect.left - RenderRect.left);
- int RenderY = CurY + (RenderRect.top - RenderRect.top);
- RenderRect.translate(CurRect.left - CurX, CurRect.top - CurY);
- Result = CharMapPtr->blit(RenderX, RenderY, Image::FLIP_NONE, &RenderRect, _modulationColor);
- if (!Result) break;
-
- CurX += CurRect.width() + FontPtr->GetGapWidth();
+ int curX = _absoluteX + (*iter).bbox.left;
+ int curY = _absoluteY + (*iter).bbox.top;
+ for (uint i = 0; i < (*iter).text.size(); ++i) {
+ Common::Rect curRect = fontPtr->getCharacterRect((byte)(*iter).text[i]);
+
+ Common::Rect renderRect(curX, curY, curX + curRect.width(), curY + curRect.height());
+ int renderX = curX + (renderRect.left - renderRect.left);
+ int renderY = curY + (renderRect.top - renderRect.top);
+ renderRect.translate(curRect.left - curX, curRect.top - curY);
+ result = charMapPtr->blit(renderX, renderY, Image::FLIP_NONE, &renderRect, _modulationColor);
+ if (!result)
+ break;
+
+ curX += curRect.width() + fontPtr->getGapWidth();
}
}
// Charactermap-Resource freigeben.
- CharMapPtr->release();
+ charMapPtr->release();
// Font-Resource freigeben.
- FontPtr->release();
+ fontPtr->release();
- return Result;
+ return result;
}
-// -----------------------------------------------------------------------------
-
-ResourceManager *Text::GetResourceManager() {
+ResourceManager *Text::getResourceManager() {
// Pointer auf den Resource-Manager holen.
- return Kernel::GetInstance()->GetResourceManager();
+ return Kernel::getInstance()->getResourceManager();
}
-// -----------------------------------------------------------------------------
-
-FontResource *Text::LockFontResource() {
- ResourceManager *RMPtr = GetResourceManager();
+FontResource *Text::lockFontResource() {
+ ResourceManager *rmPtr = getResourceManager();
// Font-Resource locken.
- FontResource *FontPtr;
+ FontResource *fontPtr;
{
- Resource *ResourcePtr = RMPtr->RequestResource(m_Font);
- if (!ResourcePtr) {
- BS_LOG_ERRORLN("Could not request resource \"%s\".", m_Font.c_str());
+ Resource *resourcePtr = rmPtr->requestResource(_font);
+ if (!resourcePtr) {
+ BS_LOG_ERRORLN("Could not request resource \"%s\".", _font.c_str());
return NULL;
}
- if (ResourcePtr->GetType() != Resource::TYPE_FONT) {
- BS_LOG_ERRORLN("Requested resource \"%s\" is not a font.", m_Font.c_str());
+ if (resourcePtr->getType() != Resource::TYPE_FONT) {
+ BS_LOG_ERRORLN("Requested resource \"%s\" is not a font.", _font.c_str());
return NULL;
}
- FontPtr = static_cast<FontResource *>(ResourcePtr);
+ fontPtr = static_cast<FontResource *>(resourcePtr);
}
- return FontPtr;
+ return fontPtr;
}
-// -----------------------------------------------------------------------------
-
-void Text::UpdateFormat() {
- FontResource *FontPtr = LockFontResource();
- BS_ASSERT(FontPtr);
+void Text::updateFormat() {
+ FontResource *fontPtr = lockFontResource();
+ BS_ASSERT(fontPtr);
- UpdateMetrics(*FontPtr);
+ updateMetrics(*fontPtr);
- m_Lines.resize(1);
- if (m_AutoWrap && (uint) _width >= m_AutoWrapThreshold && m_Text.size() >= 2) {
+ _lines.resize(1);
+ if (_autoWrap && (uint) _width >= _autoWrapThreshold && _text.size() >= 2) {
_width = 0;
- uint CurLineWidth = 0;
- uint CurLineHeight = 0;
- uint CurLine = 0;
- uint TempLineWidth = 0;
- uint LastSpace = 0; // we need at least 1 space character to start a new line...
- m_Lines[0].Text = "";
- for (uint i = 0; i < m_Text.size(); ++i) {
+ uint curLineWidth = 0;
+ uint curLineHeight = 0;
+ uint curLine = 0;
+ uint tempLineWidth = 0;
+ uint lastSpace = 0; // we need at least 1 space character to start a new line...
+ _lines[0].text = "";
+ for (uint i = 0; i < _text.size(); ++i) {
uint j;
- TempLineWidth = 0;
- LastSpace = 0;
- for (j = i; j < m_Text.size(); ++j) {
- if ((byte)m_Text[j] == ' ') LastSpace = j;
+ tempLineWidth = 0;
+ lastSpace = 0;
+ for (j = i; j < _text.size(); ++j) {
+ if ((byte)_text[j] == ' ')
+ lastSpace = j;
- const Common::Rect &CurCharRect = FontPtr->GetCharacterRect((byte)m_Text[j]);
- TempLineWidth += CurCharRect.width();
- TempLineWidth += FontPtr->GetGapWidth();
+ const Common::Rect &curCharRect = fontPtr->getCharacterRect((byte)_text[j]);
+ tempLineWidth += curCharRect.width();
+ tempLineWidth += fontPtr->getGapWidth();
- if ((TempLineWidth >= m_AutoWrapThreshold) && (LastSpace > 0))
+ if ((tempLineWidth >= _autoWrapThreshold) && (lastSpace > 0))
break;
}
- if (j == m_Text.size()) LastSpace = m_Text.size(); // everything in 1 line.
+ if (j == _text.size()) // everything in 1 line.
+ lastSpace = _text.size();
- CurLineWidth = 0;
- CurLineHeight = 0;
- for (j = i; j < LastSpace; ++j) {
- m_Lines[CurLine].Text += m_Text[j];
+ curLineWidth = 0;
+ curLineHeight = 0;
+ for (j = i; j < lastSpace; ++j) {
+ _lines[curLine].text += _text[j];
- const Common::Rect &CurCharRect = FontPtr->GetCharacterRect((byte)m_Text[j]);
- CurLineWidth += CurCharRect.width();
- CurLineWidth += FontPtr->GetGapWidth();
- if ((uint) CurCharRect.height() > CurLineHeight) CurLineHeight = CurCharRect.height();
+ const Common::Rect &curCharRect = fontPtr->getCharacterRect((byte)_text[j]);
+ curLineWidth += curCharRect.width();
+ curLineWidth += fontPtr->getGapWidth();
+ if ((uint)curCharRect.height() > curLineHeight)
+ curLineHeight = curCharRect.height();
}
- m_Lines[CurLine].BBox.right = CurLineWidth;
- m_Lines[CurLine].BBox.bottom = CurLineHeight;
- if ((uint) _width < CurLineWidth) _width = CurLineWidth;
+ _lines[curLine].bbox.right = curLineWidth;
+ _lines[curLine].bbox.bottom = curLineHeight;
+ if ((uint)_width < curLineWidth)
+ _width = curLineWidth;
- if (LastSpace < m_Text.size()) {
- ++CurLine;
- BS_ASSERT(CurLine == m_Lines.size());
- m_Lines.resize(CurLine + 1);
- m_Lines[CurLine].Text = "";
+ if (lastSpace < _text.size()) {
+ ++curLine;
+ BS_ASSERT(curLine == _lines.size());
+ _lines.resize(curLine + 1);
+ _lines[curLine].text = "";
}
- i = LastSpace;
+ i = lastSpace;
}
// Bounding-Box der einzelnen Zeilen relativ zur ersten festlegen (vor allem zentrieren).
_height = 0;
- Common::Array<LINE>::iterator Iter = m_Lines.begin();
- for (; Iter != m_Lines.end(); ++Iter) {
- Common::Rect &BBox = (*Iter).BBox;
- BBox.left = (_width - BBox.right) / 2;
- BBox.right = BBox.left + BBox.right;
- BBox.top = (Iter - m_Lines.begin()) * FontPtr->GetLineHeight();
- BBox.bottom = BBox.top + BBox.bottom;
- _height += BBox.height();
+ Common::Array<Line>::iterator iter = _lines.begin();
+ for (; iter != _lines.end(); ++iter) {
+ Common::Rect &bbox = (*iter).bbox;
+ bbox.left = (_width - bbox.right) / 2;
+ bbox.right = bbox.left + bbox.right;
+ bbox.top = (iter - _lines.begin()) * fontPtr->getLineHeight();
+ bbox.bottom = bbox.top + bbox.bottom;
+ _height += bbox.height();
}
} else {
// Keine automatische Formatierung, also wird der gesamte Text in nur eine Zeile kopiert.
- m_Lines[0].Text = m_Text;
- m_Lines[0].BBox = Common::Rect(0, 0, _width, _height);
+ _lines[0].text = _text;
+ _lines[0].bbox = Common::Rect(0, 0, _width, _height);
}
- FontPtr->release();
+ fontPtr->release();
}
-// -----------------------------------------------------------------------------
-
-void Text::UpdateMetrics(FontResource &FontResource) {
+void Text::updateMetrics(FontResource &fontResource) {
_width = 0;
_height = 0;
- for (uint i = 0; i < m_Text.size(); ++i) {
- const Common::Rect &CurRect = FontResource.GetCharacterRect((byte)m_Text[i]);
- _width += CurRect.width();
- if (i != m_Text.size() - 1) _width += FontResource.GetGapWidth();
- if (_height < CurRect.height()) _height = CurRect.height();
+ for (uint i = 0; i < _text.size(); ++i) {
+ const Common::Rect &curRect = fontResource.getCharacterRect((byte)_text[i]);
+ _width += curRect.width();
+ if (i != _text.size() - 1)
+ _width += fontResource.getGapWidth();
+ if (_height < curRect.height())
+ _height = curRect.height();
}
}
-// -----------------------------------------------------------------------------
-// Persistenz
-// -----------------------------------------------------------------------------
-
bool Text::persist(OutputPersistenceBlock &writer) {
bool result = true;
result &= RenderObject::persist(writer);
writer.write(_modulationColor);
- writer.write(m_Font);
- writer.write(m_Text);
- writer.write(m_AutoWrap);
- writer.write(m_AutoWrapThreshold);
+ writer.writeString(_font);
+ writer.writeString(_text);
+ writer.write(_autoWrap);
+ writer.write(_autoWrapThreshold);
result &= RenderObject::persistChildren(writer);
@@ -360,21 +334,21 @@ bool Text::unpersist(InputPersistenceBlock &reader) {
// Beim Laden der anderen Member werden die Set-Methoden benutzt statt der tatsächlichen Member.
// So wird das Layout automatisch aktualisiert und auch alle anderen notwendigen Methoden ausgeführt.
- Common::String Font;
- reader.read(Font);
- SetFont(Font);
+ Common::String font;
+ reader.readString(font);
+ setFont(font);
Common::String text;
- reader.read(text);
- SetText(text);
+ reader.readString(text);
+ setText(text);
- bool AutoWrap;
- reader.read(AutoWrap);
- SetAutoWrap(AutoWrap);
+ bool autoWrap;
+ reader.read(autoWrap);
+ setAutoWrap(autoWrap);
- uint AutoWrapThreshold;
- reader.read(AutoWrapThreshold);
- SetAutoWrapThreshold(AutoWrapThreshold);
+ uint autoWrapThreshold;
+ reader.read(autoWrapThreshold);
+ setAutoWrapThreshold(autoWrapThreshold);
result &= RenderObject::unpersistChildren(reader);
diff --git a/engines/sword25/gfx/text.h b/engines/sword25/gfx/text.h
index ed3a83e630..42c1cd7c5d 100644
--- a/engines/sword25/gfx/text.h
+++ b/engines/sword25/gfx/text.h
@@ -35,28 +35,16 @@
#ifndef SWORD25_TEXT_H
#define SWORD25_TEXT_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "common/rect.h"
#include "sword25/gfx/renderobject.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Forward Declarations
-// -----------------------------------------------------------------------------
-
class Kernel;
class FontResource;
class ResourceManager;
-// -----------------------------------------------------------------------------
-// Klassendefinition
-// -----------------------------------------------------------------------------
-
class Text : public RenderObject {
friend class RenderObject;
@@ -66,13 +54,13 @@ public:
@param Font der Dateiname der Fontdatei.
@return Gibt false zurück, wenn der Font nicht gefunden wurde.
*/
- bool SetFont(const Common::String &Font);
+ bool setFont(const Common::String &font);
/**
@brief Setzt den darzustellenden Text.
@param Text der darzustellende Text
*/
- void SetText(const Common::String &text);
+ void setText(const Common::String &text);
/**
@brief Setzt den Alphawert des Textes.
@@ -88,27 +76,27 @@ public:
@param AutoWrap gibt an, ob der automatische Umbruch aktiviert oder deaktiviert werden soll.
@remark Dieses Attribut wird mit dem Wert false initialisiert.
*/
- void SetAutoWrap(bool AutoWrap);
+ void setAutoWrap(bool autoWrap);
/**
@brief Legt die Längengrenze des Textes in Pixeln fest, ab der ein automatischer Zeilenumbruch vorgenommen wird.
@remark Dieses Attribut wird mit dem Wert 300 initialisiert.
@remark Eine automatische Formatierung wird nur vorgenommen, wenn diese durch einen Aufruf von SetAutoWrap() aktiviert wurde.
*/
- void SetAutoWrapThreshold(uint AutoWrapThreshold);
+ void setAutoWrapThreshold(uint autoWrapThreshold);
/**
@brief Gibt den dargestellten Text zurück.
*/
- const Common::String &GetText() {
- return m_Text;
+ const Common::String &getText() {
+ return _text;
}
/**
@brief Gibt den Namen das momentan benutzten Fonts zurück.
*/
- const Common::String &GetFont() {
- return m_Font;
+ const Common::String &getFont() {
+ return _font;
}
/**
@@ -136,44 +124,44 @@ public:
/**
@brief Gibt zurück, ob die automatische Formatierung aktiviert ist.
*/
- bool IsAutoWrapActive() const {
- return m_AutoWrap;
+ bool isAutoWrapActive() const {
+ return _autoWrap;
}
/**
@brief Gibt die Längengrenze des Textes in Pixeln zurück, ab der eine automatische Formatierung vorgenommen wird.
*/
- uint GetAutoWrapThreshold() const {
- return m_AutoWrapThreshold;
+ uint getAutoWrapThreshold() const {
+ return _autoWrapThreshold;
}
- virtual bool persist(OutputPersistenceBlock &writer);
- virtual bool unpersist(InputPersistenceBlock &reader);
+ virtual bool persist(OutputPersistenceBlock &writer);
+ virtual bool unpersist(InputPersistenceBlock &reader);
protected:
virtual bool doRender();
private:
- Text(RenderObjectPtr<RenderObject> ParentPtr);
- Text(InputPersistenceBlock &Reader, RenderObjectPtr<RenderObject> ParentPtr, uint Handle);
-
- uint _modulationColor;
- Common::String m_Font;
- Common::String m_Text;
- bool m_AutoWrap;
- uint m_AutoWrapThreshold;
-
- struct LINE {
- Common::Rect BBox;
- Common::String Text;
+ Text(RenderObjectPtr<RenderObject> parentPtr);
+ Text(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle);
+
+ uint _modulationColor;
+ Common::String _font;
+ Common::String _text;
+ bool _autoWrap;
+ uint _autoWrapThreshold;
+
+ struct Line {
+ Common::Rect bbox;
+ Common::String text;
};
- Common::Array<LINE> m_Lines;
+ Common::Array<Line> _lines;
- void UpdateFormat();
- void UpdateMetrics(FontResource &FontResource);
- ResourceManager *GetResourceManager();
- FontResource *LockFontResource();
+ void updateFormat();
+ void updateMetrics(FontResource &fontResource);
+ ResourceManager *getResourceManager();
+ FontResource *lockFontResource();
};
} // End of namespace Sword25
diff --git a/engines/sword25/gfx/timedrenderobject.h b/engines/sword25/gfx/timedrenderobject.h
index 94d882d18e..6fee19882a 100644
--- a/engines/sword25/gfx/timedrenderobject.h
+++ b/engines/sword25/gfx/timedrenderobject.h
@@ -32,14 +32,6 @@
*
*/
-// -----------------------------------------------------------------------------
-// System Includes
-// -----------------------------------------------------------------------------
-
-// -----------------------------------------------------------------------------
-// Engine Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/gfx/renderobject.h"
diff --git a/engines/sword25/input/inputengine.cpp b/engines/sword25/input/inputengine.cpp
index a57af23e6b..8dc98ba3fb 100644
--- a/engines/sword25/input/inputengine.cpp
+++ b/engines/sword25/input/inputengine.cpp
@@ -39,7 +39,6 @@
#include "common/system.h"
#include "common/util.h"
#include "sword25/kernel/kernel.h"
-#include "sword25/kernel/callbackregistry.h"
#include "sword25/kernel/inputpersistenceblock.h"
#include "sword25/kernel/outputpersistenceblock.h"
#include "sword25/input/inputengine.h"
@@ -51,24 +50,24 @@ namespace Sword25 {
InputEngine::InputEngine(Kernel *pKernel) :
Service(pKernel),
- m_CurrentState(0),
- m_LeftMouseDown(false),
- m_RightMouseDown(false),
- m_MouseX(0),
- m_MouseY(0),
- m_LeftDoubleClick(false),
- m_DoubleClickTime(DOUBLE_CLICK_TIME),
- m_DoubleClickRectWidth(DOUBLE_CLICK_RECT_SIZE),
- m_DoubleClickRectHeight(DOUBLE_CLICK_RECT_SIZE),
- m_LastLeftClickTime(0),
- m_LastLeftClickMouseX(0),
- m_LastLeftClickMouseY(0) {
- memset(m_KeyboardState[0], 0, sizeof(m_KeyboardState[0]));
- memset(m_KeyboardState[1], 0, sizeof(m_KeyboardState[1]));
- m_LeftMouseState[0] = false;
- m_LeftMouseState[1] = false;
- m_RightMouseState[0] = false;
- m_RightMouseState[1] = false;
+ _currentState(0),
+ _leftMouseDown(false),
+ _rightMouseDown(false),
+ _mouseX(0),
+ _mouseY(0),
+ _leftDoubleClick(false),
+ _doubleClickTime(DOUBLE_CLICK_TIME),
+ _doubleClickRectWidth(DOUBLE_CLICK_RECT_SIZE),
+ _doubleClickRectHeight(DOUBLE_CLICK_RECT_SIZE),
+ _lastLeftClickTime(0),
+ _lastLeftClickMouseX(0),
+ _lastLeftClickMouseY(0) {
+ memset(_keyboardState[0], 0, sizeof(_keyboardState[0]));
+ memset(_keyboardState[1], 0, sizeof(_keyboardState[1]));
+ _leftMouseState[0] = false;
+ _leftMouseState[1] = false;
+ _rightMouseState[0] = false;
+ _rightMouseState[1] = false;
if (!registerScriptBindings())
BS_LOG_ERRORLN("Script bindings could not be registered.");
@@ -76,22 +75,25 @@ InputEngine::InputEngine(Kernel *pKernel) :
BS_LOGLN("Script bindings registered.");
}
-Service *InputEngine_CreateObject(Kernel *pKernel) {
- return new InputEngine(pKernel);
+InputEngine::~InputEngine() {
+ unregisterScriptBindings();
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::Init() {
+bool InputEngine::init() {
// No initialisation needed
return true;
}
-// -----------------------------------------------------------------------------
-
-void InputEngine::Update() {
+void InputEngine::update() {
Common::Event event;
- m_CurrentState ^= 1;
+
+ // We keep two sets of keyboard states: The current one, and that of
+ // the previous frame. This allows us to detect which keys changed
+ // state. Also, by keeping a single central keystate array, we
+ // ensure that all script queries for key state during a single
+ // frame get the same consistent replies.
+ _currentState ^= 1;
+ memcpy(_keyboardState[_currentState], _keyboardState[_currentState ^ 1], sizeof(_keyboardState[0]));
// Loop through processing any pending events
bool handleEvents = true;
@@ -99,31 +101,27 @@ void InputEngine::Update() {
switch (event.type) {
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
- m_LeftMouseDown = event.type == Common::EVENT_LBUTTONDOWN;
- m_MouseX = event.mouse.x;
- m_MouseY = event.mouse.y;
+ _leftMouseDown = event.type == Common::EVENT_LBUTTONDOWN;
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
handleEvents = false;
break;
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
- m_RightMouseDown = event.type == Common::EVENT_RBUTTONDOWN;
- m_MouseX = event.mouse.x;
- m_MouseY = event.mouse.y;
+ _rightMouseDown = event.type == Common::EVENT_RBUTTONDOWN;
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
handleEvents = false;
break;
case Common::EVENT_MOUSEMOVE:
- m_MouseX = event.mouse.x;
- m_MouseY = event.mouse.y;
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
break;
case Common::EVENT_KEYDOWN:
case Common::EVENT_KEYUP:
- AlterKeyboardState(event.kbd.keycode, (event.type == Common::EVENT_KEYDOWN) ? 0x80 : 0);
- break;
-
- case Common::EVENT_QUIT:
- Kernel::GetInstance()->GetWindow()->SetWindowAlive(false);
+ alterKeyboardState(event.kbd.keycode, (event.type == Common::EVENT_KEYDOWN) ? 0x80 : 0);
break;
default:
@@ -131,267 +129,153 @@ void InputEngine::Update() {
}
}
- m_LeftMouseState[m_CurrentState] = m_LeftMouseDown;
- m_RightMouseState[m_CurrentState] = m_RightMouseDown;
+ _leftMouseState[_currentState] = _leftMouseDown;
+ _rightMouseState[_currentState] = _rightMouseDown;
- TestForLeftDoubleClick();
+ testForLeftDoubleClick();
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::IsLeftMouseDown() {
- return m_LeftMouseDown;
+bool InputEngine::isLeftMouseDown() {
+ return _leftMouseDown;
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::IsRightMouseDown() {
- return m_RightMouseDown;
+bool InputEngine::isRightMouseDown() {
+ return _rightMouseDown;
}
-// -----------------------------------------------------------------------------
-
-void InputEngine::TestForLeftDoubleClick() {
- m_LeftDoubleClick = false;
+void InputEngine::testForLeftDoubleClick() {
+ _leftDoubleClick = false;
// Only bother checking for a double click if the left mouse button was clicked
- if (WasLeftMouseDown()) {
+ if (wasLeftMouseDown()) {
// Get the time now
- uint Now = Kernel::GetInstance()->GetMilliTicks();
+ uint now = Kernel::getInstance()->getMilliTicks();
// A double click is signalled if
// 1. The two clicks are close enough together
// 2. The mouse cursor hasn't moved much
- if (Now - m_LastLeftClickTime <= m_DoubleClickTime &&
- ABS(m_MouseX - m_LastLeftClickMouseX) <= m_DoubleClickRectWidth / 2 &&
- ABS(m_MouseY - m_LastLeftClickMouseY) <= m_DoubleClickRectHeight / 2) {
- m_LeftDoubleClick = true;
+ if (now - _lastLeftClickTime <= _doubleClickTime &&
+ ABS(_mouseX - _lastLeftClickMouseX) <= _doubleClickRectWidth / 2 &&
+ ABS(_mouseY - _lastLeftClickMouseY) <= _doubleClickRectHeight / 2) {
+ _leftDoubleClick = true;
// Reset the time and position of the last click, so that clicking is not
// interpreted as the first click of a further double-click
- m_LastLeftClickTime = 0;
- m_LastLeftClickMouseX = 0;
- m_LastLeftClickMouseY = 0;
+ _lastLeftClickTime = 0;
+ _lastLeftClickMouseX = 0;
+ _lastLeftClickMouseY = 0;
} else {
// There is no double click. Remember the position and time of the click,
// in case it's the first click of a double-click sequence
- m_LastLeftClickTime = Now;
- m_LastLeftClickMouseX = m_MouseX;
- m_LastLeftClickMouseY = m_MouseY;
+ _lastLeftClickTime = now;
+ _lastLeftClickMouseX = _mouseX;
+ _lastLeftClickMouseY = _mouseY;
}
}
}
-// -----------------------------------------------------------------------------
-
-void InputEngine::AlterKeyboardState(int keycode, byte newState) {
- m_KeyboardState[m_CurrentState][keycode] = newState;
+void InputEngine::alterKeyboardState(int keycode, byte newState) {
+ assert(keycode < ARRAYSIZE(_keyboardState[_currentState]));
+ _keyboardState[_currentState][keycode] = newState;
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::IsLeftDoubleClick() {
- return m_LeftDoubleClick;
+bool InputEngine::isLeftDoubleClick() {
+ return _leftDoubleClick;
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::WasLeftMouseDown() {
- return (m_LeftMouseState[m_CurrentState] == false) && (m_LeftMouseState[m_CurrentState ^ 1] == true);
+bool InputEngine::wasLeftMouseDown() {
+ return (_leftMouseState[_currentState] == false) && (_leftMouseState[_currentState ^ 1] == true);
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::WasRightMouseDown() {
- return (m_RightMouseState[m_CurrentState] == false) && (m_RightMouseState[m_CurrentState ^ 1] == true);
+bool InputEngine::wasRightMouseDown() {
+ return (_rightMouseState[_currentState] == false) && (_rightMouseState[_currentState ^ 1] == true);
}
-// -----------------------------------------------------------------------------
-
-int InputEngine::GetMouseX() {
- return m_MouseX;
+int InputEngine::getMouseX() {
+ return _mouseX;
}
-// -----------------------------------------------------------------------------
-
-int InputEngine::GetMouseY() {
- return m_MouseY;
+int InputEngine::getMouseY() {
+ return _mouseY;
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::IsKeyDown(uint KeyCode) {
- return (m_KeyboardState[m_CurrentState][KeyCode] & 0x80) != 0;
+bool InputEngine::isKeyDown(uint keyCode) {
+ assert(keyCode < ARRAYSIZE(_keyboardState[_currentState]));
+ return (_keyboardState[_currentState][keyCode] & 0x80) != 0;
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::WasKeyDown(uint KeyCode) {
- return ((m_KeyboardState[m_CurrentState][KeyCode] & 0x80) == 0) &&
- ((m_KeyboardState[m_CurrentState ^ 1][KeyCode] & 0x80) != 0);
+bool InputEngine::wasKeyDown(uint keyCode) {
+ assert(keyCode < ARRAYSIZE(_keyboardState[_currentState]));
+ return ((_keyboardState[_currentState][keyCode] & 0x80) == 0) &&
+ ((_keyboardState[_currentState ^ 1][keyCode] & 0x80) != 0);
}
-// -----------------------------------------------------------------------------
-
-void InputEngine::SetMouseX(int PosX) {
- m_MouseX = PosX;
- g_system->warpMouse(m_MouseX, m_MouseY);
+void InputEngine::setMouseX(int posX) {
+ _mouseX = posX;
+ g_system->warpMouse(_mouseX, _mouseY);
}
-// -----------------------------------------------------------------------------
-
-void InputEngine::SetMouseY(int PosY) {
- m_MouseY = PosY;
- g_system->warpMouse(m_MouseX, m_MouseY);
+void InputEngine::setMouseY(int posY) {
+ _mouseY = posY;
+ g_system->warpMouse(_mouseX, _mouseY);
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::RegisterCharacterCallback(CharacterCallback Callback) {
- if (Common::find(m_CharacterCallbacks.begin(), m_CharacterCallbacks.end(), Callback) == m_CharacterCallbacks.end()) {
- m_CharacterCallbacks.push_back(Callback);
- return true;
- } else {
- BS_LOG_WARNINGLN("Tried to register an CharacterCallback that was already registered.");
- return false;
- }
+void InputEngine::setCharacterCallback(CharacterCallback callback) {
+ _characterCallback = callback;
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::UnregisterCharacterCallback(CharacterCallback Callback) {
- Common::List<CharacterCallback>::iterator CallbackIter = Common::find(m_CharacterCallbacks.begin(),
- m_CharacterCallbacks.end(), Callback);
- if (CallbackIter != m_CharacterCallbacks.end()) {
- m_CharacterCallbacks.erase(CallbackIter);
- return true;
- } else {
- BS_LOG_WARNINGLN("Tried to unregister an CharacterCallback that was not previously registered.");
- return false;
- }
+void InputEngine::setCommandCallback(CommandCallback callback) {
+ _commandCallback = callback;
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::RegisterCommandCallback(CommandCallback Callback) {
- if (Common::find(m_CommandCallbacks.begin(), m_CommandCallbacks.end(), Callback) == m_CommandCallbacks.end()) {
- m_CommandCallbacks.push_back(Callback);
- return true;
- } else {
- BS_LOG_WARNINGLN("Tried to register an CommandCallback that was already registered.");
- return false;
- }
+void InputEngine::reportCharacter(byte character) {
+ if (_characterCallback)
+ (*_characterCallback)(character);
}
-// -----------------------------------------------------------------------------
-
-bool InputEngine::UnregisterCommandCallback(CommandCallback Callback) {
- Common::List<CommandCallback>::iterator CallbackIter =
- Common::find(m_CommandCallbacks.begin(), m_CommandCallbacks.end(), Callback);
- if (CallbackIter != m_CommandCallbacks.end()) {
- m_CommandCallbacks.erase(CallbackIter);
- return true;
- } else {
- BS_LOG_WARNINGLN("Tried to unregister an CommandCallback that was not previously registered.");
- return false;
- }
+void InputEngine::reportCommand(KEY_COMMANDS command) {
+ if (_commandCallback)
+ (*_commandCallback)(command);
}
-// -----------------------------------------------------------------------------
-
-void InputEngine::ReportCharacter(byte Character) {
- Common::List<CharacterCallback>::const_iterator CallbackIter = m_CharacterCallbacks.begin();
- while (CallbackIter != m_CharacterCallbacks.end()) {
- // Iterator vor dem Aufruf erhöhen und im Folgendem auf einer Kopie arbeiten.
- // Dieses Vorgehen ist notwendig da der Iterator möglicherweise von der Callbackfunktion durch das Deregistrieren des Callbacks
- // invalidiert wird.
- Common::List<CharacterCallback>::const_iterator CurCallbackIter = CallbackIter;
- ++CallbackIter;
-
- (*CurCallbackIter)(Character);
- }
-}
-
-// -----------------------------------------------------------------------------
-
-void InputEngine::ReportCommand(KEY_COMMANDS Command) {
- Common::List<CommandCallback>::const_iterator CallbackIter = m_CommandCallbacks.begin();
- while (CallbackIter != m_CommandCallbacks.end()) {
- // Iterator vor dem Aufruf erhöhen und im Folgendem auf einer Kopie arbeiten.
- // Dieses Vorgehen ist notwendig da der Iterator möglicherweise von der Callbackfunktion durch das Deregistrieren des Callbacks
- // invalidiert wird.
- Common::List<CommandCallback>::const_iterator CurCallbackIter = CallbackIter;
- ++CallbackIter;
-
- (*CurCallbackIter)(Command);
- }
-}
-
-// -----------------------------------------------------------------------------
-// Persistenz
-// -----------------------------------------------------------------------------
-
bool InputEngine::persist(OutputPersistenceBlock &writer) {
- // Anzahl an Command-Callbacks persistieren.
- writer.write(m_CommandCallbacks.size());
-
- // Alle Command-Callbacks einzeln persistieren.
- {
- Common::List<CommandCallback>::const_iterator It = m_CommandCallbacks.begin();
- while (It != m_CommandCallbacks.end()) {
- writer.write(CallbackRegistry::getInstance().resolveCallbackPointer(*It));
- ++It;
- }
- }
-
- // Anzahl an Character-Callbacks persistieren.
- writer.write(m_CharacterCallbacks.size());
-
- // Alle Character-Callbacks einzeln persistieren.
- {
- Common::List<CharacterCallback>::const_iterator It = m_CharacterCallbacks.begin();
- while (It != m_CharacterCallbacks.end()) {
- writer.write(CallbackRegistry::getInstance().resolveCallbackPointer(*It));
- ++It;
- }
- }
+ // Write out the number of command callbacks and their names.
+ // Note: We do this only for compatibility with older engines resp.
+ // the original engine.
+ writer.write((uint)1);
+ writer.writeString("LuaCommandCB");
+
+ // Write out the number of command callbacks and their names.
+ // Note: We do this only for compatibility with older engines resp.
+ // the original engine.
+ writer.write((uint)1);
+ writer.writeString("LuaCharacterCB");
return true;
}
-// -----------------------------------------------------------------------------
-
bool InputEngine::unpersist(InputPersistenceBlock &reader) {
- // Command-Callbackliste leeren.
- m_CommandCallbacks.clear();
-
- // Anzahl an Command-Callbacks lesen.
- uint CommandCallbackCount;
- reader.read(CommandCallbackCount);
-
- // Alle Command-Callbacks wieder herstellen.
- for (uint i = 0; i < CommandCallbackCount; ++i) {
- Common::String CallbackFunctionName;
- reader.read(CallbackFunctionName);
-
- m_CommandCallbacks.push_back(reinterpret_cast<CommandCallback>(
- CallbackRegistry::getInstance().resolveCallbackFunction(CallbackFunctionName)));
- }
-
- // Character-Callbackliste leeren.
- m_CharacterCallbacks.clear();
-
- // Anzahl an Character-Callbacks lesen.
- uint CharacterCallbackCount;
- reader.read(CharacterCallbackCount);
-
- // Alle Character-Callbacks wieder herstellen.
- for (uint i = 0; i < CharacterCallbackCount; ++i) {
- Common::String CallbackFunctionName;
- reader.read(CallbackFunctionName);
-
- m_CharacterCallbacks.push_back(reinterpret_cast<CharacterCallback>(CallbackRegistry::getInstance().resolveCallbackFunction(CallbackFunctionName)));
- }
+ Common::String callbackFunctionName;
+
+ // Read number of command callbacks and their names.
+ // Note: We do this only for compatibility with older engines resp.
+ // the original engine.
+ uint commandCallbackCount;
+ reader.read(commandCallbackCount);
+ assert(commandCallbackCount == 1);
+
+ reader.readString(callbackFunctionName);
+ assert(callbackFunctionName == "LuaCommandCB");
+
+ // Read number of character callbacks and their names.
+ // Note: We do this only for compatibility with older engines resp.
+ // the original engine.
+ uint characterCallbackCount;
+ reader.read(characterCallbackCount);
+ assert(characterCallbackCount == 1);
+
+ reader.readString(callbackFunctionName);
+ assert(callbackFunctionName == "LuaCharacterCB");
return reader.isGood();
}
diff --git a/engines/sword25/input/inputengine.h b/engines/sword25/input/inputengine.h
index 540817b5ce..946d6a8e5e 100644
--- a/engines/sword25/input/inputengine.h
+++ b/engines/sword25/input/inputengine.h
@@ -45,11 +45,11 @@
#ifndef SWORD25_INPUTENGINE_H
#define SWORD25_INPUTENGINE_H
-/// Includes
+#include "common/keyboard.h"
+
#include "sword25/kernel/common.h"
#include "sword25/kernel/service.h"
#include "sword25/kernel/persistable.h"
-#include "sword25/kernel/callbackregistry.h"
namespace Sword25 {
@@ -58,104 +58,106 @@ namespace Sword25 {
class InputEngine : public Service, public Persistable {
public:
InputEngine(Kernel *pKernel);
- ~InputEngine() {};
+ ~InputEngine();
// NOTE: These codes are registered in inputengine_script.cpp
- // Any changes to these enums must also adjust the above file.
+ // If you add or remove entries of this enum, you must also adjust
+ // the above file.
enum KEY_CODES {
- KEY_BACKSPACE = 0x08,
- KEY_TAB = 0x09,
- KEY_CLEAR = 0x0C,
- KEY_RETURN = 0x0D,
- KEY_PAUSE = 0x13,
- KEY_CAPSLOCK = 0x14,
- KEY_ESCAPE = 0x1B,
- KEY_SPACE = 0x20,
- KEY_PAGEUP = 0x21,
- KEY_PAGEDOWN = 0x22,
- KEY_END = 0x23,
- KEY_HOME = 0x24,
- KEY_LEFT = 0x25,
- KEY_UP = 0x26,
- KEY_RIGHT = 0x27,
- KEY_DOWN = 0x28,
- KEY_PRINTSCREEN = 0x2C,
- KEY_INSERT = 0x2D,
- KEY_DELETE = 0x2E,
- KEY_0 = 0x30,
- KEY_1 = 0x31,
- KEY_2 = 0x32,
- KEY_3 = 0x33,
- KEY_4 = 0x34,
- KEY_5 = 0x35,
- KEY_6 = 0x36,
- KEY_7 = 0x37,
- KEY_8 = 0x38,
- KEY_9 = 0x39,
- KEY_A = 0x41,
- KEY_B = 0x42,
- KEY_C = 0x43,
- KEY_D = 0x44,
- KEY_E = 0x45,
- KEY_F = 0x46,
- KEY_G = 0x47,
- KEY_H = 0x48,
- KEY_I = 0x49,
- KEY_J = 0x4A,
- KEY_K = 0x4B,
- KEY_L = 0x4C,
- KEY_M = 0x4D,
- KEY_N = 0x4E,
- KEY_O = 0x4F,
- KEY_P = 0x50,
- KEY_Q = 0x51,
- KEY_R = 0x52,
- KEY_S = 0x53,
- KEY_T = 0x54,
- KEY_U = 0x55,
- KEY_V = 0x56,
- KEY_W = 0x57,
- KEY_X = 0x58,
- KEY_Y = 0x59,
- KEY_Z = 0x5A,
- KEY_NUMPAD0 = 0x60,
- KEY_NUMPAD1 = 0x61,
- KEY_NUMPAD2 = 0x62,
- KEY_NUMPAD3 = 0x63,
- KEY_NUMPAD4 = 0x64,
- KEY_NUMPAD5 = 0x65,
- KEY_NUMPAD6 = 0x66,
- KEY_NUMPAD7 = 0x67,
- KEY_NUMPAD8 = 0x68,
- KEY_NUMPAD9 = 0x69,
- KEY_MULTIPLY = 0x6A,
- KEY_ADD = 0x6B,
- KEY_SEPARATOR = 0x6C,
- KEY_SUBTRACT = 0x6D,
- KEY_DECIMAL = 0x6E,
- KEY_DIVIDE = 0x6F,
- KEY_F1 = 0x70,
- KEY_F2 = 0x71,
- KEY_F3 = 0x72,
- KEY_F4 = 0x73,
- KEY_F5 = 0x74,
- KEY_F6 = 0x75,
- KEY_F7 = 0x76,
- KEY_F8 = 0x77,
- KEY_F9 = 0x78,
- KEY_F10 = 0x79,
- KEY_F11 = 0x7A,
- KEY_F12 = 0x7B,
- KEY_NUMLOCK = 0x90,
- KEY_SCROLL = 0x91,
- KEY_LSHIFT = 0xA0,
- KEY_RSHIFT = 0xA1,
- KEY_LCONTROL = 0xA2,
- KEY_RCONTROL = 0xA3
+ KEY_BACKSPACE = Common::KEYCODE_BACKSPACE,
+ KEY_TAB = Common::KEYCODE_TAB,
+ KEY_CLEAR = Common::KEYCODE_CLEAR,
+ KEY_RETURN = Common::KEYCODE_RETURN,
+ KEY_PAUSE = Common::KEYCODE_PAUSE,
+ KEY_CAPSLOCK = Common::KEYCODE_CAPSLOCK,
+ KEY_ESCAPE = Common::KEYCODE_ESCAPE,
+ KEY_SPACE = Common::KEYCODE_SPACE,
+ KEY_PAGEUP = Common::KEYCODE_PAGEUP,
+ KEY_PAGEDOWN = Common::KEYCODE_PAGEDOWN,
+ KEY_END = Common::KEYCODE_END,
+ KEY_HOME = Common::KEYCODE_HOME,
+ KEY_LEFT = Common::KEYCODE_LEFT,
+ KEY_UP = Common::KEYCODE_UP,
+ KEY_RIGHT = Common::KEYCODE_RIGHT,
+ KEY_DOWN = Common::KEYCODE_DOWN,
+ KEY_PRINTSCREEN = Common::KEYCODE_PRINT,
+ KEY_INSERT = Common::KEYCODE_INSERT,
+ KEY_DELETE = Common::KEYCODE_DELETE,
+ KEY_0 = Common::KEYCODE_0,
+ KEY_1 = Common::KEYCODE_1,
+ KEY_2 = Common::KEYCODE_2,
+ KEY_3 = Common::KEYCODE_3,
+ KEY_4 = Common::KEYCODE_4,
+ KEY_5 = Common::KEYCODE_5,
+ KEY_6 = Common::KEYCODE_6,
+ KEY_7 = Common::KEYCODE_7,
+ KEY_8 = Common::KEYCODE_8,
+ KEY_9 = Common::KEYCODE_9,
+ KEY_A = Common::KEYCODE_a,
+ KEY_B = Common::KEYCODE_b,
+ KEY_C = Common::KEYCODE_c,
+ KEY_D = Common::KEYCODE_d,
+ KEY_E = Common::KEYCODE_e,
+ KEY_F = Common::KEYCODE_f,
+ KEY_G = Common::KEYCODE_g,
+ KEY_H = Common::KEYCODE_h,
+ KEY_I = Common::KEYCODE_i,
+ KEY_J = Common::KEYCODE_j,
+ KEY_K = Common::KEYCODE_k,
+ KEY_L = Common::KEYCODE_l,
+ KEY_M = Common::KEYCODE_m,
+ KEY_N = Common::KEYCODE_n,
+ KEY_O = Common::KEYCODE_o,
+ KEY_P = Common::KEYCODE_p,
+ KEY_Q = Common::KEYCODE_q,
+ KEY_R = Common::KEYCODE_r,
+ KEY_S = Common::KEYCODE_s,
+ KEY_T = Common::KEYCODE_t,
+ KEY_U = Common::KEYCODE_u,
+ KEY_V = Common::KEYCODE_v,
+ KEY_W = Common::KEYCODE_w,
+ KEY_X = Common::KEYCODE_x,
+ KEY_Y = Common::KEYCODE_y,
+ KEY_Z = Common::KEYCODE_z,
+ KEY_NUMPAD0 = Common::KEYCODE_KP0,
+ KEY_NUMPAD1 = Common::KEYCODE_KP1,
+ KEY_NUMPAD2 = Common::KEYCODE_KP2,
+ KEY_NUMPAD3 = Common::KEYCODE_KP3,
+ KEY_NUMPAD4 = Common::KEYCODE_KP4,
+ KEY_NUMPAD5 = Common::KEYCODE_KP5,
+ KEY_NUMPAD6 = Common::KEYCODE_KP6,
+ KEY_NUMPAD7 = Common::KEYCODE_KP7,
+ KEY_NUMPAD8 = Common::KEYCODE_KP8,
+ KEY_NUMPAD9 = Common::KEYCODE_KP9,
+ KEY_MULTIPLY = Common::KEYCODE_KP_MULTIPLY,
+ KEY_ADD = Common::KEYCODE_KP_PLUS,
+ KEY_SEPARATOR = Common::KEYCODE_EQUALS, // FIXME: This mapping is just a wild guess!!
+ KEY_SUBTRACT = Common::KEYCODE_KP_MINUS,
+ KEY_DECIMAL = Common::KEYCODE_KP_PERIOD,
+ KEY_DIVIDE = Common::KEYCODE_KP_DIVIDE,
+ KEY_F1 = Common::KEYCODE_F1,
+ KEY_F2 = Common::KEYCODE_F2,
+ KEY_F3 = Common::KEYCODE_F3,
+ KEY_F4 = Common::KEYCODE_F4,
+ KEY_F5 = Common::KEYCODE_F5,
+ KEY_F6 = Common::KEYCODE_F6,
+ KEY_F7 = Common::KEYCODE_F7,
+ KEY_F8 = Common::KEYCODE_F8,
+ KEY_F9 = Common::KEYCODE_F9,
+ KEY_F10 = Common::KEYCODE_F10,
+ KEY_F11 = Common::KEYCODE_F11,
+ KEY_F12 = Common::KEYCODE_F12,
+ KEY_NUMLOCK = Common::KEYCODE_NUMLOCK,
+ KEY_SCROLL = Common::KEYCODE_SCROLLOCK,
+ KEY_LSHIFT = Common::KEYCODE_LSHIFT,
+ KEY_RSHIFT = Common::KEYCODE_RSHIFT,
+ KEY_LCONTROL = Common::KEYCODE_LCTRL,
+ KEY_RCONTROL = Common::KEYCODE_RCTRL
};
- // NOTE: These codes are registered in inputengine_script.cpp.
- // Any changes to these enums must also adjust the above file.
+ // NOTE: These codes are registered in inputengine_script.cpp
+ // If you add or remove entries of this enum, you must also adjust
+ // the above file.
enum KEY_COMMANDS {
KEY_COMMAND_ENTER = 1,
KEY_COMMAND_LEFT = 2,
@@ -176,7 +178,7 @@ public:
* Initialises the input engine
* @return Returns a true on success, otherwise false.
*/
- bool Init();
+ bool init();
/**
* Performs a "tick" of the input engine.
@@ -185,17 +187,17 @@ public:
* of the input engine that are not running in their own thread, or to perform
* additional administrative tasks that are needed.
*/
- void Update();
+ void update();
/**
* Returns true if the left mouse button is pressed
*/
- bool IsLeftMouseDown();
+ bool isLeftMouseDown();
/**
* Returns true if the right mouse button is pressed.
*/
- bool IsRightMouseDown();
+ bool isRightMouseDown();
/**
* Returns true if the left mouse button was pressed and released.
@@ -203,7 +205,7 @@ public:
* The difference between this and IsLeftMouseDown() is that this only returns
* true when the left mouse button is released.
*/
- bool WasLeftMouseDown();
+ bool wasLeftMouseDown();
/**
* Returns true if the right mouse button was pressed and released.
@@ -211,39 +213,39 @@ public:
* The difference between this and IsRightMouseDown() is that this only returns
* true when the right mouse button is released.
*/
- bool WasRightMouseDown();
+ bool wasRightMouseDown();
/**
* Returns true if the left mouse button double click was done
*/
- bool IsLeftDoubleClick();
+ bool isLeftDoubleClick();
/**
* Returns the X position of the cursor in pixels
*/
- int GetMouseX();
+ int getMouseX();
/**
* Returns the Y position of the cursor in pixels
*/
- int GetMouseY();
+ int getMouseY();
/**
* Sets the X position of the cursor in pixels
*/
- void SetMouseX(int PosX);
+ void setMouseX(int posX);
/**
* Sets the Y position of the cursor in pixels
*/
- void SetMouseY(int PosY);
+ void setMouseY(int posY);
/**
* Returns true if a given key was pressed
* @param KeyCode The key code to be checked
* @return Returns true if the given key is done, otherwise false.
*/
- bool IsKeyDown(uint KeyCode);
+ bool isKeyDown(uint keyCode);
/**
* Returns true if a certain key was pushed and released.
@@ -253,79 +255,66 @@ public:
* strings that users type.
* @param KeyCode The key code to be checked
*/
- bool WasKeyDown(uint KeyCode);
+ bool wasKeyDown(uint keyCode);
- typedef CallbackPtr CharacterCallback;
+ typedef void (*CharacterCallback)(int command);
/**
* Registers a callback function for keyboard input.
*
- * The callbacks that are registered with this function will be called whenever an
+ * The callback that is registered with this function will be called whenever an
* input key is pressed. A letter entry is different from the query using the
- * methods IsKeyDown () and WasKeyDown () in the sense that are treated instead
+ * methods isKeyDown() and wasKeyDown() in the sense that are treated instead
* of actual scan-coded letters. These were taken into account, among other things:
* the keyboard layout, the condition the Shift and Caps Lock keys and the repetition
* of longer holding the key.
* The input of strings by the user through use of callbacks should be implemented.
- * @return Returns true if the function was registered, otherwise false.
*/
- bool RegisterCharacterCallback(CallbackPtr Callback);
-
- /**
- * De-registeres a previously registered callback function.
- * @return Returns true if the function could be de-registered, otherwise false.
- */
- bool UnregisterCharacterCallback(CallbackPtr Callback);
+ void setCharacterCallback(CharacterCallback callback);
- typedef CallbackPtr CommandCallback;
+ typedef void (*CommandCallback)(int command);
/**
* Registers a callback function for the input of commands that can have influence on the string input
*
- * The callbacks that are registered with this function will be called whenever the input service
+ * The callback that is registered with this function will be called whenever the input service
* has a key that affects the character string input. This could be the following keys:
* Enter, End, Left, Right, ...
* The input of strings by the user through the use of callbacks should be implemented.
- * @return Returns true if the function was registered, otherwise false.
- */
- bool RegisterCommandCallback(CallbackPtr Callback);
-
- /**
- * Un-register a callback function for the input of commands that can have an influence on the string input.
- * @return Returns true if the function could be de-registered, otherwise false.
*/
- bool UnregisterCommandCallback(CommandCallback Callback);
+ void setCommandCallback(CommandCallback callback);
- void ReportCharacter(byte Character);
- void ReportCommand(KEY_COMMANDS Command);
+ void reportCharacter(byte character);
+ void reportCommand(KEY_COMMANDS command);
bool persist(OutputPersistenceBlock &writer);
bool unpersist(InputPersistenceBlock &reader);
private:
bool registerScriptBindings();
+ void unregisterScriptBindings();
private:
- void TestForLeftDoubleClick();
- void AlterKeyboardState(int keycode, byte newState);
-
- byte m_KeyboardState[2][256];
- bool m_LeftMouseState[2];
- bool m_RightMouseState[2];
- uint m_CurrentState;
- int m_MouseX;
- int m_MouseY;
- bool m_LeftMouseDown;
- bool m_RightMouseDown;
- bool m_LeftDoubleClick;
- uint m_DoubleClickTime;
- int m_DoubleClickRectWidth;
- int m_DoubleClickRectHeight;
- uint m_LastLeftClickTime;
- int m_LastLeftClickMouseX;
- int m_LastLeftClickMouseY;
- Common::List<CommandCallback> m_CommandCallbacks;
- Common::List<CharacterCallback> m_CharacterCallbacks;
+ void testForLeftDoubleClick();
+ void alterKeyboardState(int keycode, byte newState);
+
+ byte _keyboardState[2][512];
+ bool _leftMouseState[2];
+ bool _rightMouseState[2];
+ uint _currentState;
+ int _mouseX;
+ int _mouseY;
+ bool _leftMouseDown;
+ bool _rightMouseDown;
+ bool _leftDoubleClick;
+ uint _doubleClickTime;
+ int _doubleClickRectWidth;
+ int _doubleClickRectHeight;
+ uint _lastLeftClickTime;
+ int _lastLeftClickMouseX;
+ int _lastLeftClickMouseY;
+ CommandCallback _commandCallback;
+ CharacterCallback _characterCallback;
};
} // End of namespace Sword25
diff --git a/engines/sword25/input/inputengine_script.cpp b/engines/sword25/input/inputengine_script.cpp
index 38ecc3cf56..2f16a21377 100644
--- a/engines/sword25/input/inputengine_script.cpp
+++ b/engines/sword25/input/inputengine_script.cpp
@@ -32,15 +32,10 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "common/ptr.h"
#include "common/str.h"
#include "sword25/kernel/common.h"
#include "sword25/kernel/kernel.h"
-#include "sword25/kernel/callbackregistry.h"
#include "sword25/script/script.h"
#include "sword25/script/luabindhelper.h"
#include "sword25/script/luacallback.h"
@@ -51,270 +46,203 @@
namespace Sword25 {
-using namespace Lua;
-
-// -----------------------------------------------------------------------------
-// Callback-Objekte
-// -----------------------------------------------------------------------------
-
-static void TheCharacterCallback(int Character);
-static void TheCommandCallback(int Command);
+static void theCharacterCallback(int character);
+static void theCommandCallback(int command);
namespace {
class CharacterCallbackClass : public LuaCallback {
public:
- CharacterCallbackClass(lua_State *L) : LuaCallback(L) {};
+ CharacterCallbackClass(lua_State *L) : LuaCallback(L) {}
- Common::String Character;
+ Common::String _character;
protected:
int PreFunctionInvokation(lua_State *L) {
- lua_pushstring(L, Character.c_str());
+ lua_pushstring(L, _character.c_str());
return 1;
}
};
-Common::SharedPtr<CharacterCallbackClass> CharacterCallbackPtr;
-// -----------------------------------------------------------------------------
+static CharacterCallbackClass *characterCallbackPtr = 0; // FIXME: should be turned into InputEngine member var
class CommandCallbackClass : public LuaCallback {
public:
CommandCallbackClass(lua_State *L) : LuaCallback(L) {
- Command = InputEngine::KEY_COMMAND_BACKSPACE;
+ _command = InputEngine::KEY_COMMAND_BACKSPACE;
}
- InputEngine::KEY_COMMANDS Command;
+ InputEngine::KEY_COMMANDS _command;
protected:
- int PreFunctionInvokation(lua_State *L) {
- lua_pushnumber(L, Command);
+ int preFunctionInvokation(lua_State *L) {
+ lua_pushnumber(L, _command);
return 1;
}
};
-Common::SharedPtr<CommandCallbackClass> CommandCallbackPtr;
-// -------------------------------------------------------------------------
+static CommandCallbackClass *commandCallbackPtr = 0; // FIXME: should be turned into InputEngine member var
-struct CallbackfunctionRegisterer {
- CallbackfunctionRegisterer() {
- CallbackRegistry::getInstance().registerCallbackFunction("LuaCommandCB", TheCommandCallback);
- CallbackRegistry::getInstance().registerCallbackFunction("LuaCharacterCB", TheCharacterCallback);
- }
-};
-static CallbackfunctionRegisterer Instance;
}
-// -----------------------------------------------------------------------------
-
-static InputEngine *GetIE() {
- Kernel *pKernel = Kernel::GetInstance();
+static InputEngine *getIE() {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- InputEngine *pIE = static_cast<InputEngine *>(pKernel->GetService("input"));
+ InputEngine *pIE = pKernel->getInput();
BS_ASSERT(pIE);
return pIE;
}
-// -----------------------------------------------------------------------------
-
-static int Init(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int init(lua_State *L) {
+ InputEngine *pIE = getIE();
- lua_pushbooleancpp(L, pIE->Init());
+ lua_pushbooleancpp(L, pIE->init());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int Update(lua_State *L) {
- InputEngine *pIE = GetIE();
-
- // Beim ersten Aufruf der Update()-Methode werden die beiden Callbacks am Input-Objekt registriert.
- // Dieses kann nicht in _RegisterScriptBindings() passieren, da diese Funktion vom Konstruktor der abstrakten Basisklasse aufgerufen wird und die
- // Register...()-Methoden abstrakt sind, im Konstruktor der Basisklasse also nicht aufgerufen werden können.
- static bool FirstCall = true;
- if (FirstCall) {
- FirstCall = false;
- pIE->RegisterCharacterCallback(TheCharacterCallback);
- pIE->RegisterCommandCallback(TheCommandCallback);
- }
+static int update(lua_State *L) {
+ InputEngine *pIE = getIE();
- pIE->Update();
+ pIE->update();
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int IsLeftMouseDown(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int isLeftMouseDown(lua_State *L) {
+ InputEngine *pIE = getIE();
- lua_pushbooleancpp(L, pIE->IsLeftMouseDown());
+ lua_pushbooleancpp(L, pIE->isLeftMouseDown());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int IsRightMouseDown(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int isRightMouseDown(lua_State *L) {
+ InputEngine *pIE = getIE();
- lua_pushbooleancpp(L, pIE->IsRightMouseDown());
+ lua_pushbooleancpp(L, pIE->isRightMouseDown());
return 1;
}
-// -----------------------------------------------------------------------------
+static int wasLeftMouseDown(lua_State *L) {
+ InputEngine *pIE = getIE();
-static int WasLeftMouseDown(lua_State *L) {
- InputEngine *pIE = GetIE();
-
- lua_pushbooleancpp(L, pIE->WasLeftMouseDown());
+ lua_pushbooleancpp(L, pIE->wasLeftMouseDown());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int WasRightMouseDown(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int wasRightMouseDown(lua_State *L) {
+ InputEngine *pIE = getIE();
- lua_pushbooleancpp(L, pIE->WasRightMouseDown());
+ lua_pushbooleancpp(L, pIE->wasRightMouseDown());
return 1;
}
-// -----------------------------------------------------------------------------
+static int isLeftDoubleClick(lua_State *L) {
+ InputEngine *pIE = getIE();
-static int IsLeftDoubleClick(lua_State *L) {
- InputEngine *pIE = GetIE();
-
- lua_pushbooleancpp(L, pIE->IsLeftDoubleClick());
+ lua_pushbooleancpp(L, pIE->isLeftDoubleClick());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetMouseX(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int getMouseX(lua_State *L) {
+ InputEngine *pIE = getIE();
- lua_pushnumber(L, pIE->GetMouseX());
+ lua_pushnumber(L, pIE->getMouseX());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetMouseY(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int getMouseY(lua_State *L) {
+ InputEngine *pIE = getIE();
- lua_pushnumber(L, pIE->GetMouseY());
+ lua_pushnumber(L, pIE->getMouseY());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int IsKeyDown(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int isKeyDown(lua_State *L) {
+ InputEngine *pIE = getIE();
- lua_pushbooleancpp(L, pIE->IsKeyDown((uint) luaL_checknumber(L, 1)));
+ lua_pushbooleancpp(L, pIE->isKeyDown((uint)luaL_checknumber(L, 1)));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int WasKeyDown(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int wasKeyDown(lua_State *L) {
+ InputEngine *pIE = getIE();
- lua_pushbooleancpp(L, pIE->WasKeyDown((uint) luaL_checknumber(L, 1)));
+ lua_pushbooleancpp(L, pIE->wasKeyDown((uint)luaL_checknumber(L, 1)));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SetMouseX(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int setMouseX(lua_State *L) {
+ InputEngine *pIE = getIE();
- pIE->SetMouseX((int) luaL_checknumber(L, 1));
+ pIE->setMouseX((int)luaL_checknumber(L, 1));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int SetMouseY(lua_State *L) {
- InputEngine *pIE = GetIE();
+static int setMouseY(lua_State *L) {
+ InputEngine *pIE = getIE();
- pIE->SetMouseY((int) luaL_checknumber(L, 1));
+ pIE->setMouseY((int)luaL_checknumber(L, 1));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static void TheCharacterCallback(int Character) {
- CharacterCallbackPtr->Character = static_cast<byte>(Character);
- lua_State *L = static_cast<lua_State *>(Kernel::GetInstance()->GetScript()->getScriptObject());
- CharacterCallbackPtr->invokeCallbackFunctions(L, 1);
+static void theCharacterCallback(int character) {
+ characterCallbackPtr->_character = static_cast<byte>(character);
+ lua_State *L = static_cast<lua_State *>(Kernel::getInstance()->getScript()->getScriptObject());
+ characterCallbackPtr->invokeCallbackFunctions(L, 1);
}
-// -----------------------------------------------------------------------------
-
-static int RegisterCharacterCallback(lua_State *L) {
+static int registerCharacterCallback(lua_State *L) {
luaL_checktype(L, 1, LUA_TFUNCTION);
- CharacterCallbackPtr->registerCallbackFunction(L, 1);
+ characterCallbackPtr->registerCallbackFunction(L, 1);
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int UnregisterCharacterCallback(lua_State *L) {
+static int unregisterCharacterCallback(lua_State *L) {
luaL_checktype(L, 1, LUA_TFUNCTION);
- CharacterCallbackPtr->unregisterCallbackFunction(L, 1);
+ characterCallbackPtr->unregisterCallbackFunction(L, 1);
return 0;
}
-// -----------------------------------------------------------------------------
-
-static void TheCommandCallback(int Command) {
- CommandCallbackPtr->Command = static_cast<InputEngine::KEY_COMMANDS>(Command);
- lua_State *L = static_cast<lua_State *>(Kernel::GetInstance()->GetScript()->getScriptObject());
- CommandCallbackPtr->invokeCallbackFunctions(L, 1);
+static void theCommandCallback(int command) {
+ commandCallbackPtr->_command = static_cast<InputEngine::KEY_COMMANDS>(command);
+ lua_State *L = static_cast<lua_State *>(Kernel::getInstance()->getScript()->getScriptObject());
+ commandCallbackPtr->invokeCallbackFunctions(L, 1);
}
-// -----------------------------------------------------------------------------
-
-static int RegisterCommandCallback(lua_State *L) {
+static int registerCommandCallback(lua_State *L) {
luaL_checktype(L, 1, LUA_TFUNCTION);
- CommandCallbackPtr->registerCallbackFunction(L, 1);
+ commandCallbackPtr->registerCallbackFunction(L, 1);
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int UnregisterCommandCallback(lua_State *L) {
+static int unregisterCommandCallback(lua_State *L) {
luaL_checktype(L, 1, LUA_TFUNCTION);
- CommandCallbackPtr->unregisterCallbackFunction(L, 1);
+ commandCallbackPtr->unregisterCallbackFunction(L, 1);
return 0;
}
-// -----------------------------------------------------------------------------
-
static const char *PACKAGE_LIBRARY_NAME = "Input";
static const luaL_reg PACKAGE_FUNCTIONS[] = {
- {"Init", Init},
- {"Update", Update},
- {"IsLeftMouseDown", IsLeftMouseDown},
- {"IsRightMouseDown", IsRightMouseDown},
- {"WasLeftMouseDown", WasLeftMouseDown},
- {"WasRightMouseDown", WasRightMouseDown},
- {"IsLeftDoubleClick", IsLeftDoubleClick},
- {"GetMouseX", GetMouseX},
- {"GetMouseY", GetMouseY},
- {"SetMouseX", SetMouseX},
- {"SetMouseY", SetMouseY},
- {"IsKeyDown", IsKeyDown},
- {"WasKeyDown", WasKeyDown},
- {"RegisterCharacterCallback", RegisterCharacterCallback},
- {"UnregisterCharacterCallback", UnregisterCharacterCallback},
- {"RegisterCommandCallback", RegisterCommandCallback},
- {"UnregisterCommandCallback", UnregisterCommandCallback},
+ {"Init", init},
+ {"Update", update},
+ {"IsLeftMouseDown", isLeftMouseDown},
+ {"IsRightMouseDown", isRightMouseDown},
+ {"WasLeftMouseDown", wasLeftMouseDown},
+ {"WasRightMouseDown", wasRightMouseDown},
+ {"IsLeftDoubleClick", isLeftDoubleClick},
+ {"GetMouseX", getMouseX},
+ {"GetMouseY", getMouseY},
+ {"SetMouseX", setMouseX},
+ {"SetMouseY", setMouseY},
+ {"IsKeyDown", isKeyDown},
+ {"WasKeyDown", wasKeyDown},
+ {"RegisterCharacterCallback", registerCharacterCallback},
+ {"UnregisterCharacterCallback", unregisterCharacterCallback},
+ {"RegisterCommandCallback", registerCommandCallback},
+ {"UnregisterCommandCallback", unregisterCommandCallback},
{0, 0}
};
@@ -336,9 +264,9 @@ static const lua_constant_reg PACKAGE_CONSTANTS[] = {
// -----------------------------------------------------------------------------
bool InputEngine::registerScriptBindings() {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ScriptEngine *pScript = static_cast<ScriptEngine *>(pKernel->GetService("script"));
+ ScriptEngine *pScript = pKernel->getScript();
BS_ASSERT(pScript);
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
BS_ASSERT(L);
@@ -346,10 +274,24 @@ bool InputEngine::registerScriptBindings() {
if (!LuaBindhelper::addFunctionsToLib(L, PACKAGE_LIBRARY_NAME, PACKAGE_FUNCTIONS)) return false;
if (!LuaBindhelper::addConstantsToLib(L, PACKAGE_LIBRARY_NAME, PACKAGE_CONSTANTS)) return false;
- CharacterCallbackPtr = Common::SharedPtr<CharacterCallbackClass>(new CharacterCallbackClass(L));
- CommandCallbackPtr = Common::SharedPtr<CommandCallbackClass>(new CommandCallbackClass(L));
+ assert(characterCallbackPtr == 0);
+ characterCallbackPtr = new CharacterCallbackClass(L);
+
+ assert(commandCallbackPtr == 0);
+ commandCallbackPtr = new CommandCallbackClass(L);
+
+ setCharacterCallback(theCharacterCallback);
+ setCommandCallback(theCommandCallback);
return true;
}
+void InputEngine::unregisterScriptBindings() {
+ delete characterCallbackPtr;
+ characterCallbackPtr = 0;
+
+ delete commandCallbackPtr;
+ commandCallbackPtr = 0;
+}
+
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/callbackregistry.cpp b/engines/sword25/kernel/callbackregistry.cpp
deleted file mode 100644
index 32b2597334..0000000000
--- a/engines/sword25/kernel/callbackregistry.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-// Alle Callbackfunktionen die von Objekten gerufen werden, die persistiert werden können, müssen hier registriert werden.
-// Beim Speichern wird statt des Pointers der Bezeichner gespeichert. Beim Laden wird der Bezeichner wieder in einen Pointer umgewandelt.
-// Diese Klasse führt also so etwas ähnliches wie eine Importtabelle für Callback-Funktionen.
-//
-// Dieses Vorgehen hat mehrere Vorteile:
-// 1. Die Speicherstände sind plattformunabhängig. Es werden keine Pointer auf Funktionen gespeichert, sondern nur Namen von Callbackfunktionen.
-// Diese können beim Laden über diese Klasse in systemabhängige Pointer umgewandelt werden.
-// 2. Speicherstände können auch nach einem Engineupdate weiterhin benutzt werden. Beim Erstellen einer neun Binary verschieben sich häufig die
-// Funktionen. Eine Callbackfunktion könnte sich also nach einem Update an einer anderen Stelle befinden als davor. Wenn im Spielstand der
-// Pointer gespeichert war, stürtzt das Programm beim Äufrufen dieser Callbackfunktion ab. Durch das Auflösungverfahren wird beim Laden der
-// Callbackbezeichner in den neuen Funktionspointer umgewandelt und der Aufruf kann erfolgen.
-
-// -----------------------------------------------------------------------------
-// Logging
-// -----------------------------------------------------------------------------
-
-#define BS_LOG_PREFIX "CALLBACKREGISTRY"
-
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
-#include "sword25/kernel/callbackregistry.h"
-
-namespace Sword25 {
-
-// -----------------------------------------------------------------------------
-
-bool CallbackRegistry::registerCallbackFunction(const Common::String &name, CallbackPtr ptr) {
- if (name == "") {
- BS_LOG_ERRORLN("The empty string is not allowed as a callback function name.");
- return false;
- }
-
- if (findPtrByName(name) != 0) {
- BS_LOG_ERRORLN("There is already a callback function with the name \"%s\".", name.c_str());
- return false;
- }
- if (findNameByPtr(ptr) != "") {
- BS_LOG_ERRORLN("There is already a callback function with the pointer 0x%x.", ptr);
- return false;
- }
-
- storeCallbackFunction(name, ptr);
-
- return true;
-}
-
-// -----------------------------------------------------------------------------
-
-CallbackPtr CallbackRegistry::resolveCallbackFunction(const Common::String &name) const {
- CallbackPtr result = findPtrByName(name);
-
- if (!result) {
- BS_LOG_ERRORLN("There is no callback function with the name \"%s\".", name.c_str());
- }
-
- return result;
-}
-
-// -----------------------------------------------------------------------------
-
-Common::String CallbackRegistry::resolveCallbackPointer(CallbackPtr ptr) const {
- const Common::String &result = findNameByPtr(ptr);
-
- if (result == "") {
- BS_LOG_ERRORLN("There is no callback function with the pointer 0x%x.", ptr);
- }
-
- return result;
-}
-
-// -----------------------------------------------------------------------------
-
-CallbackPtr CallbackRegistry::findPtrByName(const Common::String &name) const {
- // Eintrag in der Map finden und den Pointer zurückgeben.
- NameToPtrMap::const_iterator it = _nameToPtrMap.find(name);
- return it == _nameToPtrMap.end() ? 0 : it->_value;
-}
-
-// -----------------------------------------------------------------------------
-
-Common::String CallbackRegistry::findNameByPtr(CallbackPtr ptr) const {
- // Eintrag in der Map finden und den Namen zurückgeben.
- PtrToNameMap::const_iterator it = _ptrToNameMap.find(ptr);
- return it == _ptrToNameMap.end() ? "" : it->_value;
-}
-
-// -----------------------------------------------------------------------------
-
-void CallbackRegistry::storeCallbackFunction(const Common::String &name, CallbackPtr ptr) {
- // Callback-Funktion in beide Maps eintragen.
- _nameToPtrMap[name] = ptr;
- _ptrToNameMap[ptr] = name;
-}
-
-} // End of namespace Sword25
diff --git a/engines/sword25/kernel/callbackregistry.h b/engines/sword25/kernel/callbackregistry.h
deleted file mode 100644
index c5076d22f5..0000000000
--- a/engines/sword25/kernel/callbackregistry.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-#ifndef SWORD25_CALLBACK_REGISTRY_H
-#define SWORD25_CALLBACK_REGISTRY_H
-
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
-#include "common/scummsys.h"
-#include "common/str.h"
-#include "common/hash-str.h"
-#include "common/hashmap.h"
-#include "sword25/kernel/bs_stdint.h"
-#include "sword25/kernel/common.h"
-
-namespace Sword25 {
-
-// -----------------------------------------------------------------------------
-// Klassendeklaration
-// -----------------------------------------------------------------------------
-
-typedef void (*CallbackPtr)(int command);
-
-class CallbackRegistry {
-public:
- static CallbackRegistry &getInstance() {
- static CallbackRegistry _instance;
- return _instance;
- }
-
- bool registerCallbackFunction(const Common::String &name, CallbackPtr ptr);
- CallbackPtr resolveCallbackFunction(const Common::String &name) const;
- Common::String resolveCallbackPointer(CallbackPtr ptr) const;
-
-private:
- typedef Common::HashMap<Common::String, CallbackPtr, Common::CaseSensitiveString_Hash, Common::CaseSensitiveString_EqualTo> NameToPtrMap;
- NameToPtrMap _nameToPtrMap;
-
- struct CallbackPtr_EqualTo {
- bool operator()(CallbackPtr x, CallbackPtr y) const {
- return x == y;
- }
- };
- struct CallbackPtr_Hash {
- uint operator()(CallbackPtr x) const {
- return static_cast<uint>((int64)x % ((int64)1 << sizeof(uint)));
- }
- };
-
- typedef Common::HashMap<CallbackPtr, Common::String, CallbackPtr_Hash, CallbackPtr_EqualTo> PtrToNameMap;
- PtrToNameMap _ptrToNameMap;
-
- CallbackPtr findPtrByName(const Common::String &name) const;
- Common::String findNameByPtr(CallbackPtr ptr) const;
- void storeCallbackFunction(const Common::String &name, CallbackPtr ptr);
-};
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/sword25/kernel/filesystemutil.cpp b/engines/sword25/kernel/filesystemutil.cpp
index 853e6b247f..d05ac922e1 100644
--- a/engines/sword25/kernel/filesystemutil.cpp
+++ b/engines/sword25/kernel/filesystemutil.cpp
@@ -32,10 +32,6 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "common/config-manager.h"
#include "common/fs.h"
#include "common/savefile.h"
@@ -47,106 +43,45 @@ namespace Sword25 {
#define BS_LOG_PREFIX "FILESYSTEMUTIL"
-// -----------------------------------------------------------------------------
-// Constants and utility functions
-// -----------------------------------------------------------------------------
-
-Common::String GetAbsolutePath(const Common::String &Path) {
- Common::FSNode node(Path);
+Common::String FileSystemUtil::getUserdataDirectory() {
+ // FIXME: This code is a hack which bypasses the savefile API,
+ // and should eventually be removed.
+ Common::String path = ConfMan.get("savepath");
- if (!node.exists()) {
- // An error has occurred finding the node
- // We can do nothing at this pointer than return an empty string
- BS_LOG_ERRORLN("A call to GetAbsolutePath failed.");
+ if (path.empty()) {
+ error("No save path has been defined");
return "";
}
- // Return the result
- return node.getPath();
+ // Return the path
+ return path;
}
-// -----------------------------------------------------------------------------
-// Class definitions
-// -----------------------------------------------------------------------------
-
-class BS_FileSystemUtilScummVM : public FileSystemUtil {
-public:
- virtual Common::String GetUserdataDirectory() {
- Common::String path = ConfMan.get("savepath");
-
- if (path.empty()) {
- error("No save path has been defined");
- return "";
- }
-
- // Return the path
- return path;
- }
-
- virtual Common::String GetPathSeparator() {
- return Common::String("/");
- }
-
- virtual int64 GetFileSize(const Common::String &Filename) {
- Common::FSNode node(Filename);
-
- // If the file does not exist, return -1 as a result
- if (!node.exists())
- return -1;
-
- // Get the size of the file and return it
- Common::File f;
- f.open(node);
- uint32 size = f.size();
- f.close();
-
- return size;
- }
-
- virtual TimeDate GetFileTime(const Common::String &Filename) {
- // TODO: There isn't any way in ScummVM to get a file's modified date/time. We will need to check
- // what code makes use of it. If it's only the save game code, for example, we may be able to
- // encode the date/time inside the savegame files themselves.
- TimeDate result;
- g_system->getTimeAndDate(result);
- return result;
- }
+Common::String FileSystemUtil::getPathSeparator() {
+ // FIXME: This code is a hack which bypasses the savefile API,
+ // and should eventually be removed.
+ return Common::String("/");
+}
- virtual bool FileExists(const Common::String &Filename) {
- Common::File f;
- if (f.exists(Filename))
- return true;
+bool FileSystemUtil::fileExists(const Common::String &filename) {
+ Common::File f;
+ if (f.exists(filename))
+ return true;
- // Check if the file exists in the save folder
- Common::FSNode folder(PersistenceService::GetSavegameDirectory());
- Common::FSNode fileNode = folder.getChild(FileSystemUtil::GetInstance().GetPathFilename(Filename));
- return fileNode.exists();
- }
-
- virtual bool CreateDirectory(const Common::String &DirectoryName) {
- // ScummVM doesn't support creating folders, so this is only a stub
- BS_LOG_ERRORLN("CreateDirectory method called");
- return false;
- }
+ // Check if the file exists in the save folder
+ Common::FSNode folder(PersistenceService::getSavegameDirectory());
+ Common::FSNode fileNode = folder.getChild(getPathFilename(filename));
+ return fileNode.exists();
+}
- virtual Common::String GetPathFilename(const Common::String &Path) {
- for (int i = Path.size() - 1; i >= 0; --i) {
- if ((Path[i] == '/') || (Path[i] == '\\')) {
- return Common::String(&Path.c_str()[i + 1]);
- }
+Common::String FileSystemUtil::getPathFilename(const Common::String &path) {
+ for (int i = path.size() - 1; i >= 0; --i) {
+ if ((path[i] == '/') || (path[i] == '\\')) {
+ return Common::String(&path.c_str()[i + 1]);
}
-
- return Path;
}
-};
-
-// -----------------------------------------------------------------------------
-// Singleton method of parent class
-// -----------------------------------------------------------------------------
-FileSystemUtil &FileSystemUtil::GetInstance() {
- static BS_FileSystemUtilScummVM Instance;
- return Instance;
+ return path;
}
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/filesystemutil.h b/engines/sword25/kernel/filesystemutil.h
index 43ce7c908e..38a3fdaa12 100644
--- a/engines/sword25/kernel/filesystemutil.h
+++ b/engines/sword25/kernel/filesystemutil.h
@@ -38,7 +38,7 @@
* operations that do not have equivalents in the C/C++ libraries.
*
* Each supported platform must implement this interface, and the method
- * BS_FileSystemUtil Singleton::getInstance()
+ * BS_FileSystemUtil Singleton::instance()
*/
#ifndef SWORD25_FILESYSTEMUTIL_H
@@ -52,7 +52,6 @@
#include "common/str.h"
#include "common/str-array.h"
#include "sword25/kernel/common.h"
-#include "sword25/kernel/bs_stdint.h"
namespace Sword25 {
@@ -62,8 +61,6 @@ namespace Sword25 {
class FileSystemUtil {
public:
- static FileSystemUtil &GetInstance();
- virtual ~FileSystemUtil() {};
/**
* This function returns the name of the directory in which all user data is to be stored.
@@ -71,42 +68,32 @@ public:
* These are for example Screenshots, game saves, configuration files, log files, ...
* @return Returns the name of the directory for user data.
*/
- virtual Common::String GetUserdataDirectory() = 0;
+ static Common::String getUserdataDirectory();
+
/**
* @return Returns the path seperator
*/
- virtual Common::String GetPathSeparator() = 0;
+ static Common::String getPathSeparator();
+
/**
* @param Filename The path to a file.
* @return Returns the size of the specified file. If the size could not be
* determined, or the file does not exist, returns -1
*/
- virtual int64 GetFileSize(const Common::String &Filename) = 0;
- /**
- * @param Filename The path to a file.
- * @return Returns the timestamp of the specified file.
- */
- virtual TimeDate GetFileTime(const Common::String &Filename) = 0;
+ static int32 getFileSize(const Common::String &filename);
+
/**
* @param Filename The path to a file.
* @return Returns true if the file exists.
*/
- virtual bool FileExists(const Common::String &Filename) = 0;
- /**
- * This function creates a directory
- *
- * If the parameter is "\b\c\d\e" is passed, and "\b\c" already exists, then folder 'd'
- * will be created, and subdirectory 'e' under it.
- * @param DirectoryName The name of the directory to be created
- * @return Returns true if the folder(s) could be created, otherwise false.
- */
- virtual bool CreateDirectory(const Common::String &DirectoryName) = 0;
+ static bool fileExists(const Common::String &filename);
+
/**
* Gets the filename from a path and filename
* @param Filename The full path and filename
* @return Returns just the filename
*/
- virtual Common::String GetPathFilename(const Common::String &Path) = 0;
+ static Common::String getPathFilename(const Common::String &path);
};
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/inputpersistenceblock.cpp b/engines/sword25/kernel/inputpersistenceblock.cpp
index b51b1037a7..652c2f362f 100644
--- a/engines/sword25/kernel/inputpersistenceblock.cpp
+++ b/engines/sword25/kernel/inputpersistenceblock.cpp
@@ -34,146 +34,116 @@
#define BS_LOG_PREFIX "INPUTPERSISTENCEBLOCK"
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/inputpersistenceblock.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Constructor / Destructor
-// -----------------------------------------------------------------------------
-
-InputPersistenceBlock::InputPersistenceBlock(const void *Data, uint DataLength) :
- m_Data(static_cast<const byte *>(Data), DataLength),
- m_ErrorState(NONE) {
- m_Iter = m_Data.begin();
+InputPersistenceBlock::InputPersistenceBlock(const void *data, uint dataLength) :
+ _data(static_cast<const byte *>(data), dataLength),
+ _errorState(NONE) {
+ _iter = _data.begin();
}
-// -----------------------------------------------------------------------------
-
InputPersistenceBlock::~InputPersistenceBlock() {
- if (m_Iter != m_Data.end()) BS_LOG_WARNINGLN("Persistence block was not read to the end.");
+ if (_iter != _data.end())
+ BS_LOG_WARNINGLN("Persistence block was not read to the end.");
}
-// -----------------------------------------------------------------------------
-// Reading
-// -----------------------------------------------------------------------------
-
-void InputPersistenceBlock::read(int16 &Value) {
+void InputPersistenceBlock::read(int16 &value) {
signed int v;
read(v);
- Value = static_cast<int16>(v);
+ value = static_cast<int16>(v);
}
-// -----------------------------------------------------------------------------
-
-void InputPersistenceBlock::read(signed int &Value) {
- if (CheckMarker(SINT_MARKER)) {
- RawRead(&Value, sizeof(signed int));
- Value = ConvertEndianessFromStorageToSystem(Value);
+void InputPersistenceBlock::read(signed int &value) {
+ if (checkMarker(SINT_MARKER)) {
+ rawRead(&value, sizeof(signed int));
+ value = convertEndianessFromStorageToSystem(value);
} else {
- Value = 0;
+ value = 0;
}
}
-// -----------------------------------------------------------------------------
-
-void InputPersistenceBlock::read(uint &Value) {
- if (CheckMarker(UINT_MARKER)) {
- RawRead(&Value, sizeof(uint));
- Value = ConvertEndianessFromStorageToSystem(Value);
+void InputPersistenceBlock::read(uint &value) {
+ if (checkMarker(UINT_MARKER)) {
+ rawRead(&value, sizeof(uint));
+ value = convertEndianessFromStorageToSystem(value);
} else {
- Value = 0;
+ value = 0;
}
}
-// -----------------------------------------------------------------------------
-
-void InputPersistenceBlock::read(float &Value) {
- if (CheckMarker(FLOAT_MARKER)) {
- RawRead(&Value, sizeof(float));
- Value = ConvertEndianessFromStorageToSystem(Value);
+void InputPersistenceBlock::read(float &value) {
+ if (checkMarker(FLOAT_MARKER)) {
+ rawRead(&value, sizeof(float));
+ value = convertEndianessFromStorageToSystem(value);
} else {
- Value = 0.0f;
+ value = 0.0f;
}
}
-// -----------------------------------------------------------------------------
-
-void InputPersistenceBlock::read(bool &Value) {
- if (CheckMarker(BOOL_MARKER)) {
- uint UIntBool;
- RawRead(&UIntBool, sizeof(float));
- UIntBool = ConvertEndianessFromStorageToSystem(UIntBool);
- Value = UIntBool == 0 ? false : true;
+void InputPersistenceBlock::read(bool &value) {
+ if (checkMarker(BOOL_MARKER)) {
+ uint uintBool;
+ rawRead(&uintBool, sizeof(float));
+ uintBool = convertEndianessFromStorageToSystem(uintBool);
+ value = uintBool == 0 ? false : true;
} else {
- Value = 0.0f;
+ value = 0.0f;
}
}
-// -----------------------------------------------------------------------------
-
-void InputPersistenceBlock::read(Common::String &Value) {
- Value = "";
+void InputPersistenceBlock::readString(Common::String &value) {
+ value = "";
- if (CheckMarker(STRING_MARKER)) {
- uint Size;
- read(Size);
+ if (checkMarker(STRING_MARKER)) {
+ uint size;
+ read(size);
- if (CheckBlockSize(Size)) {
- Value = Common::String(reinterpret_cast<const char *>(&*m_Iter), Size);
- m_Iter += Size;
+ if (checkBlockSize(size)) {
+ value = Common::String(reinterpret_cast<const char *>(&*_iter), size);
+ _iter += size;
}
}
}
-// -----------------------------------------------------------------------------
+void InputPersistenceBlock::readByteArray(Common::Array<byte> &value) {
+ if (checkMarker(BLOCK_MARKER)) {
+ uint size;
+ read(size);
-void InputPersistenceBlock::read(Common::Array<byte> &Value) {
- if (CheckMarker(BLOCK_MARKER)) {
- uint Size;
- read(Size);
-
- if (CheckBlockSize(Size)) {
- Value = Common::Array<byte>(m_Iter, Size);
- m_Iter += Size;
+ if (checkBlockSize(size)) {
+ value = Common::Array<byte>(_iter, size);
+ _iter += size;
}
}
}
-// -----------------------------------------------------------------------------
-
-void InputPersistenceBlock::RawRead(void *DestPtr, size_t Size) {
- if (CheckBlockSize(Size)) {
- memcpy(DestPtr, &*m_Iter, Size);
- m_Iter += Size;
+void InputPersistenceBlock::rawRead(void *destPtr, size_t size) {
+ if (checkBlockSize(size)) {
+ memcpy(destPtr, &*_iter, size);
+ _iter += size;
}
}
-// -----------------------------------------------------------------------------
-
-bool InputPersistenceBlock::CheckBlockSize(int Size) {
- if (m_Data.end() - m_Iter >= Size) {
+bool InputPersistenceBlock::checkBlockSize(int size) {
+ if (_data.end() - _iter >= size) {
return true;
} else {
- m_ErrorState = END_OF_DATA;
+ _errorState = END_OF_DATA;
BS_LOG_ERRORLN("Unexpected end of persistence block.");
return false;
}
}
-// -----------------------------------------------------------------------------
-
-bool InputPersistenceBlock::CheckMarker(byte Marker) {
- if (!isGood() || !CheckBlockSize(1)) return false;
+bool InputPersistenceBlock::checkMarker(byte marker) {
+ if (!isGood() || !checkBlockSize(1))
+ return false;
- if (*m_Iter++ == Marker) {
+ if (*_iter++ == marker) {
return true;
} else {
- m_ErrorState = OUT_OF_SYNC;
+ _errorState = OUT_OF_SYNC;
BS_LOG_ERRORLN("Wrong type marker found in persistence block.");
return false;
}
diff --git a/engines/sword25/kernel/inputpersistenceblock.h b/engines/sword25/kernel/inputpersistenceblock.h
index a6978e5899..f6ab256460 100644
--- a/engines/sword25/kernel/inputpersistenceblock.h
+++ b/engines/sword25/kernel/inputpersistenceblock.h
@@ -35,20 +35,12 @@
#ifndef SWORD25_INPUTPERSISTENCEBLOCK_H
#define SWORD25_INPUTPERSISTENCEBLOCK_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "common/array.h"
#include "sword25/kernel/common.h"
#include "sword25/kernel/persistenceblock.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Class declaration
-// -----------------------------------------------------------------------------
-
class InputPersistenceBlock : public PersistenceBlock {
public:
enum ErrorState {
@@ -57,32 +49,32 @@ public:
OUT_OF_SYNC
};
- InputPersistenceBlock(const void *Data, uint DataLength);
+ InputPersistenceBlock(const void *data, uint dataLength);
virtual ~InputPersistenceBlock();
- void read(int16 &Value);
- void read(signed int &Value);
- void read(uint &Value);
- void read(float &Value);
- void read(bool &Value);
- void read(Common::String &Value);
- void read(Common::Array<byte> &Value);
+ void read(int16 &value);
+ void read(signed int &value);
+ void read(uint &value);
+ void read(float &value);
+ void read(bool &value);
+ void readString(Common::String &value);
+ void readByteArray(Common::Array<byte> &value);
bool isGood() const {
- return m_ErrorState == NONE;
+ return _errorState == NONE;
}
- ErrorState GetErrorState() const {
- return m_ErrorState;
+ ErrorState getErrorState() const {
+ return _errorState;
}
private:
- bool CheckMarker(byte Marker);
- bool CheckBlockSize(int Size);
- void RawRead(void *DestPtr, size_t Size);
+ bool checkMarker(byte marker);
+ bool checkBlockSize(int size);
+ void rawRead(void *destPtr, size_t size);
- Common::Array<byte> m_Data;
- Common::Array<byte>::const_iterator m_Iter;
- ErrorState m_ErrorState;
+ Common::Array<byte> _data;
+ Common::Array<byte>::const_iterator _iter;
+ ErrorState _errorState;
};
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/kernel.cpp b/engines/sword25/kernel/kernel.cpp
index 3e7e7f125f..9bd8ac5ff7 100644
--- a/engines/sword25/kernel/kernel.cpp
+++ b/engines/sword25/kernel/kernel.cpp
@@ -38,417 +38,174 @@
#include "sword25/input/inputengine.h"
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/persistenceservice.h"
-#include "sword25/kernel/service_ids.h"
+#include "sword25/math/geometry.h"
#include "sword25/package/packagemanager.h"
-#include "sword25/script/script.h"
+#include "sword25/script/luascript.h"
#include "sword25/sfx/soundengine.h"
namespace Sword25 {
#define BS_LOG_PREFIX "KERNEL"
-Kernel *Kernel::_Instance = 0;
+Kernel *Kernel::_instance = 0;
Kernel::Kernel() :
- _pWindow(NULL),
- _Running(false),
- _pResourceManager(NULL),
- _InitSuccess(false) {
+ _resourceManager(NULL),
+ _initSuccess(false),
+ _gfx(0),
+ _sfx(0),
+ _input(0),
+ _package(0),
+ _script(0),
+ _fmv(0)
+ {
// Log that the kernel is beign created
BS_LOGLN("created.");
-
- // Read the BS_SERVICE_TABLE and prepare kernel structures
- for (uint i = 0; i < BS_SERVICE_COUNT; i++) {
- // Is the superclass already registered?
- Superclass *pCurSuperclass = NULL;
- Common::Array<Superclass *>::iterator Iter;
- for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter)
- if ((*Iter)->GetIdentifier() == BS_SERVICE_TABLE[i].SuperclassIdentifier) {
- pCurSuperclass = *Iter;
- break;
- }
-
- // If the superclass isn't already registered, then add it in
- if (!pCurSuperclass)
- _SuperclassList.push_back(new Superclass(this, BS_SERVICE_TABLE[i].SuperclassIdentifier));
- }
-
- // Create window object
- _pWindow = Window::CreateBSWindow(0, 0, 0, 0, false);
- if (!_pWindow) {
- BS_LOG_ERRORLN("Failed to create the window.");
- } else
- BS_LOGLN("Window created.");
+ _instance = this;
// Create the resource manager
- _pResourceManager = new ResourceManager(this);
+ _resourceManager = new ResourceManager(this);
// Initialise the script engine
- ScriptEngine *pScript = static_cast<ScriptEngine *>(NewService("script", "lua"));
- if (!pScript || !pScript->init()) {
- _InitSuccess = false;
+ _script = new LuaScriptEngine(this);
+ if (!_script || !_script->init()) {
+ _initSuccess = false;
return;
}
// Register kernel script bindings
- if (!_RegisterScriptBindings()) {
+ if (!registerScriptBindings()) {
BS_LOG_ERRORLN("Script bindings could not be registered.");
- _InitSuccess = false;
+ _initSuccess = false;
return;
}
BS_LOGLN("Script bindings registered.");
- _InitSuccess = true;
-}
-
-Kernel::~Kernel() {
- // Services are de-registered in reverse order of creation
- while (!_ServiceCreationOrder.empty()) {
- Superclass *superclass = GetSuperclassByIdentifier(_ServiceCreationOrder.top());
- if (superclass) superclass->DisconnectService();
- _ServiceCreationOrder.pop();
- }
-
- // Empty the Superclass list
- while (_SuperclassList.size()) {
- delete _SuperclassList.back();
- _SuperclassList.pop_back();
- }
-
- // Release the window object
- delete _pWindow;
- BS_LOGLN("Window destroyed.");
-
- // Resource-Manager freigeben
- delete _pResourceManager;
-
- BS_LOGLN("destroyed.");
-}
-
-// Service Methoden
-// ----------------
-
-Kernel::Superclass::Superclass(Kernel *pKernel, const Common::String &Identifier) :
- _pKernel(pKernel),
- _Identifier(Identifier),
- _ServiceCount(0),
- _ActiveService(NULL) {
- for (uint i = 0; i < BS_SERVICE_COUNT; i++)
- if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier)
- _ServiceCount++;
-}
-
-Kernel::Superclass::~Superclass() {
- DisconnectService();
-}
-
-/**
- * Gets the identifier of a service with a given superclass.
- * The number of services in a superclass can be learned with GetServiceCount().
- * @param SuperclassIdentifier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- * @param Number die Nummer des Services, dessen Bezeichner man erfahren will.<br>
- * Hierbei ist zu beachten, dass der erste Service die Nummer 0 erhält. Number muss also eine Zahl zwischen
- * 0 und GetServiceCount() - 1 sein.
- */
-Common::String Kernel::Superclass::GetServiceIdentifier(uint Number) {
- if (Number > _ServiceCount) return NULL;
-
- uint CurServiceOrd = 0;
- for (uint i = 0; i < BS_SERVICE_COUNT; i++) {
- if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier) {
- if (Number == CurServiceOrd)
- return BS_SERVICE_TABLE[i].ServiceIdentifier;
- else
- CurServiceOrd++;
- }
- }
-
- return Common::String("");
-}
-
-/**
- * Creates a new service with the given identifier. Returns a pointer to the service, or null if the
- * service could not be created
- * Note: All services must be registered in service_ids.h, otherwise they cannot be created here
- * @param SuperclassIdentifier The name of the superclass of the service
- * z.B: "sfx", "gfx", "package" ...
- * @param ServiceIdentifier The name of the service
- * For the superclass "sfx" an example could be "Fmod" or "directsound"
- */
-Service *Kernel::Superclass::NewService(const Common::String &ServiceIdentifier) {
- for (uint i = 0; i < BS_SERVICE_COUNT; i++)
- if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier &&
- BS_SERVICE_TABLE[i].ServiceIdentifier == ServiceIdentifier) {
- Service *NewService_ = BS_SERVICE_TABLE[i].CreateMethod(_pKernel);
-
- if (NewService_) {
- DisconnectService();
- BS_LOGLN("Service '%s' created from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
- _ActiveService = NewService_;
- _ActiveServiceName = BS_SERVICE_TABLE[i].ServiceIdentifier;
- return _ActiveService;
- } else {
- BS_LOG_ERRORLN("Failed to create service '%s' from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
- return NULL;
- }
- }
-
- BS_LOG_ERRORLN("Service '%s' is not avaliable from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
- return NULL;
-}
-
-/**
- * Ends the current service of a superclass. Returns true on success, and false if the superclass
- * does not exist or if not service was active
- * @param SuperclassIdentfier The name of the superclass which is to be disconnected
- * z.B: "sfx", "gfx", "package" ...
- */
-bool Kernel::Superclass::DisconnectService() {
- if (_ActiveService) {
- delete _ActiveService;
- _ActiveService = 0;
- BS_LOGLN("Active service '%s' disconnected from superclass '%s'.", _ActiveServiceName.c_str(), _Identifier.c_str());
- return true;
- }
-
- return false;
-}
-
-Kernel::Superclass *Kernel::GetSuperclassByIdentifier(const Common::String &Identifier) {
- Common::Array<Superclass *>::iterator Iter;
- for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter) {
- if ((*Iter)->GetIdentifier() == Identifier)
- return *Iter;
- }
-
- // BS_LOG_ERRORLN("Superclass '%s' does not exist.", Identifier.c_str());
- return NULL;
-}
-
-/**
- * Returns the number of register superclasses
- */
-uint Kernel::GetSuperclassCount() {
- return _SuperclassList.size();
-}
-
-/**
- * Returns the name of a superclass with the specified index.
- * Note: The number of superclasses can be retrieved using GetSuperclassCount
- * @param Number The number of the superclass to return the identifier for.
- * It should be noted that the number should be between 0 und GetSuperclassCount() - 1.
- */
-Common::String Kernel::GetSuperclassIdentifier(uint Number) {
- if (Number > _SuperclassList.size()) return NULL;
+ _input = new InputEngine(this);
+ assert(_input);
- uint CurSuperclassOrd = 0;
- Common::Array<Superclass *>::iterator Iter;
- for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter) {
- if (CurSuperclassOrd == Number)
- return ((*Iter)->GetIdentifier());
+ _gfx = new GraphicEngine(this);
+ assert(_gfx);
- CurSuperclassOrd++;
- }
+ _sfx = new SoundEngine(this);
+ assert(_sfx);
- return Common::String("");
-}
+ _package = new PackageManager(this);
+ assert(_package);
-/**
- * Returns the number of services registered with a given superclass
- * @param SuperclassIdentifier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- */
-uint Kernel::GetServiceCount(const Common::String &SuperclassIdentifier) {
- Superclass *pSuperclass;
- if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier)))
- return 0;
+ _geometry = new Geometry(this);
+ assert(_geometry);
- return pSuperclass->GetServiceCount();
+#ifdef USE_THEORADEC
+ _fmv = new MoviePlayer(this);
+ assert(_fmv);
+#endif
+ _initSuccess = true;
}
-/**
- * Gets the identifier of a service with a given superclass.
- * The number of services in a superclass can be learned with GetServiceCount().
- * @param SuperclassIdentifier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- * @param Number die Nummer des Services, dessen Bezeichner man erfahren will.<br>
- * Hierbei ist zu beachten, dass der erste Service die Nummer 0 erhält. Number muss also eine Zahl zwischen
- * 0 und GetServiceCount() - 1 sein.
- */
-Common::String Kernel::GetServiceIdentifier(const Common::String &SuperclassIdentifier, uint Number) {
- Superclass *pSuperclass;
- if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
-
- return (pSuperclass->GetServiceIdentifier(Number));
-}
+Kernel::~Kernel() {
+ // Services are de-registered in reverse order of creation
-/**
- * Creates a new service with the given identifier. Returns a pointer to the service, or null if the
- * service could not be created
- * Note: All services must be registered in service_ids.h, otherwise they cannot be created here
- * @param SuperclassIdentifier The name of the superclass of the service
- * z.B: "sfx", "gfx", "package" ...
- * @param ServiceIdentifier The name of the service
- * For the superclass "sfx" an example could be "Fmod" or "directsound"
- */
-Service *Kernel::NewService(const Common::String &SuperclassIdentifier, const Common::String &ServiceIdentifier) {
- Superclass *pSuperclass;
- if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
+ delete _input;
+ _input = 0;
- // Die Reihenfolge merken, in der Services erstellt werden, damit sie später in umgekehrter Reihenfolge entladen werden können.
- _ServiceCreationOrder.push(SuperclassIdentifier);
+ delete _gfx;
+ _gfx = 0;
- return pSuperclass->NewService(ServiceIdentifier);
-}
+ delete _sfx;
+ _sfx = 0;
-/**
- * Ends the current service of a superclass. Returns true on success, and false if the superclass
- * does not exist or if not service was active
- * @param SuperclassIdentfier The name of the superclass which is to be disconnected
- * z.B: "sfx", "gfx", "package" ...
- */
-bool Kernel::DisconnectService(const Common::String &SuperclassIdentifier) {
- Superclass *pSuperclass;
- if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return false;
+ delete _package;
+ _package = 0;
- return pSuperclass->DisconnectService();
-}
+ delete _geometry;
+ _geometry = 0;
-/**
- * Returns a pointer to the currently active service object of a superclass
- * @param SuperclassIdentfier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- */
-Service *Kernel::GetService(const Common::String &SuperclassIdentifier) {
- Superclass *pSuperclass;
- if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
+#ifdef USE_THEORADEC
+ delete _fmv;
+ _fmv = 0;
+#endif
- return (pSuperclass->GetActiveService());
-}
+ delete _script;
+ _script = 0;
-/**
- * Returns the name of the currentl active service object of a superclass.
- * If an error occurs, then an empty string is returned
- * @param SuperclassIdentfier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- */
-Common::String Kernel::GetActiveServiceIdentifier(const Common::String &SuperclassIdentifier) {
- Superclass *pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier);
- if (!pSuperclass) return Common::String("");
+ // Resource-Manager freigeben
+ delete _resourceManager;
- return (pSuperclass->GetActiveServiceName());
+ BS_LOGLN("destroyed.");
}
-// -----------------------------------------------------------------------------
-
/**
* Returns a random number
* @param Min The minimum allowed value
* @param Max The maximum allowed value
*/
-int Kernel::GetRandomNumber(int Min, int Max) {
- BS_ASSERT(Min <= Max);
+int Kernel::getRandomNumber(int min, int max) {
+ BS_ASSERT(min <= max);
- return Min + _rnd.getRandomNumber(Max - Min + 1);
+ return min + _rnd.getRandomNumber(max - min + 1);
}
/**
* Returns the elapsed time since startup in milliseconds
*/
-uint Kernel::GetMilliTicks() {
+uint Kernel::getMilliTicks() {
return g_system->getMillis();
}
/**
- * Returns the elapsed time since the system start in microseconds.
- * This method should be used only if GetMilliTick() for the desired application is inaccurate.
- */
-uint64 Kernel::GetMicroTicks() {
- return g_system->getMillis() * 1000;
-}
-
-// Other methods
-// -----------------
-
-/**
* Returns how much memory is being used
*/
-size_t Kernel::GetUsedMemory() {
+size_t Kernel::getUsedMemory() {
return 0;
-
-#ifdef SCUMMVM_DISABLED_CODE
- PROCESS_MEMORY_COUNTERS pmc;
- pmc.cb = sizeof(pmc);
- if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
- return pmc.WorkingSetSize;
- } else {
- BS_LOG_ERRORLN("Call to GetProcessMemoryInfo() failed. Error code: %d", GetLastError());
- return 0;
- }
-#endif
}
-// -----------------------------------------------------------------------------
-
/**
- * Returns a pointer to the active Gfx Service, or NULL if no Gfx service is active
+ * Returns a pointer to the active Gfx Service, or NULL if no Gfx service is active.
*/
-GraphicEngine *Kernel::GetGfx() {
- return static_cast<GraphicEngine *>(GetService("gfx"));
+GraphicEngine *Kernel::getGfx() {
+ return _gfx;
}
-// -----------------------------------------------------------------------------
-
/**
- * Returns a pointer to the active Sfx Service, or NULL if no Sfx service is active
+ * Returns a pointer to the active Sfx Service, or NULL if no Sfx service is active.
*/
-SoundEngine *Kernel::GetSfx() {
- return static_cast<SoundEngine *>(GetService("sfx"));
+SoundEngine *Kernel::getSfx() {
+ return _sfx;
}
-// -----------------------------------------------------------------------------
-
/**
- * Returns a pointer to the active input service, or NULL if no input service is active
+ * Returns a pointer to the active input service, or NULL if no input service is active.
*/
-InputEngine *Kernel::GetInput() {
- return static_cast<InputEngine *>(GetService("input"));
+InputEngine *Kernel::getInput() {
+ return _input;
}
-// -----------------------------------------------------------------------------
-
/**
- * Returns a pointer to the active package manager, or NULL if no manager is active
+ * Returns a pointer to the active package manager, or NULL if no manager is active.
*/
-PackageManager *Kernel::GetPackage() {
- return static_cast<PackageManager *>(GetService("package"));
+PackageManager *Kernel::getPackage() {
+ return _package;
}
-// -----------------------------------------------------------------------------
-
/**
- * Returns a pointer to the script engine, or NULL if it is not active
+ * Returns a pointer to the script engine, or NULL if it is not active.
*/
-ScriptEngine *Kernel::GetScript() {
- return static_cast<ScriptEngine *>(GetService("script"));
+ScriptEngine *Kernel::getScript() {
+ return _script;
}
-// -----------------------------------------------------------------------------
-
/**
- * Returns a pointer to the movie player, or NULL if it is not active
+ * Returns a pointer to the movie player, or NULL if it is not active.
*/
-MoviePlayer *Kernel::GetFMV() {
- return static_cast<MoviePlayer *>(GetService("fmv"));
+MoviePlayer *Kernel::getFMV() {
+ return _fmv;
}
-// -----------------------------------------------------------------------------
-
-void Kernel::Sleep(uint Msecs) const {
- g_system->delayMillis(Msecs);
+void Kernel::sleep(uint msecs) const {
+ g_system->delayMillis(msecs);
}
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/kernel.h b/engines/sword25/kernel/kernel.h
index 55a64c783f..252de64e80 100644
--- a/engines/sword25/kernel/kernel.h
+++ b/engines/sword25/kernel/kernel.h
@@ -45,7 +45,6 @@
#ifndef SWORD25_KERNEL_H
#define SWORD25_KERNEL_H
-// Includes
#include "common/scummsys.h"
#include "common/random.h"
#include "common/stack.h"
@@ -53,14 +52,13 @@
#include "engines/engine.h"
#include "sword25/kernel/common.h"
-#include "sword25/kernel/bs_stdint.h"
-#include "sword25/kernel/window.h"
#include "sword25/kernel/resmanager.h"
namespace Sword25 {
// Class definitions
class Service;
+class Geometry;
class GraphicEngine;
class ScriptEngine;
class SoundEngine;
@@ -76,154 +74,73 @@ class MoviePlayer;
*/
class Kernel {
public:
- // Window methods
- // ----------------
-
- /**
- * Returns a pointer to the window object
- */
- Window *GetWindow() {
- return _pWindow;
- }
-
- // Service Methods
- // ---------------
-
- /**
- * Creates a new service with the given identifier. Returns a pointer to the service, or null if the
- * service could not be created
- * Note: All services must be registered in service_ids.h, otherwise they cannot be created here
- * @param SuperclassIdentifier The name of the superclass of the service
- * z.B: "sfx", "gfx", "package" ...
- * @param ServiceIdentifier The name of the service
- * For the superclass "sfx" an example could be "Fmod" or "directsound"
- */
- Service *NewService(const Common::String &SuperclassIdentifier, const Common::String &ServiceIdentifier);
-
- /**
- * Ends the current service of a superclass. Returns true on success, and false if the superclass
- * does not exist or if not service was active
- * @param SuperclassIdentfier The name of the superclass which is to be disconnected
- * z.B: "sfx", "gfx", "package" ...
- */
- bool DisconnectService(const Common::String &SuperclassIdentifier);
-
- /**
- * Returns a pointer to the currently active service object of a superclass
- * @param SuperclassIdentfier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- */
- Service *GetService(const Common::String &SuperclassIdentifier);
-
- /**
- * Returns the name of the currentl active service object of a superclass.
- * If an error occurs, then an empty string is returned
- * @param SuperclassIdentfier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- */
- Common::String GetActiveServiceIdentifier(const Common::String &SuperclassIdentifier);
-
- /**
- * Returns the number of register superclasses
- */
- uint GetSuperclassCount();
-
- /**
- * Returns the name of a superclass with the specified index.
- * Note: The number of superclasses can be retrieved using GetSuperclassCount
- * @param Number The number of the superclass to return the identifier for.
- * It should be noted that the number should be between 0 und GetSuperclassCount() - 1.
- */
- Common::String GetSuperclassIdentifier(uint Number);
-
- /**
- * Returns the number of services registered with a given superclass
- * @param SuperclassIdentifier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- */
- uint GetServiceCount(const Common::String &SuperclassIdentifier);
-
- /**
- * Gets the identifier of a service with a given superclass.
- * The number of services in a superclass can be learned with GetServiceCount().
- * @param SuperclassIdentifier The name of the superclass
- * z.B: "sfx", "gfx", "package" ...
- * @param Number die Nummer des Services, dessen Bezeichner man erfahren will.<br>
- * Hierbei ist zu beachten, dass der erste Service die Nummer 0 erhält. Number muss also eine Zahl zwischen
- * 0 und GetServiceCount() - 1 sein.
- */
- Common::String GetServiceIdentifier(const Common::String &SuperclassIdentifier, uint Number);
/**
* Returns the elapsed time since startup in milliseconds
*/
- uint GetMilliTicks();
-
- /**
- * Returns the elapsed time since the system start in microseconds.
- * This method should be used only if GetMilliTick() for the desired application is inaccurate.
- */
- uint64 GetMicroTicks();
+ uint getMilliTicks();
/**
* Specifies whether the kernel was successfully initialised
*/
- bool GetInitSuccess() {
- return _InitSuccess;
+ bool getInitSuccess() const {
+ return _initSuccess;
}
/**
* Returns a pointer to the BS_ResourceManager
*/
- ResourceManager *GetResourceManager() {
- return _pResourceManager;
+ ResourceManager *getResourceManager() {
+ return _resourceManager;
}
/**
* Returns how much memory is being used
*/
- size_t GetUsedMemory();
+ size_t getUsedMemory();
/**
* Returns a random number
* @param Min The minimum allowed value
* @param Max The maximum allowed value
*/
- int GetRandomNumber(int Min, int Max);
+ int getRandomNumber(int min, int max);
/**
* Returns a pointer to the active Gfx Service, or NULL if no Gfx service is active
*/
- GraphicEngine *GetGfx();
+ GraphicEngine *getGfx();
/**
* Returns a pointer to the active Sfx Service, or NULL if no Sfx service is active
*/
- SoundEngine *GetSfx();
+ SoundEngine *getSfx();
/**
* Returns a pointer to the active input service, or NULL if no input service is active
*/
- InputEngine *GetInput();
+ InputEngine *getInput();
/**
* Returns a pointer to the active package manager, or NULL if no manager is active
*/
- PackageManager *GetPackage();
+ PackageManager *getPackage();
/**
* Returns a pointer to the script engine, or NULL if it is not active
*/
- ScriptEngine *GetScript();
+ ScriptEngine *getScript();
+
/**
* Returns a pointer to the movie player, or NULL if it is not active
*/
- MoviePlayer *GetFMV();
+ MoviePlayer *getFMV();
/**
* Pauses for the specified amount of time
* @param Msecs The amount of time in milliseconds
*/
- void Sleep(uint Msecs) const;
+ void sleep(uint msecs) const;
/**
* Returns the singleton instance for the kernel
*/
- static Kernel *GetInstance() {
- if (!_Instance) _Instance = new Kernel();
- return _Instance;
+ static Kernel *getInstance() {
+ if (!_instance)
+ _instance = new Kernel();
+ return _instance;
}
/**
@@ -231,18 +148,18 @@ public:
* This method should only be called when the game is ended. No subsequent calls to any kernel
* methods should be done after calling this method.
*/
- static void DeleteInstance() {
- if (_Instance) {
- delete _Instance;
- _Instance = NULL;
+ static void deleteInstance() {
+ if (_instance) {
+ delete _instance;
+ _instance = NULL;
}
}
/**
* Raises an error. This method is used in crashing testing.
*/
- void Crash() const {
- error("BS_Kernel::Crash");
+ void crash() const {
+ error("Kernel::Crash");
}
private:
@@ -257,114 +174,29 @@ private:
// -----------------------------------------------------------------------------
// Singleton instance
// -----------------------------------------------------------------------------
- static Kernel *_Instance;
-
- // Superclass class
- // ----------------
- class Superclass {
- private:
- Kernel *_pKernel;
- uint _ServiceCount;
- Common::String _Identifier;
- Service *_ActiveService;
- Common::String _ActiveServiceName;
-
- public:
- Superclass(Kernel *pKernel, const Common::String &Identifier);
- ~Superclass();
-
- uint GetServiceCount() const {
- return _ServiceCount;
- }
- Common::String GetIdentifier() const {
- return _Identifier;
- }
- Service *GetActiveService() const {
- return _ActiveService;
- }
- Common::String GetActiveServiceName() const {
- return _ActiveServiceName;
- }
- Common::String GetServiceIdentifier(uint Number);
- Service *NewService(const Common::String &ServiceIdentifier);
- bool DisconnectService();
- };
+ static Kernel *_instance;
- Common::Array<Superclass *> _SuperclassList;
- Common::Stack<Common::String> _ServiceCreationOrder;
- Superclass *GetSuperclassByIdentifier(const Common::String &Identifier);
-
- bool _InitSuccess; // Specifies whether the engine was set up correctly
- bool _Running; // Specifies whether the application should keep running on the next main loop iteration
-
- // Active window
- // -------------
- Window *_pWindow;
+ bool _initSuccess; // Specifies whether the engine was set up correctly
// Random number generator
// -----------------------
Common::RandomSource _rnd;
- /*
- // Features variables and methods
- // ----------------------------------
- enum _CPU_FEATURES_BITMASKS
- {
- _MMX_BITMASK = (1 << 23),
- _SSE_BITMASK = (1 << 25),
- _SSE2_BITMASK = (1 << 26),
- _3DNOW_BITMASK = (1 << 30),
- _3DNOWEXT_BITMASK = (1 << 31)
- };
-
- bool _DetectCPU();
-
- bool _MMXPresent;
- bool _SSEPresent;
- bool _SSE2Present;
- bool _3DNowPresent;
- bool _3DNowExtPresent;
- CPU_TYPES _CPUType;
- Common::String _CPUVendorID;
- */
-
// Resourcemanager
// ---------------
- ResourceManager *_pResourceManager;
+ ResourceManager *_resourceManager;
- bool _RegisterScriptBindings();
-};
+ GraphicEngine *_gfx;
+ SoundEngine *_sfx;
+ InputEngine *_input;
+ PackageManager *_package;
+ ScriptEngine *_script;
+ Geometry *_geometry;
+ MoviePlayer *_fmv;
-/**
- * This is only a small class that manages the data of a service. It is a little ugly, I know,
- * but with Common::String a simple struct could not be used.
- */
-class BS_ServiceInfo {
-public:
- BS_ServiceInfo(const Common::String &SuperclassIdentifier_, const Common::String &ServiceIdentifier_,
- Service*(*CreateMethod_)(Kernel *)) {
- this->SuperclassIdentifier = SuperclassIdentifier_;
- this->ServiceIdentifier = ServiceIdentifier_;
- this->CreateMethod = CreateMethod_;
- };
-
- Common::String SuperclassIdentifier;
- Common::String ServiceIdentifier;
- Service*(*CreateMethod)(Kernel *);
+ bool registerScriptBindings();
};
-template<class T>
-void ReverseArray(Common::Array<T> &Arr) {
- if (Arr.size() < 2)
- return;
-
- for (uint i = 0; i <= (Arr.size() / 2 - 1); ++i) {
- T temp = Arr[i];
- Arr[i] = Arr[Arr.size() - i - 1];
- Arr[Arr.size() - i - 1] = temp;
- }
-}
-
} // End of namespace Sword25
#endif
diff --git a/engines/sword25/kernel/kernel_script.cpp b/engines/sword25/kernel/kernel_script.cpp
index 1b87dfdc6e..d4b9a56d8e 100644
--- a/engines/sword25/kernel/kernel_script.cpp
+++ b/engines/sword25/kernel/kernel_script.cpp
@@ -32,14 +32,9 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/filesystemutil.h"
-#include "sword25/kernel/window.h"
#include "sword25/kernel/resmanager.h"
#include "sword25/kernel/persistenceservice.h"
#include "sword25/script/script.h"
@@ -47,131 +42,92 @@
namespace Sword25 {
-// -----------------------------------------------------------------------------
-
-static int DisconnectService(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
-
- lua_pushboolean(L, pKernel->DisconnectService(luaL_checkstring(L, 1)));
+static int disconnectService(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushboolean(L, true);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetActiveServiceIdentifier(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
-
- lua_pushstring(L, pKernel->GetActiveServiceIdentifier(luaL_checkstring(L, 1)).c_str());
+static int getActiveServiceIdentifier(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushstring(L, "QUUX");
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetSuperclassCount(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
-
- lua_pushnumber(L, pKernel->GetSuperclassCount());
+static int getSuperclassCount(lua_State *L) {
+ // This function is only used by a single function in system/kernel.lua which is never called.
+ lua_pushnumber(L, 0);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetSuperclassIdentifier(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
-
- lua_pushstring(L, pKernel->GetSuperclassIdentifier(
- static_cast<uint>(luaL_checknumber(L, 1))).c_str());
+static int getSuperclassIdentifier(lua_State *L) {
+ // This function is only used by a single function in system/kernel.lua which is never called.
+ lua_pushstring(L, "FOO");
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetServiceCount(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
-
- lua_pushnumber(L, pKernel->GetServiceCount(luaL_checkstring(L, 1)));
+static int getServiceCount(lua_State *L) {
+ // This function is only used by a single function in system/kernel.lua which is never called.
+ lua_pushnumber(L, 0);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetServiceIdentifier(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
-
- lua_pushstring(L, pKernel->GetServiceIdentifier(luaL_checkstring(L, 1),
- static_cast<uint>(luaL_checknumber(L, 2))).c_str());
+static int getServiceIdentifier(lua_State *L) {
+ // This function is only used by a single function in system/kernel.lua which is never called.
+ lua_pushstring(L, "BAR");
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetMilliTicks(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int getMilliTicks(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- lua_pushnumber(L, pKernel->GetMilliTicks());
+ lua_pushnumber(L, pKernel->getMilliTicks());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetTimer(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int getTimer(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- lua_pushnumber(L, static_cast<lua_Number>(pKernel->GetMicroTicks()) / 1000000.0);
+ lua_pushnumber(L, static_cast<lua_Number>(pKernel->getMilliTicks()) / 1000.0);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int StartService(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
-
- lua_pushbooleancpp(L, pKernel->NewService(luaL_checkstring(L, 1), luaL_checkstring(L, 2)) != NULL);
+static int startService(lua_State *L) {
+ // This function is used by system/boot.lua to init all services.
+ // However, we do nothing here, as we just hard code the init sequence.
+ lua_pushbooleancpp(L, true);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int Sleep(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int sleep(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- pKernel->Sleep(static_cast<uint>(luaL_checknumber(L, 1) * 1000));
+ pKernel->sleep(static_cast<uint>(luaL_checknumber(L, 1) * 1000));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int Crash(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int crash(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- pKernel->Crash();
+ pKernel->crash();
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int ExecuteFile(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int executeFile(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ScriptEngine *pSE = static_cast<ScriptEngine *>(pKernel->GetService("script"));
+ ScriptEngine *pSE = pKernel->getScript();
BS_ASSERT(pSE);
lua_pushbooleancpp(L, pSE->executeFile(luaL_checkstring(L, 1)));
@@ -179,551 +135,406 @@ static int ExecuteFile(lua_State *L) {
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int GetUserdataDirectory(lua_State *L) {
- lua_pushstring(L, FileSystemUtil::GetInstance().GetUserdataDirectory().c_str());
+static int getUserdataDirectory(lua_State *L) {
+ lua_pushstring(L, FileSystemUtil::getUserdataDirectory().c_str());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetPathSeparator(lua_State *L) {
- lua_pushstring(L, FileSystemUtil::GetInstance().GetPathSeparator().c_str());
+static int getPathSeparator(lua_State *L) {
+ lua_pushstring(L, FileSystemUtil::getPathSeparator().c_str());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int FileExists(lua_State *L) {
- lua_pushbooleancpp(L, FileSystemUtil::GetInstance().FileExists(luaL_checkstring(L, 1)));
+static int fileExists(lua_State *L) {
+ lua_pushbooleancpp(L, FileSystemUtil::fileExists(luaL_checkstring(L, 1)));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int CreateDirectory(lua_State *L) {
- lua_pushbooleancpp(L, FileSystemUtil::GetInstance().CreateDirectory(luaL_checkstring(L, 1)));
+static int createDirectory(lua_State *L) {
+ // ScummVM engines cannot create directories, so we do nothing here.
+ lua_pushbooleancpp(L, false);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetWinCode(lua_State *L) {
+static int getWinCode(lua_State *L) {
lua_pushstring(L, "ScummVM");
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetSubversionRevision(lua_State *L) {
+static int getSubversionRevision(lua_State *L) {
// ScummVM is 1337
lua_pushnumber(L, 1337);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetUsedMemory(lua_State *L) {
- lua_pushnumber(L, Kernel::GetInstance()->GetUsedMemory());
+static int getUsedMemory(lua_State *L) {
+ lua_pushnumber(L, Kernel::getInstance()->getUsedMemory());
return 1;
}
-// -----------------------------------------------------------------------------
-
static const char *KERNEL_LIBRARY_NAME = "Kernel";
static const luaL_reg KERNEL_FUNCTIONS[] = {
- {"DisconnectService", DisconnectService},
- {"GetActiveServiceIdentifier", GetActiveServiceIdentifier},
- {"GetSuperclassCount", GetSuperclassCount},
- {"GetSuperclassIdentifier", GetSuperclassIdentifier},
- {"GetServiceCount", GetServiceCount},
- {"GetServiceIdentifier", GetServiceIdentifier},
- {"GetMilliTicks", GetMilliTicks},
- {"GetTimer", GetTimer},
- {"StartService", StartService},
- {"Sleep", Sleep},
- {"Crash", Crash},
- {"ExecuteFile", ExecuteFile},
- {"GetUserdataDirectory", GetUserdataDirectory},
- {"GetPathSeparator", GetPathSeparator},
- {"FileExists", FileExists},
- {"CreateDirectory", CreateDirectory},
- {"GetWinCode", GetWinCode},
- {"GetSubversionRevision", GetSubversionRevision},
- {"GetUsedMemory", GetUsedMemory},
+ {"DisconnectService", disconnectService},
+ {"GetActiveServiceIdentifier", getActiveServiceIdentifier},
+ {"GetSuperclassCount", getSuperclassCount},
+ {"GetSuperclassIdentifier", getSuperclassIdentifier},
+ {"GetServiceCount", getServiceCount},
+ {"GetServiceIdentifier", getServiceIdentifier},
+ {"GetMilliTicks", getMilliTicks},
+ {"GetTimer", getTimer},
+ {"StartService", startService},
+ {"Sleep", sleep},
+ {"Crash", crash},
+ {"ExecuteFile", executeFile},
+ {"GetUserdataDirectory", getUserdataDirectory},
+ {"GetPathSeparator", getPathSeparator},
+ {"FileExists", fileExists},
+ {"CreateDirectory", createDirectory},
+ {"GetWinCode", getWinCode},
+ {"GetSubversionRevision", getSubversionRevision},
+ {"GetUsedMemory", getUsedMemory},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static int IsVisible(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushbooleancpp(L, pWindow->IsVisible());
+static int isVisible(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushbooleancpp(L, true);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SetVisible(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- pWindow->SetVisible(lua_tobooleancpp(L, 1));
+static int setVisible(lua_State *L) {
+ // This function apparently is not used by the game scripts
+// pWindow->setVisible(lua_tobooleancpp(L, 1));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int GetX(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushnumber(L, pWindow->GetX());
+static int getX(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushnumber(L, 0);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetY(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushnumber(L, pWindow->GetY());
+static int getY(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushnumber(L, 0);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SetX(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- pWindow->SetX(static_cast<int>(luaL_checknumber(L, 1)));
+static int setX(lua_State *L) {
+ // This is called by system/boot.lua with -1 as value.
+// pWindow->setX(static_cast<int>(luaL_checknumber(L, 1)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int SetY(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- pWindow->SetY(static_cast<int>(luaL_checknumber(L, 1)));
+static int setY(lua_State *L) {
+ // This is called by system/boot.lua with -1 as value.
+// pWindow->setY(static_cast<int>(luaL_checknumber(L, 1)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int GetClientX(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushnumber(L, pWindow->GetClientX());
+static int getClientX(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushnumber(L, 0);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetClientY(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushnumber(L, pWindow->GetClientY());
+static int getClientY(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushnumber(L, 0);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetWidth(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushnumber(L, pWindow->GetWidth());
+static int getWidth(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushnumber(L, 800);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetHeight(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushnumber(L, pWindow->GetHeight());
+static int getHeight(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushnumber(L, 600);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SetWidth(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- pWindow->SetWidth(static_cast<int>(luaL_checknumber(L, 1)));
+static int setWidth(lua_State *L) {
+ // This is called by system/boot.lua with 800 as value.
+// pWindow->setWidth(static_cast<int>(luaL_checknumber(L, 1)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int SetHeight(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- pWindow->SetHeight(static_cast<int>(luaL_checknumber(L, 1)));
+static int setHeight(lua_State *L) {
+ // This is called by system/boot.lua with 600 as value.
+// pWindow->setHeight(static_cast<int>(luaL_checknumber(L, 1)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int GetTitle(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushstring(L, pWindow->GetTitle().c_str());
+static int getTitle(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushstring(L, "");
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SetTitle(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- pWindow->SetTitle(luaL_checkstring(L, 1));
+static int setTitle(lua_State *L) {
+ // This is called by system/boot.lua and system/menu.lua, to
+ // set the window title to the (localized) game name.
+ // FIXME: Should we call OSystem::setWindowCaption() here?
+// pWindow->setTitle(luaL_checkstring(L, 1));
return 0;
}
-// -----------------------------------------------------------------------------
+static int processMessages(lua_State *L) {
+ // This is called by the main loop in system/boot.lua,
+ // and the game keeps running as true is returned here.
+ // It terminates if we return false.
-static int ProcessMessages(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
+ // TODO: We could do more stuff here if desired...
+
+ // TODO: We could always return true here, and leave quit handling
+ // to the closeWanted() opcode; see also the TODO comment in there.
- lua_pushbooleancpp(L, pWindow->ProcessMessages());
+ lua_pushbooleancpp(L, !Engine::shouldQuit());
return 1;
}
-// -----------------------------------------------------------------------------
+static int closeWanted(lua_State *L) {
+ // This is called by system/interface.lua to determine whether the
+ // user requested the game to close (e.g. by clicking the 'close' widget
+ // of the game window). As a consequence (i.e. this function returns true),
+ // a quit confirmation dialog is shown.
-static int CloseWanted(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushbooleancpp(L, pWindow->CloseWanted());
+ // TODO: ScummVM currently has a bug / misfeature where some engines provide
+ // quit confirmation dialogs, some don't; in addition, we have a global confirmation
+ // dialog (but the user has to explicitly activate that in the config).
+ // Anyway, this can lead to *two* confirmation dialogs being shown.
+ // If it wasn't for that, we could simply check for Engine::shouldQuit() here,
+ // and then invoke EventMan::resetQuit. But currently this would result in
+ // the user seeing two confirmation dialogs. Bad.
+ lua_pushbooleancpp(L, false);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int WaitForFocus(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushbooleancpp(L, pWindow->WaitForFocus());
+static int waitForFocus(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushbooleancpp(L, true);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int HasFocus(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
- BS_ASSERT(pKernel);
- Window *pWindow = pKernel->GetWindow();
- BS_ASSERT(pWindow);
-
- lua_pushbooleancpp(L, pWindow->HasFocus());
+static int hasFocus(lua_State *L) {
+ // This function apparently is not used by the game scripts
+ lua_pushbooleancpp(L, true);
return 1;
}
-// -----------------------------------------------------------------------------
-
static const char *WINDOW_LIBRARY_NAME = "Window";
static const luaL_reg WINDOW_FUNCTIONS[] = {
- {"IsVisible", IsVisible},
- {"SetVisible", SetVisible},
- {"GetX", GetX},
- {"SetX", SetX},
- {"GetY", GetY},
- {"SetY", SetY},
- {"GetClientX", GetClientX},
- {"GetClientY", GetClientY},
- {"GetWidth", GetWidth},
- {"GetHeight", GetHeight},
- {"SetWidth", SetWidth},
- {"SetHeight", SetHeight},
- {"GetTitle", GetTitle},
- {"SetTitle", SetTitle},
- {"ProcessMessages", ProcessMessages},
- {"CloseWanted", CloseWanted},
- {"WaitForFocus", WaitForFocus},
- {"HasFocus", HasFocus},
+ {"IsVisible", isVisible},
+ {"SetVisible", setVisible},
+ {"GetX", getX},
+ {"SetX", setX},
+ {"GetY", getY},
+ {"SetY", setY},
+ {"GetClientX", getClientX},
+ {"GetClientY", getClientY},
+ {"GetWidth", getWidth},
+ {"GetHeight", getHeight},
+ {"SetWidth", setWidth},
+ {"SetHeight", setHeight},
+ {"GetTitle", getTitle},
+ {"SetTitle", setTitle},
+ {"ProcessMessages", processMessages},
+ {"CloseWanted", closeWanted},
+ {"WaitForFocus", waitForFocus},
+ {"HasFocus", hasFocus},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static int PrecacheResource(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int precacheResource(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ResourceManager *pResource = pKernel->GetResourceManager();
+ ResourceManager *pResource = pKernel->getResourceManager();
BS_ASSERT(pResource);
- lua_pushbooleancpp(L, pResource->PrecacheResource(luaL_checkstring(L, 1)));
+ lua_pushbooleancpp(L, pResource->precacheResource(luaL_checkstring(L, 1)));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int ForcePrecacheResource(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int forcePrecacheResource(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ResourceManager *pResource = pKernel->GetResourceManager();
+ ResourceManager *pResource = pKernel->getResourceManager();
BS_ASSERT(pResource);
- lua_pushbooleancpp(L, pResource->PrecacheResource(luaL_checkstring(L, 1), true));
+ lua_pushbooleancpp(L, pResource->precacheResource(luaL_checkstring(L, 1), true));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetMaxMemoryUsage(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int getMaxMemoryUsage(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ResourceManager *pResource = pKernel->GetResourceManager();
+ ResourceManager *pResource = pKernel->getResourceManager();
BS_ASSERT(pResource);
- lua_pushnumber(L, pResource->GetMaxMemoryUsage());
+ lua_pushnumber(L, pResource->getMaxMemoryUsage());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SetMaxMemoryUsage(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int setMaxMemoryUsage(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ResourceManager *pResource = pKernel->GetResourceManager();
+ ResourceManager *pResource = pKernel->getResourceManager();
BS_ASSERT(pResource);
- pResource->SetMaxMemoryUsage(static_cast<uint>(lua_tonumber(L, 1)));
+ pResource->setMaxMemoryUsage(static_cast<uint>(lua_tonumber(L, 1)));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int EmptyCache(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int emptyCache(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ResourceManager *pResource = pKernel->GetResourceManager();
+ ResourceManager *pResource = pKernel->getResourceManager();
BS_ASSERT(pResource);
- pResource->EmptyCache();
+ pResource->emptyCache();
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int IsLogCacheMiss(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int isLogCacheMiss(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ResourceManager *pResource = pKernel->GetResourceManager();
+ ResourceManager *pResource = pKernel->getResourceManager();
BS_ASSERT(pResource);
- lua_pushbooleancpp(L, pResource->IsLogCacheMiss());
+ lua_pushbooleancpp(L, pResource->isLogCacheMiss());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SetLogCacheMiss(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int setLogCacheMiss(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ResourceManager *pResource = pKernel->GetResourceManager();
+ ResourceManager *pResource = pKernel->getResourceManager();
BS_ASSERT(pResource);
- pResource->SetLogCacheMiss(lua_tobooleancpp(L, 1));
+ pResource->setLogCacheMiss(lua_tobooleancpp(L, 1));
return 0;
}
-// -----------------------------------------------------------------------------
-
-static int DumpLockedResources(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+static int dumpLockedResources(lua_State *L) {
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ResourceManager *pResource = pKernel->GetResourceManager();
+ ResourceManager *pResource = pKernel->getResourceManager();
BS_ASSERT(pResource);
- pResource->DumpLockedResources();
+ pResource->dumpLockedResources();
return 0;
}
-// -----------------------------------------------------------------------------
-
static const char *RESOURCE_LIBRARY_NAME = "Resource";
static const luaL_reg RESOURCE_FUNCTIONS[] = {
- {"PrecacheResource", PrecacheResource},
- {"ForcePrecacheResource", ForcePrecacheResource},
- {"GetMaxMemoryUsage", GetMaxMemoryUsage},
- {"SetMaxMemoryUsage", SetMaxMemoryUsage},
- {"EmptyCache", EmptyCache},
- {"IsLogCacheMiss", IsLogCacheMiss},
- {"SetLogCacheMiss", SetLogCacheMiss},
- {"DumpLockedResources", DumpLockedResources},
+ {"PrecacheResource", precacheResource},
+ {"ForcePrecacheResource", forcePrecacheResource},
+ {"GetMaxMemoryUsage", getMaxMemoryUsage},
+ {"SetMaxMemoryUsage", setMaxMemoryUsage},
+ {"EmptyCache", emptyCache},
+ {"IsLogCacheMiss", isLogCacheMiss},
+ {"SetLogCacheMiss", setLogCacheMiss},
+ {"DumpLockedResources", dumpLockedResources},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-static int ReloadSlots(lua_State *L) {
- PersistenceService::GetInstance().ReloadSlots();
+static int reloadSlots(lua_State *L) {
+ PersistenceService::getInstance().reloadSlots();
lua_pushnil(L);
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetSlotCount(lua_State *L) {
- lua_pushnumber(L, PersistenceService::GetInstance().GetSlotCount());
+static int getSlotCount(lua_State *L) {
+ lua_pushnumber(L, PersistenceService::getInstance().getSlotCount());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int IsSlotOccupied(lua_State *L) {
- lua_pushbooleancpp(L, PersistenceService::GetInstance().IsSlotOccupied(
- static_cast<uint>(luaL_checknumber(L, 1)) - 1));
+static int isSlotOccupied(lua_State *L) {
+ lua_pushbooleancpp(L, PersistenceService::getInstance().isSlotOccupied(static_cast<uint>(luaL_checknumber(L, 1)) - 1));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetSavegameDirectory(lua_State *L) {
- lua_pushstring(L, PersistenceService::GetInstance().GetSavegameDirectory().c_str());
+static int getSavegameDirectory(lua_State *L) {
+ lua_pushstring(L, PersistenceService::getInstance().getSavegameDirectory().c_str());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int IsSavegameCompatible(lua_State *L) {
- lua_pushbooleancpp(L, PersistenceService::GetInstance().IsSavegameCompatible(
+static int isSavegameCompatible(lua_State *L) {
+ lua_pushbooleancpp(L, PersistenceService::getInstance().isSavegameCompatible(
static_cast<uint>(luaL_checknumber(L, 1)) - 1));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetSavegameDescription(lua_State *L) {
- lua_pushstring(L, PersistenceService::GetInstance().GetSavegameDescription(
+static int getSavegameDescription(lua_State *L) {
+ lua_pushstring(L, PersistenceService::getInstance().getSavegameDescription(
static_cast<uint>(luaL_checknumber(L, 1)) - 1).c_str());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int GetSavegameFilename(lua_State *L) {
- lua_pushstring(L, PersistenceService::GetInstance().GetSavegameFilename(static_cast<uint>(luaL_checknumber(L, 1)) - 1).c_str());
+static int getSavegameFilename(lua_State *L) {
+ lua_pushstring(L, PersistenceService::getInstance().getSavegameFilename(static_cast<uint>(luaL_checknumber(L, 1)) - 1).c_str());
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int LoadGame(lua_State *L) {
- lua_pushbooleancpp(L, PersistenceService::GetInstance().LoadGame(static_cast<uint>(luaL_checknumber(L, 1)) - 1));
+static int loadGame(lua_State *L) {
+ lua_pushbooleancpp(L, PersistenceService::getInstance().loadGame(static_cast<uint>(luaL_checknumber(L, 1)) - 1));
return 1;
}
-// -----------------------------------------------------------------------------
-
-static int SaveGame(lua_State *L) {
- lua_pushbooleancpp(L, PersistenceService::GetInstance().SaveGame(static_cast<uint>(luaL_checknumber(L, 1)) - 1, luaL_checkstring(L, 2)));
+static int saveGame(lua_State *L) {
+ lua_pushbooleancpp(L, PersistenceService::getInstance().saveGame(static_cast<uint>(luaL_checknumber(L, 1)) - 1, luaL_checkstring(L, 2)));
return 1;
}
-// -----------------------------------------------------------------------------
-
static const char *PERSISTENCE_LIBRARY_NAME = "Persistence";
static const luaL_reg PERSISTENCE_FUNCTIONS[] = {
- {"ReloadSlots", ReloadSlots},
- {"GetSlotCount", GetSlotCount},
- {"IsSlotOccupied", IsSlotOccupied},
- {"GetSavegameDirectory", GetSavegameDirectory},
- {"IsSavegameCompatible", IsSavegameCompatible},
- {"GetSavegameDescription", GetSavegameDescription},
- {"GetSavegameFilename", GetSavegameFilename},
- {"LoadGame", LoadGame},
- {"SaveGame", SaveGame},
+ {"ReloadSlots", reloadSlots},
+ {"GetSlotCount", getSlotCount},
+ {"IsSlotOccupied", isSlotOccupied},
+ {"GetSavegameDirectory", getSavegameDirectory},
+ {"IsSavegameCompatible", isSavegameCompatible},
+ {"GetSavegameDescription", getSavegameDescription},
+ {"GetSavegameFilename", getSavegameFilename},
+ {"LoadGame", loadGame},
+ {"SaveGame", saveGame},
{0, 0}
};
-// -----------------------------------------------------------------------------
-
-bool Kernel::_RegisterScriptBindings() {
- ScriptEngine *pScript = static_cast<ScriptEngine *>(GetService("script"));
+bool Kernel::registerScriptBindings() {
+ ScriptEngine *pScript = getScript();
BS_ASSERT(pScript);
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
BS_ASSERT(L);
diff --git a/engines/sword25/kernel/log.cpp b/engines/sword25/kernel/log.cpp
index 259c02449f..91b0c36ac1 100644
--- a/engines/sword25/kernel/log.cpp
+++ b/engines/sword25/kernel/log.cpp
@@ -39,33 +39,31 @@
namespace Sword25 {
-// Constants
static const char *BF_LOG_FILENAME = "log.txt";
static const size_t LOG_BUFFERSIZE = 1024 * 16;
// Logging will take place only when it's activated
#ifdef BS_ACTIVATE_LOGGING
-Common::WriteStream *BS_Log::_LogFile = NULL;
-bool BS_Log::_LineBegin = true;
-const char *BS_Log::_Prefix = NULL;
-const char *BS_Log::_File = NULL;
-int BS_Log::_Line = 0;
-bool BS_Log::_AutoNewline = false;
-Common::Array<BS_Log::LOG_LISTENER_CALLBACK> BS_Log::_LogListener;
+Common::WriteStream *BS_Log::_logFile = NULL;
+bool BS_Log::_lineBegin = true;
+const char *BS_Log::_prefix = NULL;
+const char *BS_Log::_file = NULL;
+int BS_Log::_line = 0;
+bool BS_Log::_autoNewline = false;
-bool BS_Log::_CreateLog() {
+bool BS_Log::createLog() {
// Open the log file
Common::FSNode dataDir(ConfMan.get("path"));
Common::FSNode file = dataDir.getChild(BF_LOG_FILENAME);
// Open the file for saving
- _LogFile = file.createWriteStream();
+ _logFile = file.createWriteStream();
- if (_LogFile) {
+ if (_logFile) {
// Add a title into the log file
- Log("Broken Sword 2.5 Engine - Build: %s - %s - VersionID: %s\n", __DATE__, __TIME__, gScummVMFullVersion);
- Log("-----------------------------------------------------------------------------------------------------\n");
+ log("Broken Sword 2.5 Engine - Build: %s - %s - VersionID: %s\n", __DATE__, __TIME__, gScummVMFullVersion);
+ log("-----------------------------------------------------------------------------------------------------\n");
return true;
}
@@ -74,140 +72,142 @@ bool BS_Log::_CreateLog() {
return false;
}
-void BS_Log::_CloseLog() {
- delete _LogFile;
- _LogFile = NULL;
+void BS_Log::closeLog() {
+ delete _logFile;
+ _logFile = NULL;
}
-void BS_Log::Log(const char *Format, ...) {
- char Message[LOG_BUFFERSIZE];
+void BS_Log::log(const char *format, ...) {
+ char message[LOG_BUFFERSIZE];
// Create the message
- va_list ArgList;
- va_start(ArgList, Format);
- vsnprintf(Message, sizeof(Message), Format, ArgList);
+ va_list argList;
+ va_start(argList, format);
+ vsnprintf(message, sizeof(message), format, argList);
// Log the message
- _WriteLog(Message);
+ writeLog(message);
- _FlushLog();
+ flushLog();
}
-void BS_Log::LogPrefix(const char *Prefix, const char *Format, ...) {
- char Message[LOG_BUFFERSIZE];
- char ExtFormat[LOG_BUFFERSIZE];
+void BS_Log::logPrefix(const char *prefix, const char *format, ...) {
+ char message[LOG_BUFFERSIZE];
+ char extFormat[LOG_BUFFERSIZE];
// If the issue has ceased at the beginning of a new line, the new issue to begin with the prefix
- ExtFormat[0] = 0;
- if (_LineBegin) {
- snprintf(ExtFormat, sizeof(ExtFormat), "%s%s: ", ExtFormat, Prefix);
- _LineBegin = false;
+ extFormat[0] = 0;
+ if (_lineBegin) {
+ snprintf(extFormat, sizeof(extFormat), "%s: ", prefix);
+ _lineBegin = false;
}
// Format String pass line by line and each line with the initial prefix
for (;;) {
- const char *NextLine = strstr(Format, "\n");
- if (!NextLine || *(NextLine + strlen("\n")) == 0) {
- snprintf(ExtFormat, sizeof(ExtFormat), "%s%s", ExtFormat, Format);
- if (NextLine) _LineBegin = true;
+ const char *nextLine = strstr(format, "\n");
+ if (!nextLine || *(nextLine + strlen("\n")) == 0) {
+ Common::strlcat(extFormat, format, sizeof(extFormat));
+ if (nextLine)
+ _lineBegin = true;
break;
} else {
- strncat(ExtFormat, Format, (NextLine - Format) + strlen("\n"));
- snprintf(ExtFormat, sizeof(ExtFormat), "%s%s: ", ExtFormat, Prefix);
+ strncat(extFormat, format, (nextLine - format) + strlen("\n"));
+ Common::strlcat(extFormat, prefix, sizeof(extFormat));
+ Common::strlcat(extFormat, ": ", sizeof(extFormat));
}
- Format = NextLine + strlen("\n");
+ format = nextLine + strlen("\n");
}
// Create message
- va_list ArgList;
- va_start(ArgList, Format);
- vsnprintf(Message, sizeof(Message), ExtFormat, ArgList);
+ va_list argList;
+ va_start(argList, format);
+ vsnprintf(message, sizeof(message), extFormat, argList);
// Log the message
- _WriteLog(Message);
+ writeLog(message);
- _FlushLog();
+ flushLog();
}
-void BS_Log::LogDecorated(const char *Format, ...) {
+void BS_Log::logDecorated(const char *format, ...) {
// Nachricht erzeugen
- char Message[LOG_BUFFERSIZE];
- va_list ArgList;
- va_start(ArgList, Format);
- vsnprintf(Message, sizeof(Message), Format, ArgList);
+ char message[LOG_BUFFERSIZE];
+ va_list argList;
+ va_start(argList, format);
+ vsnprintf(message, sizeof(message), format, argList);
- // Zweiten Prefix erzeugen, falls gewünscht
- char SecondaryPrefix[1024];
- if (_File && _Line)
- snprintf(SecondaryPrefix, sizeof(SecondaryPrefix), "(file: %s, line: %d) - ", _File, _Line);
+ // Zweiten prefix erzeugen, falls gewünscht
+ char secondaryPrefix[1024];
+ if (_file && _line)
+ snprintf(secondaryPrefix, sizeof(secondaryPrefix), "(file: %s, line: %d) - ", _file, _line);
// Nachricht zeilenweise ausgeben und an jeden Zeilenanfang das Präfix setzen
- char *MessageWalker = Message;
+ char *messageWalker = message;
for (;;) {
- char *NextLine = strstr(MessageWalker, "\n");
- if (NextLine) {
- *NextLine = 0;
- if (_LineBegin) {
- _WriteLog(_Prefix);
- if (_File && _Line)
- _WriteLog(SecondaryPrefix);
+ char *nextLine = strstr(messageWalker, "\n");
+ if (nextLine) {
+ *nextLine = 0;
+ if (_lineBegin) {
+ writeLog(_prefix);
+ if (_file && _line)
+ writeLog(secondaryPrefix);
}
- _WriteLog(MessageWalker);
- _WriteLog("\n");
- MessageWalker = NextLine + sizeof("\n") - 1;
- _LineBegin = true;
+ writeLog(messageWalker);
+ writeLog("\n");
+ messageWalker = nextLine + sizeof("\n") - 1;
+ _lineBegin = true;
} else {
- if (_LineBegin) {
- _WriteLog(_Prefix);
- if (_File && _Line)
- _WriteLog(SecondaryPrefix);
+ if (_lineBegin) {
+ writeLog(_prefix);
+ if (_file && _line)
+ writeLog(secondaryPrefix);
}
- _WriteLog(MessageWalker);
- _LineBegin = false;
+ writeLog(messageWalker);
+ _lineBegin = false;
break;
}
}
// Falls gewünscht, wird ans Ende der Nachricht automatisch ein Newline angehängt.
- if (_AutoNewline) {
- _WriteLog("\n");
- _LineBegin = true;
+ if (_autoNewline) {
+ writeLog("\n");
+ _lineBegin = true;
}
// Pseudoparameter zurücksetzen
- _Prefix = NULL;
- _File = 0;
- _Line = 0;
- _AutoNewline = false;
+ _prefix = NULL;
+ _file = 0;
+ _line = 0;
+ _autoNewline = false;
- _FlushLog();
+ flushLog();
}
-int BS_Log::_WriteLog(const char *Message) {
- if (!_LogFile) if (!_CreateLog()) return false;
+int BS_Log::writeLog(const char *message) {
+ if (!_logFile && !createLog())
+ return false;
- Common::Array<LOG_LISTENER_CALLBACK>::iterator Iter = _LogListener.begin();
- for (; Iter != _LogListener.end(); ++Iter)
- (*Iter)(Message);
+ debugN(0, "%s", message);
- _LogFile->writeString(Message);
+ _logFile->writeString(message);
return true;
}
-void BS_Log::_FlushLog() {
- _LogFile->flush();
+void BS_Log::flushLog() {
+ if (_logFile)
+ _logFile->flush();
}
-void (*BS_LogPtr)(const char *, ...) = BS_Log::Log;
+void (*BS_LogPtr)(const char *, ...) = BS_Log::log;
-void BS_Log_C(const char *Message) {
- BS_LogPtr(Message);
+void BS_Log_C(const char *message) {
+ BS_LogPtr(message);
}
#else
-void BS_Log_C(const char *Message) {};
+void BS_Log_C(const char *message) {};
#endif
diff --git a/engines/sword25/kernel/log.h b/engines/sword25/kernel/log.h
index 1fe9ff4ed6..e7c5789a53 100644
--- a/engines/sword25/kernel/log.h
+++ b/engines/sword25/kernel/log.h
@@ -46,63 +46,50 @@ namespace Sword25 {
#ifdef BS_ACTIVATE_LOGGING
// Logging-Makros
-#define BS_LOG BS_Log::SetPrefix(BS_LOG_PREFIX ": "), BS_Log::LogDecorated
-#define BS_LOGLN BS_Log::SetPrefix(BS_LOG_PREFIX ": "), BS_Log::SetAutoNewline(true), BS_Log::LogDecorated
-#define BS_LOG_WARNING BS_Log::SetPrefix(BS_LOG_PREFIX ": WARNING - "), BS_Log::LogDecorated
-#define BS_LOG_WARNINGLN BS_Log::SetPrefix(BS_LOG_PREFIX ": WARNING - "), BS_Log::SetAutoNewline(true), BS_Log::LogDecorated
-#define BS_LOG_ERROR BS_Log::SetPrefix(BS_LOG_PREFIX ": ERROR - "), BS_Log::LogDecorated
-#define BS_LOG_ERRORLN BS_Log::SetPrefix(BS_LOG_PREFIX ": ERROR - "), BS_Log::SetAutoNewline(true), BS_Log::LogDecorated
-#define BS_LOG_EXTERROR BS_Log::SetPrefix(BS_LOG_PREFIX ": ERROR "), BS_Log::SetFile(__FILE__), BS_Log::SetLine(__LINE__), BS_Log::LogDecorated
-#define BS_LOG_EXTERRORLN BS_Log::SetPrefix(BS_LOG_PREFIX ": ERROR "), BS_Log::SetFile(__FILE__), BS_Log::SetLine(__LINE__), BS_Log::SetAutoNewline(true), BS_Log::LogDecorated
+#define BS_LOG BS_Log::setPrefix(BS_LOG_PREFIX ": "), BS_Log::logDecorated
+#define BS_LOGLN BS_Log::setPrefix(BS_LOG_PREFIX ": "), BS_Log::setAutoNewline(true), BS_Log::logDecorated
+#define BS_LOG_WARNING BS_Log::setPrefix(BS_LOG_PREFIX ": WARNING - "), BS_Log::logDecorated
+#define BS_LOG_WARNINGLN BS_Log::setPrefix(BS_LOG_PREFIX ": WARNING - "), BS_Log::setAutoNewline(true), BS_Log::logDecorated
+#define BS_LOG_ERROR BS_Log::setPrefix(BS_LOG_PREFIX ": ERROR - "), BS_Log::logDecorated
+#define BS_LOG_ERRORLN BS_Log::setPrefix(BS_LOG_PREFIX ": ERROR - "), BS_Log::setAutoNewline(true), BS_Log::logDecorated
+#define BS_LOG_EXTERROR BS_Log::setPrefix(BS_LOG_PREFIX ": ERROR "), BS_Log::setFile(__FILE__), BS_Log::setLine(__LINE__), BS_Log::logDecorated
+#define BS_LOG_EXTERRORLN BS_Log::setPrefix(BS_LOG_PREFIX ": ERROR "), BS_Log::setFile(__FILE__), BS_Log::setLine(__LINE__), BS_Log::setAutoNewline(true), BS_Log::logDecorated
// Die Version der Logging-Klasse mit aktiviertem Logging
class BS_Log {
public:
- static void Clear();
- static void Log(const char *Format, ...);
- static void LogPrefix(const char *Prefix, const char *Format, ...);
- static void LogDecorated(const char *Format, ...);
+ static void clear();
+ static void log(const char *format, ...);
+ static void logPrefix(const char *prefix, const char *format, ...);
+ static void logDecorated(const char *format, ...);
- static void SetPrefix(const char *Prefix) {
- _Prefix = Prefix;
+ static void setPrefix(const char *prefix) {
+ _prefix = prefix;
}
- static void SetFile(const char *File) {
- _File = File;
+ static void setFile(const char *file) {
+ _file = file;
}
- static void SetLine(int Line) {
- _Line = Line;
+ static void setLine(int line) {
+ _line = line;
}
- static void SetAutoNewline(bool AutoNewline) {
- _AutoNewline = AutoNewline;
+ static void setAutoNewline(bool autoNewline) {
+ _autoNewline = autoNewline;
}
- typedef void (*LOG_LISTENER_CALLBACK)(const char *);
- static void RegisterLogListener(LOG_LISTENER_CALLBACK Callback) {
- _LogListener.push_back(Callback);
- }
- static bool IsListenerRegistered(LOG_LISTENER_CALLBACK Callback) {
- Common::Array<LOG_LISTENER_CALLBACK>::iterator i;
- for (i = _LogListener.begin(); i != _LogListener.end(); ++i) {
- if (**i == Callback)
- return true;
- }
- return false;
- }
- static void _CloseLog();
+ static void closeLog();
private:
- static Common::WriteStream *_LogFile;
- static bool _LineBegin;
- static const char *_Prefix;
- static const char *_File;
- static int _Line;
- static bool _AutoNewline;
- static Common::Array<LOG_LISTENER_CALLBACK> _LogListener;
-
- static bool _CreateLog();
-
- static int _WriteLog(const char *Message);
- static void _FlushLog();
+ static Common::WriteStream *_logFile;
+ static bool _lineBegin;
+ static const char *_prefix;
+ static const char *_file;
+ static int _line;
+ static bool _autoNewline;
+
+ static bool createLog();
+
+ static int writeLog(const char *message);
+ static void flushLog();
};
// Auxiliary function that allows to log C functions (needed for Lua).
@@ -125,17 +112,17 @@ private:
class BS_Log {
public:
// This version implements all the various methods as empty stubs
- static void Log(const char *Text, ...) {};
- static void LogPrefix(const char *Prefix, const char *Format, ...) {};
- static void LogDecorated(const char *Format, ...) {};
+ static void log(const char *text, ...) {};
+ static void logPrefix(const char *prefix, const char *format, ...) {};
+ static void logDecorated(const char *format, ...) {};
- static void SetPrefix(const char *Prefix) {};
- static void SetFile(const char *File) {};
- static void SetLine(int Line) {};
- static void SetAutoNewline(bool AutoNewline) {};
+ static void setPrefix(const char *prefix) {};
+ static void setFile(const char *file) {};
+ static void setLine(int line) {};
+ static void setAutoNewline(bool autoNewline) {};
typedef void (*LOG_LISTENER_CALLBACK)(const char *);
- static void RegisterLogListener(LOG_LISTENER_CALLBACK Callback) {};
+ static void registerLogListener(LOG_LISTENER_CALLBACK callback) {};
};
#define BS_Log_C error
diff --git a/engines/sword25/kernel/objectregistry.h b/engines/sword25/kernel/objectregistry.h
index dc702f2d75..3a27ba4942 100644
--- a/engines/sword25/kernel/objectregistry.h
+++ b/engines/sword25/kernel/objectregistry.h
@@ -37,7 +37,6 @@
#include "common/func.h"
#include "common/hashmap.h"
-#include "sword25/kernel/bs_stdint.h"
#include "sword25/kernel/common.h"
namespace Sword25 {
@@ -131,7 +130,6 @@ public:
}
protected:
- // FIXME: I'm not entirely sure my current hash function is legitimate
struct ClassPointer_EqualTo {
bool operator()(const T *x, const T *y) const {
return x == y;
@@ -139,7 +137,7 @@ protected:
};
struct ClassPointer_Hash {
uint operator()(const T *x) const {
- return static_cast<uint>((int64)x % ((int64)1 << sizeof(uint)));
+ return *(uint *)&x;
}
};
diff --git a/engines/sword25/kernel/outputpersistenceblock.cpp b/engines/sword25/kernel/outputpersistenceblock.cpp
index 438fa7b222..b1c3233b59 100644
--- a/engines/sword25/kernel/outputpersistenceblock.cpp
+++ b/engines/sword25/kernel/outputpersistenceblock.cpp
@@ -34,97 +34,67 @@
#define BS_LOG_PREFIX "OUTPUTPERSISTENCEBLOCK"
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/outputpersistenceblock.h"
-// -----------------------------------------------------------------------------
-// Constants
-// -----------------------------------------------------------------------------
-
namespace {
const uint INITIAL_BUFFER_SIZE = 1024 * 64;
}
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Construction / Destruction
-// -----------------------------------------------------------------------------
-
OutputPersistenceBlock::OutputPersistenceBlock() {
- m_Data.reserve(INITIAL_BUFFER_SIZE);
+ _data.reserve(INITIAL_BUFFER_SIZE);
}
-// -----------------------------------------------------------------------------
-// Writing
-// -----------------------------------------------------------------------------
-
-void OutputPersistenceBlock::write(signed int Value) {
- WriteMarker(SINT_MARKER);
- Value = ConvertEndianessFromSystemToStorage(Value);
- RawWrite(&Value, sizeof(Value));
+void OutputPersistenceBlock::write(signed int value) {
+ writeMarker(SINT_MARKER);
+ value = convertEndianessFromSystemToStorage(value);
+ rawWrite(&value, sizeof(value));
}
-// -----------------------------------------------------------------------------
-
-void OutputPersistenceBlock::write(uint Value) {
- WriteMarker(UINT_MARKER);
- Value = ConvertEndianessFromSystemToStorage(Value);
- RawWrite(&Value, sizeof(Value));
+void OutputPersistenceBlock::write(uint value) {
+ writeMarker(UINT_MARKER);
+ value = convertEndianessFromSystemToStorage(value);
+ rawWrite(&value, sizeof(value));
}
-// -----------------------------------------------------------------------------
-
-void OutputPersistenceBlock::write(float Value) {
- WriteMarker(FLOAT_MARKER);
- Value = ConvertEndianessFromSystemToStorage(Value);
- RawWrite(&Value, sizeof(Value));
+void OutputPersistenceBlock::write(float value) {
+ writeMarker(FLOAT_MARKER);
+ value = convertEndianessFromSystemToStorage(value);
+ rawWrite(&value, sizeof(value));
}
-// -----------------------------------------------------------------------------
+void OutputPersistenceBlock::write(bool value) {
+ writeMarker(BOOL_MARKER);
-void OutputPersistenceBlock::write(bool Value) {
- WriteMarker(BOOL_MARKER);
-
- uint UIntBool = Value ? 1 : 0;
- UIntBool = ConvertEndianessFromSystemToStorage(UIntBool);
- RawWrite(&UIntBool, sizeof(UIntBool));
+ uint uintBool = value ? 1 : 0;
+ uintBool = convertEndianessFromSystemToStorage(uintBool);
+ rawWrite(&uintBool, sizeof(uintBool));
}
-// -----------------------------------------------------------------------------
-
-void OutputPersistenceBlock::write(const Common::String &String) {
- WriteMarker(STRING_MARKER);
+void OutputPersistenceBlock::writeString(const Common::String &string) {
+ writeMarker(STRING_MARKER);
- write(String.size());
- RawWrite(String.c_str(), String.size());
+ write(string.size());
+ rawWrite(string.c_str(), string.size());
}
-// -----------------------------------------------------------------------------
-
-void OutputPersistenceBlock::write(const void *BufferPtr, size_t Size) {
- WriteMarker(BLOCK_MARKER);
+void OutputPersistenceBlock::writeByteArray(Common::Array<byte> &value) {
+ writeMarker(BLOCK_MARKER);
- write(Size);
- RawWrite(BufferPtr, Size);
+ write((uint)value.size());
+ rawWrite(&value[0], value.size());
}
-// -----------------------------------------------------------------------------
-
-void OutputPersistenceBlock::WriteMarker(byte Marker) {
- m_Data.push_back(Marker);
+void OutputPersistenceBlock::writeMarker(byte marker) {
+ _data.push_back(marker);
}
-// -----------------------------------------------------------------------------
-
-void OutputPersistenceBlock::RawWrite(const void *DataPtr, size_t Size) {
- if (Size > 0) {
- uint OldSize = m_Data.size();
- m_Data.resize(OldSize + Size);
- memcpy(&m_Data[OldSize], DataPtr, Size);
+void OutputPersistenceBlock::rawWrite(const void *dataPtr, size_t size) {
+ if (size > 0) {
+ uint oldSize = _data.size();
+ _data.resize(oldSize + size);
+ memcpy(&_data[oldSize], dataPtr, size);
}
}
diff --git a/engines/sword25/kernel/outputpersistenceblock.h b/engines/sword25/kernel/outputpersistenceblock.h
index 154dbc9763..71dbe68a52 100644
--- a/engines/sword25/kernel/outputpersistenceblock.h
+++ b/engines/sword25/kernel/outputpersistenceblock.h
@@ -35,42 +35,34 @@
#ifndef SWORD25_OUTPUTPERSISTENCEBLOCK_H
#define SWORD25_OUTPUTPERSISTENCEBLOCK_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
#include "sword25/kernel/persistenceblock.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Class declaration
-// -----------------------------------------------------------------------------
-
class OutputPersistenceBlock : public PersistenceBlock {
public:
OutputPersistenceBlock();
- void write(signed int Value);
- void write(uint Value);
- void write(float Value);
- void write(bool Value);
- void write(const Common::String &String);
- void write(const void *BufferPtr, size_t Size);
+ void write(signed int value);
+ void write(uint value);
+ void write(float value);
+ void write(bool value);
+ void writeString(const Common::String &string);
+ void writeByteArray(Common::Array<byte> &value);
- const void *GetData() const {
- return &m_Data[0];
+ const void *getData() const {
+ return &_data[0];
}
- uint GetDataSize() const {
- return m_Data.size();
+ uint getDataSize() const {
+ return _data.size();
}
private:
- void WriteMarker(byte Marker);
- void RawWrite(const void *DataPtr, size_t Size);
+ void writeMarker(byte marker);
+ void rawWrite(const void *dataPtr, size_t size);
- Common::Array<byte> m_Data;
+ Common::Array<byte> _data;
};
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/persistable.h b/engines/sword25/kernel/persistable.h
index fc314688d5..25cf70fda0 100644
--- a/engines/sword25/kernel/persistable.h
+++ b/engines/sword25/kernel/persistable.h
@@ -42,7 +42,7 @@ class InputPersistenceBlock;
class Persistable {
public:
- virtual ~Persistable() {};
+ virtual ~Persistable() {}
virtual bool persist(OutputPersistenceBlock &writer) = 0;
virtual bool unpersist(InputPersistenceBlock &reader) = 0;
diff --git a/engines/sword25/kernel/persistenceblock.h b/engines/sword25/kernel/persistenceblock.h
index 1f043aa68a..4a64eff11b 100644
--- a/engines/sword25/kernel/persistenceblock.h
+++ b/engines/sword25/kernel/persistenceblock.h
@@ -35,34 +35,26 @@
#ifndef SWORD25_PERSISTENCEBLOCK_H
#define SWORD25_PERSISTENCEBLOCK_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Class definition
-// -----------------------------------------------------------------------------
-
class PersistenceBlock {
public:
- static uint GetSInt32Size() {
+ static uint getSInt32Size() {
return sizeof(signed int) + sizeof(byte);
}
- static uint GetUInt32Size() {
+ static uint getUInt32Size() {
return sizeof(uint) + sizeof(byte);
}
- static uint GetFloat32Size() {
+ static uint getFloat32Size() {
return sizeof(float) + sizeof(byte);
}
- static uint GetBoolSize() {
+ static uint getBoolSize() {
return sizeof(byte) + sizeof(byte);
}
- static uint GetStringSize(const Common::String &String) {
- return static_cast<uint>(sizeof(uint) + String.size() + sizeof(byte));
+ static uint getStringSize(const Common::String &string) {
+ return static_cast<uint>(sizeof(uint) + string.size() + sizeof(byte));
}
protected:
@@ -84,43 +76,41 @@ protected:
//
template<typename T>
- static T ConvertEndianessFromSystemToStorage(T Value) {
- if (IsBigEndian()) ReverseByteOrder(&Value);
- return Value;
+ static T convertEndianessFromSystemToStorage(T value) {
+ if (isBigEndian())
+ reverseByteOrder(&value);
+ return value;
}
template<typename T>
- static T ConvertEndianessFromStorageToSystem(T Value) {
- if (IsBigEndian()) ReverseByteOrder(&Value);
- return Value;
+ static T convertEndianessFromStorageToSystem(T value) {
+ if (isBigEndian())
+ reverseByteOrder(&value);
+ return value;
}
private:
- static bool IsBigEndian() {
- uint Dummy = 1;
- byte *DummyPtr = reinterpret_cast<byte *>(&Dummy);
- return DummyPtr[0] == 0;
+ static bool isBigEndian() {
+ uint dummy = 1;
+ byte *dummyPtr = reinterpret_cast<byte *>(&dummy);
+ return dummyPtr[0] == 0;
}
template<typename T>
- static void Swap(T &One, T &Two) {
- T Temp = One;
- One = Two;
- Two = Temp;
+ static void swap(T &one, T &two) {
+ T temp = one;
+ one = two;
+ two = temp;
}
- static void ReverseByteOrder(void *Ptr) {
+ static void reverseByteOrder(void *ptr) {
// Reverses the byte order of the 32-bit word pointed to by Ptr
- byte *CharPtr = static_cast<byte *>(Ptr);
- Swap(CharPtr[0], CharPtr[3]);
- Swap(CharPtr[1], CharPtr[2]);
+ byte *charPtr = static_cast<byte *>(ptr);
+ swap(charPtr[0], charPtr[3]);
+ swap(charPtr[1], charPtr[2]);
}
};
-// -----------------------------------------------------------------------------
-// Compile time asserts
-// -----------------------------------------------------------------------------
-
#define CTASSERT(ex) typedef char ctassert_type[(ex) ? 1 : -1]
CTASSERT(sizeof(byte) == 1);
CTASSERT(sizeof(signed int) == 4);
diff --git a/engines/sword25/kernel/persistenceservice.cpp b/engines/sword25/kernel/persistenceservice.cpp
index 871bc37e2a..564f031cf3 100644
--- a/engines/sword25/kernel/persistenceservice.cpp
+++ b/engines/sword25/kernel/persistenceservice.cpp
@@ -32,10 +32,6 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "common/fs.h"
#include "common/savefile.h"
#include "sword25/kernel/kernel.h"
@@ -52,37 +48,30 @@
#define BS_LOG_PREFIX "PERSISTENCESERVICE"
-// -----------------------------------------------------------------------------
-// Constants and utility functions
-// -----------------------------------------------------------------------------
-
namespace Sword25 {
-const char *SAVEGAME_EXTENSION = ".b25s";
-const char *SAVEGAME_DIRECTORY = "saves";
-const char *FILE_MARKER = "BS25SAVEGAME";
-const uint SLOT_COUNT = 18;
-const uint FILE_COPY_BUFFER_SIZE = 1024 * 10;
-const char *VERSIONID = "SCUMMVM1";
-
-// -------------------------------------------------------------------------
-
-Common::String GenerateSavegameFilename(uint slotID) {
- char buffer[10];
- sprintf(buffer, "%d%s", slotID, SAVEGAME_EXTENSION);
- return Common::String(buffer);
-}
-// -------------------------------------------------------------------------
+//static const char *SAVEGAME_EXTENSION = ".b25s";
+static const char *SAVEGAME_DIRECTORY = "saves";
+static const char *FILE_MARKER = "BS25SAVEGAME";
+static const uint SLOT_COUNT = 18;
+static const uint FILE_COPY_BUFFER_SIZE = 1024 * 10;
+static const char *VERSIONID = "SCUMMVM1";
-Common::String GenerateSavegamePath(uint SlotID) {
- Common::FSNode folder(PersistenceService::GetSavegameDirectory());
-
- return folder.getChild(GenerateSavegameFilename(SlotID)).getPath();
+#define MAX_SAVEGAME_SIZE 100
+
+char gameTarget[MAX_SAVEGAME_SIZE];
+
+void setGameTarget(const char *target) {
+ strncpy(gameTarget, target, MAX_SAVEGAME_SIZE);
}
-// -------------------------------------------------------------------------
+static Common::String generateSavegameFilename(uint slotID) {
+ char buffer[MAX_SAVEGAME_SIZE];
+ snprintf(buffer, MAX_SAVEGAME_SIZE, "%s.%.3d", gameTarget, slotID);
+ return Common::String(buffer);
+}
-Common::String FormatTimestamp(TimeDate Time) {
+static Common::String formatTimestamp(TimeDate time) {
// In the original BS2.5 engine, this used a local object to show the date/time as as a string.
// For now in ScummVM it's being hardcoded to 'dd-MON-yyyy hh:mm:ss'
Common::String monthList[12] = {
@@ -90,157 +79,129 @@ Common::String FormatTimestamp(TimeDate Time) {
};
char buffer[100];
snprintf(buffer, 100, "%.2d-%s-%.4d %.2d:%.2d:%.2d",
- Time.tm_mday, monthList[Time.tm_mon].c_str(), 1900 + Time.tm_year,
- Time.tm_hour, Time.tm_min, Time.tm_sec
+ time.tm_mday, monthList[time.tm_mon].c_str(), 1900 + time.tm_year,
+ time.tm_hour, time.tm_min, time.tm_sec
);
return Common::String(buffer);
}
-// -------------------------------------------------------------------------
+static Common::String loadString(Common::InSaveFile *in, uint maxSize = 999) {
+ Common::String result;
-Common::String LoadString(Common::InSaveFile *In, uint MaxSize = 999) {
- Common::String Result;
-
- char ch = (char)In->readByte();
- while ((ch != '\0') && (ch != ' ')) {
- Result += ch;
- if (Result.size() >= MaxSize) break;
- ch = (char)In->readByte();
+ char ch = (char)in->readByte();
+ while (ch != '\0') {
+ result += ch;
+ if (result.size() >= maxSize)
+ break;
+ ch = (char)in->readByte();
}
- return Result;
-}
-
+ return result;
}
-namespace Sword25 {
-
-// -----------------------------------------------------------------------------
-// Private Implementation
-// -----------------------------------------------------------------------------
-
struct SavegameInformation {
- bool IsOccupied;
- bool IsCompatible;
- Common::String Description;
- Common::String Filename;
- uint GamedataLength;
- uint GamedataOffset;
- uint GamedataUncompressedLength;
+ bool isOccupied;
+ bool isCompatible;
+ Common::String description;
+ Common::String filename;
+ uint gamedataLength;
+ uint gamedataOffset;
+ uint gamedataUncompressedLength;
SavegameInformation() {
- Clear();
+ clear();
}
- void Clear() {
- IsOccupied = false;
- IsCompatible = false;
- Description = "";
- Filename = "";
- GamedataLength = 0;
- GamedataOffset = 0;
- GamedataUncompressedLength = 0;
+ void clear() {
+ isOccupied = false;
+ isCompatible = false;
+ description = "";
+ filename = "";
+ gamedataLength = 0;
+ gamedataOffset = 0;
+ gamedataUncompressedLength = 0;
}
};
struct PersistenceService::Impl {
- SavegameInformation m_SavegameInformations[SLOT_COUNT];
-
- // -----------------------------------------------------------------------------
+ SavegameInformation _savegameInformations[SLOT_COUNT];
Impl() {
- ReloadSlots();
+ reloadSlots();
}
- // -----------------------------------------------------------------------------
-
- void ReloadSlots() {
+ void reloadSlots() {
// Über alle Spielstanddateien iterieren und deren Infos einlesen.
for (uint i = 0; i < SLOT_COUNT; ++i) {
- ReadSlotSavegameInformation(i);
+ readSlotSavegameInformation(i);
}
}
- void ReadSlotSavegameInformation(uint SlotID) {
+ void readSlotSavegameInformation(uint slotID) {
// Aktuelle Slotinformationen in den Ausgangszustand versetzen, er wird im Folgenden neu gefüllt.
- SavegameInformation &CurSavegameInfo = m_SavegameInformations[SlotID];
- CurSavegameInfo.Clear();
+ SavegameInformation &curSavegameInfo = _savegameInformations[slotID];
+ curSavegameInfo.clear();
// Den Dateinamen für den Spielstand des Slots generieren.
- Common::String Filename = GenerateSavegameFilename(SlotID);
+ Common::String filename = generateSavegameFilename(slotID);
// Try to open the savegame for loading
Common::SaveFileManager *sfm = g_system->getSavefileManager();
- Common::InSaveFile *File = sfm->openForLoading(Filename);
+ Common::InSaveFile *file = sfm->openForLoading(filename);
- if (File) {
+ if (file) {
// Read in the header
- Common::String StoredMarker = LoadString(File);
- Common::String StoredVersionID = LoadString(File);
- Common::String gameDataLength = LoadString(File);
- CurSavegameInfo.GamedataLength = atoi(gameDataLength.c_str());
- Common::String gamedataUncompressedLength = LoadString(File);
- CurSavegameInfo.GamedataUncompressedLength = atoi(gamedataUncompressedLength.c_str());
+ Common::String storedMarker = loadString(file);
+ Common::String storedVersionID = loadString(file);
+ Common::String gameDescription = loadString(file);
+ Common::String gameDataLength = loadString(file);
+ curSavegameInfo.gamedataLength = atoi(gameDataLength.c_str());
+ Common::String gamedataUncompressedLength = loadString(file);
+ curSavegameInfo.gamedataUncompressedLength = atoi(gamedataUncompressedLength.c_str());
// If the header can be read in and is detected to be valid, we will have a valid file
- if (StoredMarker == FILE_MARKER) {
+ if (storedMarker == FILE_MARKER) {
// Der Slot wird als belegt markiert.
- CurSavegameInfo.IsOccupied = true;
+ curSavegameInfo.isOccupied = true;
// Speichern, ob der Spielstand kompatibel mit der aktuellen Engine-Version ist.
- CurSavegameInfo.IsCompatible = (StoredVersionID == Common::String(VERSIONID));
+ curSavegameInfo.isCompatible = (storedVersionID == Common::String(VERSIONID));
// Dateinamen des Spielstandes speichern.
- CurSavegameInfo.Filename = GenerateSavegameFilename(SlotID);
+ curSavegameInfo.filename = generateSavegameFilename(slotID);
// Die Beschreibung des Spielstandes besteht aus einer textuellen Darstellung des Änderungsdatums der Spielstanddatei.
- CurSavegameInfo.Description = FormatTimestamp(FileSystemUtil::GetInstance().GetFileTime(Filename));
+ curSavegameInfo.description = gameDescription;
// Den Offset zu den gespeicherten Spieldaten innerhalb der Datei speichern.
// Dieses entspricht der aktuellen Position, da nach der letzten Headerinformation noch ein Leerzeichen als trenner folgt.
- CurSavegameInfo.GamedataOffset = static_cast<uint>(File->pos());
+ curSavegameInfo.gamedataOffset = static_cast<uint>(file->pos());
}
- delete File;
+ delete file;
}
}
};
-// -----------------------------------------------------------------------------
-// Construction / Destruction
-// -----------------------------------------------------------------------------
-
-PersistenceService &PersistenceService::GetInstance() {
- static PersistenceService Instance;
- return Instance;
+PersistenceService &PersistenceService::getInstance() {
+ static PersistenceService instance;
+ return instance;
}
-// -----------------------------------------------------------------------------
-
-PersistenceService::PersistenceService() : m_impl(new Impl) {
+PersistenceService::PersistenceService() : _impl(new Impl) {
}
-// -----------------------------------------------------------------------------
-
PersistenceService::~PersistenceService() {
- delete m_impl;
+ delete _impl;
}
-// -----------------------------------------------------------------------------
-// Implementation
-// -----------------------------------------------------------------------------
-
-void PersistenceService::ReloadSlots() {
- m_impl->ReloadSlots();
+void PersistenceService::reloadSlots() {
+ _impl->reloadSlots();
}
-// -----------------------------------------------------------------------------
-
-uint PersistenceService::GetSlotCount() {
+uint PersistenceService::getSlotCount() {
return SLOT_COUNT;
}
-// -----------------------------------------------------------------------------
-
-Common::String PersistenceService::GetSavegameDirectory() {
- Common::FSNode node(FileSystemUtil::GetInstance().GetUserdataDirectory());
+Common::String PersistenceService::getSavegameDirectory() {
+ Common::FSNode node(FileSystemUtil::getUserdataDirectory());
Common::FSNode childNode = node.getChild(SAVEGAME_DIRECTORY);
// Try and return the path using the savegame subfolder. But if doesn't exist, fall back on the data directory
@@ -250,13 +211,11 @@ Common::String PersistenceService::GetSavegameDirectory() {
return node.getPath();
}
-// -----------------------------------------------------------------------------
-
namespace {
-bool CheckSlotID(uint SlotID) {
+bool checkslotID(uint slotID) {
// Überprüfen, ob die Slot-ID zulässig ist.
- if (SlotID >= SLOT_COUNT) {
- BS_LOG_ERRORLN("Tried to access an invalid slot (%d). Only slot ids from 0 to %d are allowed.", SlotID, SLOT_COUNT - 1);
+ if (slotID >= SLOT_COUNT) {
+ BS_LOG_ERRORLN("Tried to access an invalid slot (%d). Only slot ids from 0 to %d are allowed.", slotID, SLOT_COUNT - 1);
return false;
} else {
return true;
@@ -264,143 +223,139 @@ bool CheckSlotID(uint SlotID) {
}
}
-// -----------------------------------------------------------------------------
-
-bool PersistenceService::IsSlotOccupied(uint SlotID) {
- if (!CheckSlotID(SlotID)) return false;
- return m_impl->m_SavegameInformations[SlotID].IsOccupied;
+bool PersistenceService::isSlotOccupied(uint slotID) {
+ if (!checkslotID(slotID))
+ return false;
+ return _impl->_savegameInformations[slotID].isOccupied;
}
-// -----------------------------------------------------------------------------
-
-bool PersistenceService::IsSavegameCompatible(uint SlotID) {
- if (!CheckSlotID(SlotID)) return false;
- return m_impl->m_SavegameInformations[SlotID].IsCompatible;
+bool PersistenceService::isSavegameCompatible(uint slotID) {
+ if (!checkslotID(slotID))
+ return false;
+ return _impl->_savegameInformations[slotID].isCompatible;
}
-// -----------------------------------------------------------------------------
-
-Common::String &PersistenceService::GetSavegameDescription(uint SlotID) {
- static Common::String EmptyString;
- if (!CheckSlotID(SlotID)) return EmptyString;
- return m_impl->m_SavegameInformations[SlotID].Description;
+Common::String &PersistenceService::getSavegameDescription(uint slotID) {
+ static Common::String emptyString;
+ if (!checkslotID(slotID))
+ return emptyString;
+ return _impl->_savegameInformations[slotID].description;
}
-// -----------------------------------------------------------------------------
-
-Common::String &PersistenceService::GetSavegameFilename(uint SlotID) {
- static Common::String EmptyString;
- if (!CheckSlotID(SlotID)) return EmptyString;
- return m_impl->m_SavegameInformations[SlotID].Filename;
+Common::String &PersistenceService::getSavegameFilename(uint slotID) {
+ static Common::String emptyString;
+ if (!checkslotID(slotID))
+ return emptyString;
+ return _impl->_savegameInformations[slotID].filename;
}
-// -----------------------------------------------------------------------------
+bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotFilename) {
+ // FIXME: This code is a hack which bypasses the savefile API,
+ // and should eventually be removed.
-bool PersistenceService::SaveGame(uint SlotID, const Common::String &ScreenshotFilename) {
// Überprüfen, ob die Slot-ID zulässig ist.
- if (SlotID >= SLOT_COUNT) {
- BS_LOG_ERRORLN("Tried to save to an invalid slot (%d). Only slot ids form 0 to %d are allowed.", SlotID, SLOT_COUNT - 1);
+ if (slotID >= SLOT_COUNT) {
+ BS_LOG_ERRORLN("Tried to save to an invalid slot (%d). Only slot ids form 0 to %d are allowed.", slotID, SLOT_COUNT - 1);
return false;
}
// Dateinamen erzeugen.
- Common::String Filename = GenerateSavegameFilename(SlotID);
-
- // Sicherstellen, dass das Verzeichnis für die Spielstanddateien existiert.
- FileSystemUtil::GetInstance().CreateDirectory(GetSavegameDirectory());
+ Common::String filename = generateSavegameFilename(slotID);
// Spielstanddatei öffnen und die Headerdaten schreiben.
Common::SaveFileManager *sfm = g_system->getSavefileManager();
- Common::OutSaveFile *File = sfm->openForSaving(Filename);
+ Common::OutSaveFile *file = sfm->openForSaving(filename);
- File->writeString(FILE_MARKER);
- File->writeByte(' ');
- File->writeString(VERSIONID);
- File->writeByte(' ');
+ file->writeString(FILE_MARKER);
+ file->writeByte(0);
+ file->writeString(VERSIONID);
+ file->writeByte(0);
- if (File->err()) {
- error("Unable to write header data to savegame file \"%s\".", Filename.c_str());
+ TimeDate dt;
+ g_system->getTimeAndDate(dt);
+ file->writeString(formatTimestamp(dt));
+ file->writeByte(0);
+
+ if (file->err()) {
+ error("Unable to write header data to savegame file \"%s\".", filename.c_str());
}
// Alle notwendigen Module persistieren.
- OutputPersistenceBlock Writer;
- bool Success = true;
- Success &= Kernel::GetInstance()->GetScript()->persist(Writer);
- Success &= RegionRegistry::getInstance().persist(Writer);
- Success &= Kernel::GetInstance()->GetGfx()->persist(Writer);
- Success &= Kernel::GetInstance()->GetSfx()->persist(Writer);
- Success &= Kernel::GetInstance()->GetInput()->persist(Writer);
- if (!Success) {
- error("Unable to persist modules for savegame file \"%s\".", Filename.c_str());
+ OutputPersistenceBlock writer;
+ bool success = true;
+ success &= Kernel::getInstance()->getScript()->persist(writer);
+ success &= RegionRegistry::instance().persist(writer);
+ success &= Kernel::getInstance()->getGfx()->persist(writer);
+ success &= Kernel::getInstance()->getSfx()->persist(writer);
+ success &= Kernel::getInstance()->getInput()->persist(writer);
+ if (!success) {
+ error("Unable to persist modules for savegame file \"%s\".", filename.c_str());
}
// Daten komprimieren.
- uLongf CompressedLength = Writer.GetDataSize() + (Writer.GetDataSize() + 500) / 1000 + 12;
- Bytef *CompressionBuffer = new Bytef[CompressedLength];
+ uLongf compressedLength = writer.getDataSize() + (writer.getDataSize() + 500) / 1000 + 12;
+ Bytef *compressionBuffer = new Bytef[compressedLength];
- if (compress2(&CompressionBuffer[0], &CompressedLength, reinterpret_cast<const Bytef *>(Writer.GetData()), Writer.GetDataSize(), 6) != Z_OK) {
- error("Unable to compress savegame data in savegame file \"%s\".", Filename.c_str());
+ if (compress2(&compressionBuffer[0], &compressedLength, reinterpret_cast<const Bytef *>(writer.getData()), writer.getDataSize(), 6) != Z_OK) {
+ error("Unable to compress savegame data in savegame file \"%s\".", filename.c_str());
}
// Länge der komprimierten Daten und der unkomprimierten Daten in die Datei schreiben.
char sBuffer[10];
- snprintf(sBuffer, 10, "%ld", CompressedLength);
- File->writeString(sBuffer);
- File->writeByte(' ');
- snprintf(sBuffer, 10, "%u", Writer.GetDataSize());
- File->writeString(sBuffer);
- File->writeByte(' ');
+ snprintf(sBuffer, 10, "%ld", compressedLength);
+ file->writeString(sBuffer);
+ file->writeByte(0);
+ snprintf(sBuffer, 10, "%u", writer.getDataSize());
+ file->writeString(sBuffer);
+ file->writeByte(0);
// Komprimierte Daten in die Datei schreiben.
- File->write(reinterpret_cast<char *>(&CompressionBuffer[0]), CompressedLength);
- if (File->err()) {
- error("Unable to write game data to savegame file \"%s\".", Filename.c_str());
+ file->write(reinterpret_cast<char *>(&compressionBuffer[0]), compressedLength);
+ if (file->err()) {
+ error("Unable to write game data to savegame file \"%s\".", filename.c_str());
}
// Get the screenshot
- Common::MemoryReadStream *thumbnail = (static_cast<GraphicEngine *>(
- Kernel::GetInstance()->GetService("gfx")))->getThumbnail();
+ Common::MemoryReadStream *thumbnail = Kernel::getInstance()->getGfx()->getThumbnail();
if (thumbnail) {
- byte *Buffer = new Byte[FILE_COPY_BUFFER_SIZE];
+ byte *buffer = new Byte[FILE_COPY_BUFFER_SIZE];
while (!thumbnail->eos()) {
- int bytesRead = thumbnail->read(&Buffer[0], FILE_COPY_BUFFER_SIZE);
- File->write(&Buffer[0], bytesRead);
+ int bytesRead = thumbnail->read(&buffer[0], FILE_COPY_BUFFER_SIZE);
+ file->write(&buffer[0], bytesRead);
}
- delete[] Buffer;
+ delete[] buffer;
} else {
- BS_LOG_WARNINGLN("The screenshot file \"%s\" does not exist. Savegame is written without a screenshot.", Filename.c_str());
+ BS_LOG_WARNINGLN("The screenshot file \"%s\" does not exist. Savegame is written without a screenshot.", filename.c_str());
}
- // Savegameinformationen für diesen Slot aktualisieren.
- m_impl->ReadSlotSavegameInformation(SlotID);
+ file->finalize();
+ delete file;
+ delete[] compressionBuffer;
- File->finalize();
- delete File;
- delete[] CompressionBuffer;
+ // Savegameinformationen für diesen Slot aktualisieren.
+ _impl->readSlotSavegameInformation(slotID);
// Erfolg signalisieren.
return true;
}
-// -----------------------------------------------------------------------------
-
-bool PersistenceService::LoadGame(uint SlotID) {
+bool PersistenceService::loadGame(uint slotID) {
Common::SaveFileManager *sfm = g_system->getSavefileManager();
- Common::InSaveFile *File;
+ Common::InSaveFile *file;
// Überprüfen, ob die Slot-ID zulässig ist.
- if (SlotID >= SLOT_COUNT) {
- BS_LOG_ERRORLN("Tried to load from an invalid slot (%d). Only slot ids form 0 to %d are allowed.", SlotID, SLOT_COUNT - 1);
+ if (slotID >= SLOT_COUNT) {
+ BS_LOG_ERRORLN("Tried to load from an invalid slot (%d). Only slot ids form 0 to %d are allowed.", slotID, SLOT_COUNT - 1);
return false;
}
- SavegameInformation &CurSavegameInfo = m_impl->m_SavegameInformations[SlotID];
+ SavegameInformation &curSavegameInfo = _impl->_savegameInformations[slotID];
// Überprüfen, ob der Slot belegt ist.
- if (!CurSavegameInfo.IsOccupied) {
- BS_LOG_ERRORLN("Tried to load from an empty slot (%d).", SlotID);
+ if (!curSavegameInfo.isOccupied) {
+ BS_LOG_ERRORLN("Tried to load from an empty slot (%d).", slotID);
return false;
}
@@ -408,54 +363,54 @@ bool PersistenceService::LoadGame(uint SlotID) {
// Im Debug-Modus wird dieser Test übersprungen. Für das Testen ist es hinderlich auf die Einhaltung dieser strengen Bedingung zu bestehen,
// da sich die Versions-ID bei jeder Codeänderung mitändert.
#ifndef DEBUG
- if (!CurSavegameInfo.IsCompatible) {
- BS_LOG_ERRORLN("Tried to load a savegame (%d) that is not compatible with this engine version.", SlotID);
+ if (!curSavegameInfo.isCompatible) {
+ BS_LOG_ERRORLN("Tried to load a savegame (%d) that is not compatible with this engine version.", slotID);
return false;
}
#endif
- byte *CompressedDataBuffer = new byte[CurSavegameInfo.GamedataLength];
- byte *UncompressedDataBuffer = new Bytef[CurSavegameInfo.GamedataUncompressedLength];
+ byte *compressedDataBuffer = new byte[curSavegameInfo.gamedataLength];
+ byte *uncompressedDataBuffer = new Bytef[curSavegameInfo.gamedataUncompressedLength];
- File = sfm->openForLoading(GenerateSavegameFilename(SlotID));
+ file = sfm->openForLoading(generateSavegameFilename(slotID));
- File->seek(CurSavegameInfo.GamedataOffset);
- File->read(reinterpret_cast<char *>(&CompressedDataBuffer[0]), CurSavegameInfo.GamedataLength);
- if (File->err()) {
- BS_LOG_ERRORLN("Unable to load the gamedata from the savegame file \"%s\".", CurSavegameInfo.Filename.c_str());
- delete[] CompressedDataBuffer;
- delete[] UncompressedDataBuffer;
+ file->seek(curSavegameInfo.gamedataOffset);
+ file->read(reinterpret_cast<char *>(&compressedDataBuffer[0]), curSavegameInfo.gamedataLength);
+ if (file->err()) {
+ BS_LOG_ERRORLN("Unable to load the gamedata from the savegame file \"%s\".", curSavegameInfo.filename.c_str());
+ delete[] compressedDataBuffer;
+ delete[] uncompressedDataBuffer;
return false;
}
// Spieldaten dekomprimieren.
- uLongf UncompressedBufferSize = CurSavegameInfo.GamedataUncompressedLength;
- if (uncompress(reinterpret_cast<Bytef *>(&UncompressedDataBuffer[0]), &UncompressedBufferSize,
- reinterpret_cast<Bytef *>(&CompressedDataBuffer[0]), CurSavegameInfo.GamedataLength) != Z_OK) {
- BS_LOG_ERRORLN("Unable to decompress the gamedata from savegame file \"%s\".", CurSavegameInfo.Filename.c_str());
- delete[] UncompressedDataBuffer;
- delete[] CompressedDataBuffer;
- delete File;
+ uLongf uncompressedBufferSize = curSavegameInfo.gamedataUncompressedLength;
+ if (uncompress(reinterpret_cast<Bytef *>(&uncompressedDataBuffer[0]), &uncompressedBufferSize,
+ reinterpret_cast<Bytef *>(&compressedDataBuffer[0]), curSavegameInfo.gamedataLength) != Z_OK) {
+ BS_LOG_ERRORLN("Unable to decompress the gamedata from savegame file \"%s\".", curSavegameInfo.filename.c_str());
+ delete[] uncompressedDataBuffer;
+ delete[] compressedDataBuffer;
+ delete file;
return false;
}
- InputPersistenceBlock Reader(&UncompressedDataBuffer[0], CurSavegameInfo.GamedataUncompressedLength);
+ InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength);
// Einzelne Engine-Module depersistieren.
- bool Success = true;
- Success &= Kernel::GetInstance()->GetScript()->unpersist(Reader);
+ bool success = true;
+ success &= Kernel::getInstance()->getScript()->unpersist(reader);
// Muss unbedingt nach Script passieren. Da sonst die bereits wiederhergestellten Regions per Garbage-Collection gekillt werden.
- Success &= RegionRegistry::getInstance().unpersist(Reader);
- Success &= Kernel::GetInstance()->GetGfx()->unpersist(Reader);
- Success &= Kernel::GetInstance()->GetSfx()->unpersist(Reader);
- Success &= Kernel::GetInstance()->GetInput()->unpersist(Reader);
+ success &= RegionRegistry::instance().unpersist(reader);
+ success &= Kernel::getInstance()->getGfx()->unpersist(reader);
+ success &= Kernel::getInstance()->getSfx()->unpersist(reader);
+ success &= Kernel::getInstance()->getInput()->unpersist(reader);
- delete[] CompressedDataBuffer;
- delete[] UncompressedDataBuffer;
- delete File;
+ delete[] compressedDataBuffer;
+ delete[] uncompressedDataBuffer;
+ delete file;
- if (!Success) {
- BS_LOG_ERRORLN("Unable to unpersist the gamedata from savegame file \"%s\".", CurSavegameInfo.Filename.c_str());
+ if (!success) {
+ BS_LOG_ERRORLN("Unable to unpersist the gamedata from savegame file \"%s\".", curSavegameInfo.filename.c_str());
return false;
}
diff --git a/engines/sword25/kernel/persistenceservice.h b/engines/sword25/kernel/persistenceservice.h
index d14185eac2..0db109d1b0 100644
--- a/engines/sword25/kernel/persistenceservice.h
+++ b/engines/sword25/kernel/persistenceservice.h
@@ -35,18 +35,10 @@
#ifndef SWORD25_PERSISTENCESERVICE_H
#define SWORD25_PERSISTENCESERVICE_H
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "sword25/kernel/common.h"
namespace Sword25 {
-// -----------------------------------------------------------------------------
-// Class declaration
-// -----------------------------------------------------------------------------
-
class PersistenceService {
public:
PersistenceService();
@@ -56,29 +48,31 @@ public:
// Singleton Method
// -----------------------------------------------------------------------------
- static PersistenceService &GetInstance();
+ static PersistenceService &getInstance();
// -----------------------------------------------------------------------------
// Interface
// -----------------------------------------------------------------------------
- static uint GetSlotCount();
- static Common::String GetSavegameDirectory();
+ static uint getSlotCount();
+ static Common::String getSavegameDirectory();
- void ReloadSlots();
- bool IsSlotOccupied(uint SlotID);
- bool IsSavegameCompatible(uint SlotID);
- Common::String &GetSavegameDescription(uint SlotID);
- Common::String &GetSavegameFilename(uint SlotID);
+ void reloadSlots();
+ bool isSlotOccupied(uint slotID);
+ bool isSavegameCompatible(uint slotID);
+ Common::String &getSavegameDescription(uint slotID);
+ Common::String &getSavegameFilename(uint slotID);
- bool SaveGame(uint SlotID, const Common::String &ScreenshotFilename);
- bool LoadGame(uint SlotID);
+ bool saveGame(uint slotID, const Common::String &screenshotFilename);
+ bool loadGame(uint slotID);
private:
struct Impl;
- Impl *m_impl;
+ Impl *_impl;
};
+void setGameTarget(const char *target);
+
} // End of namespace Sword25
#endif
diff --git a/engines/sword25/kernel/resmanager.cpp b/engines/sword25/kernel/resmanager.cpp
index 9e80f32f8d..1979e6e6c6 100644
--- a/engines/sword25/kernel/resmanager.cpp
+++ b/engines/sword25/kernel/resmanager.cpp
@@ -36,7 +36,6 @@
#include "sword25/kernel/resource.h"
#include "sword25/kernel/resservice.h"
-#include "sword25/kernel/string.h"
#include "sword25/package/packagemanager.h"
namespace Sword25 {
@@ -45,60 +44,35 @@ namespace Sword25 {
ResourceManager::~ResourceManager() {
// Clear all unlocked resources
- EmptyCache();
+ emptyCache();
// All remaining resources are not released, so print warnings and release
- Common::List<Resource *>::iterator Iter = m_Resources.begin();
- for (; Iter != m_Resources.end(); ++Iter) {
- BS_LOG_WARNINGLN("Resource \"%s\" was not released.", (*Iter)->getFileName().c_str());
+ Common::List<Resource *>::iterator iter = _resources.begin();
+ for (; iter != _resources.end(); ++iter) {
+ BS_LOG_WARNINGLN("Resource \"%s\" was not released.", (*iter)->getFileName().c_str());
// Set the lock count to zero
- while ((*Iter)->GetLockCount() > 0) {
- (*Iter)->release();
+ while ((*iter)->getLockCount() > 0) {
+ (*iter)->release();
};
// Delete the resource
- delete(*Iter);
+ delete(*iter);
}
}
/**
- * Returns a resource by it's ordinal index. Returns NULL if any error occurs
- * Note: This method is not optimised for speed and should be used only for debugging purposes
- * @param Ord Ordinal number of the resource. Must be between 0 and GetResourceCount() - 1.
- */
-Resource *ResourceManager::GetResourceByOrdinal(int Ord) const {
- // Überprüfen ob der Index Ord innerhald der Listengrenzen liegt.
- if (Ord < 0 || Ord >= GetResourceCount()) {
- BS_LOG_ERRORLN("Resource ordinal (%d) out of bounds (0 - %d).", Ord, GetResourceCount() - 1);
- return NULL;
- }
-
- // Liste durchlaufen und die Resource mit dem gewünschten Index zurückgeben.
- int CurOrd = 0;
- Common::List<Resource *>::const_iterator Iter = m_Resources.begin();
- for (; Iter != m_Resources.end(); ++Iter, ++CurOrd) {
- if (CurOrd == Ord)
- return (*Iter);
- }
-
- // Die Ausführung sollte nie an diesem Punkt ankommen.
- BS_LOG_EXTERRORLN("Execution reached unexpected point.");
- return NULL;
-}
-
-/**
* Registers a RegisterResourceService. This method is the constructor of
* BS_ResourceService, and thus helps all resource services in the ResourceManager list
* @param pService Which service
*/
-bool ResourceManager::RegisterResourceService(ResourceService *pService) {
+bool ResourceManager::registerResourceService(ResourceService *pService) {
if (!pService) {
BS_LOG_ERRORLN("Can't register NULL resource service.");
return false;
}
- m_ResourceServices.push_back(pService);
+ _resourceServices.push_back(pService);
return true;
}
@@ -106,34 +80,36 @@ bool ResourceManager::RegisterResourceService(ResourceService *pService) {
/**
* Deletes resources as necessary until the specified memory limit is not being exceeded.
*/
-void ResourceManager::DeleteResourcesIfNecessary() {
+void ResourceManager::deleteResourcesIfNecessary() {
// If enough memory is available, or no resources are loaded, then the function can immediately end
- if (m_KernelPtr->GetUsedMemory() < m_MaxMemoryUsage || m_Resources.empty()) return;
+ if (_kernelPtr->getUsedMemory() < _maxMemoryUsage || _resources.empty())
+ return;
// Keep deleting resources until the memory usage of the process falls below the set maximum limit.
// The list is processed backwards in order to first release those resources who have been
// not been accessed for the longest
- Common::List<Resource *>::iterator Iter = m_Resources.end();
+ Common::List<Resource *>::iterator iter = _resources.end();
do {
- --Iter;
+ --iter;
// The resource may be released only if it isn't locked
- if ((*Iter)->GetLockCount() == 0) Iter = DeleteResource(*Iter);
- } while (Iter != m_Resources.begin() && m_KernelPtr->GetUsedMemory() > m_MaxMemoryUsage);
+ if ((*iter)->getLockCount() == 0)
+ iter = deleteResource(*iter);
+ } while (iter != _resources.begin() && _kernelPtr->getUsedMemory() > _maxMemoryUsage);
}
/**
* Releases all resources that are not locked.
- **/
-void ResourceManager::EmptyCache() {
+ */
+void ResourceManager::emptyCache() {
// Scan through the resource list
- Common::List<Resource *>::iterator Iter = m_Resources.begin();
- while (Iter != m_Resources.end()) {
- if ((*Iter)->GetLockCount() == 0) {
+ Common::List<Resource *>::iterator iter = _resources.begin();
+ while (iter != _resources.end()) {
+ if ((*iter)->getLockCount() == 0) {
// Delete the resource
- Iter = DeleteResource(*Iter);
+ iter = deleteResource(*iter);
} else
- ++Iter;
+ ++iter;
}
}
@@ -141,29 +117,30 @@ void ResourceManager::EmptyCache() {
* Returns a requested resource. If any error occurs, returns NULL
* @param FileName Filename of resource
*/
-Resource *ResourceManager::RequestResource(const Common::String &FileName) {
+Resource *ResourceManager::requestResource(const Common::String &fileName) {
// Get the absolute path to the file
- Common::String UniqueFileName = GetUniqueFileName(FileName);
- if (UniqueFileName == "")
+ Common::String uniqueFileName = getUniqueFileName(fileName);
+ if (uniqueFileName.empty())
return NULL;
// Determine whether the resource is already loaded
// If the resource is found, it will be placed at the head of the resource list and returned
{
- Resource *pResource = GetResource(UniqueFileName);
+ Resource *pResource = getResource(uniqueFileName);
if (pResource) {
- MoveToFront(pResource);
- (pResource)->AddReference();
+ moveToFront(pResource);
+ (pResource)->addReference();
return pResource;
}
}
// The resource was not found, therefore, must not be loaded yet
- if (m_LogCacheMiss) BS_LOG_WARNINGLN("\"%s\" was not precached.", UniqueFileName.c_str());
+ if (_logCacheMiss)
+ BS_LOG_WARNINGLN("\"%s\" was not precached.", uniqueFileName.c_str());
- Resource *pResource;
- if ((pResource = loadResource(UniqueFileName))) {
- pResource->AddReference();
+ Resource *pResource = loadResource(uniqueFileName);
+ if (pResource) {
+ pResource->addReference();
return pResource;
}
@@ -176,26 +153,26 @@ Resource *ResourceManager::RequestResource(const Common::String &FileName) {
* @param ForceReload Indicates whether the file should be reloaded if it's already in the cache.
* This is useful for files that may have changed in the interim
*/
-bool ResourceManager::PrecacheResource(const Common::String &FileName, bool ForceReload) {
+bool ResourceManager::precacheResource(const Common::String &fileName, bool forceReload) {
// Get the absolute path to the file
- Common::String UniqueFileName = GetUniqueFileName(FileName);
- if (UniqueFileName == "")
+ Common::String uniqueFileName = getUniqueFileName(fileName);
+ if (uniqueFileName.empty())
return false;
- Resource *ResourcePtr = GetResource(UniqueFileName);
+ Resource *resourcePtr = getResource(uniqueFileName);
- if (ForceReload && ResourcePtr) {
- if (ResourcePtr->GetLockCount()) {
- BS_LOG_ERRORLN("Could not force precaching of \"%s\". The resource is locked.", FileName.c_str());
+ if (forceReload && resourcePtr) {
+ if (resourcePtr->getLockCount()) {
+ BS_LOG_ERRORLN("Could not force precaching of \"%s\". The resource is locked.", fileName.c_str());
return false;
} else {
- DeleteResource(ResourcePtr);
- ResourcePtr = 0;
+ deleteResource(resourcePtr);
+ resourcePtr = 0;
}
}
- if (!ResourcePtr && loadResource(UniqueFileName) == NULL) {
- BS_LOG_ERRORLN("Could not precache \"%s\",", FileName.c_str());
+ if (!resourcePtr && loadResource(uniqueFileName) == NULL) {
+ BS_LOG_ERRORLN("Could not precache \"%s\",", fileName.c_str());
return false;
}
@@ -206,13 +183,13 @@ bool ResourceManager::PrecacheResource(const Common::String &FileName, bool Forc
* Moves a resource to the top of the resource list
* @param pResource The resource
*/
-void ResourceManager::MoveToFront(Resource *pResource) {
+void ResourceManager::moveToFront(Resource *pResource) {
// Erase the resource from it's current position
- m_Resources.erase(pResource->_iterator);
+ _resources.erase(pResource->_iterator);
// Re-add the resource at the front of the list
- m_Resources.push_front(pResource);
+ _resources.push_front(pResource);
// Reset the resource iterator to the repositioned item
- pResource->_iterator = m_Resources.begin();
+ pResource->_iterator = _resources.begin();
}
/**
@@ -223,24 +200,24 @@ void ResourceManager::MoveToFront(Resource *pResource) {
*/
Resource *ResourceManager::loadResource(const Common::String &fileName) {
// ResourceService finden, der die Resource laden kann.
- for (uint i = 0; i < m_ResourceServices.size(); ++i) {
- if (m_ResourceServices[i]->canLoadResource(fileName)) {
+ for (uint i = 0; i < _resourceServices.size(); ++i) {
+ if (_resourceServices[i]->canLoadResource(fileName)) {
// If more memory is desired, memory must be released
- DeleteResourcesIfNecessary();
+ deleteResourcesIfNecessary();
// Load the resource
- Resource *pResource;
- if (!(pResource = m_ResourceServices[i]->loadResource(fileName))) {
+ Resource *pResource = _resourceServices[i]->loadResource(fileName);
+ if (!pResource) {
BS_LOG_ERRORLN("Responsible service could not load resource \"%s\".", fileName.c_str());
return NULL;
}
// Add the resource to the front of the list
- m_Resources.push_front(pResource);
- pResource->_iterator = m_Resources.begin();
+ _resources.push_front(pResource);
+ pResource->_iterator = _resources.begin();
// Also store the resource in the hash table for quick lookup
- m_ResourceHashTable[pResource->GetFileNameHash() % HASH_TABLE_BUCKETS].push_front(pResource);
+ _resourceHashMap[pResource->getFileName()] = pResource;
return pResource;
}
@@ -254,70 +231,60 @@ Resource *ResourceManager::loadResource(const Common::String &fileName) {
* Returns the full path of a given resource filename.
* It will return an empty string if a path could not be created.
*/
-Common::String ResourceManager::GetUniqueFileName(const Common::String &FileName) const {
+Common::String ResourceManager::getUniqueFileName(const Common::String &fileName) const {
// Get a pointer to the package manager
- PackageManager *pPackage = (PackageManager *)m_KernelPtr->GetService("package");
+ PackageManager *pPackage = (PackageManager *)_kernelPtr->getPackage();
if (!pPackage) {
BS_LOG_ERRORLN("Could not get package manager.");
- return Common::String("");
+ return Common::String();
}
// Absoluten Pfad der Datei bekommen und somit die Eindeutigkeit des Dateinamens sicherstellen
- Common::String UniqueFileName = pPackage->getAbsolutePath(FileName);
- if (UniqueFileName == "")
- BS_LOG_ERRORLN("Could not create absolute file name for \"%s\".", FileName.c_str());
+ Common::String uniquefileName = pPackage->getAbsolutePath(fileName);
+ if (uniquefileName.empty())
+ BS_LOG_ERRORLN("Could not create absolute file name for \"%s\".", fileName.c_str());
- return UniqueFileName;
+ return uniquefileName;
}
/**
* Deletes a resource, removes it from the lists, and updates m_UsedMemory
*/
-Common::List<Resource *>::iterator ResourceManager::DeleteResource(Resource *pResource) {
+Common::List<Resource *>::iterator ResourceManager::deleteResource(Resource *pResource) {
// Remove the resource from the hash table
- m_ResourceHashTable[pResource->GetFileNameHash() % HASH_TABLE_BUCKETS].remove(pResource);
-
- Resource *pDummy = pResource;
+ _resourceHashMap.erase(pResource->_fileName);
// Delete the resource from the resource list
- Common::List<Resource *>::iterator Result = m_Resources.erase(pResource->_iterator);
+ Common::List<Resource *>::iterator result = _resources.erase(pResource->_iterator);
// Delete the resource
- delete(pDummy);
+ delete pResource;
// Return the iterator
- return Result;
+ return result;
}
/**
* Returns a pointer to a loaded resource. If any error occurs, NULL will be returned.
- * @param UniqueFileName The absolute path and filename
- * Gibt einen Pointer auf die angeforderte Resource zurück, oder NULL, wenn die Resourcen nicht geladen ist.
+ * @param UniquefileName The absolute path and filename
*/
-Resource *ResourceManager::GetResource(const Common::String &UniqueFileName) const {
+Resource *ResourceManager::getResource(const Common::String &uniquefileName) const {
// Determine whether the resource is already loaded
- const Common::List<Resource *>& HashBucket = m_ResourceHashTable[
- BS_String::GetHash(UniqueFileName) % HASH_TABLE_BUCKETS];
- {
- Common::List<Resource *>::const_iterator Iter = HashBucket.begin();
- for (; Iter != HashBucket.end(); ++Iter) {
- // Wenn die Resource gefunden wurde wird sie zurückgegeben.
- if ((*Iter)->getFileName() == UniqueFileName)
- return *Iter;
- }
- }
+ ResMap::iterator it = _resourceHashMap.find(uniquefileName);
+ if (it != _resourceHashMap.end())
+ return it->_value;
- // Resource wurde nicht gefunden, ist also nicht geladen
+ // Resource was not found, i.e. has not yet been loaded.
return NULL;
}
/**
* Writes the names of all currently locked resources to the log file
*/
-void ResourceManager::DumpLockedResources() {
- for (Common::List<Resource *>::iterator Iter = m_Resources.begin(); Iter != m_Resources.end(); ++Iter) {
- if ((*Iter)->GetLockCount() > 0) {
- BS_LOGLN("%s", (*Iter)->getFileName().c_str());
+void ResourceManager::dumpLockedResources() {
+ for (Common::List<Resource *>::iterator iter = _resources.begin(); iter != _resources.end(); ++iter) {
+ if ((*iter)->getLockCount() > 0) {
+ BS_LOGLN("%s", (*iter)->getFileName().c_str());
}
}
}
@@ -328,9 +295,9 @@ void ResourceManager::DumpLockedResources() {
* as a guideline, and not as a fixed boundary. It is not guaranteed not to be exceeded;
* the whole game engine may still use more memory than any amount specified.
*/
-void ResourceManager::SetMaxMemoryUsage(uint MaxMemoryUsage) {
- m_MaxMemoryUsage = MaxMemoryUsage;
- DeleteResourcesIfNecessary();
+void ResourceManager::setMaxMemoryUsage(uint maxMemoryUsage) {
+ _maxMemoryUsage = maxMemoryUsage;
+ deleteResourcesIfNecessary();
}
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/resmanager.h b/engines/sword25/kernel/resmanager.h
index 578f121fec..613bb3a3a2 100644
--- a/engines/sword25/kernel/resmanager.h
+++ b/engines/sword25/kernel/resmanager.h
@@ -35,14 +35,14 @@
#ifndef SWORD25_RESOURCEMANAGER_H
#define SWORD25_RESOURCEMANAGER_H
-// Includes
#include "common/list.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
#include "sword25/kernel/common.h"
namespace Sword25 {
-// Class definitions
class ResourceService;
class Resource;
class Kernel;
@@ -55,7 +55,7 @@ public:
* Returns a requested resource. If any error occurs, returns NULL
* @param FileName Filename of resource
*/
- Resource *RequestResource(const Common::String &FileName);
+ Resource *requestResource(const Common::String &fileName);
/**
* Loads a resource into the cache
@@ -63,39 +63,25 @@ public:
* @param ForceReload Indicates whether the file should be reloaded if it's already in the cache.
* This is useful for files that may have changed in the interim
*/
- bool PrecacheResource(const Common::String &FileName, bool ForceReload = false);
-
- /**
- * Returns the number of loaded resources
- */
- int GetResourceCount() const {
- return static_cast<int>(m_Resources.size());
- }
-
- /**
- * Returns a resource by it's ordinal index. Returns NULL if any error occurs
- * Note: This method is not optimised for speed and should be used only for debugging purposes
- * @param Ord Ordinal number of the resource. Must be between 0 and GetResourceCount() - 1.
- */
- Resource *GetResourceByOrdinal(int Ord) const;
+ bool precacheResource(const Common::String &fileName, bool forceReload = false);
/**
* Registers a RegisterResourceService. This method is the constructor of
* BS_ResourceService, and thus helps all resource services in the ResourceManager list
* @param pService Which service
*/
- bool RegisterResourceService(ResourceService *pService);
+ bool registerResourceService(ResourceService *pService);
/**
* Releases all resources that are not locked.
**/
- void EmptyCache();
+ void emptyCache();
/**
* Returns the maximum memory the kernel has used
*/
- int GetMaxMemoryUsage() const {
- return m_MaxMemoryUsage;
+ int getMaxMemoryUsage() const {
+ return _maxMemoryUsage;
}
/**
@@ -104,28 +90,28 @@ public:
* as a guideline, and not as a fixed boundary. It is not guaranteed not to be exceeded;
* the whole game engine may still use more memory than any amount specified.
*/
- void SetMaxMemoryUsage(uint MaxMemoryUsage);
+ void setMaxMemoryUsage(uint maxMemoryUsage);
/**
* Specifies whether a warning is written to the log when a cache miss occurs.
* THe default value is "false".
*/
- bool IsLogCacheMiss() const {
- return m_LogCacheMiss;
+ bool isLogCacheMiss() const {
+ return _logCacheMiss;
}
/**
* Sets whether warnings are written to the log if a cache miss occurs.
* @param Flag If "true", then future warnings will be logged
*/
- void SetLogCacheMiss(bool Flag) {
- m_LogCacheMiss = Flag;
+ void setLogCacheMiss(bool flag) {
+ _logCacheMiss = flag;
}
/**
* Writes the names of all currently locked resources to the log file
*/
- void DumpLockedResources();
+ void dumpLockedResources();
private:
/**
@@ -133,21 +119,17 @@ private:
* Only the BS_Kernel class can generate copies this class. Thus, the constructor is private
*/
ResourceManager(Kernel *pKernel) :
- m_KernelPtr(pKernel),
- m_MaxMemoryUsage(100000000),
- m_LogCacheMiss(false)
- {};
+ _kernelPtr(pKernel),
+ _maxMemoryUsage(100000000),
+ _logCacheMiss(false)
+ {}
virtual ~ResourceManager();
- enum {
- HASH_TABLE_BUCKETS = 256
- };
-
/**
* Moves a resource to the top of the resource list
* @param pResource The resource
*/
- void MoveToFront(Resource *pResource);
+ void moveToFront(Resource *pResource);
/**
* Loads a resource and updates the m_UsedMemory total
@@ -161,31 +143,31 @@ private:
* Returns the full path of a given resource filename.
* It will return an empty string if a path could not be created.
*/
- Common::String GetUniqueFileName(const Common::String &FileName) const;
+ Common::String getUniqueFileName(const Common::String &fileName) const;
/**
* Deletes a resource, removes it from the lists, and updates m_UsedMemory
*/
- Common::List<Resource *>::iterator DeleteResource(Resource *pResource);
+ Common::List<Resource *>::iterator deleteResource(Resource *pResource);
/**
* Returns a pointer to a loaded resource. If any error occurs, NULL will be returned.
* @param UniqueFileName The absolute path and filename
- * Gibt einen Pointer auf die angeforderte Resource zurück, oder NULL, wenn die Resourcen nicht geladen ist.
*/
- Resource *GetResource(const Common::String &UniqueFileName) const;
+ Resource *getResource(const Common::String &uniqueFileName) const;
/**
* Deletes resources as necessary until the specified memory limit is not being exceeded.
*/
- void DeleteResourcesIfNecessary();
-
- Kernel *m_KernelPtr;
- uint m_MaxMemoryUsage;
- Common::Array<ResourceService *> m_ResourceServices;
- Common::List<Resource *> m_Resources;
- Common::List<Resource *> m_ResourceHashTable[HASH_TABLE_BUCKETS];
- bool m_LogCacheMiss;
+ void deleteResourcesIfNecessary();
+
+ Kernel *_kernelPtr;
+ uint _maxMemoryUsage;
+ Common::Array<ResourceService *> _resourceServices;
+ Common::List<Resource *> _resources;
+ typedef Common::HashMap<Common::String, Resource *> ResMap;
+ ResMap _resourceHashMap;
+ bool _logCacheMiss;
};
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/resource.cpp b/engines/sword25/kernel/resource.cpp
index f6f4f13f68..40eea2138c 100644
--- a/engines/sword25/kernel/resource.cpp
+++ b/engines/sword25/kernel/resource.cpp
@@ -33,7 +33,6 @@
*/
#include "sword25/kernel/resource.h"
-#include "sword25/kernel/string.h"
#include "sword25/kernel/kernel.h"
#include "sword25/package/packagemanager.h"
@@ -44,10 +43,10 @@ namespace Sword25 {
Resource::Resource(const Common::String &fileName, RESOURCE_TYPES type) :
_type(type),
_refCount(0) {
- BS_ASSERT(Kernel::GetInstance()->GetService("package"));
+ PackageManager *pPM = Kernel::getInstance()->getPackage();
+ BS_ASSERT(pPM);
- _fileName = static_cast<PackageManager *>(Kernel::GetInstance()->GetService("package"))->getAbsolutePath(fileName);
- _fileNameHash = BS_String::GetHash(fileName);
+ _fileName = pPM->getAbsolutePath(fileName);
}
void Resource::release() {
diff --git a/engines/sword25/kernel/resource.h b/engines/sword25/kernel/resource.h
index 2a4d197138..5c6108a281 100644
--- a/engines/sword25/kernel/resource.h
+++ b/engines/sword25/kernel/resource.h
@@ -62,7 +62,7 @@ public:
* Prevents the resource from being released.
* @remarks This method allows a resource to be locked multiple times.
**/
- void AddReference() {
+ void addReference() {
++_refCount;
}
@@ -77,7 +77,7 @@ public:
* Returns the current lock count for the resource
* @return The current lock count
**/
- int GetLockCount() const {
+ int getLockCount() const {
return _refCount;
}
@@ -89,27 +89,19 @@ public:
}
/**
- * Returns the hash of the filename of a resource
- */
- uint GetFileNameHash() const {
- return _fileNameHash;
- }
-
- /**
* Returns a resource's type
*/
- uint GetType() const {
+ uint getType() const {
return _type;
}
protected:
- virtual ~Resource() {};
+ virtual ~Resource() {}
private:
- Common::String _fileName; ///< The absolute filename
- uint _fileNameHash; ///< The hash value of the filename
- uint _refCount; ///< The number of locks
- uint _type; ///< The type of the resource
+ Common::String _fileName; ///< The absolute filename
+ uint _refCount; ///< The number of locks
+ uint _type; ///< The type of the resource
Common::List<Resource *>::iterator _iterator; ///< Points to the resource position in the LRU list
};
diff --git a/engines/sword25/kernel/resservice.h b/engines/sword25/kernel/resservice.h
index d5961d52ae..a0f2669231 100644
--- a/engines/sword25/kernel/resservice.h
+++ b/engines/sword25/kernel/resservice.h
@@ -35,7 +35,6 @@
#ifndef SWORD25_RESOURCESERVICE_H
#define SWORD25_RESOURCESERVICE_H
-// Includes
#include "sword25/kernel/common.h"
#include "sword25/kernel/service.h"
#include "sword25/kernel/kernel.h"
@@ -48,8 +47,8 @@ class Resource;
class ResourceService : public Service {
public:
ResourceService(Kernel *pKernel) : Service(pKernel) {
- ResourceManager *pResource = pKernel->GetResourceManager();
- pResource->RegisterResourceService(this);
+ ResourceManager *pResource = pKernel->getResourceManager();
+ pResource->registerResourceService(this);
}
virtual ~ResourceService() {}
diff --git a/engines/sword25/kernel/scummvmwindow.cpp b/engines/sword25/kernel/scummvmwindow.cpp
deleted file mode 100644
index 35fd27a05c..0000000000
--- a/engines/sword25/kernel/scummvmwindow.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-#include "common/system.h"
-#include "engines/util.h"
-#include "graphics/pixelformat.h"
-#include "sword25/kernel/scummvmwindow.h"
-#include "sword25/kernel/kernel.h"
-#include "sword25/input/inputengine.h"
-
-#define BS_LOG_PREFIX "WIN32WINDOW"
-
-namespace Sword25 {
-
-bool ScummVMWindow::_ClassRegistered = false;
-
-// Constructor / Destructor
-// ------------------------
-ScummVMWindow::ScummVMWindow(int X, int Y, int Width, int Height, bool Visible) {
- // Presume that init will fail
- _InitSuccess = false;
-
- // We don't support any window creation except at the origin 0,0
- assert(X == 0);
- assert(Y == 0);
-
- if (!_ClassRegistered) {
- // Nothing here currently
-
- _ClassRegistered = true;
- }
-
- // Fenstersichtbarkeit setzen
- SetVisible(Visible);
-
- // Indicate success
- _InitSuccess = true;
- _WindowAlive = true;
- _CloseWanted = false;
-}
-
-ScummVMWindow::~ScummVMWindow() {
-}
-
-// Get Methods
-// ------------
-int ScummVMWindow::GetX() {
- return 0;
-}
-
-int ScummVMWindow::GetY() {
- return 0;
-}
-
-int ScummVMWindow::GetClientX() {
- return 0;
-}
-
-int ScummVMWindow::GetClientY() {
- return 0;
-}
-
-int ScummVMWindow::GetWidth() {
- return g_system->getWidth();
-}
-
-int ScummVMWindow::GetHeight() {
- return g_system->getHeight();
-}
-
-Common::String ScummVMWindow::GetTitle() {
- return Common::String("");
-}
-
-bool ScummVMWindow::IsVisible() {
- return true;
-}
-
-bool ScummVMWindow::HasFocus() {
- // FIXME: Is there a way to tell if ScummVM has the focus in Windowed mode?
- return true;
-}
-
-uint ScummVMWindow::GetWindowHandle() {
- return 0;
-}
-
-void ScummVMWindow::SetWindowAlive(bool v) {
- _WindowAlive = v;
-}
-
-
-// Set Methods
-// ------------
-
-void ScummVMWindow::SetX(int X) {
- // No implementation
-}
-
-void ScummVMWindow::SetY(int Y) {
- // No implementation
-}
-
-void ScummVMWindow::SetWidth(int Width) {
- // No implementation
-}
-
-void ScummVMWindow::SetHeight(int Height) {
- // No implementation
-}
-
-void ScummVMWindow::SetVisible(bool Visible) {
- // No implementation
-}
-
-void ScummVMWindow::SetTitle(const Common::String &Title) {
- // No implementation
-}
-
-bool ScummVMWindow::ProcessMessages() {
- // All messages are handled separately in the input manager. The only thing we
- // need to do here is to keep returning whether the window/game is still alive
- return _WindowAlive;
-}
-
-bool ScummVMWindow::WaitForFocus() {
- // No implementation
- return true;
-}
-
-// FIXME: Special keys detected here need to be moved into the Input Engine
-/*
-// Die WindowProc aller Fenster der Klasse
-LRESULT CALLBACK BS_ScummVMWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- switch(uMsg)
- {
- case WM_PAINT:
- ValidateRect(hwnd, NULL);
- break;
-
- case WM_DESTROY:
- // Das Fenster wird zerstört
- PostQuitMessage(0);
- break;
-
- case WM_CLOSE:
- {
- BS_Window * WindowPtr = BS_Kernel::GetInstance()->GetWindow();
- if (WindowPtr) {
- WindowPtr->SetCloseWanted(true);
- }
- break;
- }
-
- case WM_KEYDOWN:
- {
- // Tastendrücke, die für das Inputmodul interessant sind, werden diesem gemeldet.
- BS_InputEngine * InputPtr = BS_Kernel::GetInstance()->GetInput();
-
- if (InputPtr)
- {
- switch (wParam)
- {
- case VK_RETURN:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_ENTER);
- break;
-
- case VK_LEFT:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_LEFT);
- break;
-
- case VK_RIGHT:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_RIGHT);
- break;
-
- case VK_HOME:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_HOME);
- break;
-
- case VK_END:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_END);
- break;
-
- case VK_BACK:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_BACKSPACE);
- break;
-
- case VK_TAB:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_TAB);
- break;
-
- case VK_INSERT:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_INSERT);
- break;
-
- case VK_DELETE:
- InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_DELETE);
- break;
- }
- }
- break;
- }
-
- case WM_KEYUP:
- case WM_SYSKEYUP:
- // Alle Tastendrücke werden ignoriert, damit Windows per DefWindowProc() nicht darauf
- // reagieren kann und damit unerwartete Seiteneffekte auslöst.
- // Zum Beispiel würden ALT und F10 Tastendrücke das "Menü" aktivieren und somit den Message-Loop zum Stillstand bringen.
- break;
-
- case WM_SYSCOMMAND:
- // Verhindern, dass der Bildschirmschoner aktiviert wird, während das Spiel läuft
- if (wParam != SC_SCREENSAVE) return DefWindowProc(hwnd,uMsg,wParam,lParam);
- break;
-
- case WM_CHAR:
- {
- byte theChar = static_cast<byte>(wParam & 0xff);
-
- // Alle Zeichen, die keine Steuerzeichen sind, werden als Buchstaben dem Input-Service mitgeteilt.
- if (theChar >= 32)
- {
- BS_InputEngine * InputPtr = BS_Kernel::GetInstance()->GetInput();
- if (InputPtr) InputPtr->ReportCharacter(theChar);
- }
- }
- break;
-
- case WM_SETCURSOR:
- {
- // Der Systemcursor wird in der Client-Area des Fensters nicht angezeigt, jedoch in der nicht Client-Area, damit der Benutzer das Fenster wie gewohnt
- // schließen und verschieben kann.
-
- // Koordinaten des Cursors in der Client-Area berechnen.
- POINT pt;
- GetCursorPos(&pt);
- ScreenToClient(hwnd, &pt);
-
- // Feststellen, ob sich der Cursor in der Client-Area befindet.
- // Get client rect
- RECT rc;
- GetClientRect(hwnd, &rc);
-
- // See if cursor is in client area
- if(PtInRect(&rc, pt))
- // In der Client-Area keinen Cursor anzeigen.
- SetCursor(NULL);
- else
- // Ausserhalb der Client-Area den Cursor anzeigen.
- SetCursor(LoadCursor(NULL, IDC_ARROW));
-
- return TRUE;
- }
- break;
-
- default:
- // Um alle anderen Vorkommnisse kümmert sich Windows
- return DefWindowProc(hwnd,uMsg,wParam,lParam);
- }
-
- return 0;
-}
-*/
-
-} // End of namespace Sword25
diff --git a/engines/sword25/kernel/scummvmwindow.h b/engines/sword25/kernel/scummvmwindow.h
deleted file mode 100644
index 2b5f514b7d..0000000000
--- a/engines/sword25/kernel/scummvmwindow.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-/*
- BS_ScummVMWindow
- ----------------
- Implementation of the BS_Window Interfaces for ScummVM
-*/
-
-#ifndef SWORD25_SCUMMVMWINDOW_H
-#define SWORD25_SCUMMVMWINDOW_H
-
-// Includes
-#include "sword25/kernel/common.h"
-#include "sword25/kernel/window.h"
-
-namespace Sword25 {
-
-// Class definition
-class ScummVMWindow : public Window {
-public:
- ScummVMWindow(int X, int Y, int Width, int Height, bool Visible);
- virtual ~ScummVMWindow();
-
- bool IsVisible();
- void SetVisible(bool Visible);
- int GetX();
- void SetX(int X);
- int GetY();
- void SetY(int X);
- int GetClientX();
- int GetClientY();
- int GetWidth();
- void SetWidth(int Width);
- int GetHeight();
- void SetHeight(int Height);
- Common::String GetTitle();
- void SetWindowAlive(bool v);
- void SetTitle(const Common::String &Title);
- bool HasFocus();
- uint GetWindowHandle();
- bool WaitForFocus();
- bool ProcessMessages();
-
-private:
- static bool _ClassRegistered;
- bool _WindowAlive;
- int _ClientXDelta;
- int _ClientYDelta;
-};
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/sword25/kernel/service.h b/engines/sword25/kernel/service.h
index addcf50a08..ef8858bb7d 100644
--- a/engines/sword25/kernel/service.h
+++ b/engines/sword25/kernel/service.h
@@ -60,14 +60,14 @@ private:
Kernel *_pKernel;
protected:
- Service(Kernel *pKernel) : _pKernel(pKernel) {};
+ Service(Kernel *pKernel) : _pKernel(pKernel) {}
Kernel *GetKernel() const {
return _pKernel;
}
public:
- virtual ~Service() {};
+ virtual ~Service() {}
};
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/service_ids.h b/engines/sword25/kernel/service_ids.h
deleted file mode 100644
index 5ffd83d743..0000000000
--- a/engines/sword25/kernel/service_ids.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-/*
- * service_ids.h
- * -------------
- * This file lists all the services.
- * EVERY new service needs to be entered here, otherwise it cannot be instantiated
- * by pKernel->NewService(..)
- *
- * Autor: Malte Thiesen
- */
-
-#ifndef SWORD25_SERVICE_IDS
-#define SWORD25_SERVICE_IDS
-
-#include "sword25/kernel/common.h"
-
-namespace Sword25 {
-
-Service *GraphicEngine_CreateObject(Kernel *pKernel);
-Service *PackageManager_CreateObject(Kernel *pKernel);
-Service *InputEngine_CreateObject(Kernel *pKernel);
-Service *SoundEngine_CreateObject(Kernel *pKernel);
-Service *LuaScriptEngine_CreateObject(Kernel *pKernel);
-Service *Geometry_CreateObject(Kernel *pKernel);
-Service *OggTheora_CreateObject(Kernel *pKernel);
-
-// Services are recorded in this table
-const BS_ServiceInfo BS_SERVICE_TABLE[] = {
- // The first two parameters are the name of the superclass and service
- // The third parameter is the static method of the class that creates an object
- // of the class and returns it
- // Example:
- // BS_ServiceInfo("Superclass", "Service", CreateMethod)
- BS_ServiceInfo("gfx", "opengl", GraphicEngine_CreateObject),
- BS_ServiceInfo("package", "archiveFS", PackageManager_CreateObject),
- BS_ServiceInfo("input", "winapi", InputEngine_CreateObject),
- BS_ServiceInfo("sfx", "fmodex", SoundEngine_CreateObject),
- BS_ServiceInfo("script", "lua", LuaScriptEngine_CreateObject),
- BS_ServiceInfo("geometry", "std", Geometry_CreateObject),
- BS_ServiceInfo("fmv", "oggtheora", OggTheora_CreateObject),
-};
-
-const uint BS_SERVICE_COUNT = sizeof(BS_SERVICE_TABLE) / sizeof(BS_ServiceInfo);
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/sword25/kernel/string.h b/engines/sword25/kernel/string.h
deleted file mode 100644
index b701e2312b..0000000000
--- a/engines/sword25/kernel/string.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-#ifndef SWORD25_STRING
-#define SWORD25_STRING
-
-#include "common/str.h"
-
-namespace BS_String {
-
-inline uint GetHash(const Common::String &Str) {
- uint Result = 0;
-
- for (uint i = 0; i < Str.size(); i++)
- Result = ((Result << 5) - Result) + Str[i];
-
- return Result;
-}
-
-inline bool ToInt(const Common::String &Str, int &Result) {
- Common::String::const_iterator Iter = Str.begin();
-
- // Skip whitespaces
- while (*Iter && (*Iter == ' ' || *Iter == '\t')) {
- ++Iter;
- }
- if (Iter == Str.end()) return false;
-
- // Read sign, if available
- bool IsNegative = false;
- if (*Iter == '-') {
- IsNegative = true;
- ++Iter;
- } else if (*Iter == '+')
- ++Iter;
-
- // Skip whitespaces
- while (*Iter && (*Iter == ' ' || *Iter == '\t')) {
- ++Iter;
- }
- if (Iter == Str.end()) return false;
-
- // Convert string to integer
- Result = 0;
- while (Iter != Str.end()) {
- if (*Iter < '0' || *Iter > '9') {
- while (*Iter && (*Iter == ' ' || *Iter == '\t')) {
- ++Iter;
- }
- if (Iter != Str.end()) return false;
- break;
- }
- Result = (Result * 10) + (*Iter - '0');
- ++Iter;
- }
-
- if (IsNegative) Result = -Result;
-
- return true;
-}
-
-inline bool ToBool(const Common::String &Str, bool &Result) {
- if (Str == "true" || Str == "TRUE") {
- Result = true;
- return true;
- } else if (Str == "false" || Str == "FALSE") {
- Result = false;
- return true;
- }
-
- return false;
-}
-
-inline void ToLower(Common::String &Str) {
- Str.toLowercase();
-}
-
-} // End of namespace BS_String
-
-#endif
diff --git a/engines/sword25/kernel/window.cpp b/engines/sword25/kernel/window.cpp
deleted file mode 100644
index 8d2dc309e7..0000000000
--- a/engines/sword25/kernel/window.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-#include "sword25/kernel/window.h"
-
-// Alle Implementationen von BS_Window müssen hier eingetragen werden
-#include "sword25/kernel/scummvmwindow.h"
-
-namespace Sword25 {
-
-// Erstellt ein Fenster des GUI des aktuellen Betriebssystems
-Window *Window::CreateBSWindow(int X, int Y, int Width, int Height, bool Visible) {
- // Fenster erstellen
- Window *pWindow = (Window *) new ScummVMWindow(X, Y, Width, Height, Visible);
-
- // Falls das Fenster erfolgreich initialisiert wurde, wird ein Pointer auf das Fensterobjekt
- // zurückgegeben
- if (pWindow->_InitSuccess)
- return pWindow;
-
- // Ansonsten wird das Fensterobjekt zerstört und NULL zurückgegeben
- delete pWindow;
- return NULL;
-}
-
-// Gibt True zurück wenn das Fenster WM_CLOSE empfangen hat -
-// solange, bis RejectClose() aufgerufen wurde.
-bool Window::CloseWanted() {
- bool result = _CloseWanted;
- _CloseWanted = false;
- return result;
-}
-
-void Window::SetCloseWanted(bool Wanted) {
- _CloseWanted = Wanted;
-}
-
-} // End of namespace Sword25
diff --git a/engines/sword25/kernel/window.h b/engines/sword25/kernel/window.h
deleted file mode 100644
index aee23087cb..0000000000
--- a/engines/sword25/kernel/window.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-/*
- * BS_Window
- * ---------
- * Simple window class interface. This is being encapsulated in a class for
- * reasons of portability.
- *
- * Autor: Malte Thiesen
- */
-
-#ifndef SWORD25_WINDOW_H
-#define SWORD25_WINDOW_H
-
-// Includes
-#include "sword25/kernel/common.h"
-
-namespace Sword25 {
-
-// Class definitions
-
-/**
- * A simple window class interface
- *
- * Windows are exclusively created by BS_Window::CreateBSWindow().
- * BS_Windows selects the correct class for the environment.
- */
-class Window {
-protected:
- bool _InitSuccess;
- bool _CloseWanted;
-
-public:
- virtual ~Window() {};
-
- /**
- * Returns the visibility of the window.
- */
- virtual bool IsVisible() = 0;
-
- /**
- * Sets the visibility of the window
- * @param Visible Specifies whether the window should be visible or hidden
- */
- virtual void SetVisible(bool Visible) = 0;
- /**
- * Returns the X position of the window
- */
- virtual int GetX() = 0;
- /**
- * Sets the X position of the window
- * @paramX The new X position for the window, or -1 for centre aligned
- */
- virtual void SetX(int X) = 0;
- /**
- * Gets the Y position of the window
- */
- virtual int GetY() = 0;
- /**
- * Sets the Y position of the window
- * @param Y The new Y position for the window, or -1 for centre aligned
- */
- virtual void SetY(int X) = 0;
- /**
- * Returns the X position of the window's client area
- */
- virtual int GetClientX() = 0;
- /**
- * Returns the Y position of the window's client area
- */
- virtual int GetClientY() = 0;
- /**
- * Returns the width of the window without the frame
- */
- virtual int GetWidth() = 0;
- /**
- * Sets the width of the window without the frame
- */
- virtual void SetWidth(int Width) = 0;
- /**
- * Gets the height of the window without the frame
- */
- virtual int GetHeight() = 0;
- /**
- * Sets the height of the window without the frame
- */
- virtual void SetHeight(int Height) = 0;
- /**
- * Returns the title of the window
- */
- virtual Common::String GetTitle() = 0;
- /**
- * Sets the title of the window
- * @param Title The new window title
- */
- virtual void SetTitle(const Common::String &Title) = 0;
- /**
- * Handle the processing of any pending window messages. This method should be called
- * during the main loop.
- */
- virtual bool ProcessMessages() = 0;
- /**
- * Pauses the applicaiton until the window has focus, or has been closed.
- * Returns false if the window was closed.
- */
- virtual bool WaitForFocus() = 0;
- /**
- * Returns true if the window has focus, false otherwise.
- */
- virtual bool HasFocus() = 0;
- /**
- * Returns the system handle that represents the window. Note that any use of the handle
- * will not be portable code.
- */
- virtual uint GetWindowHandle() = 0;
-
- virtual void SetWindowAlive(bool v) = 0;
-
- /**
- * Specifies whether the window is wanted to be closed. This is used together with CloseWanted()
- * to allow scripts to query when the main window should be closed, or the user is asking it to close
- **/
- void SetCloseWanted(bool Wanted);
- /**
- * Returns the previous value set in a call to SetCloseWanted.
- * Note that calling this also resets the value back to false, until such time as the SetCloseWanted()
- * method is called again.
- **/
- bool CloseWanted();
-
- /**
- * Creates a new window instance. Returns a pointer to the window, or NULL if the creation failed.
- * Note: It is the responsibility of the client to free the pointer when done with it.
- * @param X The X position of the window, or -1 for centre horizontal alignment
- * @param Y The Y position of the window, or -1 for centre vertical alignment
- * @param Width The width of the window without the frame
- * @param Height The height of the window without the frame
- * @param Visible Specifies whether window should be visible
- */
- static Window *CreateBSWindow(int X, int Y, int Width, int Height, bool Visible);
-};
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/sword25/math/geometry.cpp b/engines/sword25/math/geometry.cpp
index caa10160e9..bad6fcdb06 100644
--- a/engines/sword25/math/geometry.cpp
+++ b/engines/sword25/math/geometry.cpp
@@ -46,8 +46,4 @@ Geometry::Geometry(Kernel *pKernel) : Service(pKernel) {
}
-Service *Geometry_CreateObject(Kernel *pKernel) {
- return new Geometry(pKernel);
-}
-
} // End of namespace Sword25
diff --git a/engines/sword25/math/geometry_script.cpp b/engines/sword25/math/geometry_script.cpp
index dac766927b..8882d5e588 100644
--- a/engines/sword25/math/geometry_script.cpp
+++ b/engines/sword25/math/geometry_script.cpp
@@ -32,10 +32,6 @@
*
*/
-// -----------------------------------------------------------------------------
-// Includes
-// -----------------------------------------------------------------------------
-
#include "common/array.h"
#include "sword25/gfx/graphicengine.h"
#include "sword25/kernel/common.h"
@@ -205,7 +201,7 @@ static uint tableRegionToRegion(lua_State *L, const char *className) {
case LUA_TNUMBER: {
Polygon polygon;
tablePolygonToPolygon(L, polygon);
- RegionRegistry::getInstance().resolveHandle(regionHandle)->init(polygon);
+ RegionRegistry::instance().resolveHandle(regionHandle)->init(polygon);
}
break;
@@ -217,7 +213,7 @@ static uint tableRegionToRegion(lua_State *L, const char *className) {
int polygonCount = luaL_getn(L, -1);
if (polygonCount == 1)
- RegionRegistry::getInstance().resolveHandle(regionHandle)->init(polygon);
+ RegionRegistry::instance().resolveHandle(regionHandle)->init(polygon);
else {
Common::Array<Polygon> holes;
holes.reserve(polygonCount - 1);
@@ -230,7 +226,7 @@ static uint tableRegionToRegion(lua_State *L, const char *className) {
}
BS_ASSERT((int)holes.size() == polygonCount - 1);
- RegionRegistry::getInstance().resolveHandle(regionHandle)->init(polygon, &holes);
+ RegionRegistry::instance().resolveHandle(regionHandle)->init(polygon, &holes);
}
}
break;
@@ -283,7 +279,7 @@ static Region *checkRegion(lua_State *L) {
uint *regionHandlePtr;
if ((regionHandlePtr = reinterpret_cast<uint *>(my_checkudata(L, 1, REGION_CLASS_NAME))) != 0 ||
(regionHandlePtr = reinterpret_cast<uint *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) {
- return RegionRegistry::getInstance().resolveHandle(*regionHandlePtr);
+ return RegionRegistry::instance().resolveHandle(*regionHandlePtr);
} else {
luaL_argcheck(L, 0, 1, "'" REGION_CLASS_NAME "' expected");
}
@@ -364,13 +360,13 @@ static int r_setY(lua_State *L) {
}
static void drawPolygon(const Polygon &polygon, uint color, const Vertex &offset) {
- GraphicEngine *pGE = static_cast<GraphicEngine *>(Kernel::GetInstance()->GetService("gfx"));
+ GraphicEngine *pGE = Kernel::getInstance()->getGfx();
BS_ASSERT(pGE);
for (int i = 0; i < polygon.vertexCount - 1; i++)
- pGE->DrawDebugLine(polygon.vertices[i] + offset, polygon.vertices[i + 1] + offset, color);
+ pGE->drawDebugLine(polygon.vertices[i] + offset, polygon.vertices[i + 1] + offset, color);
- pGE->DrawDebugLine(polygon.vertices[polygon.vertexCount - 1] + offset, polygon.vertices[0] + offset, color);
+ pGE->drawDebugLine(polygon.vertices[polygon.vertexCount - 1] + offset, polygon.vertices[0] + offset, color);
}
static void drawRegion(const Region &region, uint color, const Vertex &offset) {
@@ -387,12 +383,12 @@ static int r_draw(lua_State *L) {
case 3: {
Vertex offset;
Vertex::luaVertexToVertex(L, 3, offset);
- drawRegion(*pR, GraphicEngine::LuaColorToARGBColor(L, 2), offset);
+ drawRegion(*pR, GraphicEngine::luaColorToARGBColor(L, 2), offset);
}
break;
case 2:
- drawRegion(*pR, GraphicEngine::LuaColorToARGBColor(L, 2), Vertex(0, 0));
+ drawRegion(*pR, GraphicEngine::luaColorToARGBColor(L, 2), Vertex(0, 0));
break;
default:
@@ -436,7 +432,7 @@ static WalkRegion *checkWalkRegion(lua_State *L) {
// The first parameter must be of type 'userdate', and the Metatable class Geo.WalkRegion
uint regionHandle;
if ((regionHandle = *reinterpret_cast<uint *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) {
- return reinterpret_cast<WalkRegion *>(RegionRegistry::getInstance().resolveHandle(regionHandle));
+ return reinterpret_cast<WalkRegion *>(RegionRegistry::instance().resolveHandle(regionHandle));
} else {
luaL_argcheck(L, 0, 1, "'" WALKREGION_CLASS_NAME "' expected");
}
@@ -474,9 +470,9 @@ static const luaL_reg WALKREGION_METHODS[] = {
};
bool Geometry::registerScriptBindings() {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ScriptEngine *pScript = static_cast<ScriptEngine *>(pKernel->GetService("script"));
+ ScriptEngine *pScript = pKernel->getScript();
BS_ASSERT(pScript);
lua_State *L = static_cast< lua_State *>(pScript->getScriptObject());
BS_ASSERT(L);
diff --git a/engines/sword25/math/polygon.cpp b/engines/sword25/math/polygon.cpp
index 700c375e8c..a83a8aa1dd 100644
--- a/engines/sword25/math/polygon.cpp
+++ b/engines/sword25/math/polygon.cpp
@@ -49,7 +49,7 @@ Polygon::Polygon(int vertexCount_, const Vertex *vertices_) : vertexCount(0), ve
init(vertexCount_, vertices_);
}
-Polygon::Polygon(const Polygon &other) : vertexCount(0), vertices(NULL) {
+Polygon::Polygon(const Polygon &other) : Persistable(other), vertexCount(0), vertices(NULL) {
init(other.vertexCount, other.vertices);
}
diff --git a/engines/sword25/math/polygon.h b/engines/sword25/math/polygon.h
index 3bd243f666..1b2a0b191c 100644
--- a/engines/sword25/math/polygon.h
+++ b/engines/sword25/math/polygon.h
@@ -193,6 +193,11 @@ public:
virtual bool persist(OutputPersistenceBlock &writer);
virtual bool unpersist(InputPersistenceBlock &reader);
+ Polygon &operator=(const Polygon &p) {
+ init(p.vertexCount, p.vertices);
+ return *this;
+ }
+
private:
bool _isCW;
bool _isConvex;
diff --git a/engines/sword25/math/region.cpp b/engines/sword25/math/region.cpp
index 454f90a8ba..ae9b76d077 100644
--- a/engines/sword25/math/region.cpp
+++ b/engines/sword25/math/region.cpp
@@ -44,11 +44,11 @@
namespace Sword25 {
Region::Region() : _valid(false), _type(RT_REGION) {
- RegionRegistry::getInstance().registerObject(this);
+ RegionRegistry::instance().registerObject(this);
}
Region::Region(InputPersistenceBlock &reader, uint handle) : _valid(false), _type(RT_REGION) {
- RegionRegistry::getInstance().registerObject(this, handle);
+ RegionRegistry::instance().registerObject(this, handle);
unpersist(reader);
}
@@ -67,7 +67,7 @@ uint Region::create(REGION_TYPE type) {
BS_ASSERT(true);
}
- return RegionRegistry::getInstance().resolvePtr(regionPtr);
+ return RegionRegistry::instance().resolvePtr(regionPtr);
}
uint Region::create(InputPersistenceBlock &reader, uint handle) {
@@ -85,11 +85,11 @@ uint Region::create(InputPersistenceBlock &reader, uint handle) {
BS_ASSERT(false);
}
- return RegionRegistry::getInstance().resolvePtr(regionPtr);
+ return RegionRegistry::instance().resolvePtr(regionPtr);
}
Region::~Region() {
- RegionRegistry::getInstance().deregisterObject(this);
+ RegionRegistry::instance().deregisterObject(this);
}
bool Region::init(const Polygon &contour, const Common::Array<Polygon> *pHoles) {
diff --git a/engines/sword25/math/regionregistry.cpp b/engines/sword25/math/regionregistry.cpp
index 1509ea9e5e..40909aebad 100644
--- a/engines/sword25/math/regionregistry.cpp
+++ b/engines/sword25/math/regionregistry.cpp
@@ -39,9 +39,9 @@
#include "sword25/math/regionregistry.h"
#include "sword25/math/region.h"
-namespace Sword25 {
+DECLARE_SINGLETON(Sword25::RegionRegistry)
-Common::SharedPtr<RegionRegistry> RegionRegistry::_instancePtr;
+namespace Sword25 {
void RegionRegistry::logErrorLn(const char *message) const {
BS_LOG_ERRORLN(message);
diff --git a/engines/sword25/math/regionregistry.h b/engines/sword25/math/regionregistry.h
index bbe2fb8370..560d4ae4a9 100644
--- a/engines/sword25/math/regionregistry.h
+++ b/engines/sword25/math/regionregistry.h
@@ -35,7 +35,8 @@
#ifndef SWORD25_REGIONREGISTRY_H
#define SWORD25_REGIONREGISTRY_H
-#include "common/ptr.h"
+#include "common/singleton.h"
+
#include "sword25/kernel/common.h"
#include "sword25/kernel/persistable.h"
#include "sword25/kernel/objectregistry.h"
@@ -44,21 +45,17 @@ namespace Sword25 {
class Region;
-class RegionRegistry : public ObjectRegistry<Region>, public Persistable {
+class RegionRegistry :
+ public ObjectRegistry<Region>,
+ public Persistable,
+ public Common::Singleton<RegionRegistry> {
public:
- static RegionRegistry &getInstance() {
- if (!_instancePtr.get()) _instancePtr = Common::SharedPtr<RegionRegistry>(new RegionRegistry());
- return *_instancePtr.get();
- }
-
virtual bool persist(OutputPersistenceBlock &writer);
virtual bool unpersist(InputPersistenceBlock &reader);
private:
virtual void logErrorLn(const char *message) const;
virtual void logWarningLn(const char *message) const;
-
- static Common::SharedPtr<RegionRegistry> _instancePtr;
};
} // End of namespace Sword25
diff --git a/engines/sword25/math/vertex.cpp b/engines/sword25/math/vertex.cpp
index 4997da09d3..d9a709ab49 100644
--- a/engines/sword25/math/vertex.cpp
+++ b/engines/sword25/math/vertex.cpp
@@ -34,15 +34,8 @@
#include "sword25/math/vertex.h"
-namespace Lua {
-
-extern "C"
-{
#include "sword25/util/lua/lua.h"
#include "sword25/util/lua/lauxlib.h"
-}
-
-}
namespace Sword25 {
diff --git a/engines/sword25/math/vertex.h b/engines/sword25/math/vertex.h
index 87e4694d48..b923841a0f 100644
--- a/engines/sword25/math/vertex.h
+++ b/engines/sword25/math/vertex.h
@@ -45,15 +45,24 @@
// Includes
#include <math.h>
#include "sword25/kernel/common.h"
-
-namespace Lua {
-
-// Forward declarations
-struct lua_State;
-
-}
-
-using namespace Lua;
+#include "sword25/util/lua/lua.h"
+
+#if defined(MACOSX) || defined(SOLARIS) || defined(__MINGW32__)
+// Older versions of Mac OS X didn't supply a powf function, so using it
+// will cause a binary incompatibility when trying to run a binary built
+// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide
+// powf, floorf, fabsf etc. at all.
+// Cross-compiled MinGW32 toolchains suffer from a cross-compile bug in
+// libstdc++. math/stubs.o should be empty, but it comes with a symbol for
+// powf, resulting in a linker error because of multiple definitions.
+// Hence we re-define them here. The only potential drawback is that it
+// might be a little bit slower this way.
+#define powf(x,y) ((float)pow(x,y))
+#define floorf(x) ((float)floor(x))
+#define fabsf(x) ((float)fabs(x))
+#define sqrtf(x) ((float)sqrt(x))
+#define atan2f(x,y) ((float)atan2(x,y))
+#endif
namespace Sword25 {
@@ -62,7 +71,7 @@ namespace Sword25 {
*/
class Vertex {
public:
- Vertex() : x(0), y(0) {};
+ Vertex() : x(0), y(0) {}
Vertex(int x_, int y_) {
this->x = x_;
this->y = y_;
diff --git a/engines/sword25/math/walkregion.cpp b/engines/sword25/math/walkregion.cpp
index 7cdd8c64c5..51818bc9e8 100644
--- a/engines/sword25/math/walkregion.cpp
+++ b/engines/sword25/math/walkregion.cpp
@@ -95,7 +95,7 @@ struct DijkstraNode {
typedef Container::iterator Iter;
typedef Container::const_iterator ConstIter;
- DijkstraNode() : cost(Infinity), chosen(false) {};
+ DijkstraNode() : cost(Infinity), chosen(false) {}
ConstIter parentIter;
int cost;
bool chosen;
@@ -164,6 +164,17 @@ static void relaxEndPoint(const Vertex &curNodePos,
}
}
+template<class T>
+void reverseArray(Common::Array<T> &arr) {
+ const uint size = arr.size();
+ if (size < 2)
+ return;
+
+ for (uint i = 0; i <= (size / 2 - 1); ++i) {
+ SWAP(arr[i], arr[size - i - 1]);
+ }
+}
+
bool WalkRegion::findPath(const Vertex &start, const Vertex &end, BS_Path &path) const {
// This is an implementation of Dijkstra's algorithm
@@ -205,7 +216,7 @@ bool WalkRegion::findPath(const Vertex &start, const Vertex &end, BS_Path &path)
// The nodes of the path must be untwisted, as they were extracted in reverse order.
// This step could be saved if the path from end to the beginning was desired
- ReverseArray<Vertex>(path);
+ reverseArray<Vertex>(path);
return true;
}
diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk
index ebe50976af..f10c6be5a9 100644
--- a/engines/sword25/module.mk
+++ b/engines/sword25/module.mk
@@ -5,8 +5,6 @@ MODULE_OBJS := \
sword25.o \
fmv/movieplayer.o \
fmv/movieplayer_script.o \
- fmv/theora_decoder.o \
- fmv/yuvtorgba.o \
gfx/animation.o \
gfx/animationdescription.o \
gfx/animationresource.o \
@@ -28,8 +26,6 @@ MODULE_OBJS := \
gfx/text.o \
gfx/timedrenderobject.o \
gfx/image/art.o \
- gfx/image/b25sloader.o \
- gfx/image/imageloader.o \
gfx/image/pngloader.o \
gfx/image/renderedimage.o \
gfx/image/swimage.o \
@@ -37,7 +33,6 @@ MODULE_OBJS := \
gfx/image/vectorimagerenderer.o \
input/inputengine.o \
input/inputengine_script.o \
- kernel/callbackregistry.o \
kernel/filesystemutil.o \
kernel/inputpersistenceblock.o \
kernel/kernel.o \
@@ -47,8 +42,6 @@ MODULE_OBJS := \
kernel/persistenceservice.o \
kernel/resmanager.o \
kernel/resource.o \
- kernel/scummvmwindow.o \
- kernel/window.o \
math/geometry.o \
math/geometry_script.o \
math/polygon.o \
@@ -90,8 +83,6 @@ MODULE_OBJS := \
util/lua/ltable.o \
util/lua/ltablib.o \
util/lua/ltm.o \
- util/lua/lua.o \
- util/lua/luac.o \
util/lua/lundump.o \
util/lua/lvm.o \
util/lua/lzio.o \
@@ -100,6 +91,12 @@ MODULE_OBJS := \
util/pluto/pluto.o \
util/pluto/plzio.o
+ifdef USE_THEORADEC
+MODULE_OBJS += \
+ fmv/theora_decoder.o \
+ fmv/yuvtorgba.o
+endif
+
# This module can be built as a plugin
ifeq ($(ENABLE_SWORD25), DYNAMIC_PLUGIN)
PLUGIN := 1
diff --git a/engines/sword25/package/packagemanager.cpp b/engines/sword25/package/packagemanager.cpp
index 063844f3ba..4765d26ed4 100644
--- a/engines/sword25/package/packagemanager.cpp
+++ b/engines/sword25/package/packagemanager.cpp
@@ -75,10 +75,6 @@ PackageManager::~PackageManager() {
}
-Service *PackageManager_CreateObject(Kernel *kernelPtr) {
- return new PackageManager(kernelPtr);
-}
-
/**
* Scans through the archive list for a specified file
*/
@@ -154,13 +150,13 @@ byte *PackageManager::getFile(const Common::String &fileName, uint *fileSizePtr)
// Savegame loading logic
Common::SaveFileManager *sfm = g_system->getSavefileManager();
Common::InSaveFile *file = sfm->openForLoading(
- FileSystemUtil::GetInstance().GetPathFilename(fileName));
+ FileSystemUtil::getPathFilename(fileName));
if (!file) {
BS_LOG_ERRORLN("Could not load savegame \"%s\".", fileName.c_str());
return 0;
}
- if (*fileSizePtr)
+ if (fileSizePtr)
*fileSizePtr = file->size();
byte *buffer = new byte[file->size()];
@@ -186,7 +182,7 @@ byte *PackageManager::getFile(const Common::String &fileName, uint *fileSizePtr)
delete in;
if (!bytesRead) {
- delete buffer;
+ delete[] buffer;
return NULL;
}
@@ -218,27 +214,14 @@ Common::String PackageManager::getAbsolutePath(const Common::String &fileName) {
return normalizePath(fileName, _currentDirectory);
}
-uint PackageManager::getFileSize(const Common::String &fileName) {
- Common::SeekableReadStream *in;
- Common::ArchiveMemberPtr fileNode = getArchiveMember(normalizePath(fileName, _currentDirectory));
- if (!fileNode)
- return 0;
- if (!(in = fileNode->createReadStream()))
- return 0;
-
- uint fileSize = in->size();
-
- return fileSize;
-}
-
-uint PackageManager::getFileType(const Common::String &fileName) {
- warning("STUB: BS_PackageManager::GetFileType(%s)", fileName.c_str());
-
- //return fileNode.isDirectory() ? BS_PackageManager::FT_DIRECTORY : BS_PackageManager::FT_FILE;
- return PackageManager::FT_FILE;
-}
-
bool PackageManager::fileExists(const Common::String &fileName) {
+ // FIXME: The current Zip implementation doesn't support getting a folder entry, which is needed for detecting
+ // the English voick pack
+ if (fileName == "/speech/en") {
+ // To get around this, change to detecting one of the files in the folder
+ return getArchiveMember(normalizePath(fileName + "/APO0001.ogg", _currentDirectory));
+ }
+
Common::ArchiveMemberPtr fileNode = getArchiveMember(normalizePath(fileName, _currentDirectory));
return fileNode;
}
diff --git a/engines/sword25/package/packagemanager.h b/engines/sword25/package/packagemanager.h
index 96f136dd83..03598012a6 100644
--- a/engines/sword25/package/packagemanager.h
+++ b/engines/sword25/package/packagemanager.h
@@ -190,23 +190,6 @@ public:
int doSearch(Common::ArchiveMemberList &list, const Common::String &filter, const Common::String &path, uint typeFilter = FT_DIRECTORY | FT_FILE);
/**
- * Returns a file's size
- * @param FileName The filename
- * @return The file size. If an error occurs, then 0xffffffff is returned.
- * @remarks For files in packages, then uncompressed size is returned.
- **/
- uint getFileSize(const Common::String &fileName);
-
- /**
- * Returns the type of a file.
- * @param FileName The filename
- * @return Returns the file type, either (BS_PackageManager::FT_DIRECTORY
- * or BS_PackageManager::FT_FILE).
- * If the file was not found, then 0 is returned.
- */
- uint getFileType(const Common::String &fileName);
-
- /**
* Determines whether a file exists
* @param FileName The filename
* @return Returns true if the file exists, otherwise false.
diff --git a/engines/sword25/package/packagemanager_script.cpp b/engines/sword25/package/packagemanager_script.cpp
index cfcea55944..9367ae3071 100644
--- a/engines/sword25/package/packagemanager_script.cpp
+++ b/engines/sword25/package/packagemanager_script.cpp
@@ -41,12 +41,10 @@
namespace Sword25 {
-using namespace Lua;
-
static PackageManager *getPM() {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- PackageManager *pPM = static_cast<PackageManager *>(pKernel->GetService("package"));
+ PackageManager *pPM = pKernel->getPackage();
BS_ASSERT(pPM);
return pPM;
}
@@ -92,17 +90,15 @@ static int getAbsolutePath(lua_State *L) {
}
static int getFileSize(lua_State *L) {
- PackageManager *pPM = getPM();
-
- lua_pushnumber(L, pPM->getFileSize(luaL_checkstring(L, 1)));
+ // This function apparently is not used by the game scripts
+ lua_pushnumber(L, 0);
return 1;
}
static int getFileType(lua_State *L) {
- PackageManager *pPM = getPM();
-
- lua_pushnumber(L, pPM->getFileType(luaL_checkstring(L, 1)));
+ // This function apparently is not used by the game scripts
+ lua_pushnumber(L, 0);
return 1;
}
@@ -199,9 +195,9 @@ static const luaL_reg PACKAGE_FUNCTIONS[] = {
};
bool PackageManager::registerScriptBindings() {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ScriptEngine *pScript = static_cast<ScriptEngine *>(pKernel->GetService("script"));
+ ScriptEngine *pScript = pKernel->getScript();
BS_ASSERT(pScript);
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
BS_ASSERT(L);
diff --git a/engines/sword25/script/lua_extensions.cpp b/engines/sword25/script/lua_extensions.cpp
index 3c0d4570a2..25a43e17d2 100644
--- a/engines/sword25/script/lua_extensions.cpp
+++ b/engines/sword25/script/lua_extensions.cpp
@@ -47,7 +47,7 @@ static int warning(lua_State *L) {
lua_pushstring(L, "WARNING - ");
lua_pushvalue(L, 1);
lua_concat(L, 3);
- BS_Log::Log("%s\n", luaL_checkstring(L, -1));
+ BS_Log::log("%s\n", luaL_checkstring(L, -1));
lua_pop(L, 1);
#ifdef DEBUG
diff --git a/engines/sword25/script/luabindhelper.h b/engines/sword25/script/luabindhelper.h
index 0dbaaa3186..dc45104d53 100644
--- a/engines/sword25/script/luabindhelper.h
+++ b/engines/sword25/script/luabindhelper.h
@@ -37,17 +37,8 @@
#include "sword25/kernel/common.h"
-namespace Lua {
-
-extern "C"
-{
#include "sword25/util/lua/lua.h"
#include "sword25/util/lua/lauxlib.h"
-}
-
-}
-
-using namespace Lua;
namespace Sword25 {
diff --git a/engines/sword25/script/luacallback.cpp b/engines/sword25/script/luacallback.cpp
index 6d2e634632..bb2c821aa8 100644
--- a/engines/sword25/script/luacallback.cpp
+++ b/engines/sword25/script/luacallback.cpp
@@ -35,18 +35,11 @@
#include "sword25/script/luacallback.h"
#include "sword25/script/luabindhelper.h"
-namespace Lua {
-
-extern "C"
-{
#include "sword25/util/lua/lua.h"
#include "sword25/util/lua/lauxlib.h"
-}
const char *CALLBACKTABLE_NAME = "__CALLBACKS";
-}
-
namespace Sword25 {
#define BS_LOG_PREFIX "LUA"
diff --git a/engines/sword25/script/luacallback.h b/engines/sword25/script/luacallback.h
index 0a5dec17d9..e097f5b499 100644
--- a/engines/sword25/script/luacallback.h
+++ b/engines/sword25/script/luacallback.h
@@ -37,14 +37,8 @@
#include "sword25/kernel/common.h"
-namespace Lua {
-
struct lua_State;
-}
-
-using namespace Lua;
-
namespace Sword25 {
class LuaCallback {
diff --git a/engines/sword25/script/luascript.cpp b/engines/sword25/script/luascript.cpp
index 82166f7c25..aa2bdb9e06 100644
--- a/engines/sword25/script/luascript.cpp
+++ b/engines/sword25/script/luascript.cpp
@@ -45,21 +45,13 @@
#include "sword25/kernel/outputpersistenceblock.h"
#include "sword25/kernel/inputpersistenceblock.h"
-namespace Lua {
-
-extern "C" {
#include "sword25/util/lua/lua.h"
#include "sword25/util/lua/lualib.h"
#include "sword25/util/lua/lauxlib.h"
#include "sword25/util/pluto/pluto.h"
-}
-
-}
namespace Sword25 {
-using namespace Lua;
-
LuaScriptEngine::LuaScriptEngine(Kernel *KernelPtr) :
ScriptEngine(KernelPtr),
_state(0),
@@ -72,10 +64,6 @@ LuaScriptEngine::~LuaScriptEngine() {
lua_close(_state);
}
-Service *LuaScriptEngine_CreateObject(Kernel *KernelPtr) {
- return new LuaScriptEngine(KernelPtr);
-}
-
namespace {
int panicCB(lua_State *L) {
BS_LOG_ERRORLN("Lua panic. Error message: %s", lua_isnil(L, -1) ? "" : lua_tostring(L, -1));
@@ -159,7 +147,7 @@ bool LuaScriptEngine::executeFile(const Common::String &fileName) {
debug(2, "LuaScriptEngine::executeFile(%s)", fileName.c_str());
// Get a pointer to the package manager
- PackageManager *pPackage = static_cast<PackageManager *>(Kernel::GetInstance()->GetService("package"));
+ PackageManager *pPackage = Kernel::getInstance()->getPackage();
BS_ASSERT(pPackage);
// File read
@@ -431,7 +419,7 @@ bool LuaScriptEngine::persist(OutputPersistenceBlock &writer) {
pluto_persist(_state, chunkwriter, &chunkData);
// Persistenzdaten in den Writer schreiben.
- writer.write(&chunkData[0], chunkData.size());
+ writer.writeByteArray(chunkData);
// Die beiden Tabellen vom Stack nehmen.
lua_pop(_state, 2);
@@ -528,7 +516,7 @@ bool LuaScriptEngine::unpersist(InputPersistenceBlock &reader) {
// Persisted Lua data
Common::Array<byte> chunkData;
- reader.read(chunkData);
+ reader.readByteArray(chunkData);
// Chunk-Reader initialisation. It is used with pluto_unpersist to restore read data
ChunkreaderData cd;
diff --git a/engines/sword25/script/luascript.h b/engines/sword25/script/luascript.h
index f557ae45f1..b66c32176a 100644
--- a/engines/sword25/script/luascript.h
+++ b/engines/sword25/script/luascript.h
@@ -39,14 +39,7 @@
#include "common/str-array.h"
#include "sword25/kernel/common.h"
#include "sword25/script/script.h"
-
-namespace Lua {
-
-struct lua_State;
-
-}
-
-using namespace Lua;
+#include "sword25/util/lua/lua.h"
namespace Sword25 {
diff --git a/engines/sword25/script/script.h b/engines/sword25/script/script.h
index 2f72cf0cc8..9ca146026e 100644
--- a/engines/sword25/script/script.h
+++ b/engines/sword25/script/script.h
@@ -49,8 +49,8 @@ class BS_InputPersistenceBlock;
class ScriptEngine : public Service, public Persistable {
public:
- ScriptEngine(Kernel *KernelPtr) : Service(KernelPtr) {};
- virtual ~ScriptEngine() {};
+ ScriptEngine(Kernel *KernelPtr) : Service(KernelPtr) {}
+ virtual ~ScriptEngine() {}
// -----------------------------------------------------------------------------
// This method must be implemented by the script engine
diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp
index c753afd9b9..fa39639f51 100644
--- a/engines/sword25/sfx/soundengine.cpp
+++ b/engines/sword25/sfx/soundengine.cpp
@@ -67,10 +67,6 @@ SoundEngine::SoundEngine(Kernel *pKernel) : ResourceService(pKernel) {
_handles[i].type = kFreeHandle;
}
-Service *SoundEngine_CreateObject(Kernel *pKernel) {
- return new SoundEngine(pKernel);
-}
-
bool SoundEngine::init(uint sampleRate, uint channels) {
warning("STUB: SoundEngine::init(%d, %d)", sampleRate, channels);
@@ -157,7 +153,7 @@ bool SoundEngine::playSound(const Common::String &fileName, SOUND_TYPES type, fl
}
uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer) {
- Common::SeekableReadStream *in = Kernel::GetInstance()->GetPackage()->getStream(fileName);
+ Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(fileName);
Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES);
uint id;
SndHandle *handle = getHandle(&id);
diff --git a/engines/sword25/sfx/soundengine.h b/engines/sword25/sfx/soundengine.h
index 81383b12cb..b8c10cc293 100644
--- a/engines/sword25/sfx/soundengine.h
+++ b/engines/sword25/sfx/soundengine.h
@@ -88,7 +88,7 @@ public:
typedef void (*DynamicSoundReadCallback)(void *UserData, void *Data, uint DataLength);
SoundEngine(Kernel *pKernel);
- ~SoundEngine() {};
+ ~SoundEngine() {}
/**
* Initialises the sound engine
diff --git a/engines/sword25/sfx/soundengine_script.cpp b/engines/sword25/sfx/soundengine_script.cpp
index 2808296799..eabbef6e5e 100644
--- a/engines/sword25/sfx/soundengine_script.cpp
+++ b/engines/sword25/sfx/soundengine_script.cpp
@@ -46,9 +46,9 @@
namespace Sword25 {
static int init(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
if (lua_gettop(L) == 0)
@@ -62,9 +62,9 @@ static int init(lua_State *L) {
}
static int update(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->update();
@@ -73,9 +73,9 @@ static int update(lua_State *L) {
}
static int setVolume(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->setVolume(static_cast<float>(luaL_checknumber(L, 1)),
@@ -85,9 +85,9 @@ static int setVolume(lua_State *L) {
}
static int getVolume(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
lua_pushnumber(L, pSfx->getVolume(static_cast<SoundEngine::SOUND_TYPES>(static_cast<uint>(luaL_checknumber(L, 1)))));
@@ -96,9 +96,9 @@ static int getVolume(lua_State *L) {
}
static int pauseAll(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->pauseAll();
@@ -107,9 +107,9 @@ static int pauseAll(lua_State *L) {
}
static int resumeAll(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->resumeAll();
@@ -118,9 +118,9 @@ static int resumeAll(lua_State *L) {
}
static int pauseLayer(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->pauseLayer(static_cast<int>(luaL_checknumber(L, 1)));
@@ -129,9 +129,9 @@ static int pauseLayer(lua_State *L) {
}
static int resumeLayer(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->resumeLayer(static_cast<int>(luaL_checknumber(L, 1)));
@@ -176,9 +176,9 @@ static void processPlayParams(lua_State *L, Common::String &fileName, SoundEngin
}
static int playSound(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
Common::String fileName;
@@ -197,9 +197,9 @@ static int playSound(lua_State *L) {
}
static int playSoundEx(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
Common::String fileName;
@@ -218,9 +218,9 @@ static int playSoundEx(lua_State *L) {
}
static int setSoundVolume(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->setSoundVolume(static_cast<uint>(luaL_checknumber(L, 1)), static_cast<float>(luaL_checknumber(L, 2)));
@@ -229,9 +229,9 @@ static int setSoundVolume(lua_State *L) {
}
static int setSoundPanning(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->setSoundPanning(static_cast<uint>(luaL_checknumber(L, 1)), static_cast<float>(luaL_checknumber(L, 2)));
@@ -240,9 +240,9 @@ static int setSoundPanning(lua_State *L) {
}
static int pauseSound(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->pauseSound(static_cast<uint>(luaL_checknumber(L, 1)));
@@ -251,9 +251,9 @@ static int pauseSound(lua_State *L) {
}
static int resumeSound(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->resumeSound(static_cast<uint>(luaL_checknumber(L, 1)));
@@ -262,9 +262,9 @@ static int resumeSound(lua_State *L) {
}
static int stopSound(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
pSfx->stopSound(static_cast<uint>(luaL_checknumber(L, 1)));
@@ -273,9 +273,9 @@ static int stopSound(lua_State *L) {
}
static int isSoundPaused(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
lua_pushbooleancpp(L, pSfx->isSoundPaused(static_cast<uint>(luaL_checknumber(L, 1))));
@@ -284,9 +284,9 @@ static int isSoundPaused(lua_State *L) {
}
static int isSoundPlaying(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
lua_pushbooleancpp(L, pSfx->isSoundPlaying(static_cast<uint>(luaL_checknumber(L, 1))));
@@ -295,9 +295,9 @@ static int isSoundPlaying(lua_State *L) {
}
static int getSoundVolume(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
lua_pushnumber(L, pSfx->getSoundVolume(static_cast<uint>(luaL_checknumber(L, 1))));
@@ -306,9 +306,9 @@ static int getSoundVolume(lua_State *L) {
}
static int getSoundPanning(lua_State *L) {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- SoundEngine *pSfx = static_cast<SoundEngine *>(Kernel::GetInstance()->GetService("sfx"));
+ SoundEngine *pSfx = pKernel->getSfx();
BS_ASSERT(pSfx);
lua_pushnumber(L, pSfx->getSoundPanning(static_cast<uint>(luaL_checknumber(L, 1))));
@@ -349,9 +349,9 @@ static const lua_constant_reg SFX_CONSTANTS[] = {
};
bool SoundEngine::registerScriptBindings() {
- Kernel *pKernel = Kernel::GetInstance();
+ Kernel *pKernel = Kernel::getInstance();
BS_ASSERT(pKernel);
- ScriptEngine *pScript = static_cast<ScriptEngine *>(pKernel->GetService("script"));
+ ScriptEngine *pScript = pKernel->getScript();
BS_ASSERT(pScript);
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
BS_ASSERT(L);
diff --git a/engines/sword25/sword25.cpp b/engines/sword25/sword25.cpp
index 4e99ade25d..5864057423 100644
--- a/engines/sword25/sword25.cpp
+++ b/engines/sword25/sword25.cpp
@@ -39,9 +39,14 @@
#include "sword25/sword25.h"
#include "sword25/kernel/filesystemutil.h"
#include "sword25/kernel/kernel.h"
+#include "sword25/kernel/persistenceservice.h"
#include "sword25/package/packagemanager.h"
#include "sword25/script/script.h"
+#include "sword25/gfx/animationtemplateregistry.h" // Needed so we can destroy the singleton
+#include "sword25/gfx/renderobjectregistry.h" // Needed so we can destroy the singleton
+#include "sword25/math/regionregistry.h" // Needed so we can destroy the singleton
+
namespace Sword25 {
#define BS_LOG_PREFIX "MAIN"
@@ -49,10 +54,6 @@ namespace Sword25 {
const char *const PACKAGE_MANAGER = "archiveFS";
const char *const DEFAULT_SCRIPT_FILE = "/system/boot.lua";
-void logToStdout(const char *Message) {
- debugN(0, "%s", Message);
-}
-
Sword25Engine::Sword25Engine(OSystem *syst, const ADGameDescription *gameDesc):
Engine(syst),
_gameDescription(gameDesc) {
@@ -83,9 +84,6 @@ Common::Error Sword25Engine::run() {
}
Common::Error Sword25Engine::appStart() {
- // All log messages will be sent to StdOut
- BS_Log::RegisterLogListener(logToStdout);
-
// Initialise the graphics mode to ARGB8888
Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
initGraphics(800, 600, true, &format);
@@ -93,19 +91,13 @@ Common::Error Sword25Engine::appStart() {
return Common::kUnsupportedColorMode;
// Kernel initialization
- if (!Kernel::GetInstance()->GetInitSuccess()) {
+ if (!Kernel::getInstance()->getInitSuccess()) {
BS_LOG_ERRORLN("Kernel initialization failed.");
return Common::kUnknownError;
}
- // Package-Manager starten, damit die Packfiles geladen werden können.
- PackageManager *packageManagerPtr = static_cast<PackageManager *>(Kernel::GetInstance()->NewService("package", PACKAGE_MANAGER));
- if (!packageManagerPtr) {
- BS_LOG_ERRORLN("PackageManager initialization failed.");
- return Common::kUnknownError;
- }
-
- // Packages laden oder das aktuelle Verzeichnis mounten, wenn das über Kommandozeile angefordert wurde.
+ // Load packages
+ PackageManager *packageManagerPtr = Kernel::getInstance()->getPackage();
if (getGameFlags() & GF_EXTRACTED) {
if (!packageManagerPtr->loadDirectoryAsPackage(ConfMan.get("path"), "/"))
return Common::kUnknownError;
@@ -114,13 +106,16 @@ Common::Error Sword25Engine::appStart() {
return Common::kUnknownError;
}
- // Einen Pointer auf den Skript-Engine holen.
- ScriptEngine *scriptPtr = static_cast<ScriptEngine *>(Kernel::GetInstance()->GetService("script"));
+ // Pass the command line to the script engine.
+ ScriptEngine *scriptPtr = Kernel::getInstance()->getScript();
if (!scriptPtr) {
BS_LOG_ERRORLN("Script intialization failed.");
return Common::kUnknownError;
}
+ // Set the game target for use in savegames
+ setGameTarget(_targetName.c_str());
+
Common::StringArray commandParameters;
scriptPtr->setCommandLine(commandParameters);
@@ -129,7 +124,7 @@ Common::Error Sword25Engine::appStart() {
bool Sword25Engine::appMain() {
// The main script start. This script loads all the other scripts and starts the actual game.
- ScriptEngine *scriptPtr = static_cast<ScriptEngine *>(Kernel::GetInstance()->GetService("script"));
+ ScriptEngine *scriptPtr = Kernel::getInstance()->getScript();
BS_ASSERT(scriptPtr);
scriptPtr->executeFile(DEFAULT_SCRIPT_FILE);
@@ -138,20 +133,25 @@ bool Sword25Engine::appMain() {
bool Sword25Engine::appEnd() {
// The kernel is shutdown, and un-initialises all subsystems
- Kernel::DeleteInstance();
+ Kernel::deleteInstance();
+
+ AnimationTemplateRegistry::destroy();
+ RenderObjectRegistry::destroy();
+ RegionRegistry::destroy();
// Free the log file if it was used
- BS_Log::_CloseLog();
+ BS_Log::closeLog();
return true;
}
bool Sword25Engine::loadPackages() {
- PackageManager *packageManagerPtr = reinterpret_cast<PackageManager *>(Kernel::GetInstance()->GetService("package"));
+ PackageManager *packageManagerPtr = Kernel::getInstance()->getPackage();
BS_ASSERT(packageManagerPtr);
// Load the main package
- if (!packageManagerPtr->loadPackage("data.b25c", "/")) return false;
+ if (!packageManagerPtr->loadPackage("data.b25c", "/"))
+ return false;
// Get the contents of the main program directory and sort them alphabetically
Common::FSNode dir(ConfMan.get("path"));
@@ -163,7 +163,7 @@ bool Sword25Engine::loadPackages() {
Common::sort(files.begin(), files.end());
- // Identity all patch packages
+ // Identify all patch packages
// The filename of patch packages must have the form patch??.b25c, with the question marks
// are placeholders for numbers.
// Since the filenames have been sorted, patches are mounted with low numbers first, through
@@ -175,7 +175,7 @@ bool Sword25Engine::loadPackages() {
return false;
}
- // Identity and mount all language packages
+ // Identify and mount all language packages
// The filename of the packages have the form lang_*.b25c (eg. lang_de.b25c)
for (Common::FSList::const_iterator it = files.begin(); it != files.end(); ++it) {
if (it->getName().matchString("lang_*.b25c", true))
@@ -186,4 +186,17 @@ bool Sword25Engine::loadPackages() {
return true;
}
+bool Sword25Engine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL);
+ // TODO: Implement more of these features?!
+#if 0
+ return
+ (f == kSupportsSubtitleOptions) ||
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+#endif
+}
+
} // End of namespace Sword25
diff --git a/engines/sword25/sword25.h b/engines/sword25/sword25.h
index 8f31a05562..2d93e2267c 100644
--- a/engines/sword25/sword25.h
+++ b/engines/sword25/sword25.h
@@ -35,6 +35,14 @@
struct ADGameDescription;
+/**
+ * This is the namespace of the Sword25 engine.
+ *
+ * Status of this engine: ???
+ *
+ * Games using this engine:
+ * - Broken Sword 2.5
+ */
namespace Sword25 {
enum {
@@ -64,6 +72,14 @@ private:
protected:
virtual Common::Error run();
+ bool hasFeature(EngineFeature f) const;
+// void pauseEngineIntern(bool pause); // TODO: Implement this!!!
+// void syncSoundSettings(); // TODO: Implement this!!!
+// Common::Error loadGameState(int slot); // TODO: Implement this?
+// Common::Error saveGameState(int slot, const char *desc); // TODO: Implement this?
+// bool canLoadGameStateCurrently(); // TODO: Implement this?
+// bool canSaveGameStateCurrently(); // TODO: Implement this?
+
void shutdown();
public:
diff --git a/engines/sword25/util/lua/lapi.c b/engines/sword25/util/lua/lapi.cpp
index d7e8931e45..b1118db368 100644
--- a/engines/sword25/util/lua/lapi.c
+++ b/engines/sword25/util/lua/lapi.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.c,v 2.55.1.3 2008/01/03 15:20:39 roberto Exp $
+** $Id$
** Lua API
** See Copyright Notice in lua.h
*/
@@ -32,9 +32,9 @@
const char lua_ident[] =
- "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n"
- "$Authors: " LUA_AUTHORS " $\n"
- "$URL: www.lua.org $\n";
+ "Lua: " LUA_RELEASE " " LUA_COPYRIGHT " \n"
+ "Authors: " LUA_AUTHORS " \n"
+ "URL: www.lua.org\n";
@@ -50,7 +50,8 @@ static TValue *index2adr (lua_State *L, int idx) {
if (idx > 0) {
TValue *o = L->base + (idx - 1);
api_check(L, idx <= L->ci->top - L->base);
- if (o >= L->top) return cast(TValue *, luaO_nilobject);
+ // FIXME: Get rid of const_cast
+ if (o >= L->top) return const_cast<TValue *>(luaO_nilobject);
else return o;
}
else if (idx > LUA_REGISTRYINDEX) {
@@ -70,7 +71,8 @@ static TValue *index2adr (lua_State *L, int idx) {
idx = LUA_GLOBALSINDEX - idx;
return (idx <= func->c.nupvalues)
? &func->c.upvalue[idx-1]
- : cast(TValue *, luaO_nilobject);
+ // FIXME: Get rid of const_cast
+ : const_cast<TValue *>(luaO_nilobject);
}
}
}
diff --git a/engines/sword25/util/lua/lapi.h b/engines/sword25/util/lua/lapi.h
index 2c3fab244e..f968ffc992 100644
--- a/engines/sword25/util/lua/lapi.h
+++ b/engines/sword25/util/lua/lapi.h
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lauxlib.c b/engines/sword25/util/lua/lauxlib.cpp
index 10f14e2c08..53c0556625 100644
--- a/engines/sword25/util/lua/lauxlib.c
+++ b/engines/sword25/util/lua/lauxlib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $
+** $Id$
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lauxlib.h b/engines/sword25/util/lua/lauxlib.h
index 34258235db..d58f290527 100644
--- a/engines/sword25/util/lua/lauxlib.h
+++ b/engines/sword25/util/lua/lauxlib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lbaselib.c b/engines/sword25/util/lua/lbaselib.cpp
index 8f97a1c246..5032e6322a 100644
--- a/engines/sword25/util/lua/lbaselib.c
+++ b/engines/sword25/util/lua/lbaselib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lbaselib.c,v 1.191.1.4 2008/01/20 13:53:22 roberto Exp $
+** $Id$
** Basic library
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lcode.c b/engines/sword25/util/lua/lcode.cpp
index cff626b7fa..6e7e10017f 100644
--- a/engines/sword25/util/lua/lcode.c
+++ b/engines/sword25/util/lua/lcode.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $
+** $Id$
** Code generator for Lua
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lcode.h b/engines/sword25/util/lua/lcode.h
index b941c60721..751b2b5695 100644
--- a/engines/sword25/util/lua/lcode.h
+++ b/engines/sword25/util/lua/lcode.h
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Code generator for Lua
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ldblib.c b/engines/sword25/util/lua/ldblib.cpp
index 67de1222a9..b2e249e9b7 100644
--- a/engines/sword25/util/lua/ldblib.c
+++ b/engines/sword25/util/lua/ldblib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $
+** $Id$
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ldebug.c b/engines/sword25/util/lua/ldebug.cpp
index 9eac4a9b41..0b26522b31 100644
--- a/engines/sword25/util/lua/ldebug.c
+++ b/engines/sword25/util/lua/ldebug.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 2.29.1.3 2007/12/28 15:32:23 roberto Exp $
+** $Id$
** Debug Interface
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ldebug.h b/engines/sword25/util/lua/ldebug.h
index ba28a97248..22226b4096 100644
--- a/engines/sword25/util/lua/ldebug.h
+++ b/engines/sword25/util/lua/ldebug.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ldo.c b/engines/sword25/util/lua/ldo.cpp
index 8de05f728e..07508fbb14 100644
--- a/engines/sword25/util/lua/ldo.c
+++ b/engines/sword25/util/lua/ldo.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $
+** $Id$
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ldo.h b/engines/sword25/util/lua/ldo.h
index 98fddac59f..4c97134805 100644
--- a/engines/sword25/util/lua/ldo.h
+++ b/engines/sword25/util/lua/ldo.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ldump.c b/engines/sword25/util/lua/ldump.cpp
index c9d3d4870f..3ce16542d6 100644
--- a/engines/sword25/util/lua/ldump.c
+++ b/engines/sword25/util/lua/ldump.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lfunc.c b/engines/sword25/util/lua/lfunc.cpp
index 813e88f583..ce7acf4e77 100644
--- a/engines/sword25/util/lua/lfunc.c
+++ b/engines/sword25/util/lua/lfunc.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $
+** $Id$
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lfunc.h b/engines/sword25/util/lua/lfunc.h
index a68cf5151c..4c2b7fd138 100644
--- a/engines/sword25/util/lua/lfunc.h
+++ b/engines/sword25/util/lua/lfunc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lgc.c b/engines/sword25/util/lua/lgc.cpp
index d9e0b78294..52ff72bdc9 100644
--- a/engines/sword25/util/lua/lgc.c
+++ b/engines/sword25/util/lua/lgc.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Garbage Collector
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lgc.h b/engines/sword25/util/lua/lgc.h
index 5a8dc605b3..5123ccb479 100644
--- a/engines/sword25/util/lua/lgc.h
+++ b/engines/sword25/util/lua/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Garbage Collector
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/linit.c b/engines/sword25/util/lua/linit.cpp
index c1f90dfab7..93f41d0350 100644
--- a/engines/sword25/util/lua/linit.c
+++ b/engines/sword25/util/lua/linit.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Initialization of libraries for lua.c
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/liolib.c b/engines/sword25/util/lua/liolib.cpp
index e79ed1cb2e..aa44dcafa3 100644
--- a/engines/sword25/util/lua/liolib.c
+++ b/engines/sword25/util/lua/liolib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $
+** $Id$
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/llex.c b/engines/sword25/util/lua/llex.cpp
index 6dc319358c..fdde2b8e5f 100644
--- a/engines/sword25/util/lua/llex.c
+++ b/engines/sword25/util/lua/llex.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/llex.h b/engines/sword25/util/lua/llex.h
index a9201cee48..fa8b7a2a28 100644
--- a/engines/sword25/util/lua/llex.h
+++ b/engines/sword25/util/lua/llex.h
@@ -1,5 +1,5 @@
/*
-** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/llimits.h b/engines/sword25/util/lua/llimits.h
index ca8dcb7224..a31ad160ad 100644
--- a/engines/sword25/util/lua/llimits.h
+++ b/engines/sword25/util/lua/llimits.h
@@ -1,5 +1,5 @@
/*
-** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lmathlib.c b/engines/sword25/util/lua/lmathlib.cpp
index 441fbf736c..ed50539f1f 100644
--- a/engines/sword25/util/lua/lmathlib.c
+++ b/engines/sword25/util/lua/lmathlib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Standard mathematical library
** See Copyright Notice in lua.h
*/
@@ -252,7 +252,17 @@ LUALIB_API int luaopen_math (lua_State *L) {
luaL_register(L, LUA_MATHLIBNAME, mathlib);
lua_pushnumber(L, PI);
lua_setfield(L, -2, "pi");
+#if defined(MACOSX) && defined(__GNUC__) && ! defined( __XLC__ )
+ // WORKAROUND for a bug in the Mac OS X 10.2.8 SDK. It defines
+ // HUGE_VAL simply to 1e500, leading to this compiler error:
+ // error: floating constant exceeds range of 'double'
+ // However, GCC (at least the version we are using for our cross
+ // compiler) has a __builtin_huge_val which returns the correct
+ // value, so we just use that.
+ lua_pushnumber(L, __builtin_huge_val());
+#else
lua_pushnumber(L, HUGE_VAL);
+#endif
lua_setfield(L, -2, "huge");
#if defined(LUA_COMPAT_MOD)
lua_getfield(L, -1, "fmod");
diff --git a/engines/sword25/util/lua/lmem.c b/engines/sword25/util/lua/lmem.cpp
index ae7d8c965f..ccd69357e0 100644
--- a/engines/sword25/util/lua/lmem.c
+++ b/engines/sword25/util/lua/lmem.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lmem.h b/engines/sword25/util/lua/lmem.h
index 7c2dcb3220..97a888c7f8 100644
--- a/engines/sword25/util/lua/lmem.h
+++ b/engines/sword25/util/lua/lmem.h
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/loadlib.c b/engines/sword25/util/lua/loadlib.cpp
index d955f3ef41..e060611450 100644
--- a/engines/sword25/util/lua/loadlib.c
+++ b/engines/sword25/util/lua/loadlib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: loadlib.c,v 1.52.1.2 2007/12/28 14:58:43 roberto Exp $
+** $Id$
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
diff --git a/engines/sword25/util/lua/lobject.c b/engines/sword25/util/lua/lobject.cpp
index 4ff50732a4..24718931ed 100644
--- a/engines/sword25/util/lua/lobject.c
+++ b/engines/sword25/util/lua/lobject.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lobject.h b/engines/sword25/util/lua/lobject.h
index e7199dfc68..35aaed028a 100644
--- a/engines/sword25/util/lua/lobject.h
+++ b/engines/sword25/util/lua/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lopcodes.c b/engines/sword25/util/lua/lopcodes.cpp
index 4cc745230b..d9da16f689 100644
--- a/engines/sword25/util/lua/lopcodes.c
+++ b/engines/sword25/util/lua/lopcodes.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lopcodes.h b/engines/sword25/util/lua/lopcodes.h
index 41224d6ee1..e1aed0f637 100644
--- a/engines/sword25/util/lua/lopcodes.h
+++ b/engines/sword25/util/lua/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/loslib.c b/engines/sword25/util/lua/loslib.cpp
index da06a572ac..70a67bccf7 100644
--- a/engines/sword25/util/lua/loslib.c
+++ b/engines/sword25/util/lua/loslib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $
+** $Id$
** Standard Operating System library
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lparser.c b/engines/sword25/util/lua/lparser.cpp
index 1e2a9a88b7..03ea333315 100644
--- a/engines/sword25/util/lua/lparser.c
+++ b/engines/sword25/util/lua/lparser.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $
+** $Id$
** Lua Parser
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lparser.h b/engines/sword25/util/lua/lparser.h
index 18836afd1c..f9b8e24913 100644
--- a/engines/sword25/util/lua/lparser.h
+++ b/engines/sword25/util/lua/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Lua Parser
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lstate.c b/engines/sword25/util/lua/lstate.cpp
index 4313b83a0c..495d75c8a6 100644
--- a/engines/sword25/util/lua/lstate.c
+++ b/engines/sword25/util/lua/lstate.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $
+** $Id$
** Global State
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lstate.h b/engines/sword25/util/lua/lstate.h
index 3bc575b6bc..94a6249461 100644
--- a/engines/sword25/util/lua/lstate.h
+++ b/engines/sword25/util/lua/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $
+** $Id$
** Global State
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lstring.c b/engines/sword25/util/lua/lstring.cpp
index 49113151cc..cd55cc63bf 100644
--- a/engines/sword25/util/lua/lstring.c
+++ b/engines/sword25/util/lua/lstring.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lstring.h b/engines/sword25/util/lua/lstring.h
index 73a2ff8b38..c88e4c12a9 100644
--- a/engines/sword25/util/lua/lstring.h
+++ b/engines/sword25/util/lua/lstring.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lstrlib.c b/engines/sword25/util/lua/lstrlib.cpp
index ca333ba168..e5501b9b49 100644
--- a/engines/sword25/util/lua/lstrlib.c
+++ b/engines/sword25/util/lua/lstrlib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.132.1.3 2007/12/28 15:32:23 roberto Exp $
+** $Id$
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ltable.c b/engines/sword25/util/lua/ltable.cpp
index ec84f4fabc..b2ec0e912a 100644
--- a/engines/sword25/util/lua/ltable.c
+++ b/engines/sword25/util/lua/ltable.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $
+** $Id$
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -272,7 +272,8 @@ static void setarrayvector (lua_State *L, Table *t, int size) {
static void setnodevector (lua_State *L, Table *t, int size) {
int lsize;
if (size == 0) { /* no elements to hash part? */
- t->node = cast(Node *, dummynode); /* use common `dummynode' */
+ // FIXME: Get rid of const_cast
+ t->node = const_cast<Node *>(dummynode); /* use common `dummynode' */
lsize = 0;
}
else {
@@ -364,7 +365,8 @@ Table *luaH_new (lua_State *L, int narray, int nhash) {
t->array = NULL;
t->sizearray = 0;
t->lsizenode = 0;
- t->node = cast(Node *, dummynode);
+ // FIXME: Get rid of const_cast
+ t->node = const_cast<Node *>(dummynode);
setarrayvector(L, t, narray);
setnodevector(L, t, nhash);
return t;
@@ -495,7 +497,8 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
const TValue *p = luaH_get(t, key);
t->flags = 0;
if (p != luaO_nilobject)
- return cast(TValue *, p);
+ // FIXME: Get rid of const_cast
+ return const_cast<TValue *>(p);
else {
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
@@ -508,7 +511,8 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
TValue *luaH_setnum (lua_State *L, Table *t, int key) {
const TValue *p = luaH_getnum(t, key);
if (p != luaO_nilobject)
- return cast(TValue *, p);
+ // FIXME: Get rid of const_cast
+ return const_cast<TValue *>(p);
else {
TValue k;
setnvalue(&k, cast_num(key));
@@ -520,7 +524,8 @@ TValue *luaH_setnum (lua_State *L, Table *t, int key) {
TValue *luaH_setstr (lua_State *L, Table *t, TString *key) {
const TValue *p = luaH_getstr(t, key);
if (p != luaO_nilobject)
- return cast(TValue *, p);
+ // FIXME: Get rid of const_cast
+ return const_cast<TValue *>(p);
else {
TValue k;
setsvalue(L, &k, key);
diff --git a/engines/sword25/util/lua/ltable.h b/engines/sword25/util/lua/ltable.h
index f5b9d5ead0..aa28914871 100644
--- a/engines/sword25/util/lua/ltable.h
+++ b/engines/sword25/util/lua/ltable.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ltablib.c b/engines/sword25/util/lua/ltablib.cpp
index 06f1c37be1..607c09ae71 100644
--- a/engines/sword25/util/lua/ltablib.c
+++ b/engines/sword25/util/lua/ltablib.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: ltablib.c,v 1.38.1.2 2007/12/28 15:32:23 roberto Exp $
+** $Id$
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ltm.c b/engines/sword25/util/lua/ltm.cpp
index c27f0f6fab..02856a58fc 100644
--- a/engines/sword25/util/lua/ltm.c
+++ b/engines/sword25/util/lua/ltm.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Tag methods
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/ltm.h b/engines/sword25/util/lua/ltm.h
index 64343b781b..1b89683ef3 100644
--- a/engines/sword25/util/lua/ltm.h
+++ b/engines/sword25/util/lua/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Tag methods
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lua.c b/engines/sword25/util/lua/lua.c
deleted file mode 100644
index 3a46609328..0000000000
--- a/engines/sword25/util/lua/lua.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
-** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
-** Lua stand-alone interpreter
-** See Copyright Notice in lua.h
-*/
-
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define lua_c
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-
-static lua_State *globalL = NULL;
-
-static const char *progname = LUA_PROGNAME;
-
-
-
-static void lstop (lua_State *L, lua_Debug *ar) {
- (void)ar; /* unused arg. */
- lua_sethook(L, NULL, 0, 0);
- luaL_error(L, "interrupted!");
-}
-
-
-static void laction (int i) {
- signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
- terminate process (default action) */
- lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
-}
-
-
-static void print_usage (void) {
- fprintf(stderr,
- "usage: %s [options] [script [args]].\n"
- "Available options are:\n"
- " -e stat execute string " LUA_QL("stat") "\n"
- " -l name require library " LUA_QL("name") "\n"
- " -i enter interactive mode after executing " LUA_QL("script") "\n"
- " -v show version information\n"
- " -- stop handling options\n"
- " - execute stdin and stop handling options\n"
- ,
- progname);
- fflush(stderr);
-}
-
-
-static void l_message (const char *pname, const char *msg) {
- if (pname) fprintf(stderr, "%s: ", pname);
- fprintf(stderr, "%s\n", msg);
- fflush(stderr);
-}
-
-
-static int report (lua_State *L, int status) {
- if (status && !lua_isnil(L, -1)) {
- const char *msg = lua_tostring(L, -1);
- if (msg == NULL) msg = "(error object is not a string)";
- l_message(progname, msg);
- lua_pop(L, 1);
- }
- return status;
-}
-
-
-static int traceback (lua_State *L) {
- if (!lua_isstring(L, 1)) /* 'message' not a string? */
- return 1; /* keep it intact */
- lua_getfield(L, LUA_GLOBALSINDEX, "debug");
- if (!lua_istable(L, -1)) {
- lua_pop(L, 1);
- return 1;
- }
- lua_getfield(L, -1, "traceback");
- if (!lua_isfunction(L, -1)) {
- lua_pop(L, 2);
- return 1;
- }
- lua_pushvalue(L, 1); /* pass error message */
- lua_pushinteger(L, 2); /* skip this function and traceback */
- lua_call(L, 2, 1); /* call debug.traceback */
- return 1;
-}
-
-
-static int docall (lua_State *L, int narg, int clear) {
- int status;
- int base = lua_gettop(L) - narg; /* function index */
- lua_pushcfunction(L, traceback); /* push traceback function */
- lua_insert(L, base); /* put it under chunk and args */
- signal(SIGINT, laction);
- status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
- signal(SIGINT, SIG_DFL);
- lua_remove(L, base); /* remove traceback function */
- /* force a complete garbage collection in case of errors */
- if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
- return status;
-}
-
-
-static void print_version (void) {
- l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT);
-}
-
-
-static int getargs (lua_State *L, char **argv, int n) {
- int narg;
- int i;
- int argc = 0;
- while (argv[argc]) argc++; /* count total number of arguments */
- narg = argc - (n + 1); /* number of arguments to the script */
- luaL_checkstack(L, narg + 3, "too many arguments to script");
- for (i=n+1; i < argc; i++)
- lua_pushstring(L, argv[i]);
- lua_createtable(L, narg, n + 1);
- for (i=0; i < argc; i++) {
- lua_pushstring(L, argv[i]);
- lua_rawseti(L, -2, i - n);
- }
- return narg;
-}
-
-
-static int dofile (lua_State *L, const char *name) {
- int status = luaL_loadfile(L, name) || docall(L, 0, 1);
- return report(L, status);
-}
-
-
-static int dostring (lua_State *L, const char *s, const char *name) {
- int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
- return report(L, status);
-}
-
-
-static int dolibrary (lua_State *L, const char *name) {
- lua_getglobal(L, "require");
- lua_pushstring(L, name);
- return report(L, docall(L, 1, 1));
-}
-
-
-static const char *get_prompt (lua_State *L, int firstline) {
- const char *p;
- lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
- p = lua_tostring(L, -1);
- if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
- lua_pop(L, 1); /* remove global */
- return p;
-}
-
-
-static int incomplete (lua_State *L, int status) {
- if (status == LUA_ERRSYNTAX) {
- size_t lmsg;
- const char *msg = lua_tolstring(L, -1, &lmsg);
- const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
- if (strstr(msg, LUA_QL("<eof>")) == tp) {
- lua_pop(L, 1);
- return 1;
- }
- }
- return 0; /* else... */
-}
-
-
-static int pushline (lua_State *L, int firstline) {
- char buffer[LUA_MAXINPUT];
- char *b = buffer;
- size_t l;
- const char *prmt = get_prompt(L, firstline);
- if (lua_readline(L, b, prmt) == 0)
- return 0; /* no input */
- l = strlen(b);
- if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
- b[l-1] = '\0'; /* remove it */
- if (firstline && b[0] == '=') /* first line starts with `=' ? */
- lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
- else
- lua_pushstring(L, b);
- lua_freeline(L, b);
- return 1;
-}
-
-
-static int loadline (lua_State *L) {
- int status;
- lua_settop(L, 0);
- if (!pushline(L, 1))
- return -1; /* no input */
- for (;;) { /* repeat until gets a complete line */
- status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
- if (!incomplete(L, status)) break; /* cannot try to add lines? */
- if (!pushline(L, 0)) /* no more input? */
- return -1;
- lua_pushliteral(L, "\n"); /* add a new line... */
- lua_insert(L, -2); /* ...between the two lines */
- lua_concat(L, 3); /* join them */
- }
- lua_saveline(L, 1);
- lua_remove(L, 1); /* remove line */
- return status;
-}
-
-
-static void dotty (lua_State *L) {
- int status;
- const char *oldprogname = progname;
- progname = NULL;
- while ((status = loadline(L)) != -1) {
- if (status == 0) status = docall(L, 0, 0);
- report(L, status);
- if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
- lua_getglobal(L, "print");
- lua_insert(L, 1);
- if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
- l_message(progname, lua_pushfstring(L,
- "error calling " LUA_QL("print") " (%s)",
- lua_tostring(L, -1)));
- }
- }
- lua_settop(L, 0); /* clear stack */
- fputs("\n", stdout);
- fflush(stdout);
- progname = oldprogname;
-}
-
-
-static int handle_script (lua_State *L, char **argv, int n) {
- int status;
- const char *fname;
- int narg = getargs(L, argv, n); /* collect arguments */
- lua_setglobal(L, "arg");
- fname = argv[n];
- if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
- fname = NULL; /* stdin */
- status = luaL_loadfile(L, fname);
- lua_insert(L, -(narg+1));
- if (status == 0)
- status = docall(L, narg, 0);
- else
- lua_pop(L, narg);
- return report(L, status);
-}
-
-
-/* check that argument has no extra characters at the end */
-#define notail(x) {if ((x)[2] != '\0') return -1;}
-
-
-static int collectargs (char **argv, int *pi, int *pv, int *pe) {
- int i;
- for (i = 1; argv[i] != NULL; i++) {
- if (argv[i][0] != '-') /* not an option? */
- return i;
- switch (argv[i][1]) { /* option */
- case '-':
- notail(argv[i]);
- return (argv[i+1] != NULL ? i+1 : 0);
- case '\0':
- return i;
- case 'i':
- notail(argv[i]);
- *pi = 1; /* go through */
- case 'v':
- notail(argv[i]);
- *pv = 1;
- break;
- case 'e':
- *pe = 1; /* go through */
- case 'l':
- if (argv[i][2] == '\0') {
- i++;
- if (argv[i] == NULL) return -1;
- }
- break;
- default: return -1; /* invalid option */
- }
- }
- return 0;
-}
-
-
-static int runargs (lua_State *L, char **argv, int n) {
- int i;
- for (i = 1; i < n; i++) {
- if (argv[i] == NULL) continue;
- lua_assert(argv[i][0] == '-');
- switch (argv[i][1]) { /* option */
- case 'e': {
- const char *chunk = argv[i] + 2;
- if (*chunk == '\0') chunk = argv[++i];
- lua_assert(chunk != NULL);
- if (dostring(L, chunk, "=(command line)") != 0)
- return 1;
- break;
- }
- case 'l': {
- const char *filename = argv[i] + 2;
- if (*filename == '\0') filename = argv[++i];
- lua_assert(filename != NULL);
- if (dolibrary(L, filename))
- return 1; /* stop if file fails */
- break;
- }
- default: break;
- }
- }
- return 0;
-}
-
-
-static int handle_luainit (lua_State *L) {
- const char *init = getenv(LUA_INIT);
- if (init == NULL) return 0; /* status OK */
- else if (init[0] == '@')
- return dofile(L, init+1);
- else
- return dostring(L, init, "=" LUA_INIT);
-}
-
-
-struct Smain {
- int argc;
- char **argv;
- int status;
-};
-
-
-static int pmain (lua_State *L) {
- struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
- char **argv = s->argv;
- int script;
- int has_i = 0, has_v = 0, has_e = 0;
- globalL = L;
- if (argv[0] && argv[0][0]) progname = argv[0];
- lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
- luaL_openlibs(L); /* open libraries */
- lua_gc(L, LUA_GCRESTART, 0);
- s->status = handle_luainit(L);
- if (s->status != 0) return 0;
- script = collectargs(argv, &has_i, &has_v, &has_e);
- if (script < 0) { /* invalid args? */
- print_usage();
- s->status = 1;
- return 0;
- }
- if (has_v) print_version();
- s->status = runargs(L, argv, (script > 0) ? script : s->argc);
- if (s->status != 0) return 0;
- if (script)
- s->status = handle_script(L, argv, script);
- if (s->status != 0) return 0;
- if (has_i)
- dotty(L);
- else if (script == 0 && !has_e && !has_v) {
- if (lua_stdin_is_tty()) {
- print_version();
- dotty(L);
- }
- else dofile(L, NULL); /* executes stdin as a file */
- }
- return 0;
-}
-
-
-int main (int argc, char **argv) {
- int status;
- struct Smain s;
- lua_State *L = lua_open(); /* create state */
- if (L == NULL) {
- l_message(argv[0], "cannot create state: not enough memory");
- return EXIT_FAILURE;
- }
- s.argc = argc;
- s.argv = argv;
- status = lua_cpcall(L, &pmain, &s);
- report(L, status);
- lua_close(L);
- return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
-}
-
diff --git a/engines/sword25/util/lua/lua.h b/engines/sword25/util/lua/lua.h
index 5bc97b746f..088a511cf9 100644
--- a/engines/sword25/util/lua/lua.h
+++ b/engines/sword25/util/lua/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.218.1.4 2008/01/03 15:41:15 roberto Exp $
+** $Id$
** Lua - An Extensible Extension Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
diff --git a/engines/sword25/util/lua/luac.c b/engines/sword25/util/lua/luac.c
deleted file mode 100644
index d07017391b..0000000000
--- a/engines/sword25/util/lua/luac.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
-** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $
-** Lua compiler (saves bytecodes to files; also list bytecodes)
-** See Copyright Notice in lua.h
-*/
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define luac_c
-#define LUA_CORE
-
-#include "lua.h"
-#include "lauxlib.h"
-
-#include "ldo.h"
-#include "lfunc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lstring.h"
-#include "lundump.h"
-
-#define PROGNAME "luac" /* default program name */
-#define OUTPUT PROGNAME ".out" /* default output file */
-
-static int listing=0; /* list bytecodes? */
-static int dumping=1; /* dump bytecodes? */
-static int stripping=0; /* strip debug information? */
-static char Output[]={ OUTPUT }; /* default output file name */
-static const char* output=Output; /* actual output file name */
-static const char* progname=PROGNAME; /* actual program name */
-
-static void fatal(const char* message)
-{
- fprintf(stderr,"%s: %s\n",progname,message);
- exit(EXIT_FAILURE);
-}
-
-static void cannot(const char* what)
-{
- fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
- exit(EXIT_FAILURE);
-}
-
-static void usage(const char* message)
-{
- if (*message=='-')
- fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
- else
- fprintf(stderr,"%s: %s\n",progname,message);
- fprintf(stderr,
- "usage: %s [options] [filenames].\n"
- "Available options are:\n"
- " - process stdin\n"
- " -l list\n"
- " -o name output to file " LUA_QL("name") " (default is \"%s\")\n"
- " -p parse only\n"
- " -s strip debug information\n"
- " -v show version information\n"
- " -- stop handling options\n",
- progname,Output);
- exit(EXIT_FAILURE);
-}
-
-#define IS(s) (strcmp(argv[i],s)==0)
-
-static int doargs(int argc, char* argv[])
-{
- int i;
- int version=0;
- if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
- for (i=1; i<argc; i++)
- {
- if (*argv[i]!='-') /* end of options; keep it */
- break;
- else if (IS("--")) /* end of options; skip it */
- {
- ++i;
- if (version) ++version;
- break;
- }
- else if (IS("-")) /* end of options; use stdin */
- break;
- else if (IS("-l")) /* list */
- ++listing;
- else if (IS("-o")) /* output file */
- {
- output=argv[++i];
- if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument");
- if (IS("-")) output=NULL;
- }
- else if (IS("-p")) /* parse only */
- dumping=0;
- else if (IS("-s")) /* strip debug information */
- stripping=1;
- else if (IS("-v")) /* show version */
- ++version;
- else /* unknown option */
- usage(argv[i]);
- }
- if (i==argc && (listing || !dumping))
- {
- dumping=0;
- argv[--i]=Output;
- }
- if (version)
- {
- printf("%s %s\n",LUA_RELEASE,LUA_COPYRIGHT);
- if (version==argc-1) exit(EXIT_SUCCESS);
- }
- return i;
-}
-
-#define toproto(L,i) (clvalue(L->top+(i))->l.p)
-
-static const Proto* combine(lua_State* L, int n)
-{
- if (n==1)
- return toproto(L,-1);
- else
- {
- int i,pc;
- Proto* f=luaF_newproto(L);
- setptvalue2s(L,L->top,f); incr_top(L);
- f->source=luaS_newliteral(L,"=(" PROGNAME ")");
- f->maxstacksize=1;
- pc=2*n+1;
- f->code=luaM_newvector(L,pc,Instruction);
- f->sizecode=pc;
- f->p=luaM_newvector(L,n,Proto*);
- f->sizep=n;
- pc=0;
- for (i=0; i<n; i++)
- {
- f->p[i]=toproto(L,i-n-1);
- f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i);
- f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1);
- }
- f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
- return f;
- }
-}
-
-static int writer(lua_State* L, const void* p, size_t size, void* u)
-{
- UNUSED(L);
- return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
-}
-
-struct Smain {
- int argc;
- char** argv;
-};
-
-static int pmain(lua_State* L)
-{
- struct Smain* s = (struct Smain*)lua_touserdata(L, 1);
- int argc=s->argc;
- char** argv=s->argv;
- const Proto* f;
- int i;
- if (!lua_checkstack(L,argc)) fatal("too many input files");
- for (i=0; i<argc; i++)
- {
- const char* filename=IS("-") ? NULL : argv[i];
- if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1));
- }
- f=combine(L,argc);
- if (listing) luaU_print(f,listing>1);
- if (dumping)
- {
- FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
- if (D==NULL) cannot("open");
- lua_lock(L);
- luaU_dump(L,f,writer,D,stripping);
- lua_unlock(L);
- if (ferror(D)) cannot("write");
- if (fclose(D)) cannot("close");
- }
- return 0;
-}
-
-int main(int argc, char* argv[])
-{
- lua_State* L;
- struct Smain s;
- int i=doargs(argc,argv);
- argc-=i; argv+=i;
- if (argc<=0) usage("no input files given");
- L=lua_open();
- if (L==NULL) fatal("not enough memory for state");
- s.argc=argc;
- s.argv=argv;
- if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1));
- lua_close(L);
- return EXIT_SUCCESS;
-}
diff --git a/engines/sword25/util/lua/luaconf.h b/engines/sword25/util/lua/luaconf.h
index d4eb2c9cd4..fa565c7697 100644
--- a/engines/sword25/util/lua/luaconf.h
+++ b/engines/sword25/util/lua/luaconf.h
@@ -1,5 +1,5 @@
/*
-** $Id: luaconf.h,v 1.82.1.6 2008/01/18 17:07:48 roberto Exp $
+** $Id$
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -319,7 +319,7 @@
** CHANGE it (define it) if you want exact compatibility with the
** behavior of setn/getn in Lua 5.0.
*/
-#define LUA_COMPAT_GETN // BS25 #undef LUA_COMPAT_GETN
+#define LUA_COMPAT_GETN /* BS25 #undef LUA_COMPAT_GETN */
/*
@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib.
diff --git a/engines/sword25/util/lua/lualib.h b/engines/sword25/util/lua/lualib.h
index 469417f670..33d4e314c2 100644
--- a/engines/sword25/util/lua/lualib.h
+++ b/engines/sword25/util/lua/lualib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Lua standard libraries
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lundump.c b/engines/sword25/util/lua/lundump.cpp
index 731c064553..4ffc623575 100644
--- a/engines/sword25/util/lua/lundump.c
+++ b/engines/sword25/util/lua/lundump.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.c,v 2.7.1.2 2008/01/18 16:39:11 roberto Exp $
+** $Id$
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lundump.h b/engines/sword25/util/lua/lundump.h
index c80189dbff..f791a4f173 100644
--- a/engines/sword25/util/lua/lundump.h
+++ b/engines/sword25/util/lua/lundump.h
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lvm.c b/engines/sword25/util/lua/lvm.cpp
index ee3256ab94..ae70fe2645 100644
--- a/engines/sword25/util/lua/lvm.c
+++ b/engines/sword25/util/lua/lvm.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $
+** $Id$
** Lua virtual machine
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lvm.h b/engines/sword25/util/lua/lvm.h
index bfe4f5678d..dff2a139f7 100644
--- a/engines/sword25/util/lua/lvm.h
+++ b/engines/sword25/util/lua/lvm.h
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Lua virtual machine
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lzio.c b/engines/sword25/util/lua/lzio.cpp
index 293edd59b0..e1e7b28a29 100644
--- a/engines/sword25/util/lua/lzio.c
+++ b/engines/sword25/util/lua/lzio.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** a generic input stream interface
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/lzio.h b/engines/sword25/util/lua/lzio.h
index 51d695d8c1..9aa9e4b537 100644
--- a/engines/sword25/util/lua/lzio.h
+++ b/engines/sword25/util/lua/lzio.h
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Buffered streams
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/lua/print.c b/engines/sword25/util/lua/print.cpp
index e240cfc3c6..22039c9861 100644
--- a/engines/sword25/util/lua/print.c
+++ b/engines/sword25/util/lua/print.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $
+** $Id$
** print bytecodes
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep.c b/engines/sword25/util/pluto/pdep.cpp
index a32c43b42d..a32c43b42d 100644
--- a/engines/sword25/util/pluto/pdep.c
+++ b/engines/sword25/util/pluto/pdep.cpp
diff --git a/engines/sword25/util/pluto/pdep/lauxlib.h b/engines/sword25/util/pluto/pdep/lauxlib.h
index 34258235db..d58f290527 100644
--- a/engines/sword25/util/pluto/pdep/lauxlib.h
+++ b/engines/sword25/util/pluto/pdep/lauxlib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/ldo.h b/engines/sword25/util/pluto/pdep/ldo.h
index 98fddac59f..4c97134805 100644
--- a/engines/sword25/util/pluto/pdep/ldo.h
+++ b/engines/sword25/util/pluto/pdep/ldo.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/lfunc.h b/engines/sword25/util/pluto/pdep/lfunc.h
index a68cf5151c..4c2b7fd138 100644
--- a/engines/sword25/util/pluto/pdep/lfunc.h
+++ b/engines/sword25/util/pluto/pdep/lfunc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/lgc.h b/engines/sword25/util/pluto/pdep/lgc.h
index 5a8dc605b3..5123ccb479 100644
--- a/engines/sword25/util/pluto/pdep/lgc.h
+++ b/engines/sword25/util/pluto/pdep/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Garbage Collector
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/llimits.h b/engines/sword25/util/pluto/pdep/llimits.h
index ca8dcb7224..a31ad160ad 100644
--- a/engines/sword25/util/pluto/pdep/llimits.h
+++ b/engines/sword25/util/pluto/pdep/llimits.h
@@ -1,5 +1,5 @@
/*
-** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/lobject.h b/engines/sword25/util/pluto/pdep/lobject.h
index e7199dfc68..35aaed028a 100644
--- a/engines/sword25/util/pluto/pdep/lobject.h
+++ b/engines/sword25/util/pluto/pdep/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/lopcodes.h b/engines/sword25/util/pluto/pdep/lopcodes.h
index 41224d6ee1..e1aed0f637 100644
--- a/engines/sword25/util/pluto/pdep/lopcodes.h
+++ b/engines/sword25/util/pluto/pdep/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/lstate.h b/engines/sword25/util/pluto/pdep/lstate.h
index 3bc575b6bc..94a6249461 100644
--- a/engines/sword25/util/pluto/pdep/lstate.h
+++ b/engines/sword25/util/pluto/pdep/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $
+** $Id$
** Global State
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/lstring.h b/engines/sword25/util/pluto/pdep/lstring.h
index 73a2ff8b38..c88e4c12a9 100644
--- a/engines/sword25/util/pluto/pdep/lstring.h
+++ b/engines/sword25/util/pluto/pdep/lstring.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/ltm.h b/engines/sword25/util/pluto/pdep/ltm.h
index 64343b781b..1b89683ef3 100644
--- a/engines/sword25/util/pluto/pdep/ltm.h
+++ b/engines/sword25/util/pluto/pdep/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Tag methods
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pdep/lua.h b/engines/sword25/util/pluto/pdep/lua.h
index 0f3f28fce5..68dd887f0f 100644
--- a/engines/sword25/util/pluto/pdep/lua.h
+++ b/engines/sword25/util/pluto/pdep/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.218.1.4 2008/01/03 15:41:15 roberto Exp $
+** $Id$
** Lua - An Extensible Extension Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
diff --git a/engines/sword25/util/pluto/pdep/lzio.h b/engines/sword25/util/pluto/pdep/lzio.h
index 4e654a52c9..2f167d7d58 100644
--- a/engines/sword25/util/pluto/pdep/lzio.h
+++ b/engines/sword25/util/pluto/pdep/lzio.h
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** Buffered streams
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pluto.c b/engines/sword25/util/pluto/pluto.cpp
index 61eb40e984..957f5af795 100644
--- a/engines/sword25/util/pluto/pluto.c
+++ b/engines/sword25/util/pluto/pluto.cpp
@@ -624,7 +624,12 @@ static void persist(PersistInfo *pi)
if(!lua_isnil(pi->L, -1)) {
/* perms reftbl ... obj ref */
int zero = 0;
- int ref = (int)lua_touserdata(pi->L, -1);
+ // 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->writer(pi->L, &zero, sizeof(int), pi->ud);
pi->writer(pi->L, &ref, sizeof(int), pi->ud);
lua_pop(pi->L, 1);
@@ -1470,6 +1475,7 @@ static void unpersistpermanent(int ref, UnpersistInfo *upi)
/* perms reftbl perm */
}
+#if 0
/* For debugging only; not called when lua_assert is empty */
static int inreftable(lua_State *L, int ref)
{
@@ -1485,6 +1491,7 @@ static int inreftable(lua_State *L, int ref)
/* perms reftbl ... */
return res;
}
+#endif
static void unpersist(UnpersistInfo *upi)
{
diff --git a/engines/sword25/util/pluto/plzio.c b/engines/sword25/util/pluto/plzio.cpp
index 7c5ab3b773..0efc3dfcf2 100644
--- a/engines/sword25/util/pluto/plzio.c
+++ b/engines/sword25/util/pluto/plzio.cpp
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
+** $Id$
** a generic input stream interface
** See Copyright Notice in lua.h
*/
diff --git a/engines/sword25/util/pluto/pptest.c b/engines/sword25/util/pluto/pptest.cpp
index 1bfecf2b75..1bfecf2b75 100644
--- a/engines/sword25/util/pluto/pptest.c
+++ b/engines/sword25/util/pluto/pptest.cpp
diff --git a/engines/sword25/util/pluto/puptest.c b/engines/sword25/util/pluto/puptest.cpp
index e9aa7ea305..e9aa7ea305 100644
--- a/engines/sword25/util/pluto/puptest.c
+++ b/engines/sword25/util/pluto/puptest.cpp
diff --git a/engines/teenagent/animation.cpp b/engines/teenagent/animation.cpp
index ce1fef009e..56812001e8 100644
--- a/engines/teenagent/animation.cpp
+++ b/engines/teenagent/animation.cpp
@@ -112,7 +112,7 @@ void Animation::load(Common::SeekableReadStream *s, Type type) {
//fixme: do not reload the same animation each time
free();
- if (s == NULL && s->size() <= 1) {
+ if (s == NULL || s->size() <= 1) {
debug(1, "empty animation");
return;
}
diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp
index a2dab9658d..d741039e8d 100644
--- a/engines/teenagent/detection.cpp
+++ b/engines/teenagent/detection.cpp
@@ -83,16 +83,27 @@ static const ADGameDescription teenAgentGameDescriptions[] = {
};
static const ADParams detectionParams = {
+ // Pointer to ADGameDescription or its superset structure
(const byte *)teenAgentGameDescriptions,
+ // Size of that superset structure
sizeof(ADGameDescription),
+ // Number of bytes to compute MD5 sum for
5000,
+ // List of all engine targets
teenAgentGames,
+ // Structure for autoupgrading obsolete targets
0,
+ // Name of single gameid (optional)
"teenagent",
+ // List of files for file-based fallback detection (optional)
0,
+ // Flags
0,
+ // Additional GUI options (for every game}
Common::GUIO_NONE,
+ // Maximum directory depth
1,
+ // List of directory globs
0
};
@@ -137,7 +148,7 @@ public:
// }
static Common::String generateGameStateFileName(const char *target, int slot) {
- return Common::String::printf("%s.%02d", target, slot);
+ return Common::String::format("%s.%02d", target, slot);
}
virtual SaveStateList listSaves(const char *target) const {
diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp
index f1527fc78d..ebc2cd152d 100644
--- a/engines/teenagent/teenagent.cpp
+++ b/engines/teenagent/teenagent.cpp
@@ -196,9 +196,9 @@ void TeenAgentEngine::deinit() {
Common::Error TeenAgentEngine::loadGameState(int slot) {
debug(0, "loading from slot %d", slot);
Common::ScopedPtr<Common::InSaveFile>
- in(_saveFileMan->openForLoading(Common::String::printf("teenagent.%02d", slot)));
+ in(_saveFileMan->openForLoading(Common::String::format("teenagent.%02d", slot)));
if (!in)
- in.reset(_saveFileMan->openForLoading(Common::String::printf("teenagent.%d", slot)));
+ in.reset(_saveFileMan->openForLoading(Common::String::format("teenagent.%d", slot)));
if (!in)
return Common::kReadPermissionDenied;
@@ -231,7 +231,7 @@ Common::Error TeenAgentEngine::loadGameState(int slot) {
Common::Error TeenAgentEngine::saveGameState(int slot, const char *desc) {
debug(0, "saving to slot %d", slot);
- Common::ScopedPtr<Common::OutSaveFile> out(_saveFileMan->openForSaving(Common::String::printf("teenagent.%02d", slot)));
+ Common::ScopedPtr<Common::OutSaveFile> out(_saveFileMan->openForSaving(Common::String::format("teenagent.%02d", slot)));
if (!out)
return Common::kWritingFailed;
diff --git a/engines/teenagent/teenagent.h b/engines/teenagent/teenagent.h
index dc195c0f4e..069e6e40d0 100644
--- a/engines/teenagent/teenagent.h
+++ b/engines/teenagent/teenagent.h
@@ -40,7 +40,7 @@ struct ADGameDescription;
*
* Status of this engine: Complete
*
- * Supported games:
+ * Games using this engine:
* - Teen Agent
*/
namespace TeenAgent {
diff --git a/engines/testbed/config.cpp b/engines/testbed/config.cpp
index fe34910204..4f871db8d2 100644
--- a/engines/testbed/config.cpp
+++ b/engines/testbed/config.cpp
@@ -246,11 +246,11 @@ void TestbedConfigManager::parseConfigFile() {
int TestbedConfigManager::getNumSuitesEnabled() {
int count = 0;
for (uint i = 0; i < _testsuiteList.size(); i++) {
- if (_testsuiteList[i]->isEnabled()) {
- count++;
+ if (_testsuiteList[i]->isEnabled()) {
+ count++;
}
- }
- return count;
+ }
+ return count;
}
Testsuite *TestbedConfigManager::getTestsuiteByName(const Common::String &name) {
diff --git a/engines/testbed/detection.cpp b/engines/testbed/detection.cpp
index 1b8a86cea6..734ed0c22a 100644
--- a/engines/testbed/detection.cpp
+++ b/engines/testbed/detection.cpp
@@ -51,16 +51,27 @@ static const ADGameDescription testbedDescriptions[] = {
};
static const ADParams detectionParams = {
+ // Pointer to ADGameDescription or its superset structure
(const byte *)testbedDescriptions,
+ // Size of that superset structure
sizeof(ADGameDescription),
+ // Number of bytes to compute MD5 sum for
512,
+ // List of all engine targets
testbed_setting,
+ // Structure for autoupgrading obsolete targets
0,
+ // Name of single gameid (optional)
"testbed",
+ // List of files for file-based fallback detection (optional)
0,
+ // Flags
ADGF_NO_FLAGS,
+ // Additional GUI options (for every game}
Common::GUIO_NONE,
+ // Maximum directory depth
1,
+ // List of directory globs
0
};
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
index 086db21c67..079239c920 100644
--- a/engines/testbed/graphics.cpp
+++ b/engines/testbed/graphics.cpp
@@ -769,7 +769,7 @@ TestExitStatus GFXtests::scaledCursors() {
// Switch Graphics mode
// FIXME: Crashes with "3x" mode now.:
- info = Common::String::printf("Testing : Scaled cursors with GFX Mode %s\n", gfxMode->name);
+ info = Common::String::format("Testing : Scaled cursors with GFX Mode %s\n", gfxMode->name);
if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) {
Testsuite::logPrintf("\tInfo! Skipping sub-test : Scaled Cursors :: GFX Mode %s\n", gfxMode->name);
gfxMode++;
@@ -1104,7 +1104,7 @@ TestExitStatus GFXtests::pixelFormats() {
Common::Point pt(0, 170);
Common::String msg;
- msg = Common::String::printf("Testing Pixel Formats, %d of %d", numFormatsTested, pfList.size());
+ msg = Common::String::format("Testing Pixel Formats, %d of %d", numFormatsTested, pfList.size());
Testsuite::writeOnScreen(msg, pt, true);
// CopyRectToScreen could have been used, but that may involve writing code which
diff --git a/engines/testbed/misc.cpp b/engines/testbed/misc.cpp
index 2159974c51..36687f570e 100644
--- a/engines/testbed/misc.cpp
+++ b/engines/testbed/misc.cpp
@@ -28,7 +28,7 @@
namespace Testbed {
Common::String MiscTests::getHumanReadableFormat(TimeDate &td) {
- return Common::String::printf("%d:%d:%d on %d/%d/%d (dd/mm/yyyy)", td.tm_hour, td.tm_min, td.tm_sec, td.tm_mday, td.tm_mon + 1, td.tm_year + 1900);
+ return Common::String::format("%d:%d:%d on %d/%d/%d (dd/mm/yyyy)", td.tm_hour, td.tm_min, td.tm_sec, td.tm_mday, td.tm_mon + 1, td.tm_year + 1900);
}
void MiscTests::timerCallback(void *arg) {
diff --git a/engines/testbed/sound.cpp b/engines/testbed/sound.cpp
index e256621553..b2f61ab714 100644
--- a/engines/testbed/sound.cpp
+++ b/engines/testbed/sound.cpp
@@ -22,7 +22,6 @@
* $Id$
*/
-#include "sound/audiocd.h"
#include "sound/softsynth/pcspk.h"
#include "testbed/sound.h"
@@ -190,17 +189,17 @@ TestExitStatus SoundSubsystem::audiocdOutput() {
// Play all tracks
for (int i = 1; i < 5; i++) {
- AudioCD.play(i, 1, 0, 0);
- while (AudioCD.isPlaying()) {
+ g_system->getAudioCDManager()->play(i, 1, 0, 0);
+ while (g_system->getAudioCDManager()->isPlaying()) {
g_system->delayMillis(500);
- Testsuite::writeOnScreen(Common::String::printf("Playing Now: track%02d", i), pt);
+ Testsuite::writeOnScreen(Common::String::format("Playing Now: track%02d", i), pt);
}
g_system->delayMillis(500);
}
Testsuite::clearScreen();
if (Testsuite::handleInteractiveInput("Were all the tracks played in order i.e 1-2-3-last ?", "Yes", "No", kOptionRight)) {
- Testsuite::logPrintf("Error! Error in AudioCD.play() or probably sound files were not detected, try -d1 (debuglevel 1)\n");
+ Testsuite::logPrintf("Error! Error in _system->getAudioCDManager()->play() or probably sound files were not detected, try -d1 (debuglevel 1)\n");
passed = kTestFailed;
}
@@ -234,19 +233,19 @@ TestExitStatus SoundSubsystem::sampleRates() {
Common::Point pt(0, 100);
mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, s1);
- Testsuite::writeOnScreen(Common::String::printf("Playing at smaple rate: %d", s1->getRate()), pt);
+ Testsuite::writeOnScreen(Common::String::format("Playing at smaple rate: %d", s1->getRate()), pt);
g_system->delayMillis(1000);
mixer->stopHandle(handle);
g_system->delayMillis(1000);
mixer->playStream(Audio::Mixer::kSpeechSoundType, &handle, s2);
- Testsuite::writeOnScreen(Common::String::printf("Playing at sample rate : %d", s2->getRate()), pt);
+ Testsuite::writeOnScreen(Common::String::format("Playing at sample rate : %d", s2->getRate()), pt);
g_system->delayMillis(1000);
mixer->stopHandle(handle);
g_system->delayMillis(1000);
mixer->playStream(Audio::Mixer::kSFXSoundType, &handle, s3);
- Testsuite::writeOnScreen(Common::String::printf("Playing at sample rate : %d", s3->getRate()), pt);
+ Testsuite::writeOnScreen(Common::String::format("Playing at sample rate : %d", s3->getRate()), pt);
g_system->delayMillis(1000);
mixer->stopHandle(handle);
g_system->delayMillis(1000);
diff --git a/engines/testbed/testbed.cpp b/engines/testbed/testbed.cpp
index 071fba8c2c..1ceecb8ebf 100644
--- a/engines/testbed/testbed.cpp
+++ b/engines/testbed/testbed.cpp
@@ -48,10 +48,10 @@ void TestbedExitDialog::init() {
GUI::ListWidget::ColorList colors;
for (Common::Array<Testsuite *>::const_iterator i = _testsuiteList.begin(); i != _testsuiteList.end(); ++i) {
- strArray.push_back(Common::String::printf("%s :", (*i)->getDescription()));
+ strArray.push_back(Common::String::format("%s :", (*i)->getDescription()));
colors.push_back(GUI::ThemeEngine::kFontColorNormal);
if ((*i)->isEnabled()) {
- strArray.push_back(Common::String::printf("Passed: %d Failed: %d Skipped: %d", (*i)->getNumTestsPassed(), (*i)->getNumTestsFailed(), (*i)->getNumTestsSkipped()));
+ strArray.push_back(Common::String::format("Passed: %d Failed: %d Skipped: %d", (*i)->getNumTestsPassed(), (*i)->getNumTestsFailed(), (*i)->getNumTestsSkipped()));
} else {
strArray.push_back("Skipped");
}
diff --git a/engines/testbed/testsuite.cpp b/engines/testbed/testsuite.cpp
index 8cb9ffe309..fa8764e869 100644
--- a/engines/testbed/testsuite.cpp
+++ b/engines/testbed/testsuite.cpp
@@ -233,7 +233,7 @@ uint Testsuite::parseEvents() {
}
void Testsuite::updateStats(const char *prefix, const char *info, uint testNum, uint numTests, Common::Point pt) {
- Common::String text = Common::String::printf(" Running %s: %s (%d of %d) ", prefix, info, testNum, numTests);
+ Common::String text = Common::String::format(" Running %s: %s (%d of %d) ", prefix, info, testNum, numTests);
writeOnScreen(text, pt);
uint barColor = kColorSpecial;
// below the text a rectangle denoting the progress in the testsuite can be drawn.
diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp
index 3577f4e0cc..27cb62f2f2 100644
--- a/engines/tinsel/actors.cpp
+++ b/engines/tinsel/actors.cpp
@@ -199,6 +199,10 @@ void RegisterActors(int num) {
void FreeActors() {
free(actorInfo);
actorInfo = NULL;
+ if (TinselV2) {
+ free(zFactors);
+ zFactors = NULL;
+ }
}
/**
@@ -625,7 +629,7 @@ int NextTaggedActor() {
PMOVER pActor;
bool hid;
- do {
+ while (ti < NumActors) {
if (actorInfo[ti].tagged) {
pActor = GetMover(ti+1);
if (pActor)
@@ -637,7 +641,8 @@ int NextTaggedActor() {
return ++ti;
}
}
- } while (++ti < NumActors);
+ ++ti;
+ }
return 0;
}
diff --git a/engines/tinsel/bmv.cpp b/engines/tinsel/bmv.cpp
index 2077789b9c..fd5088636f 100644
--- a/engines/tinsel/bmv.cpp
+++ b/engines/tinsel/bmv.cpp
@@ -514,7 +514,7 @@ void BMVPlayer::MovieText(CORO_PARAM, int stringId, int x, int y, int fontId, CO
LoadSubString(stringId, 0, TextBufferAddr(), TBUFSZ);
texts[index].dieFrame = currentFrame + duration;
- texts[index].pText = ObjectTextOut(coroParam, GetPlayfieldList(FIELD_STATUS),
+ texts[index].pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(),
0,
x, y,
diff --git a/engines/tinsel/coroutine.cpp b/engines/tinsel/coroutine.cpp
new file mode 100644
index 0000000000..72f39bb21e
--- /dev/null
+++ b/engines/tinsel/coroutine.cpp
@@ -0,0 +1,86 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "tinsel/coroutine.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+
+namespace Tinsel {
+
+
+CoroContext nullContext = NULL;
+
+
+#if COROUTINE_DEBUG
+namespace {
+static int s_coroCount = 0;
+
+typedef Common::HashMap<Common::String, int> CoroHashMap;
+static CoroHashMap *s_coroFuncs = 0;
+
+static void changeCoroStats(const char *func, int change) {
+ if (!s_coroFuncs)
+ s_coroFuncs = new CoroHashMap();
+
+ (*s_coroFuncs)[func] += change;
+}
+
+static void displayCoroStats() {
+ debug("%d active coros", s_coroCount);
+
+ // Loop over s_coroFuncs and print info about active coros
+ if (!s_coroFuncs)
+ return;
+ for (CoroHashMap::const_iterator it = s_coroFuncs->begin();
+ it != s_coroFuncs->end(); ++it) {
+ if (it->_value != 0)
+ debug(" %3d x %s", it->_value, it->_key.c_str());
+ }
+}
+
+}
+#endif
+
+CoroBaseContext::CoroBaseContext(const char *func)
+ : _line(0), _sleep(0), _subctx(0) {
+#if COROUTINE_DEBUG
+ _funcName = func;
+ changeCoroStats(_funcName, +1);
+ s_coroCount++;
+#endif
+}
+
+CoroBaseContext::~CoroBaseContext() {
+#if COROUTINE_DEBUG
+ s_coroCount--;
+ changeCoroStats(_funcName, -1);
+ debug("Deleting coro in %s at %p (subctx %p)",
+ _funcName, (void *)this, (void *)_subctx);
+ displayCoroStats();
+#endif
+ delete _subctx;
+}
+
+} // End of namespace Tinsel
+
diff --git a/engines/tinsel/coroutine.h b/engines/tinsel/coroutine.h
index d4cd54a8db..82bc2c4cca 100644
--- a/engines/tinsel/coroutine.h
+++ b/engines/tinsel/coroutine.h
@@ -27,6 +27,7 @@
#define TINSEL_COROUTINE_H
#include "common/scummsys.h"
+#include "common/util.h" // for SCUMMVM_CURRENT_FUNCTION
namespace Tinsel {
@@ -58,6 +59,10 @@ namespace Tinsel {
*/
//@{
+
+// Enable this macro to enable some debugging support in the coroutine code.
+//#define COROUTINE_DEBUG 1
+
/**
* The core of any coroutine context which captures the 'state' of a coroutine.
* Private use only.
@@ -66,8 +71,11 @@ struct CoroBaseContext {
int _line;
int _sleep;
CoroBaseContext *_subctx;
- CoroBaseContext() : _line(0), _sleep(0), _subctx(0) {}
- ~CoroBaseContext() { delete _subctx; }
+#if COROUTINE_DEBUG
+ const char *_funcName;
+#endif
+ CoroBaseContext(const char *func);
+ ~CoroBaseContext();
};
typedef CoroBaseContext *CoroContext;
@@ -101,9 +109,7 @@ public:
};
-#define CORO_PARAM CoroContext &coroParam
-
-#define CORO_SUBCTX coroParam->_subctx
+#define CORO_PARAM CoroContext &coroParam
/**
@@ -124,10 +130,13 @@ public:
*
* @see CORO_END_CONTEXT
*
- * @note We always declare a variable 'DUMMY' to allow the user to specify
- * an 'empty' context.
+ * @note We declare a variable 'DUMMY' to allow the user to specify an 'empty'
+ * context, and so compilers won't complain about ";" following the macro.
*/
-#define CORO_BEGIN_CONTEXT struct CoroContextTag : CoroBaseContext { int DUMMY
+#define CORO_BEGIN_CONTEXT \
+ struct CoroContextTag : CoroBaseContext { \
+ CoroContextTag() : CoroBaseContext(SCUMMVM_CURRENT_FUNCTION) {} \
+ int DUMMY
/**
* End the declaration of a coroutine context.
@@ -152,7 +161,10 @@ public:
* @see CORO_END_CODE
*/
#define CORO_END_CODE \
- if (&coroParam == &nullContext) nullContext = NULL; \
+ if (&coroParam == &nullContext) { \
+ delete nullContext; \
+ nullContext = NULL; \
+ } \
}
/**
@@ -174,11 +186,28 @@ public:
#define CORO_KILL_SELF() \
do { if (&coroParam != &nullContext) { coroParam->_sleep = -1; } return; } while (0)
+
+/**
+ * This macro is to be used in conjunction with CORO_INVOKE_ARGS and
+ * similar macros for calling coroutines-enabled subroutines.
+ */
+#define CORO_SUBCTX coroParam->_subctx
+
/**
* Invoke another coroutine.
*
* What makes this tricky is that the coroutine we called my yield/sleep,
* and we need to deal with this adequately.
+ *
+ * @param subCoro name of the coroutine-enabled function to invoke
+ * @param ARGS list of arguments to pass to subCoro
+ *
+ * @note ARGS must be surrounded by parentheses, and the first argument
+ * in this list must always be CORO_SUBCTX. For example, the
+ * regular function call
+ * myFunc(a, b);
+ * becomes the following:
+ * CORO_INVOKE_ARGS(myFunc, (CORO_SUBCTX, a, b));
*/
#define CORO_INVOKE_ARGS(subCoro, ARGS) \
do {\
diff --git a/engines/tinsel/debugger.cpp b/engines/tinsel/debugger.cpp
index f422c88e94..ed877587c7 100644
--- a/engines/tinsel/debugger.cpp
+++ b/engines/tinsel/debugger.cpp
@@ -57,7 +57,8 @@ int strToInt(const char *s) {
// Hexadecimal string
uint tmp;
- sscanf(s, "%xh", &tmp);
+ if (!sscanf(s, "%xh", &tmp))
+ tmp = 0;
return (int)tmp;
}
@@ -116,7 +117,7 @@ bool Console::cmd_music(int argc, const char **argv) {
int param = strToInt(argv[1]);
if (param == 0) {
- DebugPrintf("Track number/offset can't be 0!\n", argv[0]);
+ DebugPrintf("Track number/offset can't be 0!\n");
} else if (param > 0) {
// Track provided
PlayMidiSequence(GetTrackOffset(param - 1), false);
diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp
index d6bdad6032..22e8806e7e 100644
--- a/engines/tinsel/detection.cpp
+++ b/engines/tinsel/detection.cpp
@@ -133,7 +133,14 @@ bool TinselMetaEngine::hasFeature(MetaEngineFeature f) const {
bool Tinsel::TinselEngine::hasFeature(EngineFeature f) const {
return
#if 0
- // FIXME: tinsel does not exit cleanly yet
+ // FIXME: It is possible to return to the launcher from tinsel.
+ // But then any attempt to re-enter the engine will lead to
+ // a crash or at least seriously broken behavior.
+ //
+ // This is because the Tinsel engine makes use of tons of
+ // global variables (static and non-static) which are never
+ // explicitly re-initialized when the engine is started
+ // for a second time.
(f == kSupportsRTL) ||
#endif
(f == kSupportsLoadingDuringRuntime);
@@ -184,7 +191,7 @@ bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGa
struct SizeMD5 {
int size;
- char md5[32+1];
+ Common::String md5;
};
typedef Common::HashMap<Common::String, SizeMD5, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SizeMD5Map;
typedef Common::HashMap<Common::String, Common::FSNode, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
@@ -205,8 +212,13 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const Common::FSList &
if (fslist.empty())
return NULL;
+ // TODO: The following code is essentially a slightly modified copy of the
+ // complete code of function detectGame() in engines/advancedDetector.cpp.
+ // That quite some hefty and undesirable code duplication. Its only purpose
+ // seems to be to treat filenames of the form "foo1.ext" as "foo.ext".
+ // It would be nice to avoid this code duplication.
+
// First we compose a hashmap of all files in fslist.
- // Includes nifty stuff like removing trailing dots and ignoring case.
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (file->isDirectory()) {
if (!scumm_stricmp(file->getName().c_str(), "dw2")) {
@@ -256,11 +268,9 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const Common::FSList &
if (testFile.open(allFiles[fname])) {
tmp.size = (int32)testFile.size();
- if (!md5_file_string(testFile, tmp.md5, detectionParams.md5Bytes))
- tmp.md5[0] = 0;
+ tmp.md5 = computeStreamMD5AsString(testFile, detectionParams.md5Bytes);
} else {
tmp.size = -1;
- tmp.md5[0] = 0;
}
filesSizeMD5[fname] = tmp;
@@ -306,7 +316,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const Common::FSList &
break;
}
- if (fileDesc->md5 != NULL && 0 != strcmp(fileDesc->md5, filesSizeMD5[tstr].md5)) {
+ if (fileDesc->md5 != NULL && fileDesc->md5 != filesSizeMD5[tstr].md5) {
fileMissing = true;
break;
}
@@ -330,12 +340,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const Common::FSList &
if (curFilesMatched > maxFilesMatched) {
maxFilesMatched = curFilesMatched;
- for (uint j = 0; j < matched.size();) {
- if (matched[j]->flags & ADGF_KEEPMATCH)
- ++j;
- else
- matched.remove_at(j);
- }
+ matched.clear(); // Remove any prior, lower ranked matches.
matched.push_back((const ADGameDescription *)g);
} else if (curFilesMatched == maxFilesMatched) {
matched.push_back((const ADGameDescription *)g);
diff --git a/engines/tinsel/detection_tables.h b/engines/tinsel/detection_tables.h
index a2a32d2e13..239e06c8dd 100644
--- a/engines/tinsel/detection_tables.h
+++ b/engines/tinsel/detection_tables.h
@@ -102,6 +102,75 @@ static const TinselGameDescription gameDescriptions[] = {
TINSEL_V1,
},
+ {
+ {
+ "dw",
+ "Floppy",
+ {
+ {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
+ {"french.txt", 0, NULL, -1},
+ {"german.txt", 0, NULL, -1},
+ {"italian.txt", 0, NULL, -1},
+ {"spanish.txt", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ ADGF_DROPLANGUAGE,
+ GUIO_NOSPEECH
+ },
+ GID_DW1,
+ 0,
+ GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ TINSEL_V1,
+ },
+
+ {
+ {
+ "dw",
+ "Floppy",
+ {
+ {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
+ {"french.txt", 0, NULL, -1},
+ {"german.txt", 0, NULL, -1},
+ {"italian.txt", 0, NULL, -1},
+ {"spanish.txt", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ ADGF_DROPLANGUAGE,
+ GUIO_NOSPEECH
+ },
+ GID_DW1,
+ 0,
+ GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ TINSEL_V1,
+ },
+
+ {
+ {
+ "dw",
+ "Floppy",
+ {
+ {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
+ {"french.txt", 0, NULL, -1},
+ {"german.txt", 0, NULL, -1},
+ {"italian.txt", 0, NULL, -1},
+ {"spanish.txt", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ ADGF_DROPLANGUAGE,
+ GUIO_NOSPEECH
+ },
+ GID_DW1,
+ 0,
+ GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ TINSEL_V1,
+ },
+
{ // Floppy V1 version, with *.gra files
{
"dw",
@@ -419,6 +488,26 @@ static const TinselGameDescription gameDescriptions[] = {
TINSEL_V1,
},
+ { // English DW2 demo
+ {
+ "dw2",
+ "Demo",
+ {
+ {"dw2.scn", 0, "853ab998f5136b69bc586991175d6eeb", 4231121},
+ {"english.smp", 0, "b5660a0e031cb4710bcb0ef5629ea61d", 28562357},
+ {NULL, 0, NULL, 0}
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ ADGF_DEMO,
+ GUIO_NONE
+ },
+ GID_DW2,
+ 0,
+ GF_CD | GF_SCNFILES | GF_DEMO,
+ TINSEL_V2,
+ },
+
{ // European/Australian Discworld 2 release
{
"dw2",
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index ed59b5669b..135db71575 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -1587,7 +1587,7 @@ static bool InvKeyIn(const Common::KeyState &kbd) {
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL3]);
iconArray[HL3] = NULL;
}
- iconArray[HL3] = ObjectTextOut(nullContext,
+ iconArray[HL3] = ObjectTextOut(
GetPlayfieldList(FIELD_STATUS), sedit, 0,
InvD[ino].inventoryX + cd.box[cd.selBox].xpos + 2,
InvD[ino].inventoryY + cd.box[cd.selBox].ypos + TYOFF,
@@ -1595,7 +1595,7 @@ static bool InvKeyIn(const Common::KeyState &kbd) {
if (MultiRightmost(iconArray[HL3]) > MAX_NAME_RIGHT) {
MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL3]);
UpdateString(Common::KeyState(Common::KEYCODE_BACKSPACE));
- iconArray[HL3] = ObjectTextOut(nullContext,
+ iconArray[HL3] = ObjectTextOut(
GetPlayfieldList(FIELD_STATUS), sedit, 0,
InvD[ino].inventoryX + cd.box[cd.selBox].xpos + 2,
InvD[ino].inventoryY + cd.box[cd.selBox].ypos + TYOFF,
@@ -1669,7 +1669,7 @@ static void Select(int i, bool force) {
}
#endif
- iconArray[HL3] = ObjectTextOut(nullContext,
+ iconArray[HL3] = ObjectTextOut(
GetPlayfieldList(FIELD_STATUS), sedit, 0,
InvD[ino].inventoryX + cd.box[i].xpos + 2,
#ifdef JAPAN
@@ -2634,17 +2634,16 @@ static void AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV,
return;
// Create text object using title string
- CoroContext dummyCoro;
if (textFrom == FROM_HANDLE) {
LoadStringRes(InvD[ino].hInvTitle, TextBufferAddr(), TBUFSZ);
- *title = ObjectTextOut(dummyCoro, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(), 0,
+ *title = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(), 0,
InvD[ino].inventoryX + width/2, InvD[ino].inventoryY + M_TOFF,
GetTagFontHandle(), TXT_CENTRE);
assert(*title); // Inventory title string produced NULL text
MultiSetZPosition(*title, Z_INV_HTEXT);
} else if (textFrom == FROM_STRING && cd.ixHeading != NO_HEADING) {
LoadStringRes(configStrings[cd.ixHeading], TextBufferAddr(), TBUFSZ);
- *title = ObjectTextOut(dummyCoro, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(), 0,
+ *title = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(), 0,
InvD[ino].inventoryX + width/2, InvD[ino].inventoryY + M_TOFF,
GetTagFontHandle(), TXT_CENTRE);
assert(*title); // Inventory title string produced NULL text
@@ -2668,7 +2667,7 @@ static void AddTitle(POBJECT *title, int extraH) {
// Create text object using title string
if (InvD[ino].hInvTitle != (SCNHANDLE)NO_HEADING) {
LoadStringRes(InvD[ino].hInvTitle, TextBufferAddr(), TBUFSZ);
- *title = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(), 0,
+ *title = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(), 0,
InvD[ino].inventoryX + (width/2)+NM_BG_POS_X, InvD[ino].inventoryY + NM_TOFF,
GetTagFontHandle(), TXT_CENTRE, 0);
assert(*title);
@@ -2749,14 +2748,14 @@ static void AddBox(int *pi, const int i) {
(!TinselV2 && (cd.box[i].ixText == USE_POINTER))) {
if (cd.box[i].boxText != NULL) {
if (cd.box[i].boxType == RGROUP) {
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), cd.box[i].boxText, 0,
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), cd.box[i].boxText, 0,
#ifdef JAPAN
x + 2, y+2, GetTagFontHandle(), 0);
#else
x + 2, y + TYOFF, GetTagFontHandle(), 0);
#endif
} else {
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), cd.box[i].boxText, 0,
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), cd.box[i].boxText, 0,
#ifdef JAPAN
// Note: it never seems to go here!
x + cd.box[i].w/2, y+2, GetTagFontHandle(), TXT_CENTRE);
@@ -2782,10 +2781,10 @@ static void AddBox(int *pi, const int i) {
}
if (TinselV2 && (cd.box[i].boxType == RGROUP))
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
0, x + 2, y + TYOFF, GetTagFontHandle(), 0, 0);
else
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0,
#ifdef JAPAN
x + cd.box[i].w/2, y+2, GetTagFontHandle(), TXT_CENTRE);
@@ -2842,7 +2841,7 @@ static void AddBox(int *pi, const int i) {
assert(cd.box[i].ixText != USE_POINTER);
LoadStringRes(configStrings[cd.box[i].ixText], TextBufferAddr(), TBUFSZ);
}
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, x + MDTEXT_XOFF, y + MDTEXT_YOFF, GetTagFontHandle(), TXT_RIGHT);
MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT);
*pi += 1;
@@ -2869,11 +2868,11 @@ static void AddBox(int *pi, const int i) {
}
if (cd.box[i].boxType == TOGGLE2) {
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, x + cd.box[i].w / 2, y + TOG2_YOFF,
GetTagFontHandle(), TXT_CENTRE, 0);
} else {
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, x + MDTEXT_XOFF, y + MDTEXT_YOFF,
GetTagFontHandle(), TXT_RIGHT, 0);
}
@@ -2908,7 +2907,7 @@ static void AddBox(int *pi, const int i) {
assert(cd.box[i].ixText != USE_POINTER);
LoadStringRes(configStrings[cd.box[i].ixText], TextBufferAddr(), TBUFSZ);
}
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, x+MDTEXT_XOFF, y+MDTEXT_YOFF, GetTagFontHandle(), TXT_RIGHT);
MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT);
*pi += 1;
@@ -2933,7 +2932,7 @@ static void AddBox(int *pi, const int i) {
// Stick in the text
assert(cd.box[i].textMethod == TM_INDEX);
LoadStringRes(SysString(cd.box[i].ixText), TextBufferAddr(), TBUFSZ);
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, x + cd.box[i].w / 2, y + TOG2_YOFF,
GetTagFontHandle(), TXT_CENTRE, 0);
MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT);
@@ -2945,7 +2944,7 @@ static void AddBox(int *pi, const int i) {
break;
LoadStringRes(LanguageDesc(displayedLanguage), TextBufferAddr(), TBUFSZ);
- iconArray[*pi] = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(), 0,
+ iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(), 0,
x + cd.box[i].w / 2, y + ROT_YOFF, GetTagFontHandle(), TXT_CENTRE, 0);
MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT);
*pi += 1;
diff --git a/engines/tinsel/graphics.cpp b/engines/tinsel/graphics.cpp
index 48270d94e3..aefc6e6144 100644
--- a/engines/tinsel/graphics.cpp
+++ b/engines/tinsel/graphics.cpp
@@ -66,8 +66,8 @@ uint8* psxPJCRLEUnwinder(uint16 imageWidth, uint16 imageHeight, uint8 *srcIdx) {
return NULL;
// Calculate needed index numbers, align width and height not next multiple of four
- imageWidth = imageWidth % 4 ? ((imageWidth / 4) + 1) * 4 : imageWidth;
- imageHeight = imageHeight % 4 ? ((imageHeight / 4) + 1) * 4 : imageHeight;
+ imageWidth = (imageWidth % 4) ? ((imageWidth / 4) + 1) * 4 : imageWidth;
+ imageHeight = (imageHeight % 4) ? ((imageHeight / 4) + 1) * 4 : imageHeight;
destinationBuffer = (uint8*)malloc((imageWidth * imageHeight) / 8);
dstIdx = destinationBuffer;
remainingBlocks = (imageWidth * imageHeight) / 16;
@@ -297,7 +297,7 @@ static void PsxDrawTiles(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool apply
} else {
for (int xp = boxBounds.left; xp <= boxBounds.right; ++xp) {
// Extract pixel value from byte
- byte pixValue = (*(p + (xp / 2)) & (xp % 2 ? 0xf0 : 0x0f)) >> (xp % 2 ? 4 : 0);
+ byte pixValue = (*(p + (xp / 2)) & ((xp % 2) ? 0xf0 : 0x0f)) >> ((xp % 2) ? 4 : 0);
if (pixValue || !transparency)
*(tempDest + SCREEN_WIDTH * (yp - boxBounds.top) + (xp - boxBounds.left)) = psxMapperTable[pixValue];
}
diff --git a/engines/tinsel/heapmem.cpp b/engines/tinsel/heapmem.cpp
index fa05c3717b..83bbf6affa 100644
--- a/engines/tinsel/heapmem.cpp
+++ b/engines/tinsel/heapmem.cpp
@@ -94,7 +94,7 @@ static void MemoryStats() {
}
}
- printf("%d nodes used, %d alloced, %d locked; %d bytes locked, %d used\n",
+ debug("%d nodes used, %d alloced, %d locked; %d bytes locked, %d used",
usedNodes, allocedNodes, lockedNodes, lockedSize, totalSize);
}
#endif
diff --git a/engines/tinsel/module.mk b/engines/tinsel/module.mk
index 6c818bcb0f..2778cec3df 100644
--- a/engines/tinsel/module.mk
+++ b/engines/tinsel/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS := \
bmv.o \
cliprect.o \
config.o \
+ coroutine.o \
cursor.o \
debugger.o \
detection.o \
diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp
index 0901cd08b8..b46424704c 100644
--- a/engines/tinsel/music.cpp
+++ b/engines/tinsel/music.cpp
@@ -381,7 +381,7 @@ void OpenMidiFiles() {
assert(curTrack < ARRAYSIZE(midiOffsets));
midiOffsets[curTrack] = curOffset + (4 * curTrack);
- //printf("%d: %d\n", curTrack, midiOffsets[curTrack]);
+ //debug("%d: %d", curTrack, midiOffsets[curTrack]);
songLength = midiStream.readUint32LE();
curOffset += songLength;
diff --git a/engines/tinsel/object.cpp b/engines/tinsel/object.cpp
index 7a93a0b30a..b67d20fa93 100644
--- a/engines/tinsel/object.cpp
+++ b/engines/tinsel/object.cpp
@@ -94,7 +94,7 @@ void KillAllObjects() {
*/
void ObjectStats() {
- printf("%i objects of %i used.\n", maxObj, NUM_OBJECTS);
+ debug("%i objects of %i used", maxObj, NUM_OBJECTS);
}
#endif
diff --git a/engines/tinsel/palette.cpp b/engines/tinsel/palette.cpp
index ec518d9e68..528adcd048 100644
--- a/engines/tinsel/palette.cpp
+++ b/engines/tinsel/palette.cpp
@@ -198,8 +198,8 @@ void ResetPalAllocator() {
* Shows the maximum number of palettes used at once.
*/
void PaletteStats() {
- printf("%i palettes of %i used.\n", maxPals, NUM_PALETTES);
- printf("%i DAC queue entries of %i used.\n", maxDACQ, VDACQLENGTH);
+ debug("%i palettes of %i used", maxPals, NUM_PALETTES);
+ debug("%i DAC queue entries of %i used", maxDACQ, VDACQLENGTH);
}
#endif
diff --git a/engines/tinsel/pdisplay.cpp b/engines/tinsel/pdisplay.cpp
index e05a6f6a9a..d55f8be260 100644
--- a/engines/tinsel/pdisplay.cpp
+++ b/engines/tinsel/pdisplay.cpp
@@ -155,7 +155,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
// New text objects
sprintf(PositionString, "%d %d", aniX + Loffset, aniY + Toffset);
- _ctx->cpText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), PositionString,
+ _ctx->cpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
0, CPOSX, POSY, GetTagFontHandle(), TXT_CENTRE);
if (DispPath) {
HPOLYGON hp = InPolygon(aniX + Loffset, aniY + Toffset, PATH);
@@ -167,7 +167,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
PolyCornerX(hp, 1), PolyCornerY(hp, 1),
PolyCornerX(hp, 2), PolyCornerY(hp, 2),
PolyCornerX(hp, 3), PolyCornerY(hp, 3));
- _ctx->cpathText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), PositionString,
+ _ctx->cpathText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
0, 4, POSY+ 10, GetTagFontHandle(), 0);
}
@@ -213,7 +213,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
// create new text object list
sprintf(PositionString, "%d %d", aniX, aniY);
- _ctx->rpText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), PositionString,
+ _ctx->rpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
0, LPOSX, POSY, GetTagFontHandle(), TXT_CENTRE);
// update previous position
@@ -232,7 +232,7 @@ void CursorPositionProcess(CORO_PARAM, const void *) {
}
sprintf(PositionString, "String: %d", newestString);
- _ctx->spText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), PositionString,
+ _ctx->spText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString,
0, SPOSX, POSY+10, GetTalkFontHandle(), TXT_CENTRE);
// update previous value
@@ -407,7 +407,7 @@ static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) {
// May have buggered cursor
EndCursorFollowed();
- *ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), tagBuffer,
+ *ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tagBuffer,
0, tagX, tagY, GetTagFontHandle(), TXT_CENTRE, 0);
assert(*ppText);
MultiSetZPosition(*ppText, Z_TAG_TEXT);
@@ -452,7 +452,7 @@ static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) {
PlayfieldGetPos(FIELD_WORLD, &tagX, &tagY);
LoadStringRes(GetActorTag(ano), TextBufferAddr(), TBUFSZ);
- *ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
+ *ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
0, xtext - tagX, ytext - tagY, GetTagFontHandle(), TXT_CENTRE);
assert(*ppText); // Actor tag string produced NULL text
MultiSetZPosition(*ppText, Z_TAG_TEXT);
@@ -555,7 +555,7 @@ static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
// May have buggered cursor
EndCursorFollowed();
- *ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ *ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, tagx - Loffset, tagy - Toffset,
GetTagFontHandle(), TXT_CENTRE, 0);
} else if (TinselV2) {
@@ -565,11 +565,11 @@ static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) {
StartCursorFollowed();
GetCursorXYNoWait(&curX, &curY, false);
- *ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
+ *ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
0, curX, curY, GetTagFontHandle(), TXT_CENTRE, 0);
} else {
// Handle displaying the tag text on-screen
- *ppText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
+ *ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
0, tagx - Loffset, tagy - Toffset,
GetTagFontHandle(), TXT_CENTRE);
assert(*ppText); // Polygon tag string produced NULL text
diff --git a/engines/tinsel/rince.cpp b/engines/tinsel/rince.cpp
index cfffe88587..17b2bf4ddc 100644
--- a/engines/tinsel/rince.cpp
+++ b/engines/tinsel/rince.cpp
@@ -361,8 +361,8 @@ static void InitMover(PMOVER pMover) {
pMover->Tline = 0;
- if (pMover->direction != FORWARD || pMover->direction != AWAY
- || pMover->direction != LEFTREEL || pMover->direction != RIGHTREEL)
+ if (pMover->direction != FORWARD && pMover->direction != AWAY
+ && pMover->direction != LEFTREEL && pMover->direction != RIGHTREEL)
pMover->direction = FORWARD;
if (pMover->scale < 0 || pMover->scale > TOTAL_SCALES)
diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp
index b010ad1fcb..bb77c962a2 100644
--- a/engines/tinsel/saveload.cpp
+++ b/engines/tinsel/saveload.cpp
@@ -106,6 +106,18 @@ enum {
#define SAVEGAME_ID (TinselV2 ? (uint32)DW2_SAVEGAME_ID : (uint32)DW1_SAVEGAME_ID)
+enum {
+ // FIXME: Save file names in ScummVM can be longer than 8.3, overflowing the
+ // name field in savedFiles. Raising it to 256 as a preliminary fix.
+ FNAMELEN = 256 // 8.3
+};
+
+struct SFILES {
+ char name[FNAMELEN];
+ char desc[SG_DESC_LEN + 2];
+ TimeDate dateTime;
+};
+
//----------------- LOCAL GLOBAL DATA --------------------
static int numSfiles = 0;
@@ -318,9 +330,9 @@ static int cmpTimeDate(const TimeDate &a, const TimeDate &b) {
}
/**
- * Interrogate the current DOS directory for saved game files.
+ * Compute a list of all available saved game files.
* Store the file details, ordered by time, in savedFiles[] and return
- * the number of files found).
+ * the number of files found.
*/
int getList(Common::SaveFileManager *saveFileMan, const Common::String &target) {
// No change since last call?
diff --git a/engines/tinsel/savescn.h b/engines/tinsel/savescn.h
index f0927baae3..271cdd5eb1 100644
--- a/engines/tinsel/savescn.h
+++ b/engines/tinsel/savescn.h
@@ -40,17 +40,7 @@ namespace Tinsel {
enum {
SG_DESC_LEN = 40, // Max. saved game description length
- MAX_SAVED_FILES = 100,
-
- // FIXME: Save file names in ScummVM can be longer than 8.3, overflowing the
- // name field in savedFiles. Raising it to 256 as a preliminary fix.
- FNAMELEN = 256 // 8.3
-};
-
-struct SFILES {
- char name[FNAMELEN];
- char desc[SG_DESC_LEN + 2];
- TimeDate dateTime;
+ MAX_SAVED_FILES = 100
};
struct SAVED_DATA {
diff --git a/engines/tinsel/scene.h b/engines/tinsel/scene.h
index e17a6ab7a0..2ef7da1289 100644
--- a/engines/tinsel/scene.h
+++ b/engines/tinsel/scene.h
@@ -78,9 +78,9 @@ enum REEL {
typedef enum { TRANS_DEF, TRANS_CUT, TRANS_FADE } TRANSITS;
// amount to shift scene handles by
-#define SCNHANDLE_SHIFT (TinselV2 ? 25 : 23)
-#define OFFSETMASK (TinselV2 ? 0x01ffffffL : 0x007fffffL)
-#define HANDLEMASK (TinselV2 ? 0xFE000000L : 0xFF800000L)
+#define SCNHANDLE_SHIFT ((TinselV2 && !IsDemo) ? 25 : 23)
+#define OFFSETMASK ((TinselV2 && !IsDemo) ? 0x01ffffffL : 0x007fffffL)
+#define HANDLEMASK ((TinselV2 && !IsDemo) ? 0xFE000000L : 0xFF800000L)
void DoHailScene(SCNHANDLE scene);
diff --git a/engines/tinsel/sched.cpp b/engines/tinsel/sched.cpp
index d8a44944fc..d90312d271 100644
--- a/engines/tinsel/sched.cpp
+++ b/engines/tinsel/sched.cpp
@@ -45,8 +45,6 @@ struct PROCESS_STRUC {
#include "common/pack-end.h" // END STRUCT PACKING
-CoroContext nullContext = NULL;
-
//----------------- LOCAL GLOBAL DATA --------------------
static uint32 numSceneProcess;
@@ -77,6 +75,14 @@ Scheduler::Scheduler() {
}
Scheduler::~Scheduler() {
+ // Kill all running processes (i.e. free memory allocated for their state).
+ PROCESS *pProc = active->pNext;
+ while (pProc != NULL) {
+ delete pProc->state;
+ pProc->state = 0;
+ pProc = pProc->pNext;
+ }
+
free(processList);
processList = NULL;
@@ -126,7 +132,7 @@ void Scheduler::reset() {
* Shows the maximum number of process used at once.
*/
void Scheduler::printStats() {
- printf("%i process of %i used.\n", maxProcs, NUM_PROCESS);
+ debug("%i process of %i used", maxProcs, NUM_PROCESS);
}
#endif
@@ -392,6 +398,7 @@ void Scheduler::killProcess(PROCESS *pKillProc) {
(pRCfunction)(pKillProc);
delete pKillProc->state;
+ pKillProc->state = 0;
// Take the process out of the active chain list
pKillProc->pPrevious->pNext = pKillProc->pNext;
@@ -458,6 +465,7 @@ int Scheduler::killMatchingProcess(int pidKill, int pidMask) {
(pRCfunction)(pProc);
delete pProc->state;
+ pProc->state = 0;
// make prev point to next to unlink pProc
pPrev->pNext = pProc->pNext;
@@ -752,6 +760,7 @@ void GlobalProcesses(uint32 numProcess, byte *pProcess) {
*/
void FreeGlobalProcesses() {
delete[] pGlobalProcess;
+ pGlobalProcess = 0;
numGlobalProcess = 0;
}
diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp
index 6e8e736e14..0a32ab143f 100644
--- a/engines/tinsel/sound.cpp
+++ b/engines/tinsel/sound.cpp
@@ -480,8 +480,8 @@ void SoundManager::setSFXVolumes(uint8 volume) {
* Opens and inits all sound sample files.
*/
void SoundManager::openSampleFiles() {
- // Floppy and demo versions have no sample files
- if (_vm->getFeatures() & GF_FLOPPY || _vm->getFeatures() & GF_DEMO)
+ // Floppy and demo versions have no sample files, except for the Discworld 2 demo
+ if (_vm->getFeatures() & GF_FLOPPY || (IsDemo && !TinselV2))
return;
TinselFile f;
diff --git a/engines/tinsel/text.cpp b/engines/tinsel/text.cpp
index c7c921b935..d2939281eb 100644
--- a/engines/tinsel/text.cpp
+++ b/engines/tinsel/text.cpp
@@ -107,7 +107,7 @@ int JustifyText(char *szStr, int xPos, const FONT *pFont, int mode) {
* @param mode Mode flags for the string
* @param sleepTime Sleep time between each character (if non-zero)
*/
-OBJECT *ObjectTextOut(CORO_PARAM, OBJECT *pList, char *szStr, int colour,
+OBJECT *ObjectTextOut(OBJECT *pList, char *szStr, int colour,
int xPos, int yPos, SCNHANDLE hFont, int mode, int sleepTime) {
int xJustify; // x position of text after justification
int yOffset; // offset to next line of text
diff --git a/engines/tinsel/text.h b/engines/tinsel/text.h
index 664f0d207c..a849e286ec 100644
--- a/engines/tinsel/text.h
+++ b/engines/tinsel/text.h
@@ -98,7 +98,7 @@ struct TEXTOUT {
* @param mode mode flags for the string
* @param sleepTime Sleep time between each character (if non-zero)
*/
-OBJECT *ObjectTextOut(CORO_PARAM, OBJECT *pList, char *szStr, int colour,
+OBJECT *ObjectTextOut(OBJECT *pList, char *szStr, int colour,
int xPos, int yPos, SCNHANDLE hFont, int mode, int sleepTime = 0);
OBJECT *ObjectTextOutIndirect( // output a string of text
diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp
index 766d4ed54a..dea60802d1 100644
--- a/engines/tinsel/tinlib.cpp
+++ b/engines/tinsel/tinlib.cpp
@@ -213,6 +213,43 @@ const MASTER_LIB_CODES DW1_CODES[] = {
HIGHEST_LIBCODE
};
+const MASTER_LIB_CODES DW2DEMO_CODES[] = {
+ ACTORBRIGHTNESS, ACTORDIRECTION, ACTORPALETTE, ACTORPRIORITY,
+ ACTORREF, ACTORRGB, ACTORSCALE, ACTORXPOS, ACTORYPOS,
+ ADDHIGHLIGHT, ADDINV, ADDINV1, ADDINV2, ADDOPENINV, ADDTOPIC,
+ BACKGROUND, CALLACTOR, CALLGLOBALPROCESS, CALLOBJECT,
+ CALLPROCESS, CALLSCENE, CALLTAG, CAMERA, CDCHANGESCENE,
+ CDDOCHANGE, CDLOAD, CDPLAY, CLEARHOOKSCENE, CLOSEINVENTORY,
+ CONTROL, CONVERSATION, CURSOR, CURSORXPOS, CURSORYPOS,
+ DECCONVW, DECCURSOR, DECFLAGS, DECINV1, DECINV2, DECINVW,
+ DECLEAD, DECSCALE, DECTAGFONT, DECTALKFONT, DELTOPIC,
+ DIMMUSIC, DROP, DROPOUT, EFFECTACTOR, ENABLEMENU, ENDACTOR,
+ ESCAPEOFF, ESCAPEON, EVENT, FACETAG, FADEIN, FADEOUT, FRAMEGRAB,
+ FREEZECURSOR, GETINVLIMIT, GHOST, GLOBALVAR, HASRESTARTED,
+ HAVE, HELDOBJECT, HIDEACTOR, HIDEBLOCK, HIDEEFFECT, HIDEPATH,
+ HIDEREFER, HIDETAG, HOLD, HOOKSCENE, IDLETIME, INSTANTSCROLL,
+ INVENTORY, INVPLAY, INWHICHINV, KILLACTOR, KILLGLOBALPROCESS,
+ KILLPROCESS, LOCALVAR, MOVECURSOR, MOVETAG, MOVETAGTO, NEWSCENE,
+ NOBLOCKING, NOPAUSE, NOSCROLL, OFFSET, OTHEROBJECT, PAUSE, PLAY,
+ PLAYMUSIC, PLAYRTF, PLAYSAMPLE, POINTACTOR, POINTTAG, POSTACTOR,
+ POSTGLOBALPROCESS, POSTOBJECT, POSTPROCESS, POSTTAG, PRINT,
+ PRINTCURSOR, PRINTOBJ, PRINTTAG, QUITGAME, RANDOM, RESETIDLETIME,
+ RESTARTGAME, RESTORESCENE, RUNMODE, SAVESCENE, SAY, SAYAT,
+ SCALINGREELS, SCREENXPOS, SCREENYPOS, SCROLL, SCROLLPARAMETERS,
+ SENDACTOR, SENDGLOBALPROCESS, SENDOBJECT, SENDPROCESS, SENDTAG,
+ SETBRIGHTNESS, SETINVLIMIT, SETINVSIZE, SETLANGUAGE, SETPALETTE,
+ SETSYSTEMSTRING, SETSYSTEMVAR, SHELL, SHOWACTOR, SHOWBLOCK,
+ SHOWEFFECT, SHOWPATH, SHOWREFER, SHOWTAG, STAND, STANDTAG,
+ STARTGLOBALPROCESS, STARTPROCESS, STARTTIMER, STOPWALK, SUBTITLES,
+ SWALK, SYSTEMVAR, TAGTAGXPOS, TAGTAGYPOS, TAGWALKXPOS, TAGWALKYPOS,
+ TALK, TALKAT, TALKPALETTEINDEX, TALKRGB, TALKVIA, THISOBJECT,
+ THISTAG, TIMER, TOPIC, TOPPLAY, TOPWINDOW, TRANSLUCENTINDEX,
+ UNDIMMUSIC, UNHOOKSCENE, WAITFRAME, WAITKEY, WAITSCROLL, WAITTIME,
+ WALK, WALKED, WALKEDPOLY, WALKEDTAG, WALKINGACTOR, WALKPOLY,
+ WALKTAG, WALKXPOS, WALKYPOS, WHICHCD, WHICHINVENTORY,
+ HIGHEST_LIBCODE
+};
+
const MASTER_LIB_CODES DW2_CODES[] = {
ACTORBRIGHTNESS, ACTORDIRECTION, ACTORPALETTE, ACTORPRIORITY,
ACTORREF, ACTORRGB, ACTORSCALE, ACTORXPOS, ACTORYPOS,
@@ -1912,7 +1949,7 @@ static void Print(CORO_PARAM, int x, int y, SCNHANDLE text, int time, bool bSust
if (TinselV2) {
int Loffset, Toffset;
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
- _ctx->pText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ _ctx->pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, x - Loffset, y - Toffset, GetTagFontHandle(),
TXT_CENTRE, 0);
assert(_ctx->pText);
@@ -1925,7 +1962,7 @@ static void Print(CORO_PARAM, int x, int y, SCNHANDLE text, int time, bool bSust
} else if (bJapDoPrintText || (!isJapanMode() && (_vm->_config->_useSubtitles || !_ctx->bSample))) {
int Loffset, Toffset; // Screen position
PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
- _ctx->pText = ObjectTextOut(coroParam, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
+ _ctx->pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
0, x - Loffset, y - Toffset,
TinselV2 ? GetTagFontHandle() : GetTalkFontHandle(), TXT_CENTRE);
assert(_ctx->pText); // string produced NULL text
@@ -2089,7 +2126,7 @@ static void PrintObj(CORO_PARAM, const SCNHANDLE hText, const INV_OBJECT *pinvo,
else
LoadStringRes(hText, TextBufferAddr(), TBUFSZ);
- _ctx->pText = ObjectTextOut(coroParam, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
+ _ctx->pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
0, _ctx->textx, _ctx->texty, GetTagFontHandle(), TXT_CENTRE);
assert(_ctx->pText); // PrintObj() string produced NULL text
@@ -2141,7 +2178,7 @@ static void PrintObj(CORO_PARAM, const SCNHANDLE hText, const INV_OBJECT *pinvo,
// Re-display in the same place
LoadStringRes(hText, TextBufferAddr(), TBUFSZ);
- _ctx->pText = ObjectTextOut(nullContext, GetPlayfieldList(FIELD_STATUS),
+ _ctx->pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, _ctx->textx, _ctx->texty, GetTagFontHandle(),
TXT_CENTRE, 0);
assert(_ctx->pText);
@@ -2258,7 +2295,7 @@ static void PrintObjPointed(CORO_PARAM, const SCNHANDLE text, const INV_OBJECT *
// Re-display in the same place
LoadStringRes(text, TextBufferAddr(), TBUFSZ);
- pText = ObjectTextOut(coroParam, GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
+ pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), TextBufferAddr(),
0, textx, texty, GetTagFontHandle(), TXT_CENTRE);
assert(pText); // PrintObj() string produced NULL text
MultiSetZPosition(pText, Z_INV_ITEXT);
@@ -3327,7 +3364,7 @@ static void TalkOrSay(CORO_PARAM, SPEECH_TYPE speechType, SCNHANDLE hText, int x
_ctx->y -= _ctx->Toffset;
}
- _ctx->pText = ObjectTextOut(coroParam, GetPlayfieldList(FIELD_STATUS),
+ _ctx->pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS),
TextBufferAddr(), 0, _ctx->x - _ctx->Loffset, _ctx->y - _ctx->Toffset,
GetTalkFontHandle(), TXT_CENTRE);
assert(_ctx->pText); // talk() string produced NULL text;
@@ -3376,7 +3413,7 @@ static void TalkOrSay(CORO_PARAM, SPEECH_TYPE speechType, SCNHANDLE hText, int x
// Kick off the sample now (perhaps with a delay)
if (bNoPause)
bNoPause = false;
- else
+ else if (!IsDemo)
CORO_SLEEP(SysVar(SV_SPEECHDELAY));
//SamplePlay(VOICE, hText, _ctx->sub, false, -1, -1, PRIORITY_TALK);
@@ -4208,6 +4245,7 @@ int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pi
int libCode;
if (TinselV0) libCode = DW1DEMO_CODES[operand];
else if (!TinselV2) libCode = DW1_CODES[operand];
+ else if (_vm->getFeatures() & GF_DEMO) libCode = DW2DEMO_CODES[operand];
else libCode = DW2_CODES[operand];
debug(7, "CallLibraryRoutine op %d (escOn %d, myEscape %d)", operand, pic->escOn, pic->myEscape);
@@ -4907,9 +4945,6 @@ int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pi
else {
Play(coroParam, pp[0], pp[1], pp[2], pp[3], pic->myEscape, false,
pic->event, pic->hPoly, pic->idActor);
-
- if (coroParam)
- return 0;
}
return -4;
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index f16b5f9100..386a402af4 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -79,6 +79,7 @@ namespace Tinsel {
// In BG.CPP
extern void SetDoFadeIn(bool tf);
extern void DropBackground();
+extern BACKGND *pCurBgnd;
// In CURSOR.CPP
extern void CursorProcess(CORO_PARAM, const void *);
@@ -1032,6 +1033,9 @@ Common::Error TinselEngine::run() {
// Write configuration
_vm->_config->writeToDisk();
+ EndScene();
+ pCurBgnd = NULL;
+
return Common::kNoError;
}
diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h
index ed70979349..c4f4a3bc13 100644
--- a/engines/tinsel/tinsel.h
+++ b/engines/tinsel/tinsel.h
@@ -48,7 +48,7 @@
*
* Status of this engine: Complete
*
- * Supported games:
+ * Games using this engine:
* - Discworld
* - Discworld 2: Missing Presumed ...!?
*/
@@ -139,6 +139,7 @@ typedef bool (*KEYFPTR)(const Common::KeyState &);
#define TinselV1 (TinselVersion == TINSEL_V1)
#define TinselV2 (TinselVersion == TINSEL_V2)
#define TinselV1PSX (TinselVersion == TINSEL_V1 && _vm->getPlatform() == Common::kPlatformPSX)
+#define IsDemo (_vm->getFeatures() & GF_DEMO)
// Global reference to the TinselEngine object
extern TinselEngine *_vm;
@@ -183,6 +184,7 @@ public:
uint32 getFeatures() const;
Common::Language getLanguage() const;
uint16 getVersion() const;
+ uint32 getFlags() const;
Common::Platform getPlatform() const;
const char *getSampleIndex(LANGUAGE lang);
diff --git a/engines/toon/anim.cpp b/engines/toon/anim.cpp
index 157422cd9d..169d53de5d 100644
--- a/engines/toon/anim.cpp
+++ b/engines/toon/anim.cpp
@@ -58,6 +58,7 @@ bool Animation::loadAnimation(Common::String file) {
uint8 *currentData = fileData + 68;
if (_paletteEntries) {
if (paletteSize) {
+ delete[] _palette;
_palette = new uint8[paletteSize];
memcpy(_palette, currentData, paletteSize);
currentData += paletteSize;
@@ -74,6 +75,7 @@ bool Animation::loadAnimation(Common::String file) {
if (READ_LE_UINT32(finalBuffer) == 0x12345678) {
uint8 *data = finalBuffer;
+ delete[] _frames;
_frames = new AnimationFrame[_numFrames];
for (int32 e = 0; e < _numFrames; e++) {
if (READ_LE_UINT32(data) != 0x12345678)
@@ -95,7 +97,11 @@ bool Animation::loadAnimation(Common::String file) {
} else {
_frames[e]._ref = -1;
_frames[e]._data = new uint8[decompressedSize];
- decompressLZSS(imageData, _frames[e]._data, decompressedSize);
+ if (compressedSize < decompressedSize) {
+ decompressLZSS(imageData, _frames[e]._data, decompressedSize);
+ } else {
+ memcpy(_frames[e]._data, imageData, compressedSize);
+ }
}
data += headerSize + compressedSize;
@@ -107,8 +113,9 @@ bool Animation::loadAnimation(Common::String file) {
}
Animation::Animation(ToonEngine *vm) : _vm(vm) {
- _palette = 0;
- _frames = 0;
+ _palette = NULL;
+ _numFrames = 0;
+ _frames = NULL;
}
Animation::~Animation() {
@@ -140,9 +147,26 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int
int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+ int32 offsX = 0;
+ int32 offsY = 0;
- if ((xx + _x1 + _frames[frame]._x1 < 0) || (yy + _y1 + _frames[frame]._y1 < 0))
+ if (xx + _x1 + _frames[frame]._x1 < 0) {
+ offsX = -(xx + _x1 + _frames[frame]._x1);
+ }
+
+ if (offsX >= rectX)
return;
+ else
+ rectX -= offsX;
+
+ if (yy + _y1 + _frames[frame]._y1 < 0) {
+ offsY = -(yy + _y1 + _frames[frame]._y1);
+ }
+
+ if (offsY >= rectY)
+ return;
+ else
+ rectY -= offsY;
if (rectX + xx + _x1 + _frames[frame]._x1 >= surface.w)
rectX = surface.w - xx - _x1 - _frames[frame]._x1;
@@ -157,8 +181,8 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int
return;
int32 destPitch = surface.pitch;
- uint8 *srcRow = _frames[frame]._data;
- uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1);
+ uint8 *srcRow = _frames[frame]._data + offsX + (_frames[frame]._x2 - _frames[frame]._x1) * offsY;
+ uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1 + offsY) * destPitch + (xx + _x1 + _frames[frame]._x1 + offsX);
for (int32 y = 0; y < rectY; y++) {
uint8 *cur = curRow;
uint8 *c = srcRow + y * (_frames[frame]._x2 - _frames[frame]._x1);
@@ -408,6 +432,7 @@ AnimationInstance::AnimationInstance(ToonEngine *vm, AnimationInstanceType type)
_playing = false;
_rangeEnd = 0;
_useMask = false;
+ _alignBottom = false;
_rangeStart = 0;
_scale = 1024;
_x = 0;
@@ -416,6 +441,7 @@ AnimationInstance::AnimationInstance(ToonEngine *vm, AnimationInstanceType type)
_layerZ = 0;
}
+
void AnimationInstance::render() {
debugC(5, kDebugAnim, "render()");
if (_visible && _animation) {
@@ -426,11 +452,22 @@ void AnimationInstance::render() {
if (frame >= _animation->_numFrames)
frame = _animation->_numFrames - 1;
+ int32 x = _x;
+ int32 y = _y;
+
+ if (_alignBottom) {
+ int32 offsetX = (_animation->_x2 - _animation->_x1) / 2 * (_scale - 1024);
+ int32 offsetY = (_animation->_y2 - _animation->_y1) * (_scale - 1024);
+
+ x -= offsetX >> 10;
+ y -= offsetY >> 10;
+ }
+
if (_useMask) {
//if (_scale == 100) { // 100% scale
// _animation->drawFrameWithMask(_vm->getMainSurface(), _currentFrame, _x, _y, _z, _vm->getMask());
//} else {
- _animation->drawFrameWithMaskAndScale(_vm->getMainSurface(), frame, _x, _y, _z, _vm->getMask(), _scale);
+ _animation->drawFrameWithMaskAndScale(_vm->getMainSurface(), frame, x, y, _z, _vm->getMask(), _scale);
//}
} else {
_animation->drawFrame(_vm->getMainSurface(), frame, _x, _y);
@@ -517,9 +554,10 @@ void AnimationInstance::setVisible(bool visible) {
_visible = visible;
}
-void AnimationInstance::setScale(int32 scale) {
+void AnimationInstance::setScale(int32 scale, bool align) {
debugC(4, kDebugAnim, "setScale(%d)", scale);
_scale = scale;
+ _alignBottom = align;
}
void AnimationInstance::setUseMask(bool useMask) {
diff --git a/engines/toon/anim.h b/engines/toon/anim.h
index 7bf633220c..01475276c5 100644
--- a/engines/toon/anim.h
+++ b/engines/toon/anim.h
@@ -102,7 +102,7 @@ public:
void forceFrame(int32 position);
void setPosition(int32 x, int32 y, int32 z, bool relative = false);
Animation *getAnimation() const { return _animation; }
- void setScale(int32 scale);
+ void setScale(int32 scale, bool align = false);
void setVisible(bool visible);
bool getVisible() const { return _visible; }
void setUseMask(bool useMask);
@@ -150,6 +150,7 @@ protected:
bool _playing;
bool _looping;
bool _visible;
+ bool _alignBottom;
ToonEngine *_vm;
};
@@ -186,6 +187,7 @@ public:
EMCState _state;
uint32 _lastTimer;
bool _frozen;
+ bool _frozenForConversation;
bool _active;
};
diff --git a/engines/toon/audio.cpp b/engines/toon/audio.cpp
index 496d626201..386d00ef77 100644
--- a/engines/toon/audio.cpp
+++ b/engines/toon/audio.cpp
@@ -45,9 +45,44 @@ static int ADPCM_table[89] = {
AudioManager::AudioManager(ToonEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
for (int32 i = 0; i < 16; i++)
_channels[i] = 0;
+
+ for (int32 i = 0; i < 4; i++)
+ _audioPacks[i] = 0;
+
+ for (int32 i = 0; i < 4; i++) {
+ _ambientSFXs[i]._delay = 0;
+ _ambientSFXs[i]._enabled = false;
+ _ambientSFXs[i]._id = -1;
+ _ambientSFXs[i]._channel = -1;
+ _ambientSFXs[i]._lastTimer = 0;
+ _ambientSFXs[i]._volume = 255;
+ }
+
+ _voiceMuted = false;
+ _musicMuted = false;
+ _sfxMuted = false;
}
AudioManager::~AudioManager(void) {
+ for (int32 i = 0; i < 4; i++) {
+ closeAudioPack(i);
+ }
+}
+
+void AudioManager::muteMusic(bool muted) {
+ setMusicVolume(muted ? 0 : 255);
+ _musicMuted = muted;
+}
+
+void AudioManager::muteVoice(bool muted) {
+ if(voiceStillPlaying() && _channels[2]) {
+ _channels[2]->setVolume(muted ? 0 : 255);
+ }
+ _voiceMuted = muted;
+}
+
+void AudioManager::muteSfx(bool muted) {
+ _sfxMuted = muted;
}
void AudioManager::removeInstance(AudioStreamInstance *inst) {
@@ -63,7 +98,7 @@ void AudioManager::playMusic(Common::String dir, Common::String music) {
debugC(1, kDebugAudio, "playMusic(%s, %s)", dir.c_str(), music.c_str());
// two musics can be played at same time
- Common::String path = Common::String::printf("act%d/%s/%s.mus", _vm->state()->_currentChapter, dir.c_str(), music.c_str());
+ Common::String path = Common::String::format("act%d/%s/%s.mus", _vm->state()->_currentChapter, dir.c_str(), music.c_str());
if (_currentMusicName == music)
return;
@@ -99,6 +134,7 @@ void AudioManager::playMusic(Common::String dir, Common::String music) {
//if (!_channels[_currentMusicChannel])
// delete _channels[_currentMusicChannel];
_channels[_currentMusicChannel] = new AudioStreamInstance(this, _mixer, srs, true);
+ _channels[_currentMusicChannel]->setVolume(_musicMuted ? 0 : 255);
_channels[_currentMusicChannel]->play(true, Audio::Mixer::kMusicSoundType);
}
@@ -125,10 +161,11 @@ void AudioManager::playVoice(int32 id, bool genericVoice) {
_channels[2] = new AudioStreamInstance(this, _mixer, stream);
_channels[2]->play(false, Audio::Mixer::kSpeechSoundType);
+ _channels[2]->setVolume(_voiceMuted ? 0 : 255);
}
-void AudioManager::playSFX(int32 id, int32 volume , bool genericSFX) {
+int32 AudioManager::playSFX(int32 id, int volume , bool genericSFX) {
debugC(4, kDebugAudio, "playSFX(%d, %d)", id, (genericSFX) ? 1 : 0);
// find a free SFX channel
@@ -140,14 +177,24 @@ void AudioManager::playSFX(int32 id, int32 volume , bool genericSFX) {
stream = _audioPacks[3]->getStream(id, true);
if (stream->size() == 0)
- return;
+ return -1;
for (int32 i = 3; i < 16; i++) {
if (!_channels[i]) {
_channels[i] = new AudioStreamInstance(this, _mixer, stream);
_channels[i]->play(false, Audio::Mixer::kSFXSoundType);
- _channels[i]->setVolume(volume);
- break;
+ _channels[i]->setVolume(_sfxMuted ? 0 : volume);
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void AudioManager::stopAllSfxs() {
+ for (int32 i = 3; i < 16; i++) {
+ if (_channels[i] && _channels[i]->isPlaying()) {
+ _channels[i]->stop(false);
}
}
}
@@ -159,9 +206,18 @@ void AudioManager::stopCurrentVoice() {
_channels[2]->stop(false);
}
+
+void AudioManager::closeAudioPack(int32 id) {
+ if(_audioPacks[id]) {
+ delete _audioPacks[id];
+ _audioPacks[id] = 0;
+ }
+}
+
bool AudioManager::loadAudioPack(int32 id, Common::String indexFile, Common::String packFile) {
debugC(4, kDebugAudio, "loadAudioPack(%d, %s, %s)", id, indexFile.c_str(), packFile.c_str());
+ closeAudioPack(id);
_audioPacks[id] = new AudioStreamPackage(_vm);
return _audioPacks[id]->loadAudioPackage(indexFile, packFile);
}
@@ -218,7 +274,7 @@ AudioStreamInstance::AudioStreamInstance(AudioManager *man, Audio::Mixer *mixer,
}
}
-int32 AudioStreamInstance::readBuffer(int16 *buffer, const int numSamples) {
+int AudioStreamInstance::readBuffer(int16 *buffer, const int numSamples) {
debugC(5, kDebugAudio, "readBuffer(buffer, %d)", numSamples);
handleFade(numSamples);
@@ -349,11 +405,11 @@ void AudioStreamInstance::play(bool fade, Audio::Mixer::SoundType soundType) {
_fadeTime = 0;
_soundType = soundType;
_musicAttenuation = 1000; // max volume
- _mixer->playStream(soundType, &_handle, this);
+ _mixer->playStream(soundType, &_handle, this, -1);
handleFade(0);
}
-void AudioStreamInstance::handleFade(int numSamples) {
+void AudioStreamInstance::handleFade(int32 numSamples) {
debugC(5, kDebugAudio, "handleFade(%d)", numSamples);
// Fading enabled only for music
@@ -426,11 +482,13 @@ void AudioStreamInstance::setVolume(int32 volume) {
}
AudioStreamPackage::AudioStreamPackage(ToonEngine *vm) : _vm(vm) {
- _indexBuffer = 0;
+ _indexBuffer = NULL;
+ _file = NULL;
}
AudioStreamPackage::~AudioStreamPackage() {
delete[] _indexBuffer;
+ delete _file;
}
bool AudioStreamPackage::loadAudioPackage(Common::String indexFile, Common::String streamFile) {
@@ -442,7 +500,6 @@ bool AudioStreamPackage::loadAudioPackage(Common::String indexFile, Common::Stri
return false;
delete[] _indexBuffer;
-
_indexBuffer = new uint32[size / 4];
memcpy(_indexBuffer, fileData, size);
@@ -476,5 +533,94 @@ Common::SeekableReadStream *AudioStreamPackage::getStream(int32 id, bool ownMemo
}
}
+void AudioManager::startAmbientSFX(int32 id, int32 delay, int32 mode, int32 volume)
+{
+ int32 found = -1;
+ for (int32 i = 0; i < 4; i++) {
+ if (!_ambientSFXs[i]._enabled) {
+ found = i;
+ break;
+ }
+ }
+
+ if (found < 0)
+ return;
+
+ _ambientSFXs[found]._lastTimer = _vm->getOldMilli() - 1;
+ _ambientSFXs[found]._delay = delay;
+ _ambientSFXs[found]._enabled = true;
+ _ambientSFXs[found]._mode = mode;
+ _ambientSFXs[found]._volume = volume;
+ _ambientSFXs[found]._id = id;
+ updateAmbientSFX();
+
+}
+
+void AudioManager::setAmbientSFXVolume(int32 id, int volume) {
+ for (int32 i = 0; i < 4; i++) {
+ AudioAmbientSFX* ambient = &_ambientSFXs[i];
+ if (ambient->_id == id && ambient->_enabled) {
+ ambient->_volume = volume;
+ if (ambient->_channel >= 0 && _channels[ambient->_channel] && _channels[ambient->_channel]->isPlaying()) {
+ _channels[ambient->_channel]->setVolume(volume);
+ }
+ break;
+ }
+ }
+}
+
+void AudioManager::killAmbientSFX(int32 id)
+{
+ for (int32 i = 0; i < 4; i++) {
+ AudioAmbientSFX* ambient = &_ambientSFXs[i];
+ if (ambient->_id == id && ambient->_enabled) {
+ ambient->_enabled = false;
+ ambient->_id = -1;
+
+ if (_channels[ambient->_channel]) {
+ _channels[ambient->_channel]->stop(false);
+ }
+ }
+
+ }
+}
+
+void AudioManager::killAllAmbientSFX()
+{
+ for (int32 i = 0; i < 4; i++) {
+ AudioAmbientSFX* ambient = &_ambientSFXs[i];
+ if (ambient->_enabled) {
+ ambient->_enabled = false;
+ ambient->_id = -1;
+ if (ambient->_channel >= 0 && _channels[ambient->_channel] && _channels[ambient->_channel]->isPlaying()) {
+ _channels[ambient->_channel]->stop(false);
+ }
+ ambient->_channel = -1;
+ }
+ }
+}
+
+void AudioManager::updateAmbientSFX()
+{
+ if (_vm->getMoviePlayer()->isPlaying()) return;
+
+ for (int32 i = 0; i < 4; i++) {
+ AudioAmbientSFX* ambient = &_ambientSFXs[i];
+ if (ambient->_enabled && (ambient->_channel < 0 || !(_channels[ambient->_channel] && _channels[ambient->_channel]->isPlaying()))) {
+ if(ambient->_mode == 1) {
+ if (_vm->randRange(0, 32767) < ambient->_delay) {
+ ambient->_channel = playSFX(ambient->_id, ambient->_volume, false);
+ }
+ } else {
+ if (_vm->getOldMilli() > ambient->_lastTimer) {
+ ambient->_channel = playSFX(ambient->_id, ambient->_volume, false);
+ ambient->_lastTimer = _vm->getOldMilli(); // + 60 * _vm->getTickLength() * ambient->_delay;
+ }
+ }
+ }
+ }
+}
+
+
} // End of namespace Toon
diff --git a/engines/toon/audio.h b/engines/toon/audio.h
index 5a8274e086..e0676c2992 100644
--- a/engines/toon/audio.h
+++ b/engines/toon/audio.h
@@ -54,7 +54,7 @@ public:
void setVolume(int32 volume);
protected:
- int32 readBuffer(int16 *buffer, const int numSamples);
+ int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const {
return false;
}
@@ -109,6 +109,16 @@ protected:
ToonEngine *_vm;
};
+struct AudioAmbientSFX {
+ int32 _id;
+ int32 _volume;
+ int32 _lastTimer;
+ int32 _delay;
+ int32 _mode;
+ int32 _channel;
+ bool _enabled;
+};
+
class AudioManager {
public:
void removeInstance(AudioStreamInstance *inst); // called by destructor
@@ -120,12 +130,25 @@ public:
void playMusic(Common::String dir, Common::String music);
void playVoice(int32 id, bool genericVoice);
- void playSFX(int32 id, int volume, bool genericSFX);
+ int32 playSFX(int32 id, int volume, bool genericSFX);
void stopCurrentVoice();
+ void stopAllSfxs();
void setMusicVolume(int32 volume);
void stopMusic();
-
-
+ void muteVoice(bool mute);
+ void muteMusic(bool mute);
+ void muteSfx(bool mute);
+ bool isVoiceMuted() { return _voiceMuted; }
+ bool isMusicMuted() { return _musicMuted; }
+ bool isSfxMuted() { return _sfxMuted; }
+
+ void startAmbientSFX(int32 id, int32 delay, int32 mode, int32 volume);
+ void killAmbientSFX(int32 id);
+ void killAllAmbientSFX();
+ void updateAmbientSFX();
+ void setAmbientSFXVolume(int32 id, int volume);
+
+ void closeAudioPack(int32 id);
bool loadAudioPack(int32 id, Common::String indexFile, Common::String packFile);
AudioStreamInstance *_channels[16]; // 0-1 : music
@@ -140,6 +163,13 @@ public:
Common::String _currentMusicName;
ToonEngine *_vm;
Audio::Mixer *_mixer;
+
+protected:
+ bool _voiceMuted;
+ bool _musicMuted;
+ bool _sfxMuted;
+
+ AudioAmbientSFX _ambientSFXs[4];
};
} // End of namespace Toon
diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp
index 50913f89c7..65c4135433 100644
--- a/engines/toon/character.cpp
+++ b/engines/toon/character.cpp
@@ -32,8 +32,8 @@ namespace Toon {
Character::Character(ToonEngine *vm) : _vm(vm) {
_animationInstance = 0;
- _shadowAnimationInstance = 0;
- _shadowAnim = 0;
+ _shadowAnimationInstance = NULL;
+ _shadowAnim = NULL;
_x = 0;
_y = 0;
_z = 0;
@@ -47,6 +47,7 @@ Character::Character(ToonEngine *vm) : _vm(vm) {
_facing = 0;
_flags = 0;
_animFlags = 0;
+ _isTalking = false;
_id = 0;
_scale = 1024;
_blockingWalk = false;
@@ -63,6 +64,8 @@ Character::Character(ToonEngine *vm) : _vm(vm) {
}
Character::~Character(void) {
+ delete _shadowAnimationInstance;
+ delete _shadowAnim;
}
void Character::init() {
@@ -96,8 +99,8 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) {
_vm->getPathFinding()->resetBlockingRects();
if (_id == 1) {
- int32 sizeX = MAX(5, 40 * _vm->getDrew()->getScale() / 1024);
- int32 sizeY = MAX(2, 20 * _vm->getDrew()->getScale() / 1024);
+ int32 sizeX = MAX<int32>(5, 40 * _vm->getDrew()->getScale() / 1024);
+ int32 sizeY = MAX<int32>(2, 20 * _vm->getDrew()->getScale() / 1024);
_vm->getPathFinding()->addBlockingEllipse(_vm->getDrew()->getFinalX(), _vm->getDrew()->getFinalY(), sizeX, sizeY);
}
@@ -126,7 +129,7 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) {
if (_blockingWalk) {
while ((_x != newPosX || _y != newPosY) && _currentPathNode < _currentPathNodeCount && !_vm->shouldQuitGame()) {
if (_currentPathNode < _currentPathNodeCount - 10) {
- int32 delta = MIN(10, _currentPathNodeCount - _currentPathNode);
+ int32 delta = MIN<int32>(10, _currentPathNodeCount - _currentPathNode);
int32 dx = _currentPathX[_currentPathNode+delta] - _x;
int32 dy = _currentPathY[_currentPathNode+delta] - _y;
setFacing(getFacingFromDirection(dx, dy));
@@ -234,6 +237,11 @@ void Character::playStandingAnim() {
}
+void Character::updateTimers(int32 relativeAdd) {
+ _nextIdleTime += relativeAdd;
+ _lastWalkTime += relativeAdd;
+}
+
void Character::stopSpecialAnim() {
debugC(4, kDebugCharacter, "stopSpecialAnim()");
// Strangerke - Commented (not used)
@@ -242,10 +250,10 @@ void Character::stopSpecialAnim() {
delete anim
#endif
if (_animScriptId != -1)
- _vm->getSceneAnimationScript(_animScriptId)->_frozen = false;
+ _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = false;
- if (_sceneAnimationId != -1)
- _animationInstance->setAnimation(_vm->getSceneAnimation(_sceneAnimationId)->_animation);
+ //if (_sceneAnimationId != -1)
+ // _animationInstance->setAnimation(_vm->getSceneAnimation(_sceneAnimationId)->_animation);
bool needStandingAnim = (_animFlags & 0x40) != 0;
@@ -265,7 +273,7 @@ void Character::update(int32 timeIncrement) {
if ((_flags & 0x1) && _currentPathNodeCount > 0) {
if (_currentPathNode < _currentPathNodeCount) {
if (_currentPathNode < _currentPathNodeCount - 10) {
- int32 delta = MIN(10, _currentPathNodeCount - _currentPathNode);
+ int32 delta = MIN<int32>(10, _currentPathNodeCount - _currentPathNode);
int32 dx = _currentPathX[_currentPathNode+delta] - _x;
int32 dy = _currentPathY[_currentPathNode+delta] - _y;
setFacing(getFacingFromDirection(dx, dy));
@@ -342,11 +350,13 @@ void Character::update(int32 timeIncrement) {
#endif
if (_animScriptId != -1)
- _vm->getSceneAnimationScript(_animScriptId)->_frozen = true;
-
+ _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = true;
+
+
// TODO setup backup //
_animFlags |= 0x10;
+ _animationInstance->setAnimation(_specialAnim);
_animationInstance->setFrame(0);
_time = _vm->getOldMilli() + 8 * _vm->getTickLength();
}
@@ -354,14 +364,11 @@ void Character::update(int32 timeIncrement) {
}
if ((_animFlags & 3) == 2) {
- if (_vm->getCurrentLineToSay() != _lineToSayId || !_vm->getAudioManager()->voiceStillPlaying()) // || (_flags & 8)) && _vm->getAudioManager()->voiceStillPlaying())
+ if ((((_animFlags & 8) == 8) && _vm->getCurrentLineToSay() != _lineToSayId) || !_vm->getAudioManager()->voiceStillPlaying()) // || (_flags & 8)) && _vm->getAudioManager()->voiceStillPlaying())
_animFlags |= 1;
-// Strangerke - Commented (not used)
-// } else {
}
- // label29 :
if (_time > _vm->getOldMilli())
return;
@@ -434,15 +441,15 @@ void Character::update(int32 timeIncrement) {
// skipped all this part.
//label78
+
+
#if 0
if (_id == 0)
- debugC(0, 0xfff, " drew animation flag %d / frame %d", _animFlags, nextFrame);
-
+ debug(" drew animation name %s / flag %d / frame %d", _specialAnim->_name, _animFlags, nextFrame);
if (_id == 1)
- debugC(0, 0xfff, " flux animation flag %d / frame %d", _animFlags, nextFrame);
-
+ debug(" flux animation flag %d / frame %d", _animFlags, nextFrame);
if (_id == 7)
- debugC(0, 0xfff, " footman animation flag %d / frame %d", _animFlags, nextFrame);
+ debug(" footman animation flag %d / frame %d", _animFlags, nextFrame);
#endif
_time = nextTime;
@@ -913,10 +920,12 @@ const SpecialCharacterAnimation *Character::getSpecialAnimation(int32 characterI
bool Character::loadShadowAnimation(Common::String animName) {
debugC(1, kDebugCharacter, "loadShadowAnimation(%s)", animName.c_str());
+ delete _shadowAnim;
_shadowAnim = new Animation(_vm);
if (!_shadowAnim->loadAnimation(animName))
return false;
+ delete _shadowAnimationInstance;
_shadowAnimationInstance = _vm->getAnimationManager()->createNewInstance(kAnimationCharacter);
_vm->getAnimationManager()->addInstance(_shadowAnimationInstance);
_shadowAnimationInstance->setAnimation(_shadowAnim);
@@ -949,11 +958,8 @@ void Character::playAnim(int32 animId, int32 unused, int32 flags) {
strcat(animName, ".CAF");
- if (_animScriptId != -1)
- _vm->getSceneAnimationScript(_animScriptId)->_frozen = true;
-
- if (_sceneAnimationId > -1)
- setAnimationInstance(_vm->getSceneAnimation(_sceneAnimationId)->_animInstance);
+ if (_animScriptId != -1 && (flags & 8) == 0)
+ _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = true;
stopSpecialAnim();
@@ -963,7 +969,18 @@ void Character::playAnim(int32 animId, int32 unused, int32 flags) {
// make the talker busy
_flags |= 1;
+
+ // wait for the character to be ready
+ while (_animScriptId != -1 && _animationInstance->getFrame() > 0 && (_specialAnim && _animationInstance->getAnimation() != _specialAnim)) {
+ _vm->simpleUpdate(false);
+ }
}
+
+
+ if (_sceneAnimationId > -1)
+ setAnimationInstance(_vm->getSceneAnimation(_sceneAnimationId)->_animInstance);
+
+
_animFlags |= flags;
if (_specialAnim)
diff --git a/engines/toon/character.h b/engines/toon/character.h
index 997a401403..43636b8eb5 100644
--- a/engines/toon/character.h
+++ b/engines/toon/character.h
@@ -95,6 +95,9 @@ public:
virtual void stopSpecialAnim();
virtual void updateIdle();
virtual int32 getRandomIdleAnim() { return 0; }
+ virtual void updateTimers(int32 relativeAdd);
+ virtual void setTalking(bool talking) { _isTalking = talking; }
+ virtual bool isTalking() { return _isTalking; }
int32 getFacingFromDirection(int32 dx, int32 dy);
static const SpecialCharacterAnimation *getSpecialAnimation(int32 characterId, int32 animationId);
@@ -125,6 +128,7 @@ protected:
int32 _speed;
int32 _lastWalkTime;
int32 _numPixelToWalk;
+ bool _isTalking;
AnimationInstance *_animationInstance;
AnimationInstance *_shadowAnimationInstance;
diff --git a/engines/toon/console.cpp b/engines/toon/console.cpp
new file mode 100644
index 0000000000..db50e28489
--- /dev/null
+++ b/engines/toon/console.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "toon/console.h"
+#include "toon/toon.h"
+
+namespace Toon {
+
+ToonConsole::ToonConsole(ToonEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
+
+ToonConsole::~ToonConsole() {
+}
+
+void ToonConsole::preEnter() {
+}
+
+void ToonConsole::postEnter() {
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/console.h b/engines/toon/console.h
new file mode 100644
index 0000000000..40b556e633
--- /dev/null
+++ b/engines/toon/console.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef TOON_CONSOLE_H
+#define TOON_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Toon {
+
+class ToonEngine;
+
+class ToonConsole : public GUI::Debugger {
+public:
+ ToonConsole(ToonEngine *vm);
+ virtual ~ToonConsole(void);
+
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+private:
+ ToonEngine *_vm;
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp
index a0017f2571..f8c4c08ce6 100644
--- a/engines/toon/detection.cpp
+++ b/engines/toon/detection.cpp
@@ -112,13 +112,21 @@ static const char * const directoryGlobs[] = {
};
static const ADParams detectionParams = {
+ // Pointer to ADGameDescription or its superset structure
(const byte *)Toon::gameDescriptions,
+ // Size of that superset structure
sizeof(ADGameDescription),
- 5000, // number of md5 bytes
+ // Number of bytes to compute MD5 sum for
+ 5000,
+ // List of all engine targets
ToonGames,
- 0, // no obsolete targets data
+ // Structure for autoupgrading obsolete targets
+ 0,
+ // Name of single gameid (optional)
"toon",
+ // List of files for file-based fallback detection (optional)
Toon::fileBasedFallback,
+ // Flags
0,
// Additional GUI options (for every game}
Common::GUIO_NONE,
@@ -145,19 +153,24 @@ public:
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;
+ virtual void removeSaveState(const char *target, int slot) const;
};
bool ToonMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
-// (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsLoadingDuringStartup) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate);
}
+void ToonMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
int ToonMetaEngine::getMaximumSaveSlot() const { return 99; }
SaveStateList ToonMetaEngine::listSaves(const char *target) const {
@@ -204,7 +217,7 @@ SaveStateList ToonMetaEngine::listSaves(const char *target) const {
}
SaveStateDescriptor ToonMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
- Common::String fileName = Common::String::printf("%s.%03d", target, slot);
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
if (file) {
diff --git a/engines/toon/font.cpp b/engines/toon/font.cpp
index be5a306d8c..a8a1091d12 100644
--- a/engines/toon/font.cpp
+++ b/engines/toon/font.cpp
@@ -32,21 +32,39 @@ FontRenderer::FontRenderer(ToonEngine *vm) : _vm(vm) {
_currentFontColor[1] = 0xc8;
_currentFontColor[2] = 0xcb;
_currentFontColor[3] = 0xce;
+}
+FontRenderer::~FontRenderer() {
}
// mapping extended characters required for foreign versions to font (animation)
static const byte map_textToFont[0x80] = {
- '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x8x
- '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x9x
- '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0xAx
- '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0xBx
- '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0xCx
- '?', 0x0b, '?', '?', '?', '?', 0x1e, '?', '?', '?', '?', '?', 0x1f, '?', '?', 0x19, // 0xDx
+ '?', '?', '?', '?', 0x03, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x8x
+ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x9x
+ '?', 0x09, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0xAx
+ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 0x0a, // 0xBx
+ '?', '?', '?', '?', 0x1d, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0xCx
+ '?', 0x0b, '?', '?', '?', '?', 0x1e, '?', '?', '?', '?', '?', 0x1f, '?', '?', 0x19, // 0xDx
0x0d, 0x04, 0x0e, '?', 0x1a, '?', '?', 0x18, 0x10, 0x0f, 0x12, 0x11, 0x09, 0x05, 0x14, 0x13, // 0xEx
0x23, 0x08, 0x23, 0x06, 0x15, 0x23, 0x1b, 0x23, 0x23, 0x16, 0x07, 0x17, 0x1c, 0x23, 0x23, 0x23 // 0xFx
};
+byte FontRenderer::textToFont(byte c) {
+ // No need to remap simple characters.
+ if (c < 0x80)
+ return c;
+
+ // The Spanish version shows grave accent over the 'e' when it should
+ // be acute. This happens both in the original interpreter and when
+ // using the common map which works for other languages, so we add a
+ // special case for it.
+ if (_vm->_language == Common::ES_ESP && c == 0xe9)
+ return 0x10;
+
+ // Use the common map to convert the extended characters.
+ return map_textToFont[c - 0x80];
+}
+
void FontRenderer::renderText(int32 x, int32 y, Common::String origText, int32 mode) {
debugC(5, kDebugFont, "renderText(%d, %d, %s, %d)", x, y, origText.c_str(), mode);
@@ -75,8 +93,7 @@ void FontRenderer::renderText(int32 x, int32 y, Common::String origText, int32 m
height = 0;
curX = x;
} else {
- if (curChar >= 0x80)
- curChar = map_textToFont[curChar - 0x80];
+ curChar = textToFont(curChar);
_currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX, curY, _currentFontColor);
curX = curX + _currentFont->getFrameWidth(curChar) - 1;
height = MAX(height, _currentFont->getFrameHeight(curChar));
@@ -105,8 +122,7 @@ void FontRenderer::computeSize(Common::String origText, int32 *retX, int32 *retY
lineHeight = 0;
lineWidth = 0;
} else {
- if (curChar >= 0x80)
- curChar = map_textToFont[curChar - 0x80];
+ curChar = textToFont(curChar);
int32 charWidth = _currentFont->getFrameWidth(curChar) - 1;
int32 charHeight = _currentFont->getFrameHeight(curChar);
lineWidth += charWidth;
@@ -192,9 +208,8 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, Common::String origText
if (curChar == 32) {
lastSpace = it;
lastSpaceX = curWidth;
- } else if (curChar >= 0x80) {
- curChar = map_textToFont[curChar - 0x80];
- }
+ } else
+ curChar = textToFont(curChar);
int width = _currentFont->getFrameWidth(curChar);
curWidth += width - 2;
@@ -259,9 +274,7 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, Common::String origText
const byte *line = lines[i];
curX = x - lineSize[i] / 2;
while (*line) {
- byte curChar = *line;
- if (curChar >= 0x80)
- curChar = map_textToFont[curChar - 0x80];
+ byte curChar = textToFont(*line);
if (curChar != 32) _currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX + _vm->state()->_currentScrollValue, curY, _currentFontColor);
curX = curX + _currentFont->getFrameWidth(curChar) - 2;
//height = MAX(height, _currentFont->getFrameHeight(curChar));
diff --git a/engines/toon/font.h b/engines/toon/font.h
index 713d8c3409..739d215e36 100644
--- a/engines/toon/font.h
+++ b/engines/toon/font.h
@@ -33,7 +33,7 @@ namespace Toon {
class FontRenderer {
public:
FontRenderer(ToonEngine *vm);
- ~FontRenderer(void);
+ ~FontRenderer();
void setFont(Animation *font);
void computeSize(Common::String origText, int32 *retX, int32 *retY);
@@ -45,6 +45,7 @@ protected:
Animation *_currentFont;
ToonEngine *_vm;
byte _currentFontColor[4];
+ byte textToFont(byte c);
};
} // End of namespace Toon
diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp
index 5af61197d7..782e49c2d5 100644
--- a/engines/toon/hotspot.cpp
+++ b/engines/toon/hotspot.cpp
@@ -33,6 +33,8 @@ Hotspots::Hotspots(ToonEngine *vm) : _vm(vm) {
_numItems = 0;
}
+Hotspots::~Hotspots() {
+}
void Hotspots::load(Common::ReadStream *Stream) {
delete[] _items;
diff --git a/engines/toon/hotspot.h b/engines/toon/hotspot.h
index 233bcebcb7..aabcd531fe 100644
--- a/engines/toon/hotspot.h
+++ b/engines/toon/hotspot.h
@@ -51,7 +51,7 @@ private:
class Hotspots {
public:
Hotspots(ToonEngine *vm);
- ~Hotspots(void);
+ ~Hotspots();
bool LoadRif(Common::String rifName, Common::String additionalRifName);
int32 Find(int32 x, int32 y);
diff --git a/engines/toon/module.mk b/engines/toon/module.mk
index 403408e497..7796203d00 100644
--- a/engines/toon/module.mk
+++ b/engines/toon/module.mk
@@ -4,6 +4,7 @@ MODULE_OBJS := \
anim.o \
audio.o \
character.o \
+ console.o \
conversation.o \
detection.o \
drew.o \
diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp
index 87a3e878b5..91ea98a91f 100644
--- a/engines/toon/movie.cpp
+++ b/engines/toon/movie.cpp
@@ -61,6 +61,7 @@ ToonstruckSmackerDecoder::ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::M
Movie::Movie(ToonEngine *vm , ToonstruckSmackerDecoder *decoder) {
_vm = vm;
+ _playing = false;
_decoder = decoder;
}
@@ -73,14 +74,16 @@ void Movie::init() const {
void Movie::play(Common::String video, int32 flags) {
debugC(1, kDebugMovie, "play(%s, %d)", video.c_str(), flags);
+ _playing = true;
if (flags & 1)
_vm->getAudioManager()->setMusicVolume(0);
_decoder->loadFile(video.c_str(), flags);
playVideo();
_vm->flushPalette();
if (flags & 1)
- _vm->getAudioManager()->setMusicVolume(100);
+ _vm->getAudioManager()->setMusicVolume(_vm->getAudioManager()->isMusicMuted() ? 0 : 255);
_decoder->close();
+ _playing = false;
}
bool Movie::playVideo() {
diff --git a/engines/toon/movie.h b/engines/toon/movie.h
index 8e1acc4a77..4d5efb3343 100644
--- a/engines/toon/movie.h
+++ b/engines/toon/movie.h
@@ -45,12 +45,15 @@ public:
void init() const;
void play(Common::String video, int32 flags = 0);
+ bool isPlaying() { return _playing; }
protected:
bool playVideo();
ToonEngine *_vm;
Audio::Mixer *_mixer;
ToonstruckSmackerDecoder *_decoder;
+ bool _playing;
+
};
} // End of namespace Toon
diff --git a/engines/toon/path.cpp b/engines/toon/path.cpp
index 484e621a64..18b7956245 100644
--- a/engines/toon/path.cpp
+++ b/engines/toon/path.cpp
@@ -27,9 +27,20 @@
namespace Toon {
+PathFindingHeap::PathFindingHeap() {
+ _count = 0;
+ _alloc = 0;
+ _data = NULL;
+}
+
+PathFindingHeap::~PathFindingHeap() {
+ delete[] _data;
+}
+
int32 PathFindingHeap::init(int32 size) {
debugC(1, kDebugPath, "init(%d)", size);
+ delete[] _data;
_data = new HeapDataGrid[size * 2];
memset(_data, 0, sizeof(HeapDataGrid) * size * 2);
_count = 0;
@@ -37,13 +48,13 @@ int32 PathFindingHeap::init(int32 size) {
return size;
}
-int PathFindingHeap::unload() {
- if (_data)
- delete[] _data;
+int32 PathFindingHeap::unload() {
+ delete[] _data;
+ _data = NULL;
return 0;
}
-int PathFindingHeap::clear() {
+int32 PathFindingHeap::clear() {
//debugC(1, kDebugPath, "clear()");
_count = 0;
@@ -51,7 +62,7 @@ int PathFindingHeap::clear() {
return 1;
}
-int PathFindingHeap::push(int x, int y, int weight) {
+int32 PathFindingHeap::push(int32 x, int32 y, int32 weight) {
//debugC(6, kDebugPath, "push(%d, %d, %d)", x, y, weight);
_count++;
@@ -126,15 +137,15 @@ PathFinding::PathFinding(ToonEngine *vm) : _vm(vm) {
_width = 0;
_height = 0;
_heap = new PathFindingHeap();
- _gridTemp = 0;
+ _gridTemp = NULL;
_numBlockingRects = 0;
}
PathFinding::~PathFinding(void) {
- if (_heap) {
+ if (_heap)
_heap->unload();
- delete _heap;
- }
+ delete _heap;
+ delete[] _gridTemp;
}
bool PathFinding::isWalkable(int32 x, int32 y) {
@@ -193,7 +204,7 @@ int32 PathFinding::findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32
}
}
-int PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) {
+int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) {
debugC(1, kDebugPath, "findPath(%d, %d, %d, %d)", x, y, destx, desty);
if (x == destx && y == desty) {
@@ -220,10 +231,10 @@ int PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) {
_heap->pop(&curX, &curY, &curWeight);
int curNode = curX + curY * _width;
- int32 endX = MIN(curX + 1, _width - 1);
- int32 endY = MIN(curY + 1, _height - 1);
- int32 startX = MAX(curX - 1, 0);
- int32 startY = MAX(curY - 1, 0);
+ int32 endX = MIN<int32>(curX + 1, _width - 1);
+ int32 endY = MIN<int32>(curY + 1, _height - 1);
+ int32 startX = MAX<int32>(curX - 1, 0);
+ int32 startY = MAX<int32>(curY - 1, 0);
for (int32 px = startX; px <= endX; px++) {
for (int py = startY; py <= endY; py++) {
@@ -271,10 +282,10 @@ next:
int32 bestX = -1;
int32 bestY = -1;
- int32 endX = MIN(curX + 1, _width - 1);
- int32 endY = MIN(curY + 1, _height - 1);
- int32 startX = MAX(curX - 1, 0);
- int32 startY = MAX(curY - 1, 0);
+ int32 endX = MIN<int32>(curX + 1, _width - 1);
+ int32 endY = MIN<int32>(curY + 1, _height - 1);
+ int32 startX = MAX<int32>(curX - 1, 0);
+ int32 startY = MAX<int32>(curY - 1, 0);
for (int32 px = startX; px <= endX; px++) {
for (int32 py = startY; py <= endY; py++) {
@@ -323,8 +334,7 @@ void PathFinding::init(Picture *mask) {
_currentMask = mask;
_heap->unload();
_heap->init(_width * _height);
- if (_gridTemp)
- delete[] _gridTemp;
+ delete[] _gridTemp;
_gridTemp = new int32[_width*_height];
}
diff --git a/engines/toon/path.h b/engines/toon/path.h
index d8ef2eac02..04a076525e 100644
--- a/engines/toon/path.h
+++ b/engines/toon/path.h
@@ -37,24 +37,27 @@ struct HeapDataGrid {
};
class PathFindingHeap {
-
-private:
- HeapDataGrid *_data;
public:
+ PathFindingHeap();
+ ~PathFindingHeap();
+
int32 _alloc;
int32 _count;
+
int32 push(int32 x, int32 y, int32 weight);
int32 pop(int32 *x, int32 *y, int32 *weight);
int32 init(int32 size);
int32 clear();
int32 unload();
-};
+private:
+ HeapDataGrid *_data;
+};
class PathFinding {
public:
PathFinding(ToonEngine *vm);
- ~PathFinding(void);
+ ~PathFinding();
int32 findPath(int32 x, int32 y, int32 destX, int32 destY);
int32 findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32 *fyy, int origX = -1, int origY = -1);
diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp
index 11a5572066..b797079c00 100644
--- a/engines/toon/picture.cpp
+++ b/engines/toon/picture.cpp
@@ -130,7 +130,13 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) {
}
Picture::Picture(ToonEngine *vm) : _vm(vm) {
+ _data = NULL;
+ _palette = NULL;
+}
+Picture::~Picture() {
+ delete[] _data;
+ delete[] _palette;
}
void Picture::setupPalette() {
diff --git a/engines/toon/picture.h b/engines/toon/picture.h
index 5065843b3c..1b0fd7f550 100644
--- a/engines/toon/picture.h
+++ b/engines/toon/picture.h
@@ -40,6 +40,7 @@ class Picture {
public:
Picture(ToonEngine *vm);
+ ~Picture();
bool loadPicture(Common::String file, bool totalPalette = false);
void setupPalette();
void draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy);
diff --git a/engines/toon/resource.cpp b/engines/toon/resource.cpp
index 348aa45ae9..470c54f8f4 100644
--- a/engines/toon/resource.cpp
+++ b/engines/toon/resource.cpp
@@ -184,6 +184,7 @@ void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool
if (preloadEntirePackage) {
_bufferSize = rs->size();
+ delete[] _buffer;
_buffer = new uint8[_bufferSize];
rs->seek(0);
rs->read(_buffer, _bufferSize);
@@ -191,9 +192,7 @@ void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool
}
void PakFile::close() {
- if (_buffer) {
- delete[] _buffer;
- }
+ delete[] _buffer;
if (_fileHandle) {
_fileHandle->close();
@@ -205,11 +204,11 @@ PakFile::~PakFile() {
close();
}
-
PakFile::PakFile() {
- _fileHandle = 0;
- _buffer = 0;
_bufferSize = 0;
+ _buffer = NULL;
+
+ _fileHandle = NULL;
}
} // End of namespace Toon
diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp
index 06d482f4e2..5e56432012 100644
--- a/engines/toon/script.cpp
+++ b/engines/toon/script.cpp
@@ -66,6 +66,9 @@ EMCInterpreter::EMCInterpreter(ToonEngine *vm) : _vm(vm), _scriptData(0), _filen
#undef OPCODE
}
+EMCInterpreter::~EMCInterpreter() {
+}
+
bool EMCInterpreter::callback(Common::IFFChunk &chunk) {
switch (chunk._type) {
case MKID_BE('TEXT'):
@@ -102,7 +105,7 @@ bool EMCInterpreter::callback(Common::IFFChunk &chunk) {
return false;
}
-bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array<const Opcode *> *opcodes) {
+bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array<const OpcodeV2 *> *opcodes) {
Common::SeekableReadStream *stream = _vm->resources()->openFile(filename);
if (!stream) {
error("Couldn't open script file '%s'", filename);
diff --git a/engines/toon/script.h b/engines/toon/script.h
index 47e04e8c82..6c46238238 100644
--- a/engines/toon/script.h
+++ b/engines/toon/script.h
@@ -36,7 +36,8 @@
namespace Toon {
struct EMCState;
-typedef Common::Functor1<EMCState *, int> Opcode;
+class ScriptFunc;
+typedef Common::Functor1Mem<EMCState *, int32, ScriptFunc> OpcodeV2;
struct EMCData {
char filename[13];
@@ -46,7 +47,7 @@ struct EMCData {
uint16 *ordr;
uint16 dataSize;
- const Common::Array<const Opcode *> *sysFuncs;
+ const Common::Array<const OpcodeV2 *> *sysFuncs;
};
struct EMCState {
@@ -97,8 +98,9 @@ public:
class EMCInterpreter {
public:
EMCInterpreter(ToonEngine *vm);
+ ~EMCInterpreter();
- bool load(const char *filename, EMCData *data, const Common::Array<const Opcode *> *opcodes);
+ bool load(const char *filename, EMCData *data, const Common::Array<const OpcodeV2 *> *opcodes);
void unload(EMCData *data);
void init(EMCState *scriptState, const EMCData *data);
@@ -146,6 +148,7 @@ private:
void op_eval(EMCState *);
void op_setRetAndJmp(EMCState *);
};
+
} // End of namespace Toon
#endif
diff --git a/engines/toon/script_func.cpp b/engines/toon/script_func.cpp
index 821a8971de..4c30b1530a 100644
--- a/engines/toon/script_func.cpp
+++ b/engines/toon/script_func.cpp
@@ -34,13 +34,12 @@
namespace Toon {
-typedef Common::Functor1Mem<EMCState *, int32, ScriptFunc> OpcodeV2;
#define SetOpcodeTable(x) table = &x;
#define Opcode(x) table->push_back(new OpcodeV2(this, &ScriptFunc::x))
#define OpcodeUnImpl() table->push_back(new OpcodeV2(this, 0))
ScriptFunc::ScriptFunc(ToonEngine *vm) {
- Common::Array<const Opcode *> *table = 0;
+ Common::Array<const OpcodeV2 *> *table = 0;
_vm = vm;
_opcodes.reserve(176);
@@ -224,7 +223,10 @@ ScriptFunc::ScriptFunc(ToonEngine *vm) {
}
ScriptFunc::~ScriptFunc(void) {
-
+ while(!_opcodes.empty()) {
+ //delete _opcodes.end();
+ _opcodes.pop_back();
+ }
}
char *GetText(int32 i, EMCState *state) {
@@ -474,6 +476,14 @@ int32 ScriptFunc::sys_Cmd_Empty_Inventory(EMCState *state) {
}
int32 ScriptFunc::sys_Cmd_Set_Anim_Scale_Size(EMCState *state) {
+ int32 animID = stackPos(0);
+ int32 scale = stackPos(1);
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(animID);
+ if (sceneAnim) {
+ sceneAnim->_animInstance->setUseMask(true);
+ sceneAnim->_animInstance->setScale(scale,true);
+ }
return 0;
}
int32 ScriptFunc::sys_Cmd_Delete_Item_From_Inventory(EMCState *state) {
@@ -541,7 +551,11 @@ int32 ScriptFunc::sys_Cmd_Exit_Conversation(EMCState *state) {
}
int32 ScriptFunc::sys_Cmd_Set_Mouse_Pos(EMCState *state) {
- _vm->getSystem()->warpMouse(stackPos(0) - _vm->state()->_currentScrollValue, stackPos(1));
+ if (_vm->state()->_inCloseUp) {
+ _vm->getSystem()->warpMouse(stackPos(0), stackPos(1));
+ } else {
+ _vm->getSystem()->warpMouse(stackPos(0) - _vm->state()->_currentScrollValue, stackPos(1));
+ }
return 0;
}
@@ -621,7 +635,7 @@ int32 ScriptFunc::sys_Cmd_Character_Talking(EMCState *state) {
int32 characterId = stackPos(0);
Character *character = _vm->getCharacterById(characterId);
if (character)
- return (character->getFlag() & 4) && (character->getFlag() & 8);
+ return character->isTalking();
return 0;
}
@@ -702,7 +716,7 @@ int32 ScriptFunc::sys_Cmd_Place_Scene_Anim(EMCState *state) {
int32 frame = stackPos(5);
SceneAnimation *sceneAnim = _vm->getSceneAnimation(sceneId);
- sceneAnim->_animInstance->setPosition(x, y, 0, false);
+ sceneAnim->_animInstance->setPosition(x, y, sceneAnim->_animInstance->getZ(), false);
sceneAnim->_animInstance->forceFrame(frame);
_vm->setSceneAnimationScriptUpdate(false);
return 0;
@@ -874,6 +888,12 @@ int32 ScriptFunc::sys_Cmd_Set_Scene_Anim_Wait(EMCState *state) {
_vm->setSceneAnimationScriptUpdate(false);
}
+ // WORKAROUND : Slow down just a little the guards dance animation so that the voices don't cut
+ if (_vm->state()->_currentScene == 2 && (sceneId == 2 || sceneId == 3)) {
+ waitTicks = 7;
+ _vm->setSceneAnimationScriptUpdate(false);
+ }
+
waitTicks *= _vm->getTickLength();
if (sceneId >= 0 && sceneId < 40) {
@@ -910,10 +930,14 @@ int32 ScriptFunc::sys_Cmd_Init_Scene_Anim(EMCState *state) {
int32 dx = stackPos(4);
int32 dy = stackPos(5);
+ int32 x = stackPos(2);
int32 layerZ = stackPos(3);
if (dx == -2)
sceneAnim->_animInstance->moveRelative(640, 0, 0);
+ else if (dx < 0) {
+ dx = sceneAnim->_animation->_x1;
+ }
else if (dx >= 0)
sceneAnim->_animInstance->setX(dx);
@@ -922,8 +946,10 @@ int32 ScriptFunc::sys_Cmd_Init_Scene_Anim(EMCState *state) {
else
dy = sceneAnim->_animation->_y1;
- if (flags & 0x20)
- sceneAnim->_animInstance->setZ(_vm->getLayerAtPoint(dx, dy));
+ if (flags & 0x20) {
+ sceneAnim->_animInstance->setZ(_vm->getLayerAtPoint(x, layerZ));
+ sceneAnim->_animInstance->setUseMask(true);
+ }
if (layerZ >= 0) {
sceneAnim->_animInstance->setLayerZ(layerZ);
@@ -961,6 +987,7 @@ int32 ScriptFunc::sys_Cmd_Draw_Scene_Anim_WSA_Frame(EMCState *state) {
SceneAnimation *sceneAnim = _vm->getSceneAnimation(animId);
if (sceneAnim->_active) {
+ sceneAnim->_animInstance->setAnimation(sceneAnim->_animation);
sceneAnim->_animInstance->setFrame(frame);
sceneAnim->_animInstance->setAnimationRange(frame, frame);
sceneAnim->_animInstance->stopAnimation();
@@ -1048,18 +1075,26 @@ int32 ScriptFunc::sys_Cmd_Play_Sfx(EMCState *state) {
}
int32 ScriptFunc::sys_Cmd_Set_Ambient_Sfx(EMCState *state) {
+ //debug("Ambient Sfx : %d %d %d %d", stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ _vm->getAudioManager()->startAmbientSFX(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
return 0;
}
int32 ScriptFunc::sys_Cmd_Kill_Ambient_Sfx(EMCState *state) {
+ //debug("Kill Sfx : %d", stackPos(0));
+ _vm->getAudioManager()->killAmbientSFX(stackPos(0));
return 0;
}
int32 ScriptFunc::sys_Cmd_Set_Ambient_Sfx_Plus(EMCState *state) {
+ //debug("Ambient Sfx Plus: %d %d %d %d %d %d %d %d", stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ _vm->getAudioManager()->startAmbientSFX(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
return 0;
}
int32 ScriptFunc::sys_Cmd_Set_Ambient_Volume(EMCState *state) {
+ //debug("Ambient Volume : %d %d", stackPos(0), stackPos(1));
+ _vm->getAudioManager()->setAmbientSFXVolume(stackPos(0), stackPos(1));
return 0;
}
diff --git a/engines/toon/script_func.h b/engines/toon/script_func.h
index 2f8972134c..76b7b0ada1 100644
--- a/engines/toon/script_func.h
+++ b/engines/toon/script_func.h
@@ -31,12 +31,15 @@
namespace Toon {
+class ScriptFunc;
+
+typedef Common::Functor1Mem<EMCState *, int32, ScriptFunc> OpcodeV2;
class ScriptFunc {
public:
ScriptFunc(ToonEngine *vm);
~ScriptFunc(void);
- Common::Array<const Opcode *> _opcodes;
+ Common::Array<const OpcodeV2 *> _opcodes;
ToonEngine *_vm;
#define SYSFUNC(x) int32 x(EMCState*)
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
index 7489f5c5d9..4221c5da8b 100644
--- a/engines/toon/toon.cpp
+++ b/engines/toon/toon.cpp
@@ -131,7 +131,6 @@ void ToonEngine::init() {
memset(_sceneAnimations, 0, sizeof(_sceneAnimations));
memset(_sceneAnimationScripts, 0, sizeof(_sceneAnimationScripts));
-
_gameState->_currentChapter = 1;
initChapter();
loadCursor();
@@ -161,7 +160,7 @@ void ToonEngine::waitForScriptStep() {
// Wait after a specified number of script steps when executing a script
// to lower CPU usage
if (++_scriptStep >= 40) {
- g_system->delayMillis(10);
+ g_system->delayMillis(1);
_scriptStep = 0;
}
}
@@ -182,16 +181,30 @@ void ToonEngine::parseInput() {
_audioManager->stopCurrentVoice();
}
if (event.kbd.keycode == Common::KEYCODE_F5) {
- saveGame(-1);
+ if(canSaveGameStateCurrently())
+ saveGame(-1, Common::String());
}
if (event.kbd.keycode == Common::KEYCODE_F6) {
- loadGame(-1);
+ if(canLoadGameStateCurrently())
+ loadGame(-1);
+ }
+ if (event.kbd.ascii == 't') {
+ _showConversationText = !_showConversationText;
+ }
+ if (event.kbd.ascii == 'm') {
+ _audioManager->muteMusic(!_audioManager->isMusicMuted());
+ }
+ if (event.kbd.ascii == 'd') {
+ _audioManager->muteVoice(!_audioManager->isVoiceMuted());
+ }
+ if (event.kbd.ascii == 's') {
+ _audioManager->muteSfx(!_audioManager->isSfxMuted());
}
if (event.kbd.flags & Common::KBD_ALT) {
int32 slotNum = event.kbd.ascii - '0';
- if (slotNum >= 0 && slotNum <= 9) {
- if (saveGame(slotNum)) {
+ if (slotNum >= 0 && slotNum <= 9 && canSaveGameStateCurrently()) {
+ if (saveGame(slotNum, Common::String())) {
// ok
char buf[256];
snprintf(buf, 256, "Saved game in slot #%d ", slotNum);
@@ -210,7 +223,7 @@ void ToonEngine::parseInput() {
if (event.kbd.flags & Common::KBD_CTRL) {
int32 slotNum = event.kbd.ascii - '0';
- if (slotNum >= 0 && slotNum <= 9) {
+ if (slotNum >= 0 && slotNum <= 9 && canLoadGameStateCurrently()) {
if (loadGame(slotNum)) {
// ok
char buf[256];
@@ -225,6 +238,11 @@ void ToonEngine::parseInput() {
dialog.runModal();
}
}
+
+ if (event.kbd.keycode == Common::KEYCODE_d) {
+ _console->attach();
+ _console->onFrame();
+ }
}
break;
// Strangerke - Commented (not used)
@@ -345,6 +363,7 @@ void ToonEngine::update(int32 timeIncrement) {
updateTimer(timeIncrement);
updateTimers();
updateScrolling(false, timeIncrement);
+ _audioManager->updateAmbientSFX();
_animationManager->update(timeIncrement);
_cursorAnimationInstance->update(timeIncrement);
@@ -400,9 +419,58 @@ void ToonEngine::render() {
}
}
+void ToonEngine::doMagnifierEffect() {
+ int32 posX = _mouseX + state()->_currentScrollValue - _cursorOffsetX;
+ int32 posY = _mouseY - _cursorOffsetY - 2;
+
+ Graphics::Surface &surface = *_mainSurface;
+
+ // fast sqrt table lookup (values up to 144 only)
+ static const byte intSqrt[] = {
+ 0, 1, 1, 1, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 12
+ };
+
+ byte tempBuffer[25*25];
+ for (int32 y = -12; y <= 12; y++) {
+ for (int32 x = -12; x <= 12; x++) {
+ int32 destPitch = surface.pitch;
+ uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x);
+ tempBuffer[(y+12) * 25 + x + 12] = *curRow;
+ }
+ }
+
+ for (int32 y = -12; y <= 12; y++) {
+ for (int32 x = -12; x <= 12; x++) {
+ int32 dist = y * y + x * x;
+ if (dist > 144)
+ continue;
+ int32 destPitch = surface.pitch;
+ uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x);
+ int32 lerp = (512 + intSqrt[dist] * 256 / 12);
+ *curRow = tempBuffer[(y*lerp/1024+12) * 25 + x*lerp/1024 + 12];
+ }
+ }
+}
+
void ToonEngine::copyToVirtualScreen(bool updateScreen) {
// render cursor last
if (!_gameState->_mouseHidden) {
+ if (_cursorAnimationInstance->getFrame() == 7) // magnifier icon needs a special effect
+ doMagnifierEffect();
_cursorAnimationInstance->setPosition(_mouseX - 40 + state()->_currentScrollValue - _cursorOffsetX, _mouseY - 40 - _cursorOffsetY, 0, false);
_cursorAnimationInstance->render();
}
@@ -631,13 +699,22 @@ Common::Error ToonEngine::run() {
initGraphics(640, 400, true);
init();
- // play producer intro
- getMoviePlayer()->play("MISC/VIELOGOM.SMK", 0x10);
-
- // show mainmenu
+ // do we need to load directly a game?
bool loadedGame = false;
- if (!showMainmenu(loadedGame)) {
- return Common::kNoError;
+ int32 slot = ConfMan.getInt("save_slot");
+ if (slot > -1) {
+ loadedGame = loadGame(slot);
+ }
+
+ if (!loadedGame) {
+
+ // play producer intro
+ getMoviePlayer()->play("MISC/VIELOGOM.SMK", 0x10);
+
+ // show mainmenu
+ if (!showMainmenu(loadedGame)) {
+ return Common::kNoError;
+ }
}
//loadScene(17);
@@ -661,6 +738,7 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
_currentPicture = 0;
_roomScaleData = 0;
_shadowLUT = 0;
+ _showConversationText = true;
_isDemo = _gameDescription->flags & ADGF_DEMO;
DebugMan.addDebugChannel(kDebugAnim, "Anim", "Animation debug level");
@@ -676,6 +754,18 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
DebugMan.addDebugChannel(kDebugTools, "Tools", "Tools debug level");
DebugMan.addDebugChannel(kDebugText, "Text", "Text debug level");
+ _moviePlayer = NULL;
+ _mainSurface = NULL;
+ _fontRenderer = NULL;
+ _fontToon = NULL;
+ _fontEZ = NULL;
+ _hotspots = NULL;
+ _genericTexts = NULL;
+ _roomTexts = NULL;
+ _script_func = NULL;
+ _script = NULL;
+ _console = new ToonConsole(this);
+
switch (_language) {
case Common::EN_GRB:
case Common::EN_USA:
@@ -692,7 +782,7 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
_gameVariant = 3;
break;
case Common::ES_ESP:
- _gameVariant = 3;
+ _gameVariant = 4;
break;
default:
// 0 - english
@@ -702,7 +792,20 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
}
ToonEngine::~ToonEngine() {
-
+ delete _moviePlayer;
+ delete _mainSurface;
+
+ delete _fontRenderer;
+ delete _fontToon;
+ delete _fontEZ;
+ delete _hotspots;
+ delete _genericTexts;
+ delete _roomTexts;
+ delete _script_func;
+ delete _script;
+
+ DebugMan.clearAllDebugChannels();
+ delete _console;
}
void ToonEngine::flushPalette() {
@@ -728,21 +831,24 @@ void ToonEngine::setPaletteEntries(uint8 *palette, int32 offset, int32 num) {
_system->setPalette(vmpalette, offset, num);
}
-void ToonEngine::simpleUpdate() {
+void ToonEngine::simpleUpdate(bool waitCharacterToTalk) {
int32 elapsedTime = _system->getMillis() - _oldTimer2;
_oldTimer2 = _system->getMillis();
_oldTimer = _oldTimer2;
+ if (!_audioManager->voiceStillPlaying() && !waitCharacterToTalk) {
+ _currentTextLine = 0;
+ _currentTextLineId = -1;
+ }
+
updateCharacters(elapsedTime);
updateAnimationSceneScripts(elapsedTime);
updateTimer(elapsedTime);
_animationManager->update(elapsedTime);
+ _audioManager->updateAmbientSFX();
render();
- if (!_audioManager->voiceStillPlaying()) {
- _currentTextLine = 0;
- _currentTextLineId = -1;
- }
+
}
void ToonEngine::fixPaletteEntries(uint8 *palette, int num) {
@@ -771,7 +877,7 @@ void ToonEngine::updateAnimationSceneScripts(int32 timeElapsed) {
do {
if (_sceneAnimationScripts[_lastProcessedSceneScript]._lastTimer <= _system->getMillis() &&
- !_sceneAnimationScripts[_lastProcessedSceneScript]._frozen) {
+ !_sceneAnimationScripts[_lastProcessedSceneScript]._frozen && !_sceneAnimationScripts[_lastProcessedSceneScript]._frozenForConversation) {
_animationSceneScriptRunFlag = true;
while (_animationSceneScriptRunFlag && _sceneAnimationScripts[_lastProcessedSceneScript]._lastTimer <= _system->getMillis() && !_shouldQuit) {
@@ -780,7 +886,7 @@ void ToonEngine::updateAnimationSceneScripts(int32 timeElapsed) {
//waitForScriptStep();
- if (_sceneAnimationScripts[_lastProcessedSceneScript]._frozen)
+ if (_sceneAnimationScripts[_lastProcessedSceneScript]._frozen || _sceneAnimationScripts[_lastProcessedSceneScript]._frozenForConversation)
break;
}
@@ -849,25 +955,29 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
_lastMouseButton = 0;
_mouseButton = 0;
- _currentHotspotItem = -1;
- _gameState->_sackVisible = true;
- _gameState->_inCloseUp = false;
- _gameState->_inConversation = false;
- _gameState->_inInventory = false;
- _gameState->_inCutaway = false;
- _gameState->_currentScrollValue = 0;
- _gameState->_currentScrollLock = false;
- _gameState->_inCloseUp = false;
+ _currentHotspotItem = 0;
+ if (!forGameLoad) {
+ _gameState->_sackVisible = true;
+ _gameState->_inCloseUp = false;
+ _gameState->_inConversation = false;
+ _gameState->_inInventory = false;
+ _gameState->_inCutaway = false;
+ _gameState->_currentScrollValue = 0;
+ _gameState->_currentScrollLock = false;
+ _gameState->_inCloseUp = false;
+ }
if (_gameState->_mouseState >= 0)
addItemToInventory(_gameState->_mouseState);
_gameState->_mouseState = -1;
+ _mouseButton = 0;
+ _lastMouseButton = 0x3;
// load package
- strcpy(temp, createRoomFilename(Common::String::printf("%s.pak", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
+ strcpy(temp, createRoomFilename(Common::String::format("%s.pak", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
resources()->openPackage(temp, true);
strcpy(temp, state()->_locations[SceneId]._name);
@@ -912,7 +1022,7 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
strcpy(temp, state()->_locations[SceneId]._name);
strcat(temp, ".svi");
- strcpy(temp2, createRoomFilename(Common::String::printf("%s.svl", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
+ strcpy(temp2, createRoomFilename(Common::String::format("%s.svl", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
_audioManager->loadAudioPack(1, temp, temp2);
strcpy(temp, state()->_locations[SceneId]._name);
strcpy(temp2, state()->_locations[SceneId]._name);
@@ -970,6 +1080,7 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
_script->start(&_sceneAnimationScripts[i]._state, 9 + i);
_sceneAnimationScripts[i]._lastTimer = getSystem()->getMillis();
_sceneAnimationScripts[i]._frozen = false;
+ _sceneAnimationScripts[i]._frozenForConversation = false;
}
}
@@ -990,7 +1101,7 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
setupGeneralPalette();
createShadowLUT();
-
+ state()->_mouseHidden = false;
if (!forGameLoad) {
@@ -1009,7 +1120,7 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
_gameState->_nextSpecialEnterX = -1;
_gameState->_nextSpecialEnterY = -1;
}
-
+
_script->start(&_scriptState[0], 3);
while (_script->run(&_scriptState[0]))
@@ -1021,8 +1132,6 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
waitForScriptStep();
}
-
- state()->_mouseHidden = false;
}
void ToonEngine::setupGeneralPalette() {
@@ -1074,6 +1183,7 @@ void ToonEngine::initChapter() {
memset(&data, 0, sizeof(data));
memset(&status, 0, sizeof(status));
+ delete _script;
_script = new EMCInterpreter(this);
_script->load("_START01.EMC", &data, &_script_func->_opcodes);
@@ -1099,7 +1209,7 @@ void ToonEngine::loadCursor() {
setCursor(5);
}
-void ToonEngine::setCursor(int32 type, bool inventory, int32 offsetX, int32 offsetY) {
+void ToonEngine::setCursor(int32 type, bool inventory, int32 offsetX, int offsetY) {
static const int32 offsets[] = {
0, 1, 1, 6, 7, 1, 8, 10, 18, 10,
@@ -1172,9 +1282,9 @@ void ToonEngine::clickEvent() {
bool leftButton = false;
bool rightButton = false;
- if ((_lastMouseButton & 0x1) == 1 && (_mouseButton & 0x1) == 0)
+ if ((_lastMouseButton & 0x1) == 0 && (_mouseButton & 0x1) == 1)
leftButton = true;
- if ((_lastMouseButton & 0x2) == 2 && (_mouseButton & 0x2) == 0)
+ if ((_lastMouseButton & 0x2) == 0 && (_mouseButton & 0x2) == 2)
rightButton = true;
_lastMouseButton = _mouseButton;
@@ -1186,7 +1296,7 @@ void ToonEngine::clickEvent() {
if (_gameState->_mouseState >= 0 && !rightButton) {
addItemToInventory(_gameState->_mouseState);
setCursor(0, false, 0, 0);
- _currentHotspotItem = -1;
+ _currentHotspotItem = 0;
return;
} else {
showInventory();
@@ -1199,7 +1309,7 @@ void ToonEngine::clickEvent() {
if (rightButton && _gameState->_mouseState >= 0) {
addItemToInventory(_gameState->_mouseState);
setCursor(0, false, 0, 0);
- _currentHotspotItem = -1;
+ _currentHotspotItem = 0;
return;
}
@@ -1492,10 +1602,18 @@ void ToonEngine::exitScene() {
_gameState->_mouseState = -1;
}
+ _audioManager->killAllAmbientSFX();
+ _audioManager->stopAllSfxs();
+ _audioManager->stopCurrentVoice();
+ _currentTextLine = 0;
+ _currentTextLineId = -1;
+ _currentTextLineCharacterId = 0;
+
char temp[256];
- strcpy(temp, createRoomFilename(Common::String::printf("%s.pak", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
+ strcpy(temp, createRoomFilename(Common::String::format("%s.pak", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
resources()->closePackage(temp);
+
_drew->stopWalk();
_flux->stopWalk();
@@ -1744,9 +1862,11 @@ void ToonEngine::playTalkAnimOnCharacter(int32 animID, int32 characterId, bool t
int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
if (blocking == false && _audioManager->voiceStillPlaying()) {
- // someone is already talking, and this voice is not important
- // skip it
- return 0;
+ if (_currentTextLineCharacterId == 0 || _currentTextLineCharacterId == 1) {
+ // Drew or Flux is already talking, and this voice is not important
+ // skip it
+ return 0;
+ }
}
int32 myId = 0;
@@ -1832,7 +1952,19 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
_currentTextLineId = dialogid;
if (blocking) {
+ Character *character = getCharacterById(talkerId);
+ if (character)
+ character->setTalking(true);
+
playTalkAnimOnCharacter(talkerAnimId, talkerId, true);
+
+ // set once more the values, they may have been overwritten when the engine
+ // waits for the character to be ready.
+ _currentTextLine = myLine;
+ _currentTextLineCharacterId = talkerId;
+ _currentTextLineId = dialogid;
+
+
} else {
Character *character = getCharacterById(talkerId);
if (character)
@@ -1856,6 +1988,10 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
while (_audioManager->voiceStillPlaying() && !_shouldQuit)
doFrame();
_gameState->_mouseHidden = oldMouseHidden && _gameState->_mouseHidden;
+
+ Character *character = getCharacterById(talkerId);
+ if (character)
+ character->setTalking(false);
}
@@ -2017,10 +2153,10 @@ void ToonEngine::processConversationClick(Conversation *conv, int32 status) {
int16 *i = (int16 *)((char *)v2->_data4 + 2);
_gameState->_firstConverstationLine = false;
- while (*i >= 0) {
- if (*i < 100) {
+ while (READ_LE_INT16(i) >= 0) {
+ if (READ_LE_INT16(i) < 100) {
if (_gameState->_exitConversation == false) {
- characterTalk(i[1]);
+ characterTalk(READ_LE_INT16(i + 1));
}
} else {
runConversationCommand(&i);
@@ -2028,24 +2164,22 @@ void ToonEngine::processConversationClick(Conversation *conv, int32 status) {
i += 2;
}
- int16 command = i[0];
- int16 value = i[1];
+ int16 command = READ_LE_INT16(i);
+ int16 value = READ_LE_INT16(i + 1);
if (command == -1) {
v2->_data2 = 0;
} else if (command == -2) {
v2->_data4 = (char *)_conversationData + value;
- v2->_data3 = *(int16 *)v2->_data4;
+ v2->_data3 = READ_LE_INT16(v2->_data4);
} else if (command == -3) {
v2->_data2 = 2;
v2->_data4 = (char *)_conversationData + value;
- v2->_data3 = *(int16 *)v2->_data4;
+ v2->_data3 = READ_LE_INT16(v2->_data4);
}
int16 *v7 = i + 2;
-// Strangerke - Commented (not used)
-// int16 v6 = conv->state[0].data2;
- int16 v8 = *v7;
+ int16 v8 = READ_LE_INT16(v7);
if (v8 == -1) {
_gameState->_mouseHidden = false;
} else {
@@ -2057,14 +2191,14 @@ retry:
// find free dialogue slot
for (int j = 0; j < 10; j++) {
if (!conv->state[j]._data2) {
- conv->state[j]._data3 = *v14;
+ conv->state[j]._data3 = READ_LE_INT16(v14);
conv->state[j]._data4 = v14;
if (getConversationFlag(_gameState->_currentScene, conv->state[j]._data3))
conv->state[j]._data2 = 1;
else
conv->state[j]._data2 = 3;
- v8 = *v7;
+ v8 = READ_LE_INT16(v7);
if (v8 == -1)
return;
@@ -2158,31 +2292,31 @@ int32 ToonEngine::getConversationFlag(int32 locationId, int32 param) {
} else if (locationId == 0x10) {
switch (param) {
case 0x3e8:
- if (!(_gameState->_gameGlobalData[83] & 1))
+ if (!(_gameState->_gameGlobalData[30] & 1))
return 0;
break;
case 0x3e9:
- if (!(_gameState->_gameGlobalData[83] & 2))
+ if (!(_gameState->_gameGlobalData[30] & 2))
return 0;
break;
case 0x3ea:
- if (!(_gameState->_gameGlobalData[83] & 4))
+ if (!(_gameState->_gameGlobalData[30] & 4))
return 0;
break;
case 0x3eb:
- if (!(_gameState->_gameGlobalData[83] & 8))
+ if (!(_gameState->_gameGlobalData[30] & 8))
return 0;
break;
case 0x3ec:
- if (!(_gameState->_gameGlobalData[83] & 16))
+ if (!(_gameState->_gameGlobalData[30] & 16))
return 0;
break;
case 0x3ed:
- if (!(_gameState->_gameGlobalData[83] & 32))
+ if (!(_gameState->_gameGlobalData[30] & 32))
return 0;
break;
case 0x3ee:
- if (!(_gameState->_gameGlobalData[83] & 64))
+ if (!(_gameState->_gameGlobalData[30] & 64))
return 0;
break;
default:
@@ -2234,14 +2368,12 @@ int32 ToonEngine::getConversationFlag(int32 locationId, int32 param) {
return 1;
}
-int ToonEngine::runConversationCommand(int16 **command) {
+int32 ToonEngine::runConversationCommand(int16 **command) {
-// Strangerke - Commented (not used)
-// int16 com = **command;
int16 *v5 = *command;
- int v2 = v5[0];
- int v4 = v5[1];
+ int v2 = READ_LE_INT16(v5);
+ int v4 = READ_LE_INT16(v5+1);
int result = v2 - 100;
switch (v2) {
case 100:
@@ -2260,7 +2392,7 @@ int ToonEngine::runConversationCommand(int16 **command) {
//
case 105:
if (getConversationFlag(_gameState->_currentScene, v4)) {
- result = *(int16 *)(*command + 4);
+ result = READ_LE_INT16(*command + 4);
*command = (int16 *)((char *)_conversationData + result);
*command = (int16 *)((char *)_conversationData + result - 4);
} else {
@@ -2347,7 +2479,7 @@ int32 ToonEngine::showInventory() {
_gameState->_inInventory = true;
_gameState->_currentScrollValue = 0;
- int32 oldMouseButton = 0;
+ int32 oldMouseButton = 0x3;
int32 justPressedButton = 0;
_firstFrame = true;
@@ -2428,7 +2560,9 @@ int32 ToonEngine::showInventory() {
}
_gameState->_currentScrollValue = oldScrollValue;
- _gameState->_inInventory = false;
+ _gameState->_inInventory = false;
+ _mouseButton = 0;
+ _lastMouseButton = 0x3;
fadeOut(5);
if (_gameState->_inCloseUp) {
@@ -2571,6 +2705,7 @@ void ToonEngine::newGame() {
}
}
+
void ToonEngine::playSFX(int32 id, int32 volume) {
if (id < 0)
_audioManager->playSFX(-id + 1, volume, true);
@@ -2657,18 +2792,56 @@ Character *ToonEngine::getCharacterById(int32 charId) {
}
void ToonEngine::drawConversationLine() {
- if (_currentTextLine) {
+ if (_currentTextLine && _showConversationText) {
_fontRenderer->setFontColorByCharacter(_currentTextLineCharacterId);
_fontRenderer->setFont(_fontToon);
_fontRenderer->renderMultiLineText(_currentTextLineX, _currentTextLineY, Common::String(_currentTextLine), 0);
}
}
+void ToonEngine::pauseEngineIntern(bool pause) {
+
+ Engine::pauseEngineIntern(pause);
+
+ static int32 pauseStart = 0;
+ if (pause) {
+ pauseStart = _system->getMillis();
+
+ } else {
+ _oldTimer = _system->getMillis();
+ _oldTimer2 = _oldTimer;
+
+ int32 diff = _oldTimer - pauseStart;
+
+ // we have to add the difference between the start and the current time
+ // to all "timer based" values.
+ for (int32 i = 0; i < _gameState->_locations[_gameState->_currentScene]._numSceneAnimations; i++) {
+ _sceneAnimationScripts[i]._lastTimer += diff;
+ }
+ for (int32 i = 0; i < 8; i++) {
+ if (_characters[i]) {
+ _characters[i]->updateTimers(diff);
+ }
+ }
+
+ _gameState->_timerTimeout[0] += diff;
+ _gameState->_timerTimeout[1] += diff;
+ }
+}
+
+bool ToonEngine::canSaveGameStateCurrently() {
+ return !_gameState->_inInventory && !_gameState->_inConversation && !_gameState->_inCutaway && !_gameState->_mouseHidden && !_moviePlayer->isPlaying();
+}
+
+bool ToonEngine::canLoadGameStateCurrently() {
+ return !_gameState->_inInventory && !_gameState->_inConversation && !_gameState->_inCutaway && !_gameState->_mouseHidden && !_moviePlayer->isPlaying();
+}
+
Common::String ToonEngine::getSavegameName(int nr) {
- return _targetName + Common::String::printf(".%03d", nr);
+ return _targetName + Common::String::format(".%03d", nr);
}
-bool ToonEngine::saveGame(int32 slot) {
+bool ToonEngine::saveGame(int32 slot, Common::String saveGameDesc) {
const EnginePlugin *plugin = NULL;
int16 savegameId;
Common::String savegameDescription;
@@ -2682,7 +2855,11 @@ bool ToonEngine::saveGame(int32 slot) {
delete dialog;
} else {
savegameId = slot;
- savegameDescription = Common::String::printf("Quick save #%d", slot);
+ if (!saveGameDesc.empty()) {
+ savegameDescription = saveGameDesc;
+ } else {
+ savegameDescription = Common::String::format("Quick save #%d", slot);
+ }
}
if (savegameId < 0)
@@ -2821,8 +2998,9 @@ bool ToonEngine::loadGame(int32 slot) {
for (int32 i = 0; i < state()->_locations[_gameState->_currentScene]._numSceneAnimations; i++) {
_sceneAnimationScripts[i]._active = loadFile->readByte();
_sceneAnimationScripts[i]._frozen = loadFile->readByte();
+ _sceneAnimationScripts[i]._frozenForConversation = false;
int32 oldTimer = loadFile->readSint32BE();
- _sceneAnimationScripts[i]._lastTimer = MAX(0,oldTimer + timerDiff);
+ _sceneAnimationScripts[i]._lastTimer = MAX<int32>(0,oldTimer + timerDiff);
_script->loadState(&_sceneAnimationScripts[i]._state, loadFile);
}
@@ -4181,7 +4359,7 @@ int32 ToonEngine::pauseSceneAnimationScript(int32 animScriptId, int32 tickToWait
}
Common::String ToonEngine::createRoomFilename(Common::String name) {
- Common::String file = Common::String::printf("ACT%d/%s/%s", _gameState->_currentChapter, _gameState->_locations[_gameState->_currentScene]._name, name.c_str());
+ Common::String file = Common::String::format("ACT%d/%s/%s", _gameState->_currentChapter, _gameState->_locations[_gameState->_currentScene]._name, name.c_str());
return file;
}
@@ -4391,10 +4569,9 @@ void SceneAnimation::load(ToonEngine *vm, Common::ReadStream *stream) {
_animation = new Animation(vm);
_animation->loadAnimation(animationName);
- if (_animInstance)
+ if (_animInstance) {
_animInstance->setAnimation(_animation, false);
-
- printf("load animation instance %d / %s / visible %d \n", _id, _animation->_name, _animInstance->getVisible());
+ }
}
}
diff --git a/engines/toon/toon.h b/engines/toon/toon.h
index 30aa344517..4c1ad21946 100644
--- a/engines/toon/toon.h
+++ b/engines/toon/toon.h
@@ -30,6 +30,7 @@
#include "engines/engine.h"
#include "graphics/surface.h"
#include "common/random.h"
+#include "common/error.h"
#include "toon/resource.h"
#include "toon/script.h"
#include "toon/script_func.h"
@@ -40,13 +41,23 @@
#include "toon/font.h"
#include "toon/text.h"
#include "toon/audio.h"
+#include "toon/console.h"
#define TOON_DAT_VER_MAJ 0 // 1 byte
#define TOON_DAT_VER_MIN 3 // 1 byte
#define TOON_SAVEGAME_VERSION 4
#define DATAALIGNMENT 4
+/**
+ * This is the namespace of the Toon engine.
+ *
+ * Status of this engine: ???
+ *
+ * Games using this engine:
+ * - Toonstruck
+ */
namespace Toon {
+
enum ToonGameType {
GType_TOON = 1
};
@@ -91,6 +102,7 @@ public:
char **_specialInfoLine;
Common::Error run();
+ GUI::Debugger *getDebugger() { return _console; }
bool showMainmenu(bool &loadedGame);
void init();
bool loadToonDat();
@@ -134,7 +146,7 @@ public:
int32 runConversationCommand(int16 **command);
void prepareConversations();
void drawConversationIcons();
- void simpleUpdate();
+ void simpleUpdate(bool waitCharacterToTalk = false);
int32 waitTicks(int32 numTicks, bool breakOnMouseClick);
void copyToVirtualScreen(bool updateScreen = true);
void getMouseEvent();
@@ -160,7 +172,7 @@ public:
Character *getCharacterById(int32 charId);
Common::String getSavegameName(int nr);
bool loadGame(int32 slot);
- bool saveGame(int32 slot);
+ bool saveGame(int32 slot, Common::String saveGameDesc);
void fadeIn(int32 numFrames) ;
void fadeOut(int32 numFrames) ;
void initCharacter(int32 characterId, int32 animScriptId, int32 animToPlayId, int32 sceneAnimationId);
@@ -186,6 +198,11 @@ public:
const char *getSpecialConversationMusic(int32 locationId);
void playRoomMusic();
void waitForScriptStep();
+ void doMagnifierEffect();
+
+ bool canSaveGameStateCurrently();
+ bool canLoadGameStateCurrently();
+ void pauseEngineIntern(bool pause);
Resources *resources() {
return _resources;
@@ -243,6 +260,10 @@ public:
return _currentTextLineId;
}
+ int32 getCurrentCharacterTalking() {
+ return _currentTextLineCharacterId;
+ }
+
CharacterDrew *getDrew() {
return (CharacterDrew *)_drew;
}
@@ -291,6 +312,22 @@ public:
return _shouldQuit;
}
+ Common::Error saveGameState(int slot, const char *desc) {
+
+ return (saveGame(slot, desc) ? Common::kWritingFailed : Common::kNoError);
+ }
+
+ Common::Error loadGameState(int slot) {
+ return (loadGame(slot) ? Common::kReadingFailed : Common::kNoError);
+ }
+
+ bool hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+ }
+
protected:
OSystem *_system;
int32 _tickLength;
@@ -381,6 +418,9 @@ protected:
bool _firstFrame;
bool _isDemo;
+ bool _showConversationText;
+private:
+ ToonConsole *_console;
};
} // End of namespace Toon
diff --git a/engines/touche/console.cpp b/engines/touche/console.cpp
new file mode 100644
index 0000000000..9d2b94d31c
--- /dev/null
+++ b/engines/touche/console.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "touche/console.h"
+#include "touche/touche.h"
+
+namespace Touche {
+
+ToucheConsole::ToucheConsole(ToucheEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
+
+ToucheConsole::~ToucheConsole() {
+}
+
+void ToucheConsole::preEnter() {
+}
+
+void ToucheConsole::postEnter() {
+}
+
+} // End of namespace Touche
diff --git a/backends/mutex/sdl/sdl-mutex.h b/engines/touche/console.h
index 88a19d398a..bcb947cf2e 100644
--- a/backends/mutex/sdl/sdl-mutex.h
+++ b/engines/touche/console.h
@@ -23,21 +23,28 @@
*
*/
-#ifndef BACKENDS_MUTEX_SDL_H
-#define BACKENDS_MUTEX_SDL_H
+#ifndef TOUCHE_CONSOLE_H
+#define TOUCHE_CONSOLE_H
-#include "backends/mutex/mutex.h"
+#include "gui/debugger.h"
-/**
- * SDL mutex manager
- */
-class SdlMutexManager : public MutexManager {
+namespace Touche {
+
+class ToucheEngine;
+
+class ToucheConsole : public GUI::Debugger {
public:
- virtual OSystem::MutexRef createMutex();
- virtual void lockMutex(OSystem::MutexRef mutex);
- virtual void unlockMutex(OSystem::MutexRef mutex);
- virtual void deleteMutex(OSystem::MutexRef mutex);
+ ToucheConsole(ToucheEngine *vm);
+ virtual ~ToucheConsole(void);
+
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+private:
+ ToucheEngine *_vm;
};
+} // End of namespace Touche
#endif
diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp
index 35f03fa657..06d15664a5 100644
--- a/engines/touche/detection.cpp
+++ b/engines/touche/detection.cpp
@@ -130,13 +130,21 @@ static const char *directoryGlobs[] = {
};
static const ADParams detectionParams = {
+ // Pointer to ADGameDescription or its superset structure
(const byte *)Touche::gameDescriptions,
+ // Size of that superset structure
sizeof(ADGameDescription),
- 4096, // number of md5 bytes
+ // Number of bytes to compute MD5 sum for
+ 4096,
+ // List of all engine targets
toucheGames,
- 0, // no obsolete targets data
+ // Structure for autoupgrading obsolete targets
+ 0,
+ // Name of single gameid (optional)
"touche",
- Touche::fileBasedFallback, // file-based detection data to enable not yet known versions to start
+ // List of files for file-based fallback detection (optional)
+ Touche::fileBasedFallback,
+ // Flags
kADFlagPrintWarningOnFileBasedFallback,
// Additional GUI options (for every game}
Common::GUIO_NONE,
diff --git a/engines/touche/module.mk b/engines/touche/module.mk
index 30965e1155..710b3169de 100644
--- a/engines/touche/module.mk
+++ b/engines/touche/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/touche
MODULE_OBJS := \
+ console.o \
detection.o \
graphics.o \
menu.o \
diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp
index 2dc8b76b4f..0bfb43a27a 100644
--- a/engines/touche/touche.cpp
+++ b/engines/touche/touche.cpp
@@ -82,11 +82,15 @@ ToucheEngine::ToucheEngine(OSystem *system, Common::Language language)
DebugMan.addDebugChannel(kDebugOpcodes, "Opcodes", "Opcodes debug level");
DebugMan.addDebugChannel(kDebugMenu, "Menu", "Menu debug level");
+ _console = new ToucheConsole(this);
+
g_eventRec.registerRandomSource(_rnd, "touche");
}
ToucheEngine::~ToucheEngine() {
DebugMan.clearAllDebugChannels();
+ delete _console;
+
delete _midiPlayer;
}
@@ -324,6 +328,9 @@ void ToucheEngine::processEvents(bool handleKeyEvents) {
if (event.kbd.hasFlags(Common::KBD_CTRL)) {
if (event.kbd.keycode == Common::KEYCODE_f) {
_fastMode = !_fastMode;
+ } else if (event.kbd.keycode == Common::KEYCODE_d) {
+ this->getDebugger()->attach();
+ this->getDebugger()->onFrame();
}
} else {
if (event.kbd.ascii == 't') {
diff --git a/engines/touche/touche.h b/engines/touche/touche.h
index 33ca81ed4f..926dab04b2 100644
--- a/engines/touche/touche.h
+++ b/engines/touche/touche.h
@@ -37,13 +37,15 @@
#include "engines/engine.h"
+#include "touche/console.h"
+
/**
* This is the namespace of the Touche engine.
*
* Status of this engine: ???
*
- * Supported games:
- * - ???
+ * Games using this engine:
+ * - Touche: The Adventures of the Fifth Musketeer
*/
namespace Touche {
@@ -382,6 +384,7 @@ public:
virtual Common::Error run();
virtual bool hasFeature(EngineFeature f) const;
virtual void syncSoundSettings();
+ GUI::Debugger *getDebugger() { return _console; }
protected:
@@ -518,6 +521,8 @@ protected:
virtual bool canLoadGameStateCurrently();
virtual bool canSaveGameStateCurrently();
+ ToucheConsole *_console;
+
void setupOpcodes();
void op_nop();
void op_jnz();
diff --git a/engines/tucker/console.cpp b/engines/tucker/console.cpp
new file mode 100644
index 0000000000..f06fd8fddb
--- /dev/null
+++ b/engines/tucker/console.cpp
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "tucker/console.h"
+#include "tucker/tucker.h"
+
+namespace Tucker {
+
+TuckerConsole::TuckerConsole(TuckerEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
+
+TuckerConsole::~TuckerConsole() {
+}
+
+void TuckerConsole::preEnter() {
+}
+
+void TuckerConsole::postEnter() {
+}
+
+} // End of namespace Tucker
diff --git a/engines/tucker/console.h b/engines/tucker/console.h
new file mode 100644
index 0000000000..2449fa3279
--- /dev/null
+++ b/engines/tucker/console.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef TUCKER_CONSOLE_H
+#define TUCKER_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Tucker {
+
+class TuckerEngine;
+
+class TuckerConsole : public GUI::Debugger {
+public:
+ TuckerConsole(TuckerEngine *vm);
+ virtual ~TuckerConsole(void);
+
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+private:
+ TuckerEngine *_vm;
+};
+
+} // End of namespace Tucker
+
+#endif
diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp
index 0a9dec9b46..f0437d2f87 100644
--- a/engines/tucker/detection.cpp
+++ b/engines/tucker/detection.cpp
@@ -106,16 +106,27 @@ static const ADGameDescription tuckerGameDescriptions[] = {
};
static const ADParams detectionParams = {
+ // Pointer to ADGameDescription or its superset structure
(const byte *)tuckerGameDescriptions,
+ // Size of that superset structure
sizeof(ADGameDescription),
+ // Number of bytes to compute MD5 sum for
512,
+ // List of all engine targets
tuckerGames,
+ // Structure for autoupgrading obsolete targets
0,
+ // Name of single gameid (optional)
"tucker",
+ // List of files for file-based fallback detection (optional)
0,
+ // Flags
0,
- Common::GUIO_NONE,
+ // Additional GUI options (for every game}
+ Common::GUIO_NOLAUNCHLOAD,
+ // Maximum directory depth
1,
+ // List of directory globs
0
};
diff --git a/engines/tucker/module.mk b/engines/tucker/module.mk
index 4847fdc3ec..d11c68b746 100644
--- a/engines/tucker/module.mk
+++ b/engines/tucker/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/tucker
MODULE_OBJS := \
+ console.o \
detection.o \
graphics.o \
locations.o \
diff --git a/engines/tucker/tucker.cpp b/engines/tucker/tucker.cpp
index c86991ab1b..2b9b4edee4 100644
--- a/engines/tucker/tucker.cpp
+++ b/engines/tucker/tucker.cpp
@@ -38,9 +38,11 @@ namespace Tucker {
TuckerEngine::TuckerEngine(OSystem *system, Common::Language language, uint32 flags)
: Engine(system), _gameLang(language), _gameFlags(flags) {
+ _console = new TuckerConsole(this);
}
TuckerEngine::~TuckerEngine() {
+ delete _console;
}
bool TuckerEngine::hasFeature(EngineFeature f) const {
@@ -628,6 +630,12 @@ void TuckerEngine::parseEvents() {
case Common::KEYCODE_ESCAPE:
_inputKeys[kInputKeyEscape] = true;
break;
+ case Common::KEYCODE_d:
+ if (ev.kbd.hasFlags(Common::KBD_CTRL)) {
+ this->getDebugger()->attach();
+ this->getDebugger()->onFrame();
+ }
+ break;
default:
break;
}
diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h
index 86f5843e77..a7d7f1cdd4 100644
--- a/engines/tucker/tucker.h
+++ b/engines/tucker/tucker.h
@@ -39,12 +39,14 @@
#include "engines/engine.h"
+#include "tucker/console.h"
+
/**
* This is the namespace of the Tucker engine.
*
* Status of this engine: Complete
*
- * Supported games:
+ * Games using this engine:
* - Bud Tucker in Double Trouble
*/
namespace Tucker {
@@ -275,6 +277,7 @@ public:
virtual Common::Error run();
virtual bool hasFeature(EngineFeature f) const;
virtual void syncSoundSettings();
+ GUI::Debugger *getDebugger() { return _console; }
protected:
@@ -566,6 +569,8 @@ protected:
virtual bool canLoadGameStateCurrently();
virtual bool canSaveGameStateCurrently();
+ TuckerConsole *_console;
+
void handleIntroSequence();
void handleCreditsSequence();
void handleCongratulationsSequence();
diff --git a/graphics/scaler/scale2x.cpp b/graphics/scaler/scale2x.cpp
index 877bbb9509..deae44c1c7 100644
--- a/graphics/scaler/scale2x.cpp
+++ b/graphics/scaler/scale2x.cpp
@@ -37,13 +37,10 @@
#include "graphics/scaler/intern.h"
#include "graphics/scaler/scale2x.h"
-#include <assert.h>
-
/***************************************************************************/
/* Scale2x C implementation */
-static inline void scale2x_8_def_single(scale2x_uint8* __restrict__ dst, const scale2x_uint8* __restrict__ src0, const scale2x_uint8* __restrict__ src1, const scale2x_uint8* __restrict__ src2, unsigned count)
-{
+static inline void scale2x_8_def_single(scale2x_uint8* __restrict__ dst, const scale2x_uint8* __restrict__ src0, const scale2x_uint8* __restrict__ src1, const scale2x_uint8* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -62,8 +59,7 @@ static inline void scale2x_8_def_single(scale2x_uint8* __restrict__ dst, const s
}
}
-static inline void scale2x_16_def_single(scale2x_uint16* __restrict__ dst, const scale2x_uint16* __restrict__ src0, const scale2x_uint16* __restrict__ src1, const scale2x_uint16* __restrict__ src2, unsigned count)
-{
+static inline void scale2x_16_def_single(scale2x_uint16* __restrict__ dst, const scale2x_uint16* __restrict__ src0, const scale2x_uint16* __restrict__ src1, const scale2x_uint16* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -82,8 +78,7 @@ static inline void scale2x_16_def_single(scale2x_uint16* __restrict__ dst, const
}
}
-static inline void scale2x_32_def_single(scale2x_uint32* __restrict__ dst, const scale2x_uint32* __restrict__ src0, const scale2x_uint32* __restrict__ src1, const scale2x_uint32* __restrict__ src2, unsigned count)
-{
+static inline void scale2x_32_def_single(scale2x_uint32* __restrict__ dst, const scale2x_uint32* __restrict__ src0, const scale2x_uint32* __restrict__ src1, const scale2x_uint32* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -107,16 +102,15 @@ static inline void scale2x_32_def_single(scale2x_uint32* __restrict__ dst, const
* The function is implemented in C.
* The pixels over the left and right borders are assumed of the same color of
* the pixels on the border.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows.
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
- * \param dst0 First destination row, double length in pixels.
- * \param dst1 Second destination row, double length in pixels.
+ * @param dst0 First destination row, double length in pixels.
+ * @param dst1 Second destination row, double length in pixels.
*/
-void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
-{
+void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) {
scale2x_8_def_single(dst0, src0, src1, src2, count);
scale2x_8_def_single(dst1, src2, src1, src0, count);
}
@@ -124,16 +118,15 @@ void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8
/**
* Scale by a factor of 2 a row of pixels of 16 bits.
* This function operates like scale2x_8_def() but for 16 bits pixels.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows.
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
- * \param dst0 First destination row, double length in pixels.
- * \param dst1 Second destination row, double length in pixels.
+ * @param dst0 First destination row, double length in pixels.
+ * @param dst1 Second destination row, double length in pixels.
*/
-void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
-{
+void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
scale2x_16_def_single(dst0, src0, src1, src2, count);
scale2x_16_def_single(dst1, src2, src1, src0, count);
}
@@ -141,16 +134,15 @@ void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_ui
/**
* Scale by a factor of 2 a row of pixels of 32 bits.
* This function operates like scale2x_8_def() but for 32 bits pixels.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows.
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
- * \param dst0 First destination row, double length in pixels.
- * \param dst1 Second destination row, double length in pixels.
+ * @param dst0 First destination row, double length in pixels.
+ * @param dst1 Second destination row, double length in pixels.
*/
-void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
-{
+void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
scale2x_32_def_single(dst0, src0, src1, src2, count);
scale2x_32_def_single(dst1, src2, src1, src0, count);
}
@@ -198,8 +190,7 @@ void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_ui
* %mm6 -> *current_upper
* %mm7 -> *current
*/
-static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
-{
+static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) {
assert(count >= 16);
assert(count % 8 == 0);
@@ -276,8 +267,7 @@ static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8*
);
}
-static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
-{
+static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
assert(count >= 8);
assert(count % 4 == 0);
@@ -354,8 +344,7 @@ static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint
);
}
-static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
-{
+static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
assert(count >= 4);
assert(count % 2 == 0);
@@ -445,16 +434,15 @@ static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint
* instruction before any floating-point operation.
* The pixels over the left and right borders are assumed of the same color of
* the pixels on the border.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows. It must
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows. It must
* be at least 16 and a multiple of 8.
- * \param dst0 First destination row, double length in pixels.
- * \param dst1 Second destination row, double length in pixels.
+ * @param dst0 First destination row, double length in pixels.
+ * @param dst1 Second destination row, double length in pixels.
*/
-void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
-{
+void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) {
if (count % 8 != 0 || count < 16) {
scale2x_8_def(dst0, dst1, src0, src1, src2, count);
} else {
@@ -469,16 +457,15 @@ void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8
/**
* Scale by a factor of 2 a row of pixels of 16 bits.
* This function operates like scale2x_8_mmx() but for 16 bits pixels.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows. It must
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows. It must
* be at least 8 and a multiple of 4.
- * \param dst0 First destination row, double length in pixels.
- * \param dst1 Second destination row, double length in pixels.
+ * @param dst0 First destination row, double length in pixels.
+ * @param dst1 Second destination row, double length in pixels.
*/
-void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
-{
+void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
if (count % 4 != 0 || count < 8) {
scale2x_16_def(dst0, dst1, src0, src1, src2, count);
} else {
@@ -493,16 +480,15 @@ void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_ui
/**
* Scale by a factor of 2 a row of pixels of 32 bits.
* This function operates like scale2x_8_mmx() but for 32 bits pixels.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows. It must
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows. It must
* be at least 4 and a multiple of 2.
- * \param dst0 First destination row, double length in pixels.
- * \param dst1 Second destination row, double length in pixels.
+ * @param dst0 First destination row, double length in pixels.
+ * @param dst1 Second destination row, double length in pixels.
*/
-void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
-{
+void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
if (count % 2 != 0 || count < 4) {
scale2x_32_def(dst0, dst1, src0, src1, src2, count);
} else {
diff --git a/graphics/scaler/scale3x.cpp b/graphics/scaler/scale3x.cpp
index 8aa33dd170..4e78796ee7 100644
--- a/graphics/scaler/scale3x.cpp
+++ b/graphics/scaler/scale3x.cpp
@@ -37,13 +37,10 @@
#include "graphics/scaler/intern.h"
#include "graphics/scaler/scale3x.h"
-#include <assert.h>
-
/***************************************************************************/
/* Scale3x C implementation */
-static inline void scale3x_8_def_border(scale3x_uint8* __restrict__ dst, const scale3x_uint8* __restrict__ src0, const scale3x_uint8* __restrict__ src1, const scale3x_uint8* __restrict__ src2, unsigned count)
-{
+static inline void scale3x_8_def_border(scale3x_uint8* __restrict__ dst, const scale3x_uint8* __restrict__ src0, const scale3x_uint8* __restrict__ src1, const scale3x_uint8* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -64,8 +61,7 @@ static inline void scale3x_8_def_border(scale3x_uint8* __restrict__ dst, const s
}
}
-static inline void scale3x_8_def_center(scale3x_uint8* __restrict__ dst, const scale3x_uint8* __restrict__ src0, const scale3x_uint8* __restrict__ src1, const scale3x_uint8* __restrict__ src2, unsigned count)
-{
+static inline void scale3x_8_def_center(scale3x_uint8* __restrict__ dst, const scale3x_uint8* __restrict__ src0, const scale3x_uint8* __restrict__ src1, const scale3x_uint8* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -86,8 +82,7 @@ static inline void scale3x_8_def_center(scale3x_uint8* __restrict__ dst, const s
}
}
-static inline void scale3x_16_def_border(scale3x_uint16* __restrict__ dst, const scale3x_uint16* __restrict__ src0, const scale3x_uint16* __restrict__ src1, const scale3x_uint16* __restrict__ src2, unsigned count)
-{
+static inline void scale3x_16_def_border(scale3x_uint16* __restrict__ dst, const scale3x_uint16* __restrict__ src0, const scale3x_uint16* __restrict__ src1, const scale3x_uint16* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -108,8 +103,7 @@ static inline void scale3x_16_def_border(scale3x_uint16* __restrict__ dst, const
}
}
-static inline void scale3x_16_def_center(scale3x_uint16* __restrict__ dst, const scale3x_uint16* __restrict__ src0, const scale3x_uint16* __restrict__ src1, const scale3x_uint16* __restrict__ src2, unsigned count)
-{
+static inline void scale3x_16_def_center(scale3x_uint16* __restrict__ dst, const scale3x_uint16* __restrict__ src0, const scale3x_uint16* __restrict__ src1, const scale3x_uint16* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -130,8 +124,7 @@ static inline void scale3x_16_def_center(scale3x_uint16* __restrict__ dst, const
}
}
-static inline void scale3x_32_def_border(scale3x_uint32* __restrict__ dst, const scale3x_uint32* __restrict__ src0, const scale3x_uint32* __restrict__ src1, const scale3x_uint32* __restrict__ src2, unsigned count)
-{
+static inline void scale3x_32_def_border(scale3x_uint32* __restrict__ dst, const scale3x_uint32* __restrict__ src0, const scale3x_uint32* __restrict__ src1, const scale3x_uint32* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -152,8 +145,7 @@ static inline void scale3x_32_def_border(scale3x_uint32* __restrict__ dst, const
}
}
-static inline void scale3x_32_def_center(scale3x_uint32* __restrict__ dst, const scale3x_uint32* __restrict__ src0, const scale3x_uint32* __restrict__ src1, const scale3x_uint32* __restrict__ src2, unsigned count)
-{
+static inline void scale3x_32_def_center(scale3x_uint32* __restrict__ dst, const scale3x_uint32* __restrict__ src0, const scale3x_uint32* __restrict__ src1, const scale3x_uint32* __restrict__ src2, unsigned count) {
/* central pixels */
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
@@ -179,17 +171,16 @@ static inline void scale3x_32_def_center(scale3x_uint32* __restrict__ dst, const
* The function is implemented in C.
* The pixels over the left and right borders are assumed of the same color of
* the pixels on the border.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows.
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
- * \param dst0 First destination row, triple length in pixels.
- * \param dst1 Second destination row, triple length in pixels.
- * \param dst2 Third destination row, triple length in pixels.
+ * @param dst0 First destination row, triple length in pixels.
+ * @param dst1 Second destination row, triple length in pixels.
+ * @param dst2 Third destination row, triple length in pixels.
*/
-void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
-{
+void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) {
scale3x_8_def_border(dst0, src0, src1, src2, count);
scale3x_8_def_center(dst1, src0, src1, src2, count);
scale3x_8_def_border(dst2, src2, src1, src0, count);
@@ -198,17 +189,16 @@ void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2
/**
* Scale by a factor of 3 a row of pixels of 16 bits.
* This function operates like scale3x_8_def() but for 16 bits pixels.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows.
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
- * \param dst0 First destination row, triple length in pixels.
- * \param dst1 Second destination row, triple length in pixels.
- * \param dst2 Third destination row, triple length in pixels.
+ * @param dst0 First destination row, triple length in pixels.
+ * @param dst1 Second destination row, triple length in pixels.
+ * @param dst2 Third destination row, triple length in pixels.
*/
-void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
-{
+void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) {
scale3x_16_def_border(dst0, src0, src1, src2, count);
scale3x_16_def_center(dst1, src0, src1, src2, count);
scale3x_16_def_border(dst2, src2, src1, src0, count);
@@ -217,17 +207,16 @@ void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16*
/**
* Scale by a factor of 3 a row of pixels of 32 bits.
* This function operates like scale3x_8_def() but for 32 bits pixels.
- * \param src0 Pointer at the first pixel of the previous row.
- * \param src1 Pointer at the first pixel of the current row.
- * \param src2 Pointer at the first pixel of the next row.
- * \param count Length in pixels of the src0, src1 and src2 rows.
+ * @param src0 Pointer at the first pixel of the previous row.
+ * @param src1 Pointer at the first pixel of the current row.
+ * @param src2 Pointer at the first pixel of the next row.
+ * @param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
- * \param dst0 First destination row, triple length in pixels.
- * \param dst1 Second destination row, triple length in pixels.
- * \param dst2 Third destination row, triple length in pixels.
+ * @param dst0 First destination row, triple length in pixels.
+ * @param dst1 Second destination row, triple length in pixels.
+ * @param dst2 Third destination row, triple length in pixels.
*/
-void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
-{
+void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) {
scale3x_32_def_border(dst0, src0, src1, src2, count);
scale3x_32_def_center(dst1, src0, src1, src2, count);
scale3x_32_def_border(dst2, src2, src1, src0, count);
diff --git a/graphics/scaler/scalebit.cpp b/graphics/scaler/scalebit.cpp
index 6a3b47b0f5..706fea8f05 100644
--- a/graphics/scaler/scalebit.cpp
+++ b/graphics/scaler/scalebit.cpp
@@ -39,34 +39,26 @@
#include "graphics/scaler/scale2x.h"
#include "graphics/scaler/scale3x.h"
-#if defined(HAVE_ALLOCA_H)
-#include <alloca.h>
-#endif
-
-#include <assert.h>
-#include <stdlib.h>
-
#define DST(bits, num) (scale2x_uint ## bits *)dst ## num
#define SRC(bits, num) (const scale2x_uint ## bits *)src ## num
/**
* Apply the Scale2x effect on a group of rows. Used internally.
*/
-static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
-{
+static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) {
switch (pixel) {
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
- case 1 : scale2x_8_mmx(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
- case 2 : scale2x_16_mmx(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
- case 4 : scale2x_32_mmx(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
+ case 1 : scale2x_8_mmx(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
+ case 2 : scale2x_16_mmx(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
+ case 4 : scale2x_32_mmx(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
#elif defined(USE_ARM_SCALER_ASM)
- case 1 : scale2x_8_arm(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
- case 2 : scale2x_16_arm(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
- case 4 : scale2x_32_arm(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
+ case 1 : scale2x_8_arm(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
+ case 2 : scale2x_16_arm(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
+ case 4 : scale2x_32_arm(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
#else
- case 1 : scale2x_8_def(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
- case 2 : scale2x_16_def(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
- case 4 : scale2x_32_def(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
+ case 1 : scale2x_8_def(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
+ case 2 : scale2x_16_def(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
+ case 4 : scale2x_32_def(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
#endif
}
}
@@ -74,20 +66,18 @@ static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const
/**
* Apply the Scale3x effect on a group of rows. Used internally.
*/
-static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
-{
+static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) {
switch (pixel) {
- case 1 : scale3x_8_def(DST(8,0), DST(8,1), DST(8,2), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
- case 2 : scale3x_16_def(DST(16,0), DST(16,1), DST(16,2), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
- case 4 : scale3x_32_def(DST(32,0), DST(32,1), DST(32,2), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
+ case 1 : scale3x_8_def(DST(8,0), DST(8,1), DST(8,2), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
+ case 2 : scale3x_16_def(DST(16,0), DST(16,1), DST(16,2), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
+ case 4 : scale3x_32_def(DST(32,0), DST(32,1), DST(32,2), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
}
}
/**
* Apply the Scale4x effect on a group of rows. Used internally.
*/
-static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row)
-{
+static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row) {
stage_scale2x(dst0, dst1, src0, src1, src2, pixel, 2 * pixel_per_row);
stage_scale2x(dst2, dst3, src1, src2, src3, pixel, 2 * pixel_per_row);
}
@@ -102,16 +92,15 @@ static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3,
* The source bitmap isn't modified.
* The destination bitmap must be manually allocated before calling the function,
* note that the resulting size is exactly 2x2 times the size of the source bitmap.
- * \param void_dst Pointer at the first pixel of the destination bitmap.
- * \param dst_slice Size in bytes of a destination bitmap row.
- * \param void_src Pointer at the first pixel of the source bitmap.
- * \param src_slice Size in bytes of a source bitmap row.
- * \param pixel Bytes per pixel of the source and destination bitmap.
- * \param width Horizontal size in pixels of the source bitmap.
- * \param height Vertical size in pixels of the source bitmap.
+ * @param void_dst Pointer at the first pixel of the destination bitmap.
+ * @param dst_slice Size in bytes of a destination bitmap row.
+ * @param void_src Pointer at the first pixel of the source bitmap.
+ * @param src_slice Size in bytes of a source bitmap row.
+ * @param pixel Bytes per pixel of the source and destination bitmap.
+ * @param width Horizontal size in pixels of the source bitmap.
+ * @param height Vertical size in pixels of the source bitmap.
*/
-static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
-{
+static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
unsigned char* dst = (unsigned char*)void_dst;
const unsigned char* src = (const unsigned char*)void_src;
unsigned count;
@@ -140,16 +129,15 @@ static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, un
* The source bitmap isn't modified.
* The destination bitmap must be manually allocated before calling the function,
* note that the resulting size is exactly 3x3 times the size of the source bitmap.
- * \param void_dst Pointer at the first pixel of the destination bitmap.
- * \param dst_slice Size in bytes of a destination bitmap row.
- * \param void_src Pointer at the first pixel of the source bitmap.
- * \param src_slice Size in bytes of a source bitmap row.
- * \param pixel Bytes per pixel of the source and destination bitmap.
- * \param width Horizontal size in pixels of the source bitmap.
- * \param height Vertical size in pixels of the source bitmap.
+ * @param void_dst Pointer at the first pixel of the destination bitmap.
+ * @param dst_slice Size in bytes of a destination bitmap row.
+ * @param void_src Pointer at the first pixel of the source bitmap.
+ * @param src_slice Size in bytes of a source bitmap row.
+ * @param pixel Bytes per pixel of the source and destination bitmap.
+ * @param width Horizontal size in pixels of the source bitmap.
+ * @param height Vertical size in pixels of the source bitmap.
*/
-static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
-{
+static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
unsigned char* dst = (unsigned char*)void_dst;
const unsigned char* src = (const unsigned char*)void_src;
unsigned count;
@@ -179,18 +167,17 @@ static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, un
* and a vertical size of 6 rows. The memory of this buffer must not be allocated
* in video memory because it's also read and not only written. Generally
* a heap (malloc) or a stack (alloca) buffer is the best choices.
- * \param void_dst Pointer at the first pixel of the destination bitmap.
- * \param dst_slice Size in bytes of a destination bitmap row.
- * \param void_mid Pointer at the first pixel of the buffer bitmap.
- * \param mid_slice Size in bytes of a buffer bitmap row.
- * \param void_src Pointer at the first pixel of the source bitmap.
- * \param src_slice Size in bytes of a source bitmap row.
- * \param pixel Bytes per pixel of the source and destination bitmap.
- * \param width Horizontal size in pixels of the source bitmap.
- * \param height Vertical size in pixels of the source bitmap.
+ * @param void_dst Pointer at the first pixel of the destination bitmap.
+ * @param dst_slice Size in bytes of a destination bitmap row.
+ * @param void_mid Pointer at the first pixel of the buffer bitmap.
+ * @param mid_slice Size in bytes of a buffer bitmap row.
+ * @param void_src Pointer at the first pixel of the source bitmap.
+ * @param src_slice Size in bytes of a source bitmap row.
+ * @param pixel Bytes per pixel of the source and destination bitmap.
+ * @param width Horizontal size in pixels of the source bitmap.
+ * @param height Vertical size in pixels of the source bitmap.
*/
-static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
-{
+static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
unsigned char* dst = (unsigned char*)void_dst;
const unsigned char* src = (const unsigned char*)void_src;
unsigned count;
@@ -242,16 +229,15 @@ static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsi
* note that the resulting size is exactly 4x4 times the size of the source bitmap.
* \note This function operates like ::scale4x_buf() but the intermediate buffer is
* automatically allocated in the stack.
- * \param void_dst Pointer at the first pixel of the destination bitmap.
- * \param dst_slice Size in bytes of a destination bitmap row.
- * \param void_src Pointer at the first pixel of the source bitmap.
- * \param src_slice Size in bytes of a source bitmap row.
- * \param pixel Bytes per pixel of the source and destination bitmap.
- * \param width Horizontal size in pixels of the source bitmap.
- * \param height Vertical size in pixels of the source bitmap.
+ * @param void_dst Pointer at the first pixel of the destination bitmap.
+ * @param dst_slice Size in bytes of a destination bitmap row.
+ * @param void_src Pointer at the first pixel of the source bitmap.
+ * @param src_slice Size in bytes of a source bitmap row.
+ * @param pixel Bytes per pixel of the source and destination bitmap.
+ * @param width Horizontal size in pixels of the source bitmap.
+ * @param height Vertical size in pixels of the source bitmap.
*/
-static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
-{
+static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
unsigned mid_slice;
void* mid;
@@ -279,10 +265,10 @@ static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, un
/**
* Check if the scale implementation is applicable at the given arguments.
- * \param scale Scale factor. 2, 3 or 4.
- * \param pixel Bytes per pixel of the source and destination bitmap.
- * \param width Horizontal size in pixels of the source bitmap.
- * \param height Vertical size in pixels of the source bitmap.
+ * @param scale Scale factor. 2, 3 or 4.
+ * @param pixel Bytes per pixel of the source and destination bitmap.
+ * @param width Horizontal size in pixels of the source bitmap.
+ * @param height Vertical size in pixels of the source bitmap.
* \return
* - -1 on precondition violated.
* - 0 on success.
@@ -332,14 +318,14 @@ int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned
/**
* Apply the Scale effect on a bitmap.
* This function is simply a common interface for ::scale2x(), ::scale3x() and ::scale4x().
- * \param scale Scale factor. 2, 3 or 4.
- * \param void_dst Pointer at the first pixel of the destination bitmap.
- * \param dst_slice Size in bytes of a destination bitmap row.
- * \param void_src Pointer at the first pixel of the source bitmap.
- * \param src_slice Size in bytes of a source bitmap row.
- * \param pixel Bytes per pixel of the source and destination bitmap.
- * \param width Horizontal size in pixels of the source bitmap.
- * \param height Vertical size in pixels of the source bitmap.
+ * @param scale Scale factor. 2, 3 or 4.
+ * @param void_dst Pointer at the first pixel of the destination bitmap.
+ * @param dst_slice Size in bytes of a destination bitmap row.
+ * @param void_src Pointer at the first pixel of the source bitmap.
+ * @param src_slice Size in bytes of a source bitmap row.
+ * @param pixel Bytes per pixel of the source and destination bitmap.
+ * @param width Horizontal size in pixels of the source bitmap.
+ * @param height Vertical size in pixels of the source bitmap.
*/
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
{
diff --git a/graphics/sjis.cpp b/graphics/sjis.cpp
index af286346ca..06712a9226 100644
--- a/graphics/sjis.cpp
+++ b/graphics/sjis.cpp
@@ -65,6 +65,7 @@ void FontSJISBase::blitCharacter(const uint8 *glyph, const int w, const int h, u
if (mask & 0x80)
*d = c;
+
++d;
mask <<= 1;
}
@@ -103,9 +104,42 @@ void FontSJISBase::createOutline(uint8 *outline, const uint8 *glyph, const int w
}
}
-void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const {
+#ifndef DISABLE_FLIPPED_MODE
+const uint8 *FontSJISBase::flipCharacter(const uint8 *glyph, const int w) const {
+ static const uint8 flipData[] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xC7, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x97, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+ };
+
+ for (int i = 0; i < w; i++) {
+ _tempGlyph[i] = flipData[glyph[(w * 2 - 1) - i]];
+ _tempGlyph[(w * 2 - 1) - i] = flipData[glyph[i]];
+ }
+
+ return _tempGlyph;
+}
+#endif
+
+void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW, int maxH) const {
const uint8 *glyphSource = 0;
int width = 0, height = 0;
+ int outlineExtraWidth = 2, outlineExtraHeight = 2;
+ int outlineXOffset = 0, outlineYOffset = 0;
+
if (is8x16(ch)) {
glyphSource = getCharData8x16(ch);
width = 8;
@@ -116,29 +150,63 @@ void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1,
height = 16;
}
+ if (maxW != -1 && maxW < width) {
+ width = maxW;
+ outlineExtraWidth = 0;
+ outlineXOffset = 1;
+ }
+
+ if (maxH != -1 && maxH < height) {
+ height = maxH;
+ outlineExtraHeight = 0;
+ outlineYOffset = 1;
+ }
+
+ if (width <= 0 || height <= 0)
+ return;
+
if (!glyphSource) {
warning("FontSJISBase::drawChar: Font does not offer data for %02X %02X", ch & 0xFF, ch >> 8);
return;
}
+#ifndef DISABLE_FLIPPED_MODE
+ if (_flippedMode)
+ glyphSource = flipCharacter(glyphSource, width);
+#endif
+
uint8 outline[18 * 18];
- if (_outlineEnabled) {
+ if (_drawMode == kOutlineMode) {
memset(outline, 0, sizeof(outline));
createOutline(outline, glyphSource, width, height);
}
if (bpp == 1) {
- if (_outlineEnabled) {
- blitCharacter<uint8>(outline, width + 2, height + 2, (uint8 *)dst, pitch, c2);
- blitCharacter<uint8>(glyphSource, width, height, (uint8 *)dst + pitch + 1, pitch, c1);
- } else {
+ if (_drawMode == kOutlineMode) {
+ blitCharacter<uint8>(outline, width + outlineExtraWidth, height + outlineExtraHeight, (uint8 *)dst, pitch, c2);
+ blitCharacter<uint8>(glyphSource, width - outlineXOffset, height - outlineYOffset, (uint8 *)dst + pitch + 1, pitch, c1);
+ } else {
+ if (_drawMode != kDefaultMode) {
+ blitCharacter<uint8>(glyphSource, width - outlineXOffset, height, ((uint8*)dst) + 1, pitch, c2);
+ blitCharacter<uint8>(glyphSource, width, height - outlineYOffset, ((uint8*)dst) + pitch, pitch, c2);
+ if (_drawMode == kShadowMode)
+ blitCharacter<uint8>(glyphSource, width - outlineXOffset, height - outlineYOffset, ((uint8*)dst) + pitch + 1, pitch, c2);
+ }
+
blitCharacter<uint8>(glyphSource, width, height, (uint8 *)dst, pitch, c1);
}
} else if (bpp == 2) {
- if (_outlineEnabled) {
- blitCharacter<uint16>(outline, width + 2, height + 2, (uint8 *)dst, pitch, c2);
- blitCharacter<uint16>(glyphSource, width, height, (uint8 *)dst + pitch + 2, pitch, c1);
+ if (_drawMode == kOutlineMode) {
+ blitCharacter<uint16>(outline, width + outlineExtraWidth, height + outlineExtraHeight, (uint8 *)dst, pitch, c2);
+ blitCharacter<uint16>(glyphSource, width - outlineXOffset, height - outlineYOffset, (uint8 *)dst + pitch + 2, pitch, c1);
} else {
+ if (_drawMode != kDefaultMode) {
+ blitCharacter<uint16>(glyphSource, width - outlineXOffset, height, ((uint8*)dst) + 2, pitch, c2);
+ blitCharacter<uint16>(glyphSource, width, height - outlineYOffset, ((uint8*)dst) + pitch, pitch, c2);
+ if (_drawMode == kShadowMode)
+ blitCharacter<uint16>(glyphSource, width - outlineXOffset, height - outlineYOffset, ((uint8*)dst) + pitch + 2, pitch, c2);
+ }
+
blitCharacter<uint16>(glyphSource, width, height, (uint8 *)dst, pitch, c1);
}
} else {
@@ -148,7 +216,7 @@ void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1,
uint FontSJISBase::getCharWidth(uint16 ch) const {
if (is8x16(ch))
- return _outlineEnabled ? 10 : 8;
+ return (_drawMode == kOutlineMode) ? 10 : (_drawMode == kDefaultMode ? 8 : 9);
else
return getMaxFontWidth();
}
diff --git a/graphics/sjis.h b/graphics/sjis.h
index e0b760fc78..365e63e470 100644
--- a/graphics/sjis.h
+++ b/graphics/sjis.h
@@ -28,7 +28,7 @@
// for dynamic engine plugins.
// If you plan to use this code in another engine, you will have
// to add the proper define check here.
-#if !(defined(ENABLE_KYRA) || defined(ENABLE_SCI) || defined(DYNAMIC_MODULES))
+#if !(defined(ENABLE_KYRA) || defined(ENABLE_SCI) || defined(ENABLE_SCUMM) || defined(DYNAMIC_MODULES))
// If neither of the above mentioned is enabled, do not include the SJIS code.
@@ -37,6 +37,14 @@
#ifndef GRAPHICS_SJIS_H
#define GRAPHICS_SJIS_H
+#ifdef __DS__
+/* This disables the flipped mode which is used in FM-Towns versions
+ * of Monkey Island 1 (and maybe other SCUMM 5 games). These are not supported
+ * on the DS, so it makes sense to have a corresponding setting here.
+ */
+#define DISABLE_FLIPPED_MODE
+#endif
+
#include "common/scummsys.h"
#include "common/stream.h"
#include "common/util.h"
@@ -71,12 +79,24 @@ public:
virtual bool loadData() = 0;
/**
- * Enable outline drawing.
+ * Enable drawing with outline or shadow.
*
* After changing outline state, getFontHeight and getMaxFontWidth / getCharWidth might return
* different values!
*/
- virtual void enableOutline(bool enable) {}
+ enum DrawingMode {
+ kDefaultMode,
+ kOutlineMode,
+ kShadowMode,
+ kFMTownsShadowMode
+ };
+
+ virtual void setDrawingMode(DrawingMode mode) {}
+
+ /**
+ * Enable flipped character drawing (e.g. in the MI1 circus scene after Guybrush gets shot out of the cannon).
+ */
+ virtual void toggleFlippedMode(bool enable) {}
/**
* Returns the height of the font.
@@ -95,13 +115,9 @@ public:
/**
* Draws a SJIS encoded character on the given surface.
- *
- * TODO: Currently there is no assurance, that this method will only draw within
- * the surface boundaries. Thus the caller has to assure the glyph will fit at
- * the specified position.
*/
void drawChar(Graphics::Surface &dst, uint16 ch, int x, int y, uint32 c1, uint32 c2) const {
- drawChar(dst.getBasePtr(x, y), ch, c1, c2, dst.pitch, dst.bytesPerPixel);
+ drawChar(dst.getBasePtr(x, y), ch, dst.pitch, dst.bytesPerPixel, c1, c2, dst.w - x, dst.h - y);
}
/**
@@ -113,8 +129,10 @@ public:
* @param bpp bytes per pixel of the destination buffer
* @param c1 forground color
* @param c2 outline color
+ * @param maxW max draw width (to ensure that character drawing takes place within surface boundaries)
+ * @param maxH max draw height (to ensure that character drawing takes place within surface boundaries)
*/
- virtual void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const = 0;
+ virtual void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW = -1, int maxH = -1) const = 0;
};
/**
@@ -122,22 +140,33 @@ public:
*/
class FontSJISBase : public FontSJIS {
public:
- FontSJISBase() : _outlineEnabled(false) {}
+ FontSJISBase() : _drawMode(kDefaultMode), _flippedMode(false) {}
- void enableOutline(bool enable) { _outlineEnabled = enable; }
+ void setDrawingMode(DrawingMode mode) { _drawMode = mode; }
- uint getFontHeight() const { return _outlineEnabled ? 18 : 16; }
- uint getMaxFontWidth() const { return _outlineEnabled ? 18 : 16; }
+ void toggleFlippedMode(bool enable) { _flippedMode = enable; }
+
+ uint getFontHeight() const { return (_drawMode == kOutlineMode) ? 18 : (_drawMode == kDefaultMode ? 16 : 17); }
+
+ uint getMaxFontWidth() const { return (_drawMode == kOutlineMode) ? 18 : (_drawMode == kDefaultMode ? 16 : 17); }
uint getCharWidth(uint16 ch) const;
- void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const;
+ void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW = -1, int maxH = -1) const;
private:
template<typename Color>
void blitCharacter(const uint8 *glyph, const int w, const int h, uint8 *dst, int pitch, Color c) const;
void createOutline(uint8 *outline, const uint8 *glyph, const int w, const int h) const;
+
+#ifndef DISABLE_FLIPPED_MODE
+ // This is used in the FM-Towns version of Monkey Island 1
+ // when Guybrush gets shot out of the cannon in the circus tent.
+ const uint8 *flipCharacter(const uint8 *glyph, const int w) const;
+ mutable uint8 _tempGlyph[32];
+#endif
protected:
- bool _outlineEnabled;
+ DrawingMode _drawMode;
+ bool _flippedMode;
bool is8x16(uint16 ch) const;
diff --git a/graphics/video/codecs/qdm2.cpp b/graphics/video/codecs/qdm2.cpp
index 0050b256d1..26b18b189b 100644
--- a/graphics/video/codecs/qdm2.cpp
+++ b/graphics/video/codecs/qdm2.cpp
@@ -1350,15 +1350,20 @@ static int getVlc2(GetBitContext *s, int16 (*table)[2], int bits, int maxDepth)
static int allocTable(VLC *vlc, int size, int use_static) {
int index;
+ int16 (*temp)[2] = NULL;
index = vlc->table_size;
vlc->table_size += size;
if (vlc->table_size > vlc->table_allocated) {
if(use_static)
error("QDM2 cant do anything, init_vlc() is used with too little memory");
vlc->table_allocated += (1 << vlc->bits);
- vlc->table = (int16 (*)[2])realloc(vlc->table, sizeof(int16 *) * 2 * vlc->table_allocated);
- if (!vlc->table)
+ temp = (int16 (*)[2])realloc(vlc->table, sizeof(int16 *) * 2 * vlc->table_allocated);
+ if (!temp) {
+ free(vlc->table);
+ vlc->table = NULL;
return -1;
+ }
+ vlc->table = temp;
}
return index;
}
@@ -3112,7 +3117,6 @@ void QDM2Stream::qdm2_fft_tone_synthesizer(uint8 sub_packet) {
}
void QDM2Stream::qdm2_calculate_fft(int channel) {
- const float gain = (_channels == 1 && _channels == 2) ? 0.5f : 1.0f;
int i;
_fft.complex[channel][0].re *= 2.0f;
@@ -3122,7 +3126,7 @@ void QDM2Stream::qdm2_calculate_fft(int channel) {
// add samples to output buffer
for (i = 0; i < ((_fftFrameSize + 15) & ~15); i++)
- _outputBuffer[_channels * i + channel] += ((float *) _fft.complex[channel])[i] * gain;
+ _outputBuffer[_channels * i + channel] += ((float *) _fft.complex[channel])[i];
}
/**
diff --git a/graphics/video/coktel_decoder.cpp b/graphics/video/coktel_decoder.cpp
index 10be09eb23..15ba049536 100644
--- a/graphics/video/coktel_decoder.cpp
+++ b/graphics/video/coktel_decoder.cpp
@@ -684,7 +684,11 @@ Surface *PreIMDDecoder::decodeNextFrame() {
}
void PreIMDDecoder::processFrame() {
+ _curFrame++;
+
uint16 frameSize = _stream->readUint16LE();
+ if (_stream->eos() || (frameSize == 0))
+ return;
uint32 nextFramePos = _stream->pos() + frameSize + 2;
@@ -748,8 +752,6 @@ void PreIMDDecoder::processFrame() {
}
_stream->seek(nextFramePos);
-
- _curFrame++;
}
// Just a simple blit
@@ -2301,12 +2303,15 @@ byte *VMDDecoder::deDPCM(const byte *data, uint32 &size, int32 init[2]) {
uint32 outSize = size + channels;
int16 *out = (int16 *)malloc(outSize * 2);
- byte *sound = (byte *) out;
+ byte *sound = (byte *)out;
+
+ if (!out)
+ return 0;
int channel = 0;
for (int i = 0; i < channels; i++) {
- *out++ = TO_BE_16(init[channel]);
+ *out++ = TO_BE_16(init[channel]);
channel = (channel + 1) % channels;
}
@@ -2464,6 +2469,7 @@ Common::MemoryReadStream *VMDDecoder::getEmbeddedFile(const Common::String &file
free(data);
warning("VMDDecoder::getEmbeddedFile(): Couldn't read %d bytes (file \"%s\")",
file->realSize, fileName.c_str());
+ return 0;
}
Common::MemoryReadStream *stream =
diff --git a/graphics/video/flic_decoder.cpp b/graphics/video/flic_decoder.cpp
index 843d3ee093..f55a74f4f3 100644
--- a/graphics/video/flic_decoder.cpp
+++ b/graphics/video/flic_decoder.cpp
@@ -70,7 +70,7 @@ bool FlicDecoder::load(Common::SeekableReadStream *stream) {
}
_fileStream->readUint16LE(); // flags
- // Note: The normal delay is a 32-bit integer (dword), whereas the overriden delay is a 16-bit integer (word)
+ // Note: The normal delay is a 32-bit integer (dword), whereas the overridden delay is a 16-bit integer (word)
// the frame delay is the FLIC "speed", in milliseconds.
_frameRate = Common::Rational(1000, _fileStream->readUint32LE());
@@ -207,7 +207,7 @@ Surface *FlicDecoder::decodeNextFrame() {
// this properly.
chunkCount = _fileStream->readUint16LE();
- // Note: The overriden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
+ // Note: The overridden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
// the frame delay is the FLIC "speed", in milliseconds.
uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds
if (newFrameDelay > 0)
diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp
index 71858dd3aa..de1eb4436f 100644
--- a/graphics/video/smk_decoder.cpp
+++ b/graphics/video/smk_decoder.cpp
@@ -252,9 +252,12 @@ BigHuffmanTree::BigHuffmanTree(BitStream &bs, int allocSize)
_loBytes = new SmallHuffmanTree(_bs);
_hiBytes = new SmallHuffmanTree(_bs);
- _markers[0] = _bs.getBits8() | (_bs.getBits8() << 8);
- _markers[1] = _bs.getBits8() | (_bs.getBits8() << 8);
- _markers[2] = _bs.getBits8() | (_bs.getBits8() << 8);
+ _markers[0] = _bs.getBits8();
+ _markers[0] |= (_bs.getBits8() << 8);
+ _markers[1] = _bs.getBits8();
+ _markers[1] |= (_bs.getBits8() << 8);
+ _markers[2] = _bs.getBits8();
+ _markers[2] |= (_bs.getBits8() << 8);
_last[0] = _last[1] = _last[2] = 0xffffffff;
@@ -780,13 +783,23 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize,
int32 bases[2];
- if (isStereo)
- bases[1] = (!is16Bits) ? audioBS.getBits8() :
- ((int16) (((audioBS.getBits8() << 8) | audioBS.getBits8())));
-
- bases[0] = (!is16Bits) ? audioBS.getBits8() :
- ((int16) (((audioBS.getBits8() << 8) | audioBS.getBits8())));
+ if (isStereo) {
+ if (is16Bits) {
+ byte hi = audioBS.getBits8();
+ byte lo = audioBS.getBits8();
+ bases[1] = (int16) ((hi << 8) | lo);
+ } else {
+ bases[1] = audioBS.getBits8();
+ }
+ }
+ if (is16Bits) {
+ byte hi = audioBS.getBits8();
+ byte lo = audioBS.getBits8();
+ bases[0] = (int16) ((hi << 8) | lo);
+ } else {
+ bases[0] = audioBS.getBits8();
+ }
// The bases are the first samples, too
for (int i = 0; i < (isStereo ? 2 : 1); i++, curPointer += (is16Bits ? 2 : 1), curPos += (is16Bits ? 2 : 1)) {
@@ -811,8 +824,9 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize,
}
} else {
for (int k = 0; k < (isStereo ? 2 : 1); k++) {
- bases[k] += (int16) (audioTrees[k * 2]->getCode(audioBS) |
- (audioTrees[k * 2 + 1]->getCode(audioBS) << 8));
+ byte lo = audioTrees[k * 2]->getCode(audioBS);
+ byte hi = audioTrees[k * 2 + 1]->getCode(audioBS);
+ bases[k] += (int16) (lo | (hi << 8));
WRITE_BE_UINT16(curPointer, bases[k]);
curPointer += 2;
diff --git a/gui/Actions.cpp b/gui/Actions.cpp
index 809188dfef..f44479a5a8 100644
--- a/gui/Actions.cpp
+++ b/gui/Actions.cpp
@@ -25,12 +25,12 @@
#include "gui/Actions.h"
#include "gui/message.h"
-#include "scumm/scumm.h"
#include "common/config-manager.h"
#ifdef _WIN32_WCE
#include "backends/platform/wince/CEActionsPocket.h"
#include "backends/platform/wince/CEActionsSmartphone.h"
+ #include "backends/platform/wince/CEDevice.h"
#elif defined(__SYMBIAN32__)
#include "backends/platform/symbian/src/SymbianActions.h"
#endif
@@ -42,8 +42,7 @@ Actions* Actions::Instance() {
}
Actions::Actions() :
- _mapping_active(false), _initialized(false)
-{
+ _mapping_active(false), _initialized(false) {
}
@@ -95,7 +94,7 @@ bool Actions::mappingActive() {
bool Actions::performMapped(unsigned int keyCode, bool pushed) {
int i;
- for (i=0; i<size(); i++) {
+ for (i = 0; i < size(); ++i) {
if (_action_mapping[i] == keyCode && _action_enabled[i])
return perform((ActionType)i, pushed);
}
@@ -112,7 +111,7 @@ bool Actions::loadMapping() {
return false;
tempo = ConfMan.get("action_mapping", domain()).c_str();
if (tempo && strlen(tempo)) {
- for (i=0; i<size(); i++) {
+ for (i = 0; i < size(); ++i) {
char x[7];
int j;
memset(x, 0, sizeof(x));
@@ -121,8 +120,7 @@ bool Actions::loadMapping() {
_action_mapping[i] = j;
}
return true;
- }
- else
+ } else
return false;
}
@@ -131,7 +129,7 @@ bool Actions::saveMapping() {
int i;
tempo[0] = '\0';
ConfMan.setInt("action_mapping_version", version(), domain());
- for (i=0; i<size(); i++) {
+ for (i = 0; i < size(); ++i) {
char x[10];
sprintf(x, "%.4x ", _action_mapping[i]);
strcat(tempo, x);
@@ -149,7 +147,7 @@ unsigned int Actions::getMapping(ActionType action) {
void Actions::setMapping(ActionType action, unsigned int keyCode) {
int i;
- for (i=0; i<size(); i++) {
+ for (i = 0; i < size(); ++i) {
if (_action_mapping[i] == keyCode)
_action_mapping[i] = 0;
}
@@ -157,8 +155,7 @@ void Actions::setMapping(ActionType action, unsigned int keyCode) {
_action_mapping[action] = keyCode;
}
-Key& Actions::getKeyAction(ActionType action)
-{
+Key& Actions::getKeyAction(ActionType action) {
return _key_action[action];
}
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index 948ef21023..a2517bb8e0 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -32,12 +32,11 @@
#include "graphics/surface.h"
#include "graphics/font.h"
-#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8"
+#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.2"
namespace Graphics {
struct DrawStep;
class VectorRenderer;
- class Font;
}
namespace GUI {
@@ -53,7 +52,6 @@ class ThemeEval;
class ThemeItem;
class ThemeParser;
-
/**
* DrawData sets enumeration.
* Each DD set corresponds to the actual looks
diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp
index b9a0c583b0..0daf2528dd 100644
--- a/gui/ThemeParser.cpp
+++ b/gui/ThemeParser.cpp
@@ -195,7 +195,7 @@ bool ThemeParser::parserCallback_text_color(ParserNode *node) {
if (_palette.contains(node->values["color"]))
getPaletteColor(node->values["color"], red, green, blue);
- else if (!parseIntegerKey(node->values["color"].c_str(), 3, &red, &green, &blue))
+ else if (!parseIntegerKey(node->values["color"], 3, &red, &green, &blue))
return parserError("Error parsing color value for text color definition.");
if (!_theme->addTextColor(colorId, red, green, blue))
@@ -216,10 +216,10 @@ bool ThemeParser::parserCallback_cursor(ParserNode *node) {
int spotx, spoty, scale;
- if (!parseIntegerKey(node->values["hotspot"].c_str(), 2, &spotx, &spoty))
+ if (!parseIntegerKey(node->values["hotspot"], 2, &spotx, &spoty))
return parserError("Error parsing cursor Hot Spot coordinates.");
- if (!parseIntegerKey(node->values["scale"].c_str(), 1, &scale))
+ if (!parseIntegerKey(node->values["scale"], 1, &scale))
return parserError("Error parsing cursor scale.");
if (!_theme->createCursor(node->values["file"], spotx, spoty, scale))
@@ -286,7 +286,7 @@ bool ThemeParser::parserCallback_color(ParserNode *node) {
int red, green, blue;
- if (parseIntegerKey(node->values["rgb"].c_str(), 3, &red, &green, &blue) == false ||
+ if (parseIntegerKey(node->values["rgb"], 3, &red, &green, &blue) == false ||
red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255)
return parserError("Error parsing RGB values for palette color '%s'", name.c_str());\
@@ -387,7 +387,7 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst
*/
#define __PARSER_ASSIGN_INT(struct_name, key_name, force) \
if (stepNode->values.contains(key_name)) { \
- if (!parseIntegerKey(stepNode->values[key_name].c_str(), 1, &x)) \
+ if (!parseIntegerKey(stepNode->values[key_name], 1, &x)) \
return parserError("Error parsing key value for '%s'.", key_name); \
\
drawstep->struct_name = x; \
@@ -411,7 +411,7 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst
red = _palette[val].r; \
green = _palette[val].g; \
blue = _palette[val].b; \
- } else if (parseIntegerKey(val.c_str(), 3, &red, &green, &blue) == false || \
+ } else if (parseIntegerKey(val, 3, &red, &green, &blue) == false || \
red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) \
return parserError("Error parsing color struct '%s'", val.c_str());\
\
@@ -481,7 +481,7 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst
drawstep->autoWidth = false;
val = stepNode->values["width"];
- if (parseIntegerKey(val.c_str(), 1, &x))
+ if (parseIntegerKey(val, 1, &x))
drawstep->w = x;
else if (val == "height")
drawstep->w = -1;
@@ -490,7 +490,7 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst
if (stepNode->values.contains("xpos")) {
val = stepNode->values["xpos"];
- if (parseIntegerKey(val.c_str(), 1, &x))
+ if (parseIntegerKey(val, 1, &x))
drawstep->x = x;
else if (val == "center")
drawstep->xAlign = Graphics::DrawStep::kVectorAlignCenter;
@@ -509,7 +509,7 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst
drawstep->autoHeight = false;
val = stepNode->values["height"];
- if (parseIntegerKey(val.c_str(), 1, &x))
+ if (parseIntegerKey(val, 1, &x))
drawstep->h = x;
else if (val == "width")
drawstep->h = -1;
@@ -518,7 +518,7 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst
if (stepNode->values.contains("ypos")) {
val = stepNode->values["ypos"];
- if (parseIntegerKey(val.c_str(), 1, &x))
+ if (parseIntegerKey(val, 1, &x))
drawstep->y = x;
else if (val == "center")
drawstep->yAlign = Graphics::DrawStep::kVectorAlignCenter;
@@ -569,7 +569,7 @@ bool ThemeParser::parserCallback_def(ParserNode *node) {
if (_theme->getEvaluator()->hasVar(node->values["value"]) == true)
value = _theme->getEvaluator()->getVar(node->values["value"]);
- else if (!parseIntegerKey(node->values["value"].c_str(), 1, &value))
+ else if (!parseIntegerKey(node->values["value"], 1, &value))
return parserError("Invalid definition for '%s'.", var.c_str());
_theme->getEvaluator()->setVar(var, value);
@@ -608,7 +608,7 @@ bool ThemeParser::parserCallback_widget(ParserNode *node) {
if (_theme->getEvaluator()->hasVar(node->values["width"]) == true)
width = _theme->getEvaluator()->getVar(node->values["width"]);
- else if (!parseIntegerKey(node->values["width"].c_str(), 1, &width))
+ else if (!parseIntegerKey(node->values["width"], 1, &width))
return parserError("Corrupted width value in key for %s", var.c_str());
}
@@ -616,7 +616,7 @@ bool ThemeParser::parserCallback_widget(ParserNode *node) {
if (_theme->getEvaluator()->hasVar(node->values["height"]) == true)
height = _theme->getEvaluator()->getVar(node->values["height"]);
- else if (!parseIntegerKey(node->values["height"].c_str(), 1, &height))
+ else if (!parseIntegerKey(node->values["height"], 1, &height))
return parserError("Corrupted height value in key for %s", var.c_str());
}
@@ -651,7 +651,7 @@ bool ThemeParser::parserCallback_dialog(ParserNode *node) {
}
if (node->values.contains("inset")) {
- if (!parseIntegerKey(node->values["inset"].c_str(), 1, &inset))
+ if (!parseIntegerKey(node->values["inset"], 1, &inset))
return false;
}
@@ -682,7 +682,7 @@ bool ThemeParser::parserCallback_layout(ParserNode *node) {
int spacing = -1;
if (node->values.contains("spacing")) {
- if (!parseIntegerKey(node->values["spacing"].c_str(), 1, &spacing))
+ if (!parseIntegerKey(node->values["spacing"], 1, &spacing))
return false;
}
@@ -697,7 +697,7 @@ bool ThemeParser::parserCallback_layout(ParserNode *node) {
if (node->values.contains("padding")) {
int paddingL, paddingR, paddingT, paddingB;
- if (!parseIntegerKey(node->values["padding"].c_str(), 4, &paddingL, &paddingR, &paddingT, &paddingB))
+ if (!parseIntegerKey(node->values["padding"], 4, &paddingL, &paddingR, &paddingT, &paddingB))
return false;
_theme->getEvaluator()->addPadding(paddingL, paddingR, paddingT, paddingB);
@@ -713,7 +713,7 @@ bool ThemeParser::parserCallback_space(ParserNode *node) {
if (_theme->getEvaluator()->hasVar(node->values["size"]))
size = _theme->getEvaluator()->getVar(node->values["size"]);
- else if (!parseIntegerKey(node->values["size"].c_str(), 1, &size))
+ else if (!parseIntegerKey(node->values["size"], 1, &size))
return parserError("Invalid value for Spacing size.");
}
@@ -734,7 +734,7 @@ bool ThemeParser::parseCommonLayoutProps(ParserNode *node, const Common::String
if (node->values.contains("size")) {
int width, height;
- if (!parseIntegerKey(node->values["size"].c_str(), 2, &width, &height)) {
+ if (!parseIntegerKey(node->values["size"], 2, &width, &height)) {
Common::StringTokenizer tokenizer(node->values["size"], " ,");
Common::String wtoken, htoken;
char *parseEnd;
@@ -779,7 +779,7 @@ bool ThemeParser::parseCommonLayoutProps(ParserNode *node, const Common::String
if (node->values.contains("pos")) {
int x, y;
- if (!parseIntegerKey(node->values["pos"].c_str(), 2, &x, &y)) {
+ if (!parseIntegerKey(node->values["pos"], 2, &x, &y)) {
Common::StringTokenizer tokenizer(node->values["pos"], " ,");
Common::String xpos, ypos;
char *parseEnd;
@@ -835,7 +835,7 @@ bool ThemeParser::parseCommonLayoutProps(ParserNode *node, const Common::String
if (node->values.contains("padding")) {
int paddingL, paddingR, paddingT, paddingB;
- if (!parseIntegerKey(node->values["padding"].c_str(), 4, &paddingL, &paddingR, &paddingT, &paddingB))
+ if (!parseIntegerKey(node->values["padding"], 4, &paddingL, &paddingR, &paddingT, &paddingB))
return false;
_theme->getEvaluator()->setVar(var + "Padding.Left", paddingL);
diff --git a/gui/about.cpp b/gui/about.cpp
index 3caab084ca..86d28b4f61 100644
--- a/gui/about.cpp
+++ b/gui/about.cpp
@@ -93,7 +93,7 @@ AboutDialog::AboutDialog()
version += gScummVMVersion;
_lines.push_back(version);
- Common::String date = Common::String::printf(_("(built on %s)"), gScummVMBuildDate);
+ Common::String date = Common::String::format(_("(built on %s)"), gScummVMBuildDate);
_lines.push_back("C2" + date);
for (i = 0; i < ARRAYSIZE(copyright_text); i++)
diff --git a/gui/browser.h b/gui/browser.h
index 8dc7eda43a..1fef041a5a 100644
--- a/gui/browser.h
+++ b/gui/browser.h
@@ -29,10 +29,6 @@
#include "common/str.h"
#include "common/fs.h"
-#ifdef MACOSX
-#include <Carbon/Carbon.h>
-#endif
-
namespace GUI {
class ListWidget;
@@ -54,7 +50,7 @@ public:
protected:
#ifdef MACOSX
- CFStringRef _titleRef;
+ const void *_titleRef;
#else
ListWidget *_fileList;
StaticTextWidget *_currentPath;
diff --git a/gui/browser_osx.mm b/gui/browser_osx.mm
index a3a09b8ed2..ea77e16c04 100644
--- a/gui/browser_osx.mm
+++ b/gui/browser_osx.mm
@@ -22,6 +22,9 @@
* $Id$
*/
+// Disable symbol overrides so that we can use system headers
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "gui/browser.h"
#include "gui/GuiManager.h"
#include "gui/ListWidget.h"
diff --git a/gui/console.cpp b/gui/console.cpp
index a53e97888b..ca3726c857 100644
--- a/gui/console.cpp
+++ b/gui/console.cpp
@@ -487,7 +487,7 @@ void ConsoleDialog::defaultKeyDownHandler(Common::KeyState &state) {
for (int i = _promptEndPos - 1; i >= _currentPos; i--)
buffer(i + 1) = buffer(i);
_promptEndPos++;
- putchar((byte)state.ascii);
+ printChar((byte)state.ascii);
scrollToCurrent();
}
}
@@ -498,7 +498,7 @@ void ConsoleDialog::insertIntoPrompt(const char* str) {
buffer(i + l) = buffer(i);
for (unsigned int j = 0; j < l; ++j) {
_promptEndPos++;
- putcharIntern(str[j]);
+ printCharIntern(str[j]);
}
}
@@ -620,7 +620,7 @@ void ConsoleDialog::historyScroll(int direction) {
else
idx = _historyIndex;
for (int i = 0; i < kLineBufferSize && _history[idx][i] != '\0'; i++)
- putcharIntern(_history[idx][i]);
+ printCharIntern(_history[idx][i]);
_promptEndPos = _currentPos;
// Ensure once more the caret is visible (in case of very long history entries)
@@ -659,38 +659,33 @@ void ConsoleDialog::updateScrollBuffer() {
_scrollBar->recalc();
}
-int ConsoleDialog::printf(const char *format, ...) {
+int ConsoleDialog::printFormat(int dummy, const char *format, ...) {
va_list argptr;
va_start(argptr, format);
- int count = this->vprintf(format, argptr);
+ int count = this->vprintFormat(dummy, format, argptr);
va_end (argptr);
return count;
}
-int ConsoleDialog::vprintf(const char *format, va_list argptr) {
+int ConsoleDialog::vprintFormat(int dummy, const char *format, va_list argptr) {
char buf[2048];
-#if defined(WIN32)
- int count = _vsnprintf(buf, sizeof(buf), format, argptr);
-#elif defined(__SYMBIAN32__)
- int count = vsprintf(buf, format, argptr);
-#else
int count = vsnprintf(buf, sizeof(buf), format, argptr);
-#endif
+ buf[sizeof(buf)-1] = 0; // ensure termination
print(buf);
return count;
}
-void ConsoleDialog::putchar(int c) {
+void ConsoleDialog::printChar(int c) {
if (_caretVisible)
drawCaret(true);
- putcharIntern(c);
+ printCharIntern(c);
drawLine(pos2line(_currentPos));
}
-void ConsoleDialog::putcharIntern(int c) {
+void ConsoleDialog::printCharIntern(int c) {
if (c == '\n')
nextLine();
else {
@@ -708,7 +703,7 @@ void ConsoleDialog::print(const char *str) {
drawCaret(true);
while (*str)
- putcharIntern(*str++);
+ printCharIntern(*str++);
draw();
}
diff --git a/gui/console.h b/gui/console.h
index bf44bdbe17..52762b065f 100644
--- a/gui/console.h
+++ b/gui/console.h
@@ -143,10 +143,10 @@ public:
void handleKeyDown(Common::KeyState state);
void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
- int printf(const char *format, ...) GCC_PRINTF(2, 3);
- int vprintf(const char *format, va_list argptr);
-#undef putchar
- void putchar(int c);
+ int printFormat(int dummy, const char *format, ...) GCC_PRINTF(3, 4);
+ int vprintFormat(int dummy, const char *format, va_list argptr);
+
+ void printChar(int c);
void setInputCallback(InputCallbackProc proc, void *refCon) {
_callbackProc = proc;
@@ -172,7 +172,7 @@ protected:
void drawLine(int line, bool restoreBg = true);
void drawCaret(bool erase);
- void putcharIntern(int c);
+ void printCharIntern(int c);
void insertIntoPrompt(const char *str);
void print(const char *str);
void updateScrollBuffer();
diff --git a/gui/credits.h b/gui/credits.h
index b469645217..d54e280a37 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -81,6 +81,13 @@ static const char *credits[] = {
"C0""Jonathan Gray",
"C2""(retired)",
"",
+"C1""Broken Sword 2.5",
+"C0""Eugene Sandulenko",
+"C0""Filippos Karapetis",
+"C0""Max Horn",
+"C0""Paul Gilbert",
+"C0""Torbj\366rn Andersson",
+"",
"C1""Cinematique evo 1",
"C0""Vincent Hamm",
"C2""(retired)",
@@ -119,6 +126,11 @@ static const char *credits[] = {
"C0""Scott Thomas",
"C0""Jordi Vilalta Prat",
"",
+"C1""Hugo",
+"C0""Arnaud Boutonn\351",
+"C0""Oystein Eftevaag",
+"C0""Eugene Sandulenko",
+"",
"C1""Kyra",
"C0""Torbj\366rn Andersson",
"C2""VQA Player",
@@ -127,6 +139,11 @@ static const char *credits[] = {
"C0""Gregory Montoir",
"C0""Johannes Schickel",
"",
+"C1""Last Express",
+"C0""Matthew Hoops",
+"C0""Jordi Vilalta Prat",
+"C0""Julien Templier",
+"",
"C1""Lure",
"C0""Paul Gilbert",
"",
@@ -181,6 +198,9 @@ static const char *credits[] = {
"C0""Filippos Karapetis",
"C0""Joost Peters",
"",
+"C1""Toon",
+"C0""Sylvain Dupont",
+"",
"C1""Touch\351",
"C0""Gregory Montoir",
"",
@@ -195,7 +215,7 @@ static const char *credits[] = {
"C1""Dreamcast",
"C0""Marcus Comstedt",
"",
-"C1""GP2X",
+"C1""GPH Devices (GP2X, GP2XWiz & Caanoo)",
"C0""John Willis",
"",
"C1""iPhone",
@@ -213,6 +233,9 @@ static const char *credits[] = {
"C1""Nintendo DS",
"C0""Neil Millstone",
"",
+"C1""OpenPandora",
+"C0""John Willis",
+"",
"C1""PocketPC / WinCE",
"C0""Nicolas Bacca",
"C2""(retired)",
@@ -245,6 +268,7 @@ static const char *credits[] = {
"C0""Max Horn",
"C2""Backend & Engine APIs, file API, sound mixer, audiostreams, data structures, etc.",
"C0""Eugene Sandulenko",
+"C0""Johannes Schickel",
"",
"C1""GUI",
"C0""Vicent Marti",
@@ -278,7 +302,7 @@ static const char *credits[] = {
"C0""Thierry Crozat",
"C2""Numerous contributions to documentation",
"C0""Joachim Eberhard",
-"C2""Numerous contributions to documentation",
+"C2""Numerous contributions to documentation (retired)",
"C0""Matthew Hoops",
"C2""Wiki editor",
"",
@@ -580,5 +604,7 @@ static const char *credits[] = {
"C0""",
"C0""David P. Gray from Gray Design Associate for sharing the source code of the Hugo trilogy.",
"C0""",
+"C0""Broken Sword 2.5 team for providing sources of their engine and their great support.",
+"C0""",
"",
};
diff --git a/gui/debugger.cpp b/gui/debugger.cpp
index 9bd3b35915..8c10154334 100644
--- a/gui/debugger.cpp
+++ b/gui/debugger.cpp
@@ -23,6 +23,9 @@
*
*/
+// NB: This is really only necessary if USE_READLINE is defined
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/system.h"
@@ -78,7 +81,7 @@ int Debugger::DebugPrintf(const char *format, ...) {
va_start(argptr, format);
int count;
#ifndef USE_TEXT_CONSOLE
- count = _debuggerDialog->vprintf(format, argptr);
+ count = _debuggerDialog->vprintFormat(1, format, argptr);
#else
count = ::vprintf(format, argptr);
#endif
diff --git a/gui/debugger.h b/gui/debugger.h
index 6f06befdf1..4bac2e1f03 100644
--- a/gui/debugger.h
+++ b/gui/debugger.h
@@ -41,7 +41,7 @@ public:
Debugger();
virtual ~Debugger();
- int DebugPrintf(const char *format, ...);
+ int DebugPrintf(const char *format, ...) GCC_PRINTF(2, 3);
/**
* The onFrame() method should be invoked by the engine at regular
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 63d3ba6954..adbc418e87 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -341,7 +341,8 @@ void EditGameDialog::open() {
e = ConfMan.hasKey("gfx_mode", _domain) ||
ConfMan.hasKey("render_mode", _domain) ||
ConfMan.hasKey("fullscreen", _domain) ||
- ConfMan.hasKey("aspect_ratio", _domain);
+ ConfMan.hasKey("aspect_ratio", _domain) ||
+ ConfMan.hasKey("disable_dithering", _domain);
_globalGraphicsOverride->setState(e);
e = ConfMan.hasKey("music_driver", _domain) ||
@@ -922,7 +923,12 @@ void LauncherDialog::loadGame(int item) {
gameId = _domains[item];
const EnginePlugin *plugin = 0;
+
+#if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
+ EngineMan.findGameOnePluginAtATime(gameId, &plugin);
+#else
EngineMan.findGame(gameId, &plugin);
+#endif
String target = _domains[item];
target.toLowercase();
diff --git a/gui/options.cpp b/gui/options.cpp
index e7888cf095..2562ed64fa 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -98,6 +98,7 @@ void OptionsDialog::init() {
_renderModePopUp = 0;
_fullscreenCheckbox = 0;
_aspectCheckbox = 0;
+ _disableDitheringCheckbox = 0;
_enableAudioSettings = false;
_midiPopUp = 0;
_oplPopUp = 0;
@@ -192,6 +193,7 @@ void OptionsDialog::open() {
// Aspect ratio setting
_aspectCheckbox->setState(ConfMan.getBool("aspect_ratio", _domain));
#endif // SMALL_SCREEN_DEVICE
+ _disableDitheringCheckbox->setState(ConfMan.getBool("disable_dithering", _domain));
}
// Audio options
@@ -213,14 +215,8 @@ void OptionsDialog::open() {
}
if (_multiMidiCheckbox) {
- if (!loadMusicDeviceSetting(_gmDevicePopUp, "gm_device")) {
- if (_domain.equals(Common::ConfigManager::kApplicationDomain)) {
- if (!loadMusicDeviceSetting(_gmDevicePopUp, Common::String(), MT_GM))
- _gmDevicePopUp->setSelected(0);
- } else {
- _gmDevicePopUp->setSelected(0);
- }
- }
+ if (!loadMusicDeviceSetting(_gmDevicePopUp, "gm_device"))
+ _gmDevicePopUp->setSelected(0);
// Multi midi setting
_multiMidiCheckbox->setState(ConfMan.getBool("multi_midi", _domain));
@@ -244,14 +240,8 @@ void OptionsDialog::open() {
// MT-32 options
if (_mt32DevicePopUp) {
- if (!loadMusicDeviceSetting(_mt32DevicePopUp, "mt32_device")) {
- if (_domain.equals(Common::ConfigManager::kApplicationDomain)) {
- if (!loadMusicDeviceSetting(_mt32DevicePopUp, Common::String(), MT_MT32))
- _mt32DevicePopUp->setSelected(0);
- } else {
- _mt32DevicePopUp->setSelected(0);
- }
- }
+ if (!loadMusicDeviceSetting(_mt32DevicePopUp, "mt32_device"))
+ _mt32DevicePopUp->setSelected(0);
// Native mt32 setting
_mt32Checkbox->setState(ConfMan.getBool("native_mt32", _domain));
@@ -309,6 +299,7 @@ void OptionsDialog::close() {
if (_enableGraphicSettings) {
ConfMan.setBool("fullscreen", _fullscreenCheckbox->getState(), _domain);
ConfMan.setBool("aspect_ratio", _aspectCheckbox->getState(), _domain);
+ ConfMan.setBool("disable_dithering", _disableDitheringCheckbox->getState(), _domain);
bool isSet = false;
@@ -332,6 +323,7 @@ void OptionsDialog::close() {
} else {
ConfMan.removeKey("fullscreen", _domain);
ConfMan.removeKey("aspect_ratio", _domain);
+ ConfMan.removeKey("disable_dithering", _domain);
ConfMan.removeKey("gfx_mode", _domain);
ConfMan.removeKey("render_mode", _domain);
}
@@ -518,6 +510,7 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
_fullscreenCheckbox->setEnabled(enabled);
_aspectCheckbox->setEnabled(enabled);
#endif
+ _disableDitheringCheckbox->setEnabled(enabled);
}
void OptionsDialog::setAudioSettingsState(bool enabled) {
@@ -657,6 +650,7 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
// Aspect ratio checkbox
_aspectCheckbox = new CheckboxWidget(boss, prefix + "grAspectCheckbox", _("Aspect ratio correction"), _("Correct aspect ratio for 320x200 games"));
+ _disableDitheringCheckbox = new CheckboxWidget(boss, prefix + "grDisableDitheringCheckbox", _("Disable EGA dithering"), _("Disable dithering in EGA games"));
_enableGraphicSettings = true;
}
@@ -679,7 +673,7 @@ void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &pref
const uint32 deviceGuiOption = MidiDriver::musicType2GUIO(d->getMusicType());
if ((_domain == Common::ConfigManager::kApplicationDomain && d->getMusicType() != MT_TOWNS // global dialog - skip useless FM-Towns, C64, Amiga, AppleIIGS options there
- && d->getMusicType() != MT_C64 && d->getMusicType() != MT_AMIGA && d->getMusicType() != MT_APPLEIIGS)
+ && d->getMusicType() != MT_C64 && d->getMusicType() != MT_AMIGA && d->getMusicType() != MT_APPLEIIGS && d->getMusicType() != MT_PC98)
|| (_domain != Common::ConfigManager::kApplicationDomain && !(_guioptions & allFlags)) // No flags are specified
|| (_guioptions & deviceGuiOption) // flag is present
// HACK/FIXME: For now we have to show GM devices, even when the game only has GUIO_MIDIMT32 set,
@@ -719,13 +713,25 @@ void OptionsDialog::addMIDIControls(GuiObject *boss, const Common::String &prefi
// Populate
const MusicPlugin::List p = MusicMan.getPlugins();
+ // Make sure the null device is the first one in the list to avoid undesired
+ // auto detection for users who don't have a saved setting yet.
for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
MusicDevices i = (**m)->getDevices();
for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
- if (d->getMusicType() >= MT_GM || d->getMusicDriverId() == "auto") {
+ if (d->getMusicDriverId() == "null")
+ _gmDevicePopUp->appendEntry(_("Don't use General MIDI music"), d->getHandle());
+ }
+ }
+ // Now we add the other devices.
+ for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
+ MusicDevices i = (**m)->getDevices();
+ for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
+ if (d->getMusicType() >= MT_GM) {
if (d->getMusicType() != MT_MT32)
_gmDevicePopUp->appendEntry(d->getCompleteName(), d->getHandle());
- }
+ } else if (d->getMusicDriverId() == "auto") {
+ _gmDevicePopUp->appendEntry(_("Use first available device"), d->getHandle());
+ }
}
}
@@ -769,12 +775,23 @@ void OptionsDialog::addMT32Controls(GuiObject *boss, const Common::String &prefi
_enableGSCheckbox = new CheckboxWidget(boss, prefix + "mcGSCheckbox", _("Enable Roland GS Mode"), _("Turns off General MIDI mapping for games with Roland MT-32 soundtrack"));
const MusicPlugin::List p = MusicMan.getPlugins();
+ // Make sure the null device is the first one in the list to avoid undesired
+ // auto detection for users who don't have a saved setting yet.
+ for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
+ MusicDevices i = (**m)->getDevices();
+ for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
+ if (d->getMusicDriverId() == "null")
+ _mt32DevicePopUp->appendEntry(_("Don't use Roland MT-32 music"), d->getHandle());
+ }
+ }
+ // Now we add the other devices.
for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
MusicDevices i = (**m)->getDevices();
for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
- if (d->getMusicType() >= MT_GM || d->getMusicDriverId() == "auto") {
+ if (d->getMusicType() >= MT_GM)
_mt32DevicePopUp->appendEntry(d->getCompleteName(), d->getHandle());
- }
+ else if (d->getMusicDriverId() == "auto")
+ _mt32DevicePopUp->appendEntry(_("Use first available device"), d->getHandle());
}
}
diff --git a/gui/options.h b/gui/options.h
index c05f263d00..0d9ea117b3 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -96,6 +96,7 @@ private:
PopUpWidget *_gfxPopUp;
CheckboxWidget *_fullscreenCheckbox;
CheckboxWidget *_aspectCheckbox;
+ CheckboxWidget *_disableDitheringCheckbox;
StaticTextWidget *_renderModePopUpDesc;
PopUpWidget *_renderModePopUp;
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 46ac4a1365..363ab0bbe2 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -177,6 +177,9 @@
"<widget name='grFullscreenCheckbox' "
"type='Checkbox' "
"/> "
+"<widget name='grDisableDitheringCheckbox' "
+"type='Checkbox' "
+"/> "
"</layout> "
"</dialog> "
"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> "
@@ -969,6 +972,9 @@
"<widget name='grFullscreenCheckbox' "
"type='Checkbox' "
"/> "
+"<widget name='grDisableDitheringCheckbox' "
+"type='Checkbox' "
+"/> "
"</layout> "
"</dialog> "
"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> "
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 2507572e40..756b77d4b9 100644
--- a/gui/themes/scummclassic.zip
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC
index c913ff6078..f0276969fe 100644
--- a/gui/themes/scummclassic/THEMERC
+++ b/gui/themes/scummclassic/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8:ScummVM Classic Theme:No Author]
+[SCUMMVM_STX0.8.2:ScummVM Classic Theme:No Author]
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 74b8bf4b2c..7804a8c821 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -218,6 +218,9 @@
<widget name = 'grFullscreenCheckbox'
type = 'Checkbox'
/>
+ <widget name = 'grDisableDitheringCheckbox'
+ type = 'Checkbox'
+ />
</layout>
</dialog>
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 65083f4bce..419c388fc8 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -216,6 +216,9 @@
<widget name = 'grFullscreenCheckbox'
type = 'Checkbox'
/>
+ <widget name = 'grDisableDitheringCheckbox'
+ type = 'Checkbox'
+ />
</layout>
</dialog>
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index 1023e82ff9..0a97511052 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/THEMERC b/gui/themes/scummmodern/THEMERC
index 34495f71fa..b8f41fc207 100644
--- a/gui/themes/scummmodern/THEMERC
+++ b/gui/themes/scummmodern/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8:ScummVM Modern Theme:No Author]
+[SCUMMVM_STX0.8.2:ScummVM Modern Theme:No Author]
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index 51f1ce6c6f..c00d0c961c 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -233,6 +233,9 @@
<widget name = 'grFullscreenCheckbox'
type = 'Checkbox'
/>
+ <widget name = 'grDisableDitheringCheckbox'
+ type = 'Checkbox'
+ />
</layout>
</dialog>
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index bd7b5fd8ea..e464c99011 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -214,6 +214,9 @@
<widget name = 'grFullscreenCheckbox'
type = 'Checkbox'
/>
+ <widget name = 'grDisableDitheringCheckbox'
+ type = 'Checkbox'
+ />
</layout>
</dialog>
diff --git a/icons/scummvm.info b/icons/scummvm.info
index 97fbfa73bc..e30a7129ef 100644
--- a/icons/scummvm.info
+++ b/icons/scummvm.info
Binary files differ
diff --git a/ports.mk b/ports.mk
index 69ffd71edf..f9012eb0bd 100644
--- a/ports.mk
+++ b/ports.mk
@@ -98,6 +98,10 @@ ifdef USE_MPEG2
OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libmpeg2.a
endif
+ifdef USE_PNG
+OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libpng.a
+endif
+
ifdef USE_ZLIB
OSX_ZLIB ?= -lz
endif
@@ -187,12 +191,7 @@ aos4dist: $(EXECUTABLE)
ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(AOS4PATH)/extras/
endif
- cp $(srcdir)/AUTHORS $(AOS4PATH)/AUTHORS.txt
- cp $(srcdir)/COPYING $(AOS4PATH)/COPYING.txt
- cp $(srcdir)/COPYING.LGPL $(AOS4PATH)/COPYING.LGPL.txt
- cp $(srcdir)/COPYRIGHT $(AOS4PATH)/COPYRIGHT.txt
- cp $(srcdir)/NEWS $(AOS4PATH)/NEWS.txt
- cp $(srcdir)/README $(AOS4PATH)/README.txt
+ cp $(DIST_FILES_DOCS) $(AOS4PATH)
# Mark special targets as phony
.PHONY: deb bundle osxsnap win32dist install uninstall
diff --git a/sound/audiostream.h b/sound/audiostream.h
index 64ad128931..b2c012841d 100644
--- a/sound/audiostream.h
+++ b/sound/audiostream.h
@@ -276,11 +276,6 @@ private:
* The same caveats apply to SubSeekableAudioStream as do to SeekableAudioStream.
*
* Manipulating the parent stream directly /will/ mess up a substream.
- *
- * IMPORTANT:
- * Note for engine authors. This object is currently under inspection. In case
- * we need to revise the looping API we might drop this. So if you really need
- * something like this object, please drop a mail to LordHoto.
*/
class SubSeekableAudioStream : public SeekableAudioStream {
public:
diff --git a/sound/decoders/adpcm.cpp b/sound/decoders/adpcm.cpp
index c8a907d13e..8a27658e4b 100644
--- a/sound/decoders/adpcm.cpp
+++ b/sound/decoders/adpcm.cpp
@@ -290,8 +290,8 @@ int Apple_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
class MSIma_ADPCMStream : public Ima_ADPCMStream {
public:
- MSIma_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
+ MSIma_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign, bool invertSamples = false)
+ : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign), _invertSamples(invertSamples) {
if (blockAlign == 0)
error("ADPCMStream(): blockAlign isn't specified for MS IMA ADPCM");
}
@@ -305,6 +305,9 @@ public:
int readBufferMSIMA1(int16 *buffer, const int numSamples);
int readBufferMSIMA2(int16 *buffer, const int numSamples);
+
+private:
+ bool _invertSamples; // Some implementations invert the way samples are decoded
};
int MSIma_ADPCMStream::readBufferMSIMA1(int16 *buffer, const int numSamples) {
@@ -324,8 +327,8 @@ int MSIma_ADPCMStream::readBufferMSIMA1(int16 *buffer, const int numSamples) {
for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
data = _stream->readByte();
_blockPos[0]++;
- buffer[samples] = decodeIMA(data & 0x0f);
- buffer[samples + 1] = decodeIMA((data >> 4) & 0x0f);
+ buffer[samples] = decodeIMA(_invertSamples ? (data >> 4) & 0x0f : data & 0x0f);
+ buffer[samples + 1] = decodeIMA(_invertSamples ? data & 0x0f : (data >> 4) & 0x0f);
}
}
return samples;
@@ -733,6 +736,8 @@ RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, Dispo
return new Oki_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
case kADPCMMSIma:
return new MSIma_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
+ case kADPCMMSImaLastExpress:
+ return new MSIma_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign, true);
case kADPCMMS:
return new MS_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
case kADPCMTinsel4:
diff --git a/sound/decoders/adpcm.h b/sound/decoders/adpcm.h
index 04dbb1a521..edcdc01ce9 100644
--- a/sound/decoders/adpcm.h
+++ b/sound/decoders/adpcm.h
@@ -50,14 +50,15 @@ class RewindableAudioStream;
// Usually, if the audio stream we're trying to play has the FourCC header
// string intact, it's easy to discern which encoding is used
enum typesADPCM {
- kADPCMOki, // Dialogic/Oki ADPCM (aka VOX)
- kADPCMMSIma, // Microsoft IMA ADPCM
- kADPCMMS, // Microsoft ADPCM
- kADPCMTinsel4, // 4-bit ADPCM used by the Tinsel engine
- kADPCMTinsel6, // 6-bit ADPCM used by the Tinsel engine
- kADPCMTinsel8, // 8-bit ADPCM used by the Tinsel engine
- kADPCMIma, // Standard IMA ADPCM
- kADPCMApple // Apple QuickTime IMA ADPCM
+ kADPCMOki, // Dialogic/Oki ADPCM (aka VOX)
+ kADPCMMSIma, // Microsoft IMA ADPCM
+ kADPCMMSImaLastExpress, // Microsoft IMA ADPCM (with inverted samples)
+ kADPCMMS, // Microsoft ADPCM
+ kADPCMTinsel4, // 4-bit ADPCM used by the Tinsel engine
+ kADPCMTinsel6, // 6-bit ADPCM used by the Tinsel engine
+ kADPCMTinsel8, // 8-bit ADPCM used by the Tinsel engine
+ kADPCMIma, // Standard IMA ADPCM
+ kADPCMApple // Apple QuickTime IMA ADPCM
};
/**
diff --git a/sound/decoders/flac.cpp b/sound/decoders/flac.cpp
index 560b83e1ee..080141f224 100644
--- a/sound/decoders/flac.cpp
+++ b/sound/decoders/flac.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides for FILE as that is used in FLAC headers
+#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
+
#include "sound/decoders/flac.h"
#ifdef USE_FLAC
@@ -302,7 +305,7 @@ int FLACStream::readBuffer(int16 *buffer, const int numSamples) {
const uint numChannels = getChannels();
if (numChannels == 0) {
- warning("FLACStream: Stream not sucessfully initialised, cant playback");
+ warning("FLACStream: Stream not successfully initialised, cant playback");
return -1; // streaminfo wasnt read!
}
diff --git a/sound/decoders/vorbis.cpp b/sound/decoders/vorbis.cpp
index 5aeb40c139..425eb6b751 100644
--- a/sound/decoders/vorbis.cpp
+++ b/sound/decoders/vorbis.cpp
@@ -23,6 +23,11 @@
*
*/
+// Disable symbol overrides for FILE and fseek as those are used in the
+// Vorbis headers.
+#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
+#define FORBIDDEN_SYMBOL_EXCEPTION_fseek
+
#include "sound/decoders/vorbis.h"
#ifdef USE_VORBIS
diff --git a/sound/decoders/wave.cpp b/sound/decoders/wave.cpp
index eeab026ae5..fcaace5301 100644
--- a/sound/decoders/wave.cpp
+++ b/sound/decoders/wave.cpp
@@ -90,15 +90,15 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate,
if (blockAlign_ != 0)
*blockAlign_ = blockAlign;
#if 0
- printf("WAVE information:\n");
- printf(" total size: %d\n", wavLength);
- printf(" fmt size: %d\n", fmtLength);
- printf(" type: %d\n", type);
- printf(" numChannels: %d\n", numChannels);
- printf(" samplesPerSec: %d\n", samplesPerSec);
- printf(" avgBytesPerSec: %d\n", avgBytesPerSec);
- printf(" blockAlign: %d\n", blockAlign);
- printf(" bitsPerSample: %d\n", bitsPerSample);
+ debug("WAVE information:");
+ debug(" total size: %d", wavLength);
+ debug(" fmt size: %d", fmtLength);
+ debug(" type: %d", type);
+ debug(" numChannels: %d", numChannels);
+ debug(" samplesPerSec: %d", samplesPerSec);
+ debug(" avgBytesPerSec: %d", avgBytesPerSec);
+ debug(" blockAlign: %d", blockAlign);
+ debug(" bitsPerSample: %d", bitsPerSample);
#endif
if (type != 1 && type != 2 && type != 17) {
@@ -152,7 +152,7 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate,
offset = stream.readUint32LE();
#if 0
- printf(" found a '%s' tag of size %d\n", buf, offset);
+ debug(" found a '%s' tag of size %d", buf, offset);
#endif
} while (memcmp(buf, "data", 4) != 0);
diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp
index aa9f8797ba..20d5a4e233 100644
--- a/sound/mididrv.cpp
+++ b/sound/mididrv.cpp
@@ -209,35 +209,40 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
hdl = getDeviceHandle("auto");
const MusicType type = getMusicType(hdl);
- if (type != MT_AUTO && type != MT_INVALID) {
- if (flags & MDT_PREFER_MT32)
- // If we have a preferred MT32 device we disable the gm/mt32 mapping (more about this in mididrv.h)
- _forceTypeMT32 = true;
- return hdl;
- }
+ // If have a "Don't use GM/MT-32" setting we skip this part and jump
+ // to AdLib, PC Speaker etc. detection right away.
+ if (type != MT_NULL) {
+ if (type != MT_AUTO && type != MT_INVALID) {
+ if (flags & MDT_PREFER_MT32)
+ // If we have a preferred MT32 device we disable the gm/mt32 mapping (more about this in mididrv.h)
+ _forceTypeMT32 = true;
+
+ return hdl;
+ }
- // If we have no specific device selected (neither in the scummvm nor in the game domain)
- // and no preferred MT32 or GM device selected we arrive here.
- // If MT32 is preferred we try for the first available device with music type 'MT_MT32' (usually the mt32 emulator)
- if (flags & MDT_PREFER_MT32) {
+ // If we have no specific device selected (neither in the scummvm nor in the game domain)
+ // and no preferred MT32 or GM device selected we arrive here.
+ // If MT32 is preferred we try for the first available device with music type 'MT_MT32' (usually the mt32 emulator)
+ if (flags & MDT_PREFER_MT32) {
+ for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
+ MusicDevices i = (**m)->getDevices();
+ for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
+ if (d->getMusicType() == MT_MT32)
+ return d->getHandle();
+ }
+ }
+ }
+
+ // Now we default to the first available device with music type 'MT_GM'
for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
MusicDevices i = (**m)->getDevices();
for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
- if (d->getMusicType() == MT_MT32)
+ if (d->getMusicType() == MT_GM || d->getMusicType() == MT_GS)
return d->getHandle();
}
}
}
-
- // Now we default to the first available device with music type 'MT_GM'
- for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
- MusicDevices i = (**m)->getDevices();
- for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
- if (d->getMusicType() == MT_GM || d->getMusicType() == MT_GS)
- return d->getHandle();
- }
- }
}
MusicType tp = MT_AUTO;
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
index cb3cc2a0f3..c40aa95d73 100644
--- a/sound/mixer.cpp
+++ b/sound/mixer.cpp
@@ -435,6 +435,7 @@ int MixerImpl::getVolumeForSoundType(SoundType type) const {
return _volumeForSoundType[type];
}
+
#pragma mark -
#pragma mark --- Channel implementations ---
#pragma mark -
diff --git a/sound/mods/tfmx.cpp b/sound/mods/tfmx.cpp
index b65a998e82..6ed1abcfb5 100644
--- a/sound/mods/tfmx.cpp
+++ b/sound/mods/tfmx.cpp
@@ -281,7 +281,7 @@ void Tfmx::macroRun(ChannelContext &channel) {
continue;
case 0x04: // Wait. Parameters: Ticks to wait(W).
- // TODO: some unkown Parameter? (macroPtr[1] & 1)
+ // TODO: some unknown Parameter? (macroPtr[1] & 1)
channel.macroWait = READ_BE_UINT16(&macroPtr[2]);
break;
@@ -1154,7 +1154,7 @@ void displayMacroStep(const void * const vptr) {
if (macroData[0] < ARRAYSIZE(tableMacros))
debug("%s %02X%02X%02X", tableMacros[macroData[0]], macroData[1], macroData[2], macroData[3]);
else
- debug("Unkown Macro #%02X %02X%02X%02X", macroData[0], macroData[1], macroData[2], macroData[3]);
+ debug("Unknown Macro #%02X %02X%02X%02X", macroData[0], macroData[1], macroData[2], macroData[3]);
}
void displayPatternstep(const void * const vptr) {
diff --git a/sound/rate_arm.cpp b/sound/rate_arm.cpp
index 5bab6ca59d..63008fcb87 100644
--- a/sound/rate_arm.cpp
+++ b/sound/rate_arm.cpp
@@ -168,18 +168,16 @@ extern "C" int SimpleRate_readFudge(Audio::AudioStream &input,
int16 *a, int b)
{
#ifdef DEBUG_RATECONV
- fprintf(stderr, "Reading ptr=%x n%d\n", a, b);
- fflush(stderr);
+ debug("Reading ptr=%x n%d", a, b);
#endif
- return input.readBuffer(a, b);
+ return input.readBuffer(a, b);
}
template<bool stereo, bool reverseStereo>
int SimpleRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
#ifdef DEBUG_RATECONV
-fprintf(stderr, "Simple st=%d rev=%d\n", stereo, reverseStereo);
-fflush(stderr);
+ debug("Simple st=%d rev=%d", stereo, reverseStereo);
#endif
st_sample_t *ostart = obuf;
@@ -318,8 +316,7 @@ template<bool stereo, bool reverseStereo>
int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
#ifdef DEBUG_RATECONV
-fprintf(stderr, "Linear st=%d rev=%d\n", stereo, reverseStereo);
-fflush(stderr);
+ debug("Linear st=%d rev=%d", stereo, reverseStereo);
#endif
st_sample_t *ostart = obuf;
@@ -393,8 +390,7 @@ public:
assert(input.isStereo() == stereo);
#ifdef DEBUG_RATECONV
-fprintf(stderr, "Copy st=%d rev=%d\n", stereo, reverseStereo);
-fflush(stderr);
+ debug("Copy st=%d rev=%d", stereo, reverseStereo);
#endif
st_size_t len;
st_sample_t *ostart = obuf;
diff --git a/sound/softsynth/cms.cpp b/sound/softsynth/cms.cpp
index 88f04a1ab9..b307146f14 100644
--- a/sound/softsynth/cms.cpp
+++ b/sound/softsynth/cms.cpp
@@ -86,35 +86,39 @@ static const int amplitude_lookup[16] = {
void CMSEmulator::portWrite(int port, int val) {
switch (port) {
- case 0x220:
- portWriteIntern(0, 1, val);
- break;
-
- case 0x221:
- _saa1099[0].selected_reg = val & 0x1f;
- if (_saa1099[0].selected_reg == 0x18 || _saa1099[0].selected_reg == 0x19) {
- /* clock the envelope channels */
- if (_saa1099[0].env_clock[0]) envelope(0, 0);
- if (_saa1099[0].env_clock[1]) envelope(0, 1);
- }
- break;
-
- case 0x222:
- portWriteIntern(1, 1, val);
- break;
-
- case 0x223:
- _saa1099[1].selected_reg = val & 0x1f;
- if (_saa1099[1].selected_reg == 0x18 || _saa1099[1].selected_reg == 0x19) {
- /* clock the envelope channels */
- if (_saa1099[1].env_clock[0]) envelope(1, 0);
- if (_saa1099[1].env_clock[1]) envelope(1, 1);
- }
- break;
+ case 0x220:
+ portWriteIntern(0, 1, val);
+ break;
+
+ case 0x221:
+ _saa1099[0].selected_reg = val & 0x1f;
+ if (_saa1099[0].selected_reg == 0x18 || _saa1099[0].selected_reg == 0x19) {
+ /* clock the envelope channels */
+ if (_saa1099[0].env_clock[0])
+ envelope(0, 0);
+ if (_saa1099[0].env_clock[1])
+ envelope(0, 1);
+ }
+ break;
+
+ case 0x222:
+ portWriteIntern(1, 1, val);
+ break;
+
+ case 0x223:
+ _saa1099[1].selected_reg = val & 0x1f;
+ if (_saa1099[1].selected_reg == 0x18 || _saa1099[1].selected_reg == 0x19) {
+ /* clock the envelope channels */
+ if (_saa1099[1].env_clock[0])
+ envelope(1, 0);
+ if (_saa1099[1].env_clock[1])
+ envelope(1, 1);
+ }
+ break;
- default:
- warning("CMSEmulator got port: 0x%X", port);
- break;
+ default:
+ warning("CMSEmulator got port: 0x%X", port);
+ break;
}
}
@@ -177,10 +181,10 @@ void CMSEmulator::update(int chip, int16 *buffer, int length) {
for (ch = 0; ch < 2; ch++) {
switch (saa->noise_params[ch]) {
- case 0: saa->noise[ch].freq = 31250.0 * 2; break;
- case 1: saa->noise[ch].freq = 15625.0 * 2; break;
- case 2: saa->noise[ch].freq = 7812.5 * 2; break;
- case 3: saa->noise[ch].freq = saa->channels[ch * 3].freq; break;
+ case 0: saa->noise[ch].freq = 31250.0 * 2; break;
+ case 1: saa->noise[ch].freq = 15625.0 * 2; break;
+ case 2: saa->noise[ch].freq = 7812.5 * 2; break;
+ case 3: saa->noise[ch].freq = saa->channels[ch * 3].freq; break;
}
}
@@ -254,95 +258,95 @@ void CMSEmulator::portWriteIntern(int chip, int offset, int data) {
int ch;
switch (reg) {
- /* channel i amplitude */
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- ch = reg & 7;
- saa->channels[ch].amplitude[LEFT] = amplitude_lookup[data & 0x0f];
- saa->channels[ch].amplitude[RIGHT] = amplitude_lookup[(data >> 4) & 0x0f];
- break;
-
- /* channel i frequency */
- case 0x08:
- case 0x09:
- case 0x0a:
- case 0x0b:
- case 0x0c:
- case 0x0d:
- ch = reg & 7;
- saa->channels[ch].frequency = data & 0xff;
- break;
-
- /* channel i octave */
- case 0x10:
- case 0x11:
- case 0x12:
- ch = (reg - 0x10) << 1;
- saa->channels[ch + 0].octave = data & 0x07;
- saa->channels[ch + 1].octave = (data >> 4) & 0x07;
- break;
-
- /* channel i frequency enable */
- case 0x14:
- saa->channels[0].freq_enable = data & 0x01;
- saa->channels[1].freq_enable = data & 0x02;
- saa->channels[2].freq_enable = data & 0x04;
- saa->channels[3].freq_enable = data & 0x08;
- saa->channels[4].freq_enable = data & 0x10;
- saa->channels[5].freq_enable = data & 0x20;
- break;
-
- /* channel i noise enable */
- case 0x15:
- saa->channels[0].noise_enable = data & 0x01;
- saa->channels[1].noise_enable = data & 0x02;
- saa->channels[2].noise_enable = data & 0x04;
- saa->channels[3].noise_enable = data & 0x08;
- saa->channels[4].noise_enable = data & 0x10;
- saa->channels[5].noise_enable = data & 0x20;
- break;
-
- /* noise generators parameters */
- case 0x16:
- saa->noise_params[0] = data & 0x03;
- saa->noise_params[1] = (data >> 4) & 0x03;
- break;
-
- /* envelope generators parameters */
- case 0x18:
- case 0x19:
- ch = reg - 0x18;
- saa->env_reverse_right[ch] = data & 0x01;
- saa->env_mode[ch] = (data >> 1) & 0x07;
- saa->env_bits[ch] = data & 0x10;
- saa->env_clock[ch] = data & 0x20;
- saa->env_enable[ch] = data & 0x80;
- /* reset the envelope */
- saa->env_step[ch] = 0;
- break;
-
- /* channels enable & reset generators */
- case 0x1c:
- saa->all_ch_enable = data & 0x01;
- saa->sync_state = data & 0x02;
- if (data & 0x02) {
- int i;
- /* Synch & Reset generators */
- for (i = 0; i < 6; i++) {
- saa->channels[i].level = 0;
- saa->channels[i].counter = 0.0;
- }
+ /* channel i amplitude */
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ ch = reg & 7;
+ saa->channels[ch].amplitude[LEFT] = amplitude_lookup[data & 0x0f];
+ saa->channels[ch].amplitude[RIGHT] = amplitude_lookup[(data >> 4) & 0x0f];
+ break;
+
+ /* channel i frequency */
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ ch = reg & 7;
+ saa->channels[ch].frequency = data & 0xff;
+ break;
+
+ /* channel i octave */
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ ch = (reg - 0x10) << 1;
+ saa->channels[ch + 0].octave = data & 0x07;
+ saa->channels[ch + 1].octave = (data >> 4) & 0x07;
+ break;
+
+ /* channel i frequency enable */
+ case 0x14:
+ saa->channels[0].freq_enable = data & 0x01;
+ saa->channels[1].freq_enable = data & 0x02;
+ saa->channels[2].freq_enable = data & 0x04;
+ saa->channels[3].freq_enable = data & 0x08;
+ saa->channels[4].freq_enable = data & 0x10;
+ saa->channels[5].freq_enable = data & 0x20;
+ break;
+
+ /* channel i noise enable */
+ case 0x15:
+ saa->channels[0].noise_enable = data & 0x01;
+ saa->channels[1].noise_enable = data & 0x02;
+ saa->channels[2].noise_enable = data & 0x04;
+ saa->channels[3].noise_enable = data & 0x08;
+ saa->channels[4].noise_enable = data & 0x10;
+ saa->channels[5].noise_enable = data & 0x20;
+ break;
+
+ /* noise generators parameters */
+ case 0x16:
+ saa->noise_params[0] = data & 0x03;
+ saa->noise_params[1] = (data >> 4) & 0x03;
+ break;
+
+ /* envelope generators parameters */
+ case 0x18:
+ case 0x19:
+ ch = reg - 0x18;
+ saa->env_reverse_right[ch] = data & 0x01;
+ saa->env_mode[ch] = (data >> 1) & 0x07;
+ saa->env_bits[ch] = data & 0x10;
+ saa->env_clock[ch] = data & 0x20;
+ saa->env_enable[ch] = data & 0x80;
+ /* reset the envelope */
+ saa->env_step[ch] = 0;
+ break;
+
+ /* channels enable & reset generators */
+ case 0x1c:
+ saa->all_ch_enable = data & 0x01;
+ saa->sync_state = data & 0x02;
+ if (data & 0x02) {
+ int i;
+ /* Synch & Reset generators */
+ for (i = 0; i < 6; i++) {
+ saa->channels[i].level = 0;
+ saa->channels[i].counter = 0.0;
}
- break;
+ }
+ break;
- default:
- // The CMS allows all registers to be written, so we just output some debug
- // message here
- debug(5, "CMS Unkown write to reg %x with %x",reg, data);
+ default:
+ // The CMS allows all registers to be written, so we just output some debug
+ // message here
+ debug(5, "CMS Unknown write to reg %x with %x",reg, data);
}
}
diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp
index e6da237881..a9e67c5266 100644
--- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -225,7 +225,6 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac
}
TownsAudioInterface::~TownsAudioInterface() {
- reset();
_ready = false;
deinit();
diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp
index 7b52b4594f..e6f94b29b5 100644
--- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -36,17 +36,15 @@ TownsEuphonyDriver::TownsEuphonyDriver(Audio::Mixer *mixer) : _activeChannels(0)
}
TownsEuphonyDriver::~TownsEuphonyDriver() {
+ delete _intf;
delete[] _activeChannels;
delete[] _sustainChannels;
delete[] _assignedChannels;
-
delete[] _tEnable;
delete[] _tMode;
delete[] _tOrdr;
delete[] _tLevel;
delete[] _tTranspose;
-
- delete _intf;
}
bool TownsEuphonyDriver::init() {
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
index 8047616dbf..303f08e6b1 100644
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
+++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
@@ -1053,7 +1053,6 @@ TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type)
}
TownsPC98_AudioDriver::~TownsPC98_AudioDriver() {
- reset();
_ready = false;
deinit();
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index e779812c42..62f7d39771 100644
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -1180,7 +1180,6 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
void TownsPC98_FmSynth::deinit() {
_ready = false;
_mixer->stopHandle(_soundHandle);
- Common::StackLock lock(_mutex);
_timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
}
diff --git a/sound/softsynth/mt32/mt32_file.cpp b/sound/softsynth/mt32/mt32_file.cpp
index f4eba73d33..ce5c2874c4 100644
--- a/sound/softsynth/mt32/mt32_file.cpp
+++ b/sound/softsynth/mt32/mt32_file.cpp
@@ -19,6 +19,12 @@
* IN THE SOFTWARE.
*/
+
+// FIXME: Disable symbol overrides so that we can use system headers.
+// But we *really* should get rid of this usage of FILE, fopen etc.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+
#include <stdio.h>
#include "mt32emu.h"
@@ -37,15 +43,15 @@ namespace MT32Emu {
}
void ANSIFile::close() {
- fclose(fp);
+ fclose((FILE *)fp);
}
size_t ANSIFile::read(void *in, size_t size) {
- return fread(in, 1, size, fp);
+ return fread(in, 1, size, (FILE *)fp);
}
bool ANSIFile::readBit8u(Bit8u *in) {
- int c = fgetc(fp);
+ int c = fgetc((FILE *)fp);
if (c == EOF)
return false;
*in = (Bit8u)c;
@@ -69,11 +75,11 @@ namespace MT32Emu {
}
size_t ANSIFile::write(const void *out, size_t size) {
- return fwrite(out, 1, size, fp);
+ return fwrite(out, 1, size, (FILE *)fp);
}
bool ANSIFile::writeBit8u(Bit8u out) {
- return fputc(out, fp) != EOF;
+ return fputc(out, (FILE *)fp) != EOF;
}
bool File::writeBit16u(Bit16u out) {
@@ -103,6 +109,6 @@ namespace MT32Emu {
}
bool ANSIFile::isEOF() {
- return feof(fp) != 0;
+ return feof((FILE *)fp) != 0;
}
}
diff --git a/sound/softsynth/mt32/mt32_file.h b/sound/softsynth/mt32/mt32_file.h
index 27c8ccbe46..b311ad9626 100644
--- a/sound/softsynth/mt32/mt32_file.h
+++ b/sound/softsynth/mt32/mt32_file.h
@@ -49,7 +49,7 @@ public:
class ANSIFile: public File {
private:
- FILE *fp;
+ void *fp;
public:
bool open(const char *filename, OpenMode mode);
void close();
diff --git a/sound/softsynth/mt32/tables.cpp b/sound/softsynth/mt32/tables.cpp
index b0414154dc..722a5e3c41 100644
--- a/sound/softsynth/mt32/tables.cpp
+++ b/sound/softsynth/mt32/tables.cpp
@@ -587,7 +587,7 @@ File *Tables::initNote(Synth *synth, NoteLookup *noteLookup, float note, float r
initSaw(noteLookup, noteLookup->div2);
//synth->printDebug("Note %f; freq=%f, div=%f", note, freq, rate / freq);
- file = initWave(synth, noteLookup, (const float)WGAMP, div2, file);
+ file = initWave(synth, noteLookup, WGAMP, div2, file);
// Create the pitch tables
if (noteLookup->wavTable == NULL)
diff --git a/test/common/md5.h b/test/common/md5.h
index c59b6dc853..f310845bb9 100644
--- a/test/common/md5.h
+++ b/test/common/md5.h
@@ -29,14 +29,14 @@ static const char *md5_test_digest[] = {
class MD5TestSuite : public CxxTest::TestSuite {
public:
- void test_md5_file() {
+ void test_computeStreamMD5() {
int i, j;
char output[33];
unsigned char md5sum[16];
for (i = 0; i < 7; i++) {
Common::MemoryReadStream stream((const byte *)md5_test_string[i], strlen(md5_test_string[i]));
- Common::md5_file(stream, md5sum);
+ Common::computeStreamMD5(stream, md5sum);
for (j = 0; j < 16; j++) {
sprintf(output + j * 2, "%02x", md5sum[j]);
diff --git a/test/common/str.h b/test/common/str.h
index 0908b21c1e..5d9fe29af9 100644
--- a/test/common/str.h
+++ b/test/common/str.h
@@ -316,12 +316,12 @@ class StringTestSuite : public CxxTest::TestSuite
}
void test_string_printf() {
- TS_ASSERT_EQUALS( Common::String::printf(""), "" );
- TS_ASSERT_EQUALS( Common::String::printf("%s", "test"), "test" );
- TS_ASSERT_EQUALS( Common::String::printf("%s.s%.02d", "monkey", 1), "monkey.s01" );
- TS_ASSERT_EQUALS( Common::String::printf("Some %s to make this string longer than the default built-in %s %d", "text", "capacity", 123456), "Some text to make this string longer than the default built-in capacity 123456" );
+ TS_ASSERT_EQUALS( Common::String::format(""), "" );
+ TS_ASSERT_EQUALS( Common::String::format("%s", "test"), "test" );
+ TS_ASSERT_EQUALS( Common::String::format("%s.s%.02d", "monkey", 1), "monkey.s01" );
+ TS_ASSERT_EQUALS( Common::String::format("Some %s to make this string longer than the default built-in %s %d", "text", "capacity", 123456), "Some text to make this string longer than the default built-in capacity 123456" );
- Common::String s = Common::String::printf("%s%X", "test", 1234);
+ Common::String s = Common::String::format("%s%X", "test", 1234);
TS_ASSERT_EQUALS(s, "test4D2");
TS_ASSERT_EQUALS(s.size(), 7U);
}
diff --git a/test/module.mk b/test/module.mk
index a092bfd7a7..8b74950217 100644
--- a/test/module.mk
+++ b/test/module.mk
@@ -12,6 +12,7 @@ TEST_LIBS := sound/libsound.a common/libcommon.a
TEST_FLAGS := --runner=StdioPrinter
TEST_CFLAGS := -I$(srcdir)/test/cxxtest
TEST_LDFLAGS := $(LIBS)
+TEST_CXXFLAGS := $(filter-out -Wglobal-constructors,$(CXXFLAGS))
ifdef HAVE_GCC3
# In test/common/str.h, we test a zero length format string. This causes GCC
@@ -28,7 +29,7 @@ endif
test: test/runner
./test/runner
test/runner: test/runner.cpp $(TEST_LIBS)
- $(QUIET_LINK)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TEST_LDFLAGS) $(TEST_CFLAGS) -o $@ $+
+ $(QUIET_LINK)$(CXX) $(TEST_CXXFLAGS) $(CPPFLAGS) $(TEST_LDFLAGS) $(TEST_CFLAGS) -o $@ $+
test/runner.cpp: $(TESTS)
@mkdir -p test
$(srcdir)/test/cxxtest/cxxtestgen.py $(TEST_FLAGS) -o $@ $+
diff --git a/tools/README b/tools/README
index 6ccd7b3694..0a9b4efa60 100644
--- a/tools/README
+++ b/tools/README
@@ -6,28 +6,28 @@ been warned :-).
agi-palex.py (buddha)
------------
- Tool for extracting palettes from Amiga AGI games' executables.
+ Tool for extracting palettes from Amiga AGI games' executables.
construct-pred-dict.pl, extract-words-tok.pl (sev)
--------------------------------------------
- Tools related to predictive input for AGI engine.
+ Tools related to predictive input for AGI engine.
convbdf
-------
- Tool which converts BDF fonts (BDF = Bitmap Distribution Format) to
- C++ source. That source, after being slightly tweaked, can be used to
- replace or add fonts for the ScummVM GUI.
+ Tool which converts BDF fonts (BDF = Bitmap Distribution Format) to
+ C++ source. That source, after being slightly tweaked, can be used to
+ replace or add fonts for the ScummVM GUI.
- There is also a ttf2bdf tool which allows you to convert TrueType
- fonts to BDF.
+ There is also a ttf2bdf tool which allows you to convert TrueType
+ fonts to BDF.
- Hint from SumthinWicked: If you use ttf2bdf, it'll convert all glyphs
- to bitmaps, but ScummVM only needs some of them. So you may want to
- do your conversion like this:
- ttf2bdf -p SIZE -l "32_160" -o FONT.bdf FONT.ttf
- where SIZE is replaced by the desired font height.
+ Hint from SumthinWicked: If you use ttf2bdf, it'll convert all glyphs
+ to bitmaps, but ScummVM only needs some of them. So you may want to
+ do your conversion like this:
+ ttf2bdf -p SIZE -l "32_160" -o FONT.bdf FONT.ttf
+ where SIZE is replaced by the desired font height.
create_drascula (sev)
@@ -39,11 +39,13 @@ create_drascula (sev)
(mostly the dialog subtitles) in English, Spanish, German, French
and Italian. This tool is used to create the drascula.dat file.
+
create_hugo (Strangerke)
-----------
- Creates hugo.dat file which contains all kinds of static data contained
+ Creates hugo.dat file which contains all kinds of static data contained
in original game executable.
+
create_kyradat (LordHoto, athrxx)
--------------
Extracts various static data from the original game executables.
@@ -70,6 +72,13 @@ create_msvc (LordHoto, Littleboy (contributor))
for further help.
+create_toon (Strangerke)
+-----------
+ This tool creates toon.dat, which contains all the game's texts
+ hardcoded in original game executable. This includes English, French,
+ German, Russian and Spanish texts.
+
+
create_translations (criezy)
-------------------
Creates the translations.dat file from po files given as arguments.
@@ -78,10 +87,10 @@ create_translations (criezy)
credits.pl
----------
- This perl script contains credits to the many people who helped with
- ScummVM, and it is used to create the credits lists that occur in
- various places, including the AUTHORS file, the about dialog, and our
- web site.
+ This perl script contains credits to the many people who helped with
+ ScummVM, and it is used to create the credits lists that occur in
+ various places, including the AUTHORS file, the about dialog, and our
+ web site.
dist-scummvm.sh
@@ -110,9 +119,9 @@ dist-scummvm.sh
make-scumm-fontdata (eriktorbjorn)
-------------------
- Tool that generates compressed font data used in SCUMM: To get rid of
- a few kilobytes of hard-coded font data, we only store how the
- French, German, Italian and Spanish fonts differ from the English one.
+ Tool that generates compressed font data used in SCUMM: To get rid of
+ a few kilobytes of hard-coded font data, we only store how the
+ French, German, Italian and Spanish fonts differ from the English one.
md5table
@@ -123,9 +132,9 @@ md5table
qtable (cyx)
-------
- This tool generates the "queen.tbl" file.
+ This tool generates the "queen.tbl" file.
skycpt (lavosspawn)
-------
- This tool generates the "SKY.CPT" file.
+ This tool generates the "SKY.CPT" file.
diff --git a/tools/create_hugo/create_hugo.cpp b/tools/create_hugo/create_hugo.cpp
index fc3ac8a168..921d09d7ef 100644
--- a/tools/create_hugo/create_hugo.cpp
+++ b/tools/create_hugo/create_hugo.cpp
@@ -25,6 +25,9 @@
* data file, used by the game engine
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
// HACK to allow building with the SDL backend on MinGW
// see bug #1800764 "TOOLS: MinGW tools building broken"
#ifdef main
@@ -55,6 +58,10 @@ static void writeByte(FILE *fp, uint8 b) {
fwrite(&b, 1, 1, fp);
}
+static void writeSByte(FILE *fp, int8 b) {
+ fwrite(&b, 1, 1, fp);
+}
+
static void writeUint16BE(FILE *fp, uint16 value) {
writeByte(fp, (uint8)(value >> 8));
writeByte(fp, (uint8)(value & 0xFF));
@@ -700,29 +707,29 @@ int main(int argc, char *argv[]) {
nbrElem = sizeof(actListArr_3d) / sizeof(actList);
writeActListArray(outFile, actListArr_3d, nbrElem);
- writeByte(outFile, NUM_TUNES_1w);
- writeByte(outFile, SILENCE_1w);
- writeByte(outFile, TEST_SOUND_1w);
+ writeSByte(outFile, NUM_TUNES_1w);
+ writeSByte(outFile, SILENCE_1w);
+ writeSByte(outFile, TEST_SOUND_1w);
- writeByte(outFile, NUM_TUNES_2w);
- writeByte(outFile, SILENCE_2w);
- writeByte(outFile, TEST_SOUND_2w);
+ writeSByte(outFile, NUM_TUNES_2w);
+ writeSByte(outFile, SILENCE_2w);
+ writeSByte(outFile, TEST_SOUND_2w);
- writeByte(outFile, NUM_TUNES_3w);
- writeByte(outFile, SILENCE_3w);
- writeByte(outFile, TEST_SOUND_3w);
+ writeSByte(outFile, NUM_TUNES_3w);
+ writeSByte(outFile, SILENCE_3w);
+ writeSByte(outFile, TEST_SOUND_3w);
- writeByte(outFile, NUM_TUNES_1d);
- writeByte(outFile, SILENCE_1d);
- writeByte(outFile, TEST_SOUND_1d);
+ writeSByte(outFile, NUM_TUNES_1d);
+ writeSByte(outFile, SILENCE_1d);
+ writeSByte(outFile, TEST_SOUND_1d);
- writeByte(outFile, NUM_TUNES_2d);
- writeByte(outFile, SILENCE_2d);
- writeByte(outFile, TEST_SOUND_2d);
+ writeSByte(outFile, NUM_TUNES_2d);
+ writeSByte(outFile, SILENCE_2d);
+ writeSByte(outFile, TEST_SOUND_2d);
- writeByte(outFile, NUM_TUNES_3d);
- writeByte(outFile, SILENCE_3d);
- writeByte(outFile, TEST_SOUND_3d);
+ writeSByte(outFile, NUM_TUNES_3d);
+ writeSByte(outFile, SILENCE_3d);
+ writeSByte(outFile, TEST_SOUND_3d);
// def_tunes_1w
nbrElem = sizeof(def_tunes_1w) / sizeof(int16);
diff --git a/tools/create_hugo/create_hugo.h b/tools/create_hugo/create_hugo.h
index 0215885c1d..bae0aa4592 100644
--- a/tools/create_hugo/create_hugo.h
+++ b/tools/create_hugo/create_hugo.h
@@ -31,7 +31,7 @@
#define DATAALIGNMENT 4
#define HUGO_DAT_VER_MAJ 0 // 1 byte
-#define HUGO_DAT_VER_MIN 25 // 1 byte
+#define HUGO_DAT_VER_MIN 27 // 1 byte
typedef unsigned char uint8;
typedef unsigned char byte;
diff --git a/tools/create_hugo/enums.h b/tools/create_hugo/enums.h
index a526c99ca5..e10cbe19b0 100644
--- a/tools/create_hugo/enums.h
+++ b/tools/create_hugo/enums.h
@@ -1388,8 +1388,6 @@ enum action_t { // Parameters:
OLD_SONG = 49 // Added by Strangerke - Set currently playing sound, old way: that is, using a string index instead of a reference in a file
};
-#define NORMAL_TPS 9 // Number of ticks (frames) per second
-
// Enumerate object numbers. ALL objects must have an entry here in order.
enum objid_1w {
HERO = 0, DOOR1_1w, EYES1_1w, EYES2_1w, BAT_1w, PKIN_1w, KEY_1w, FENCE_1w, TREE1_1w,
diff --git a/tools/create_hugo/staticdata.h b/tools/create_hugo/staticdata.h
index 54704749db..4c72744bb3 100644
--- a/tools/create_hugo/staticdata.h
+++ b/tools/create_hugo/staticdata.h
@@ -33,15 +33,17 @@
#ifndef STATICDATA_H
#define STATICDATA_H
-#define NUM_VARIANTE 6
-#define MAZE_SCREEN 39 // First maze screen
-#define DONT_CARE 0xFF // Any state allowed in command verb
-#define DOORDELAY 12 // Time for a door to open
-#define PENDELAY 25 // Hold off going upstairs
-#define STORYDELAY (5 * NORMAL_TPS)
-#define LIPDX 11 // To position LIPS object on person
-#define LIPDY 8
-#define DARTTIME 70 // This many ticks to fall asleep
+#define NUM_VARIANTE 6
+#define MAZE_SCREEN 39 // First maze screen
+#define DONT_CARE 0xFF // Any state allowed in command verb
+#define DOORDELAY 12 // Time for a door to open
+#define PENDELAY 25 // Hold off going upstairs
+#define LIPDX 11 // To position LIPS object on person
+#define LIPDY 8
+#define DARTTIME 70 // This many ticks to fall asleep
+#define NORMAL_TPS_v1d 8 // Number of ticks (frames) per second
+#define NORMAL_TPS_v2d 9 // Number of ticks (frames) per second
+#define STORYDELAY (5 * NORMAL_TPS_v2d)
//***************************************************************************
// Hugo 1 Windows
@@ -398,6 +400,7 @@ const char *textData_1d[] = {
"It is already locked",
"It is already unlocked",
"It is locked",
+// 10
"It is already closed",
"It is already smashed",
"It is already open",
@@ -408,6 +411,7 @@ const char *textData_1d[] = {
"You already oiled it,\nwhy don't you just\nopen it???",
"Despite your best efforts the\nbolt refuses to budge",
"I believe you already did!",
+//20
"Ok.",
"The shed seems to have fallen\ninto disuse and is pretty\nmuch full of garbage, either\nbroken or rusted to pieces.\nYou are just on the point of\nleaving when you notice an\noilcan sitting on a shelf",
"I said it's an oil-CAN,\nnot an oil-LAMP dummy!",
@@ -418,6 +422,7 @@ const char *textData_1d[] = {
"It is you, the hero.",
"Why not try opening it?",
"I can see no more than\nyou at this moment",
+//30
"They appear to be looking at you!",
"It's just flapping around up there",
"There appears to be\nsomething inside it",
@@ -428,6 +433,7 @@ const char *textData_1d[] = {
"It appears to be a halloween mask\nlooking somewhat like a grotesque\nmonkey's head!",
"I don't think you want to mess with\nthis guy!",
"A rather yummy looking pork chop",
+// 40
"This little oilcan looks like\nit contains some oil",
"Believe me, this is no Lassie!",
"It looks like a serviceable\nboat. I wonder whether it\nwould get you to the other side?",
@@ -438,6 +444,7 @@ const char *textData_1d[] = {
"He looks totally gone!",
"He has a certain charm,\nI suppose!",
"Well, it's sort of\nround and rubbery!",
+// 50
"Nobody answers!",
".", // No song
".O0L5CL1DL3D#CL6..L5CL1DL3D#CL6G#L1GGFEbEbDL5CL1DL3D#CL6..L5CL1DL3D#CL6O1L1C>B<CC#DD#L3ECO2L1F.FE.CD.DC.>A<L3DL6CL1CDEL1F.FE.CD.DC.>A<Eb..L9D>L1GGAA#A#<L6C>L1AAA#<CCL6DL1>GGGbGGAA#A#AGG<DL9CL1CDEF.FE.CD.DC.>A<L3DL6CL1>AAGFFA<CCD#DDC>BbBbA<DDDL9DL1>GGAA#A#<L3CL1DEEL3FL1C>L3AL6<DL1C.C>B.<CC#.DD#.EL3FGG#AL1BbFDBbFDAFCAFCGECGECAFCAFCBbFDBbFDAFCAFC>CB<CC#DEF>..F.",
@@ -459,6 +466,7 @@ const char *textData_2d[] = {
"That wouldn't work",
"It is already closed",
"It is already smashed",
+// 10
"It is already open",
"There is nothing in there",
"Cousin Harry is too convulsed\nwith laughter to talk!",
@@ -466,10 +474,10 @@ const char *textData_2d[] = {
"You don't have any\nmore quarters!",
"Click!\nOops, I think you\nemptied it buster!",
"Ok.",
- "Ok.",
"Now it's gone for ever!",
"You break off a shoot and\nplace it near the cat.\nThe cat awakes from its\nreverie and sniffs your\ngift excitedly. After 5\nminutes of friendly play\nit falls asleep again,\nrather contentedly!",
"Why don't you just\ntry reading it?",
+// 20
"Quietly opening it, you quickly\nscan it. It appears to be a\nletter from Hester's attorney\nconcerning the life insurance\npolicy on Great Uncle Horace.\nFeeling rather uncomfortable\nabout reading other peoples'\nmail, you return it to its\nenvelope without reading any\nfurther.",
"It won't open!",
"Just walk through!\nThis door will\nopen automatically!",
@@ -480,6 +488,7 @@ const char *textData_2d[] = {
"It is the pretty Penelope!",
"Why not try opening it?",
"You see a saucy looking french maid!",
+//30
"What a cute doggy!",
"He looks at least\n200 years old!!",
"You can see a rather impressive\nbook collection.\nOne yellow book in particular\nseems to stand out",
@@ -490,6 +499,7 @@ const char *textData_2d[] = {
"The rope looks climbable",
"Ugh! The garlic smells foul!",
"The gardener returns your stare!",
+// 40
"You can see 4 colored buttons.\nUnderneath the buttons is some\nlettering. The lettering is\nvery faded and you can only make\nout the following characters\nunder the green button:\nb*g *a*pe*",
"They are small but have\nvery vicious looking\nproboscises",
"It is one of the rarer\nvenomous species:\nbeautiful but very deadly!",
@@ -500,6 +510,7 @@ const char *textData_2d[] = {
"Just your regular genie type!",
"It's Hugo's affable cousin Harry!",
"It's Hugo's lovable aunt Hester!",
+// 50
"Yes, there is an envelope\non the table with a letter\ninside it!",
"This mysterious fellow calls himself\n""the Doctor"".\nWho he is and where he comes from\nI have simply no idea!",
"It's the cook!",
@@ -510,6 +521,7 @@ const char *textData_2d[] = {
"It looks real, I\nwonder if it works?",
"Looking through the\nkeyhole, you can\nsee the key has been\nleft in the lock.\nToo bad it's on the\nother side!",
"It is a magnifying glass\nused (for example) for\nreading small print.",
+// 60
"It is a pretty solid\nlooking safe, I don't\nthink there's any way\nto open it unless you\nknow the combination!",
"It is an extremely intricate\nlooking device, I'm afraid\nit's workings are quite\nbeyond me!",
"It has some printing\non it, some of which\nis readable.",
@@ -520,6 +532,7 @@ const char *textData_2d[] = {
"It's not locked!",
"You need to say which\ncolor button to press!",
".",
+// 70
".O2L1C^EGBACEAGAGFEDEFG^GCGvD^GvG^GvEFEDC.^C.vC^EGBACEAGAGFEDEFG^GCGvD^GvG^GvEFEDC.^C.vCDCvABAG.^CDCvABAG.^C.CvBA.^D.vB^CvBAGvG^ABvC^EGBACEAGAGFEDEFG^GCGvD^GvG^GvEFEDC.^C.",
".O2L1CEG^C.",
".O3L1CvGEC.",
@@ -545,6 +558,7 @@ const char *textData_3d[] = {
"You don't have anything\nto stick in it.",
"There are three things\nrequired to perform an\nexorcism. You do not\nhave all of them...",
"That wouldn't work.",
+// 10
"It is already closed.",
"It is already smashed.",
"It is already open.",
@@ -555,6 +569,7 @@ const char *textData_3d[] = {
"It is already lit.",
"It is not lit.",
"Ok.",
+// 20
"Now it's gone for ever!",
"It won't open!",
" LOST!\n\nNear the mighty boulder,\nMy precious crystal ball,\nI guess I couldn't hold 'er,\nSo I must've let her fall!\n\nIf anyone should find it,\nPlease return it to my keep,\nBe careful if you use it,\nFor its powers runneth deep!\n\nsigned: The old man.",
@@ -565,6 +580,7 @@ const char *textData_3d[] = {
"It's not locked!",
"It is the handsome Hugo!",
"It is the pretty Penelope!",
+// 30
"It doesn't look too badly damaged.",
"The vines look pretty sturdy.",
"Not the kind of guy you'd\nwant to meet in a dark alley!",
@@ -575,6 +591,7 @@ const char *textData_3d[] = {
"It is a flask for\nholding drinking water.",
"It is gray and furry\nand rather cute!",
"It is a small cage suitable\nfor holding small animals.",
+// 40
"You can see a blowpipe with\nsome darts full of\nsleeping potion!",
"It's just sitting there,\nminding its own business!",
"It is a box of bouillon cubes\nnormally used as seasoning in\ncooking but often carried for\nemergency rations in aircraft.",
@@ -585,6 +602,7 @@ const char *textData_3d[] = {
"The ghost does not appear\nto be very friendly and\nwill not let you pass.",
"The bell is small and golden.\nIt makes a pleasant tinkling\nring which you find rather\ncomforting for some reason.",
"The book is old and very worn.\nThe pages although yellow with\nage, still have discernible\nwriting on them. You feel\nthe book has hidden powers.",
+//50
"The candle stick is golden and\nvery heavy. The flickering of\nthe candle feels comforting,\neven in the daylight.",
".",
".O4L1C.C.C.",
@@ -595,6 +613,7 @@ const char *textData_3d[] = {
".O0L1CC#CC#CC#CC#CC#CC#CC#CC#CC#.",
".O1L3^CvL1G.GL3G#L1G.....L1B..^C.",
"O3L1E.vE^EF.vF^FE.vE^EF.vF^FE.F.G.A.G.A.B.^C.D.DbCvB.^D.Db.C.E.F.L4EFL6E.",
+// 60
"O2L4G^CvGEL6CL2AGEL4GL9D.",
".O2L1AAbAA#BAL2G^CvGL1^CvC.",
".O2L1DGB^D.vB^L5D.",
@@ -1823,34 +1842,34 @@ const uint16 *arrayReqs_3d[] = {rDummy, rpins_3d, rcheese_3d, rcrystal_3d, rexor
// [+ viewx (or -1), viewy, direction for exits only]
hotspot_t hotspots_1w[] = {
- {0, 30, 132, 50, 168, kALscr1_1w, 33, 175, Common::KEYCODE_UP}, // Front of house to hall
- {1, 99, 178, 136, 186, kALscr10_1w, 110, 181, Common::KEYCODE_DOWN}, // Hall to front of house
- {1, 288, 110, 315, 175, kALscr13_1w, 290, 171, Common::KEYCODE_RIGHT}, // Hall to dining room
- {1, 199, 110, 243, 158, kALscr15_1w, 211, 155, Common::KEYCODE_UP}, // Hall to kitchen
- {1, 268, 53, 302, 101, kALscr115_1w, 273, 98, Common::KEYCODE_RIGHT}, // Hall to lab
- {2, 158, 132, 193, 140, kALscr21_1w, 168, 132, Common::KEYCODE_DOWN}, // Bed1 to hall
- {3, 3, 73, 14, 168, kALscr31_1w, 12, 161, Common::KEYCODE_LEFT}, // Dining room to hall
- {3, 47, 66, 63, 126, kALscr35_1w, 62, 124, Common::KEYCODE_LEFT}, // Dining room to kitchen
- {4, 126, 165, 160, 173, kALscr41_1w, 135, 166, Common::KEYCODE_DOWN}, // Bathroom to hall
- {5, 215, 169, 272, 177, kALscr51_1w, 242, 172, Common::KEYCODE_DOWN}, // Kitchen to hall
- {5, 262, 79, 280, 146, kALscr53_1w, 270, 140, Common::KEYCODE_RIGHT}, // Kitchen to dining room
- {5, 213, 79, 244, 133, kALscr56_1w, 222, 140, Common::KEYCODE_UP}, // Kitchen to garden
- {5, 25, 87, 43, 157, kALscr57_1w, 44, 150, Common::KEYCODE_LEFT}, // Kitchen to store room
- {6, 232, 180, 312, 192, kALscr65_1w, 250, 180, Common::KEYCODE_DOWN}, // Garden to kitchen
- {7, 263, 90, 285, 156, kALscr75_1w, 265, 150, Common::KEYCODE_RIGHT}, // Store room to kitchen
- {8, 150, 141, 186, 143, kALscr89_1w, 152, 142, Common::KEYCODE_RIGHT}, // Basement to batcave
- {8, 80, 30, 144, 58, kALscr87_1w, 120, 60, Common::KEYCODE_UP}, // Basement to storeroom
- {9, 95, 74, 147, 109, kALscr910_1w, 108, 108, Common::KEYCODE_UP}, // Batcave to mummy room
- {9, 250, 177, 319, 185, kALscr98_1w, 275, 179, Common::KEYCODE_DOWN}, // Batcave to basement
- {10, 30, 178, 218, 188, kALscr109_1w, 107, 178, Common::KEYCODE_DOWN}, // Mummy room to batcave
- {10, 258, 57, 282, 122, kALscr1011_1w, 265, 125, Common::KEYCODE_UP}, // Mummy room to lake room
- {11, 43, 180, 88, 193, kALscr1110_1w, 55, 182, Common::KEYCODE_DOWN}, // Lake room to mummy room
- {11, 300, 30, 319, 86, kALscr1112_1w, 300, 70, Common::KEYCODE_RIGHT}, // Lake room to dead-end
- {12, 52, 175, 295, 190, kALscr1211_1w, 142, 176, Common::KEYCODE_DOWN}, // Dead-end to lake room
- {12, 137, 33, 178, 80, kALscr1213_1w, 152, 75, Common::KEYCODE_UP}, // Dead-end to jail
- {15, 19, 110, 34, 182, kALscr151_1w, 30, 177, Common::KEYCODE_LEFT}, // Laboratory to hall
- {15, 109, 150, 144, 156, kALbox_1w, -1, -1, -1}, // Professor's box
- {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
+ {0, 30, 132, 50, 168, kALscr1_1w, 33, 175, Common::KEYCODE_UP}, // Front of house to hall
+ {1, 99, 178, 136, 186, kALscr10_1w, 110, 181, Common::KEYCODE_DOWN}, // Hall to front of house
+ {1, 288, 110, 315, 175, kALscr13_1w, 290, 171, Common::KEYCODE_RIGHT}, // Hall to dining room
+ {1, 199, 110, 243, 158, kALscr15_1w, 211, 155, Common::KEYCODE_UP}, // Hall to kitchen
+ {1, 268, 53, 302, 101, kALscr115_1w, 273, 98, Common::KEYCODE_RIGHT}, // Hall to lab
+ {2, 158, 132, 193, 140, kALscr21_1w, 168, 132, Common::KEYCODE_DOWN}, // Bed1 to hall
+ {3, 3, 73, 14, 168, kALscr31_1w, 12, 161, Common::KEYCODE_LEFT}, // Dining room to hall
+ {3, 47, 66, 63, 126, kALscr35_1w, 62, 124, Common::KEYCODE_LEFT}, // Dining room to kitchen
+ {4, 126, 165, 160, 173, kALscr41_1w, 135, 166, Common::KEYCODE_DOWN}, // Bathroom to hall
+ {5, 215, 169, 272, 177, kALscr51_1w, 242, 172, Common::KEYCODE_DOWN}, // Kitchen to hall
+ {5, 262, 79, 280, 146, kALscr53_1w, 270, 140, Common::KEYCODE_RIGHT}, // Kitchen to dining room
+ {5, 213, 79, 244, 133, kALscr56_1w, 222, 140, Common::KEYCODE_UP}, // Kitchen to garden
+ {5, 25, 87, 43, 157, kALscr57_1w, 44, 150, Common::KEYCODE_LEFT}, // Kitchen to store room
+ {6, 232, 180, 312, 192, kALscr65_1w, 250, 180, Common::KEYCODE_DOWN}, // Garden to kitchen
+ {7, 263, 90, 285, 156, kALscr75_1w, 265, 150, Common::KEYCODE_RIGHT}, // Store room to kitchen
+ {8, 150, 141, 186, 143, kALscr89_1w, 152, 142, Common::KEYCODE_RIGHT}, // Basement to batcave
+ {8, 80, 30, 144, 58, kALscr87_1w, 120, 60, Common::KEYCODE_UP}, // Basement to storeroom
+ {9, 95, 74, 147, 109, kALscr910_1w, 108, 108, Common::KEYCODE_UP}, // Batcave to mummy room
+ {9, 250, 177, 319, 185, kALscr98_1w, 275, 179, Common::KEYCODE_DOWN}, // Batcave to basement
+ {10, 30, 178, 218, 188, kALscr109_1w, 107, 178, Common::KEYCODE_DOWN}, // Mummy room to batcave
+ {10, 258, 57, 282, 122, kALscr1011_1w, 265, 125, Common::KEYCODE_UP}, // Mummy room to lake room
+ {11, 43, 180, 88, 193, kALscr1110_1w, 55, 182, Common::KEYCODE_DOWN}, // Lake room to mummy room
+ {11, 300, 30, 319, 86, kALscr1112_1w, 300, 70, Common::KEYCODE_RIGHT}, // Lake room to dead-end
+ {12, 52, 175, 295, 190, kALscr1211_1w, 142, 176, Common::KEYCODE_DOWN}, // Dead-end to lake room
+ {12, 137, 33, 178, 80, kALscr1213_1w, 152, 75, Common::KEYCODE_UP}, // Dead-end to jail
+ {15, 19, 110, 34, 182, kALscr151_1w, 30, 177, Common::KEYCODE_LEFT}, // Laboratory to hall
+ {15, 109, 150, 144, 156, kALbox_1w, -1, -1, -1}, // Professor's box
+ {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
};
hotspot_t hotspots_2w[] = {
@@ -1871,7 +1890,7 @@ hotspot_t hotspots_2w[] = {
{9, 34, 76, 66, 137, kALscr0908_2w, 64, 133, Common::KEYCODE_LEFT}, // inside shed to shed
{10, 0, 96, 15, 160, kALscr1007_2w, 10, 132, Common::KEYCODE_LEFT}, // venus to backdoor
{10, 299, 96, 319, 160, kALscrgate1_2w, 301, 124, Common::KEYCODE_RIGHT}, // venus to gates
- {10, 32, 97, 298, 158, kALvenus_2w, -1, -1, -1}, // venus fly traps
+ {10, 32, 97, 298, 158, kALvenus_2w, -1, -1, -1}, // venus fly traps
{11, 0, 155, 12, 185, kALscr1108_2w, 11, 172, Common::KEYCODE_LEFT}, // gates (open) to shed
{12, 0, 155, 12, 185, kALscr1108_2w, 11, 172, Common::KEYCODE_LEFT}, // gates (close) to shed
{11, 300, 157, 319, 185, kALscr1113_2w, 301, 172, Common::KEYCODE_RIGHT}, // gates (open) to stream
@@ -1879,7 +1898,7 @@ hotspot_t hotspots_2w[] = {
{11, 145, 103, 195, 145, kAL11maze_2w, 167, 143, Common::KEYCODE_UP}, // gatesopn to maze
{13, 0, 133, 14, 163, kALscrgate2_2w, 14, 145, Common::KEYCODE_LEFT}, // stream to gates
{13, 303, 146, 319, 173, kALscr1314_2w, 305, 153, Common::KEYCODE_RIGHT}, // stream to zapper
- {13, 158, 115, 226, 147, kALbridge_2w, -1, -1, -1}, // bridge over stream
+ {13, 158, 115, 226, 147, kALbridge_2w, -1, -1, -1}, // bridge over stream
{14, 0, 96, 14, 160, kALscr1413_2w, 10, 134, Common::KEYCODE_LEFT}, // zapper to stream
{14, 301, 96, 319, 160, kALscr1415_2w, 302, 134, Common::KEYCODE_RIGHT}, // zapper to mushroom
{15, 0, 96, 16, 130, kALscr1514_2w, 14, 130, Common::KEYCODE_LEFT}, // mushroom to zapper
@@ -1893,7 +1912,7 @@ hotspot_t hotspots_2w[] = {
{18, 0, 122, 15, 181, kALscr1819l_2w, 13, 136, Common::KEYCODE_LEFT}, // phonebox to street (left)
{18, 0, 175, 319, 199, kALscr1819c_2w, 155, 177, Common::KEYCODE_DOWN}, // phonebox to street (center)
{18, 304, 95, 319, 199, kALscr1819r_2w, 307, 136, Common::KEYCODE_RIGHT}, // phonebox to street (right)
- {18, 15, 122, 56, 130, kALphonebox_2w, -1, -1, -1}, // in the phonebox
+ {18, 15, 122, 56, 130, kALphonebox_2w, -1, -1, -1}, // in the phonebox
{19, 0, 122, 20, 183, kALscr1918l_2w, 19, 131, Common::KEYCODE_LEFT}, // street to phonebox (left)
{19, 0, 175, 319, 199, kALscr1918c_2w, 153, 175, Common::KEYCODE_DOWN}, // street to phonebox (center)
{19, 301, 122, 319, 199, kALscr1918r_2w, 304, 131, Common::KEYCODE_RIGHT}, // street to phonebox (right)
@@ -1905,7 +1924,7 @@ hotspot_t hotspots_2w[] = {
{23, 273, 40, 296, 100, kALscr2326_2w, 291, 87, Common::KEYCODE_RIGHT}, // threeway to passage
{24, 300, 83, 319, 183, kALscr2423_2w, 304, 120, Common::KEYCODE_RIGHT}, // lampcave to threeway
{25, 0, 98, 15, 171, kALscr2523_2w, 14, 167, Common::KEYCODE_LEFT}, // chasm to threeway
- {25, 172, 95, 221, 172, kALchasm_2w, -1, -1, -1}, // chasm
+ {25, 172, 95, 221, 172, kALchasm_2w, -1, -1, -1}, // chasm
{26, 0, 94, 19, 179, kALscr2623_2w, 17, 157, Common::KEYCODE_LEFT}, // passage to threeway
{26, 300, 87, 319, 179, kALscr2627_2w, 302, 157, Common::KEYCODE_RIGHT}, // passage to ladder
{27, 0, 100, 15, 180, kALscr2726_2w, 14, 152, Common::KEYCODE_LEFT}, // ladder to passage
@@ -1926,18 +1945,18 @@ hotspot_t hotspots_2w[] = {
{34, 7, 180, 311, 199, kALscr3429_2w, 168, 186, Common::KEYCODE_DOWN}, // hall3 to hall2
{35, 65, 176, 101, 188, kALscr3534_2w, 74, 178, Common::KEYCODE_DOWN}, // organ to hall3
{36, 238, 164, 272, 177, kALscr3634_2w, 250, 166, Common::KEYCODE_DOWN}, // hestroom to hall3
- {36, 62, 140, 158, 158, kALhtable_2w, -1, -1, -1}, // hestroom table
+ {36, 62, 140, 158, 158, kALhtable_2w, -1, -1, -1}, // hestroom table
{37, 253, 82, 286, 84, kALscr3718_2w, 254, 83, Common::KEYCODE_RIGHT}, // retupmoc to phonebox
{38, 275, 116, 307, 166, kALscr3829_2w, 279, 164, Common::KEYCODE_RIGHT}, // hall1 to hall2
{38, 142, 108, 172, 150, kALscr3834_2w, 152, 150, Common::KEYCODE_UP}, // hall1 to hall3
{MAZE_SCREEN + 59, 100, 140, 180, 160, kALexitmaze_2w, 133, 143, Common::KEYCODE_DOWN}, // Exit maze
- {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
+ {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
};
hotspot_t hotspots_3w[] = {
{CRASH_3w, 0, 163, 30, 190, kALcrash_web_3w, 11, 176, Common::KEYCODE_LEFT},
{CRASH_3w, 164, 102, 205, 144, kALplane_3w, 178, 153, Common::KEYCODE_UP},
- {PLANE_3w, 120, 126, 220, 170, kALexit_3w, 0, 0, Common::KEYCODE_DOWN}, // Hero invisible so exit is instant
+ {PLANE_3w, 120, 126, 220, 170, kALexit_3w, 0, 0, Common::KEYCODE_DOWN}, // Hero invisible so exit is instant
{WEB_3w, 296, 73, 319, 190, kALweb_crash_3w, 307, 149, Common::KEYCODE_RIGHT},
{WEB_3w, 0, 156, 30, 190, kALweb_path_3w, 15, 182, Common::KEYCODE_LEFT},
{PATH_UL_3w, 293, 161, 319, 190, kALpath_web_3w, 305, 181, Common::KEYCODE_RIGHT},
@@ -1989,7 +2008,7 @@ hotspot_t hotspots_3w[] = {
{WBASE_3w, 295, 146, 319, 190, kALwbase_wfall_3w, 306, 154, Common::KEYCODE_RIGHT},
{WBASE_3w, 0, 149, 26, 190, kALwbase_garden_3w, 14, 154, Common::KEYCODE_LEFT},
{GARDEN_3w, 294, 165, 319, 190, kALgarden_wbase_3w, 306, 177, Common::KEYCODE_RIGHT},
- {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
+ {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
};
hotspot_t hotspots_1d[] = {
@@ -2020,7 +2039,7 @@ hotspot_t hotspots_1d[] = {
{12, 137, 67, 178, 76, kALscr1213_1d, -1, -1, -1}, // Dead-end to jail
{15, 19, 171, 34, 182, kALscr151_1d, -1, -1, -1}, // Laboratory to hall
{15, 109, 150, 144, 156, kALbox_1d, -1, -1, -1}, // Professor's box
- {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
+ {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
};
hotspot_t hotspots_2d[] = {
@@ -2101,7 +2120,7 @@ hotspot_t hotspots_2d[] = {
{38, 275, 156, 307, 166, kALscr3829_2d, -1, -1, -1}, // hall1 to hall2
{38, 142, 138, 172, 150, kALscr3834_2d, -1, -1, -1}, // hall1 to hall3
{MAZE_SCREEN+59, 100, 140, 180, 160, kALexitmaze_2d, -1, -1, -1}, // Exit maze
- {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
+ {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
};
hotspot_t hotspots_3d[] = {
@@ -2158,7 +2177,7 @@ hotspot_t hotspots_3d[] = {
{WBASE_3d, 295, 146, 319, 190, kALwbase_wfall_3d, -1, -1, -1},
{WBASE_3d, 0, 149, 26, 190, kALwbase_garden_3d, -1, -1, -1},
{GARDEN_3d, 294, 165, 319, 190, kALgarden_wbase_3d, -1, -1, -1},
- {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
+ {-1, -1, -1, -1, -1, 0, -1, -1, -1} // End of list marker
};
// List all objects that can appear in inventory list
@@ -2245,33 +2264,33 @@ uses_t uses_3d[] = {
};
background_t catchall_1w[] = { // Generally applicable phrases
- {kVJump_1w, 0, kSTnojump_1w, false, 0, 0},
- {kVGo_1w, 0, kSTtrywalk_1w, false, 0, 0},
- {kVEnter_1w, 0, kSTtrywalk_1w, false, 0, 0},
- {kVClimb_1w, 0, kSTnoclimb_1w, false, 0, 0},
- {kVShout_1w, 0, kSTnothing_1w, false, 0, 0},
- {kVTalk_1w, 0, kSTnotalk_1w, false, 0, 0},
- {kVSwitch_1w, 0, kSTenopurps_1w, false, 0, 0},
- {kVThrowit_1w, 0, kSTenopurps_1w, false, 0, 0},
- {kVAttack_1w, 0, kSTnoattack_1w, false, 0, 0},
- {kVBreak_1w, 0, kSTnobreak_1w, false, 0, 0},
- {kVListen_1w, 0, kSTnonoise_1w, false, 0, 0},
- {kVSmell_1w, 0, kSTnosmell_1w, false, 0, 0},
- {kVQuery_1w, 0, kSTnoidea_1w, false, 0, 0},
+ {kVJump_1w, 0, kSTnojump_1w, false, 0, 0},
+ {kVGo_1w, 0, kSTtrywalk_1w, false, 0, 0},
+ {kVEnter_1w, 0, kSTtrywalk_1w, false, 0, 0},
+ {kVClimb_1w, 0, kSTnoclimb_1w, false, 0, 0},
+ {kVShout_1w, 0, kSTnothing_1w, false, 0, 0},
+ {kVTalk_1w, 0, kSTnotalk_1w, false, 0, 0},
+ {kVSwitch_1w, 0, kSTenopurps_1w, false, 0, 0},
+ {kVThrowit_1w, 0, kSTenopurps_1w, false, 0, 0},
+ {kVAttack_1w, 0, kSTnoattack_1w, false, 0, 0},
+ {kVBreak_1w, 0, kSTnobreak_1w, false, 0, 0},
+ {kVListen_1w, 0, kSTnonoise_1w, false, 0, 0},
+ {kVSmell_1w, 0, kSTnosmell_1w, false, 0, 0},
+ {kVQuery_1w, 0, kSTnoidea_1w, false, 0, 0},
{kVLook_1w, kNSky_1w, kSTlooksky_1w, false, 0, 0},
{kVLook_1w, kNWall_1w, kSTedull_1w, false, 0, 0},
{kVLook_1w, kNGround_1w, kSTedull_1w, false, 0, 0},
- {kVHelp_1w, 0, kSTaskhelp_1w, false, 0, 0},
- {kVMagic_1w, 0, kSTabracadabra_1w, false, 0, 0},
- {kVDig_1w, 0, kSTnodig_1w, false, 0, 0},
- {kVRude_1w, 0, kSTnorude_1w, false, 0, 0},
- {kVKnock_1w, 0, kSTnoanswer_1w, false, 0, 0},
+ {kVHelp_1w, 0, kSTaskhelp_1w, false, 0, 0},
+ {kVMagic_1w, 0, kSTabracadabra_1w, false, 0, 0},
+ {kVDig_1w, 0, kSTnodig_1w, false, 0, 0},
+ {kVRude_1w, 0, kSTnorude_1w, false, 0, 0},
+ {kVKnock_1w, 0, kSTnoanswer_1w, false, 0, 0},
{kVTake_1w, kNPicture_1w, kSTenopurps_1w, false, 0, 0},
{kVHero, kNCut_1w, kSTCutHero_1w, false, 0, 0},
{kVHero, kNOil_1w, kSTOilHero_1w, false, 0, 0},
{kVMakeUseOf_1w, kNGold_1w, kSTGoldHero_1w, false, 0, 0},
{kVLook_1w, kNMonkey_1w, kSTLookMonkey_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen0_desc_1w[] = { // Outside house
@@ -2286,8 +2305,8 @@ background_t screen0_desc_1w[] = { // Outside house
{kVClimb_1w, kNFence_1w, kSTclimbfence_1w, false, 0, 0},
{kVEat_1w, kNPkin_1w, kSTeatpumpkin_1w, false, 0, 0},
{kVUnder_1w, kNCarpet_1w, kSTundermat_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen0_1w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVLook_1w, 0, kSTlookscreen0_1w, true, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen1_desc_1w[] = { // Hall
@@ -2297,9 +2316,9 @@ background_t screen1_desc_1w[] = { // Hall
{kVLook_1w, kNCarpet_1w, kSTedull_1w, false, 0, 0},
{kVLook_1w, kNStairs_1w, kSTlookupstairs_1w, false, 0, 0},
{kVLook_1w, kNLight_1w, kSTlooklight_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen1_1w, true, 0, 0},
- {kVListen_1w, 0, kSTlistenhall_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVLook_1w, 0, kSTlookscreen1_1w, true, 0, 0},
+ {kVListen_1w, 0, kSTlistenhall_1w, false, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen2_desc_1w[] = { // Bedroom 1
@@ -2312,8 +2331,8 @@ background_t screen2_desc_1w[] = { // Bedroom 1
{kVLook_1w, kNWindow_1w, kSTlookbed1win_1w, false, 0, 0},
{kVLook_1w, kNLight_1w, kSTedull_1w, false, 0, 0},
{kVLook_1w, kNFace_1w, kSTlookface_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen2_1w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVLook_1w, 0, kSTlookscreen2_1w, true, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen3_desc_1w[] = { // Dining room
@@ -2327,17 +2346,17 @@ background_t screen3_desc_1w[] = { // Dining room
{kVLook_1w, kNMan_1w, kSTlookdiningman_1w, false, 0, 0},
{kVLook_1w, kNCupb_1w, kSTedull_1w, false, 0, 0},
{kVLook_1w, kNWoman_1w, kSTlookwoman_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen3_1w, true, 0, 0},
- {kVSit_1w, 0, kSTsitdown_1w, false, 0, 0},
+ {kVLook_1w, 0, kSTlookscreen3_1w, true, 0, 0},
+ {kVSit_1w, 0, kSTsitdown_1w, false, 0, 0},
{kVTake_1w, kNFood_1w, kSTtakefood_1w, false, 0, 0},
- {kVEat_1w, 0, kSTtakefood_1w, false, 0, 0},
+ {kVEat_1w, 0, kSTtakefood_1w, false, 0, 0},
{kVTalk_1w, kNMan_1w, kSTtalkdiningman_1w, false, 0, 0},
{kVTalk_1w, kNWoman_1w, kSTtalkdiningwoman_1w, false, 0, 0},
{kVTalk_1w, kNButler_1w, kSTtalkbutler_1w, false, 0, 0},
- {kVKiss_1w, 0, kSTskiss_1w, false, 0, 0},
- {kVListen_1w, 0, kSTlistendining_1w, false, 0, 0},
- {kVDrink_1w, 0, kSTdrinkdining_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVKiss_1w, 0, kSTskiss_1w, false, 0, 0},
+ {kVListen_1w, 0, kSTlistendining_1w, false, 0, 0},
+ {kVDrink_1w, 0, kSTdrinkdining_1w, false, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen4_desc_1w[] = { // Bathroom
@@ -2347,15 +2366,15 @@ background_t screen4_desc_1w[] = { // Bathroom
{kVLook_1w, kNToilet_1w, kSTlooktoilet_1w, false, 0, 0},
{kVLook_1w, kNBath_1w, kSTlooktub_1w, false, 0, 0},
{kVLook_1w, kNSink_1w, kSTedull_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen4_1w, true, 0, 0},
- {kVCrap_1w, 0, kSTdopoo_1w, false, 0, 0},
+ {kVLook_1w, 0, kSTlookscreen4_1w, true, 0, 0},
+ {kVCrap_1w, 0, kSTdopoo_1w, false, 0, 0},
{kVSit_1w, kNToilet_1w, kSTdowee_1w, false, 0, 0},
{kVRide_1w, kNToilet_1w, kSTdowee_1w, false, 0, 0},
{kVInto_1w, kNBath_1w, kSTusetub_1w, false, 0, 0},
{kVTake_1w, kNBath_1w, kSTusetub_1w, false, 0, 0},
- {kVSit_1w, 0, kSTsittoilet_1w, false, 0, 0},
+ {kVSit_1w, 0, kSTsittoilet_1w, false, 0, 0},
{kVWash_1w, kNHands_1w, kSTwashhands_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen5_desc_1w[] = { // Kitchen
@@ -2366,10 +2385,10 @@ background_t screen5_desc_1w[] = { // Kitchen
{kVLook_1w, kNBroom_1w, kSTlookbroom_1w, false, 0, 0},
{kVTake_1w, kNBroom_1w, kSTtakebroom_1w, false, 0, 0},
{kVRide_1w, kNBroom_1w, kSTridebroom_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen5_1w, true, 0, 0},
- {kVSweep_1w, 0, kSTsweepbroom_1w, false, 0, 0},
- {kVListen_1w, 0, kSTlistenkitchen_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVLook_1w, 0, kSTlookscreen5_1w, true, 0, 0},
+ {kVSweep_1w, 0, kSTsweepbroom_1w, false, 0, 0},
+ {kVListen_1w, 0, kSTlistenkitchen_1w, false, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen6_desc_1w[] = { // Garden
@@ -2378,8 +2397,8 @@ background_t screen6_desc_1w[] = { // Garden
{kVLook_1w, kNTree_1w, kSTlooktree_1w, false, 0, 0},
{kVClimb_1w, kNTree_1w, kSTclimbtree_1w, false, 0, 0},
{kVLook_1w, kNGardenbits_1w, kSTlookgarden_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen6_1w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVLook_1w, 0, kSTlookscreen6_1w, true, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen7_desc_1w[] = { // Store room
@@ -2392,8 +2411,8 @@ background_t screen7_desc_1w[] = { // Store room
{kVStroke_1w, kNDog_1w, kSTStrokeDog_1w, false, 0, 0},
{kVGive_1w, kNChop_1w, kSTchop1_1w, false, 0, 0},
{kVFeed_1w, kNDog_1w, kSTchop1_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen7_1w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVLook_1w, 0, kSTlookscreen7_1w, true, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen8_desc_1w[] = { // Basement
@@ -2413,23 +2432,23 @@ background_t screen8_desc_1w[] = { // Basement
{kVKnock_1w, kNDoor_1w, kSTknockbasedoor_1w, false, 0, 0},
{kVTalk_1w, kNPenelope_1w, kSTtalkpenelope_1w, false, 0, 0},
{kVShout_1w, kNPenelope_1w, kSTtalkpenelope_1w, false, 0, 0},
- {kVListen_1w, 0, kSTlistenbase_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen8_1w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVListen_1w, 0, kSTlistenbase_1w, false, 0, 0},
+ {kVLook_1w, 0, kSTlookscreen8_1w, true, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen9_desc_1w[] = { // Bat cave
- {kVLook_1w, 0, kSTlookscreen9_1w, true, 0, 0},
+ {kVLook_1w, 0, kSTlookscreen9_1w, true, 0, 0},
{kVLook_1w, kNRock_1w, kSTlookrock_1w, false, 0, 0},
{kVPush_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
{kVLift_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
{kVMove_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
{kVUnder_1w, kNRock_1w, kSTnounder_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen10_desc_1w[] = { // Mummy room
- {kVLook_1w, 0, kSTlookscreen10_1w, true, 0, 0},
+ {kVLook_1w, 0, kSTlookscreen10_1w, true, 0, 0},
{kVLook_1w, kNRock_1w, kSTlookrock_1w, false, 0, 0},
{kVPush_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
{kVLift_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
@@ -2438,7 +2457,7 @@ background_t screen10_desc_1w[] = { // Mummy room
{kVLook_1w, kNTomb_1w, kSTlooktomb_1w, false, 0, 0},
{kVLook_1w, kNMummy_1w, kSTLookMummy_1w, false, 0, 0},
{kVTalk_1w, kNMummy_1w, kSTTalkMummy_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen11_desc_1w[] = { // Lake room
@@ -2447,12 +2466,12 @@ background_t screen11_desc_1w[] = { // Lake room
{kVLift_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
{kVMove_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
{kVUnder_1w, kNRock_1w, kSTnounder_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen11_1w, true, 0, 0},
- {kVLakeverbs_1w, 0, kSTsuggestboat_1w, false, 0, 0},
- {kVDrink_1w, 0, kSTnotthirsty_1w, false, 0, 0},
- {kVPlug_1w, 0, kSTqueryplug_1w, false, 0, 0},
+ {kVLook_1w, 0, kSTlookscreen11_1w, true, 0, 0},
+ {kVLakeverbs_1w, 0, kSTsuggestboat_1w, false, 0, 0},
+ {kVDrink_1w, 0, kSTnotthirsty_1w, false, 0, 0},
+ {kVPlug_1w, 0, kSTqueryplug_1w, false, 0, 0},
{kVMakeUseOf_1w, kNBoat_1w, kSTsShutup_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen12_desc_1w[] = { // Dead end
@@ -2461,9 +2480,9 @@ background_t screen12_desc_1w[] = { // Dead end
{kVLift_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
{kVMove_1w, kNRock_1w, kSTnowayhose_1w, false, 0, 0},
{kVUnder_1w, kNRock_1w, kSTnounder_1w, false, 0, 0},
- {kVLook_1w, 0, kSTlookscreen12_1w, true, 0, 0},
+ {kVLook_1w, 0, kSTlookscreen12_1w, true, 0, 0},
{kVTalk_1w, kNGuard_1w, kSTtalkguard_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen13_desc_1w[] = { // Jail
@@ -2475,7 +2494,7 @@ background_t screen14_desc_1w[] = { // The end
};
background_t screen15_desc_1w[] = { // Laboratory
- {kVLook_1w, 0, kSTlookscreen15_1w, true, 0, 0},
+ {kVLook_1w, 0, kSTlookscreen15_1w, true, 0, 0},
{kVTalk_1w, kNIgor_1w, kSTtalkigor_1w, false, 0, 0},
{kVTalk_1w, kNProf_1w, kSTtalkprof_1w, false, 0, 0},
{kVLook_1w, kNMachinebits_1w, kSTlookmachine_1w, false, 0, 0},
@@ -2485,7 +2504,7 @@ background_t screen15_desc_1w[] = { // Laboratory
{kVOpen_1w, kNDoor_1w, kSTuseboxdoor_1w, false, 0, 0},
{kVLook_1w, kNLight_1w, kSTlooklights_1w, false, 0, 0},
{kVLook_1w, kNBooth_1w, kSTlookbooth_1w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
@@ -2510,56 +2529,56 @@ background_t catchall_2w[] = { // Generally applicable phrases
{kVLook_2w, kNPicture_2w, kSTSpicture_2w, false, DONT_CARE, 0},
{kVLook_2w, kNMirror_2w, kSTDull_2w, false, DONT_CARE, 0},
{kVLook_2w, kNTable_2w, kSTNo_on_2w, false, DONT_CARE, 0},
- {kVJump_2w, 0, kSTSjump_2w, false, DONT_CARE, 0},
- {kVGo_2w, 0, kSTTrywalk_2w, false, DONT_CARE, 0},
- {kVInto_2w, 0, kSTTrywalk_2w, false, DONT_CARE, 0},
- {kVClimb_2w, 0, kSTSclimb_2w, false, DONT_CARE, 0},
- {kVShout_2w, 0, kSTNothing_2w, false, DONT_CARE, 0},
- {kVTalk_2w, 0, kSTStalk_2w, false, DONT_CARE, 0},
- {kVSwitch_2w, 0, kSTMorespecific_2w, false, DONT_CARE, 0},
- {kVThrowit_2w, 0, kSTNopurps_2w, false, DONT_CARE, 0},
- {kVAttack_2w, 0, kSTSattack_2w, false, DONT_CARE, 0},
- {kVBreak_2w, 0, kSTSbreak_2w, false, DONT_CARE, 0},
- {kVListen_2w, 0, kSTQuiet_2w, false, DONT_CARE, 0},
- {kVSmell_2w, 0, kSTAroma_2w, false, DONT_CARE, 0},
- {kVQuery_2w, 0, kSTNoidea_2w, false, DONT_CARE, 0},
+ {kVJump_2w, 0, kSTSjump_2w, false, DONT_CARE, 0},
+ {kVGo_2w, 0, kSTTrywalk_2w, false, DONT_CARE, 0},
+ {kVInto_2w, 0, kSTTrywalk_2w, false, DONT_CARE, 0},
+ {kVClimb_2w, 0, kSTSclimb_2w, false, DONT_CARE, 0},
+ {kVShout_2w, 0, kSTNothing_2w, false, DONT_CARE, 0},
+ {kVTalk_2w, 0, kSTStalk_2w, false, DONT_CARE, 0},
+ {kVSwitch_2w, 0, kSTMorespecific_2w, false, DONT_CARE, 0},
+ {kVThrowit_2w, 0, kSTNopurps_2w, false, DONT_CARE, 0},
+ {kVAttack_2w, 0, kSTSattack_2w, false, DONT_CARE, 0},
+ {kVBreak_2w, 0, kSTSbreak_2w, false, DONT_CARE, 0},
+ {kVListen_2w, 0, kSTQuiet_2w, false, DONT_CARE, 0},
+ {kVSmell_2w, 0, kSTAroma_2w, false, DONT_CARE, 0},
+ {kVQuery_2w, 0, kSTNoidea_2w, false, DONT_CARE, 0},
{kVLook_2w, kNSky_2w, kSTFalling_2w, false, DONT_CARE, 0},
{kVLook_2w, kNWall_2w, kSTDull_2w, false, DONT_CARE, 0},
{kVLook_2w, kNGround_2w, kSTDull_2w, false, DONT_CARE, 0},
- {kVHelp_2w, 0, kSTShelp_2w, false, DONT_CARE, 0},
- {kVMagic_2w, 0, kSTSmagic_2w, false, DONT_CARE, 0},
- {kVWish_2w, 0, kSTSmagic_2w, false, DONT_CARE, 0},
- {kVDig_2w, 0, kSTSdig_2w, false, DONT_CARE, 0},
- {kVRude_2w, 0, kSTSrude_2w, false, DONT_CARE, 0},
- {kVKnock_2w, 0, kSTNoanswer_2w, false, DONT_CARE, 0},
+ {kVHelp_2w, 0, kSTShelp_2w, false, DONT_CARE, 0},
+ {kVMagic_2w, 0, kSTSmagic_2w, false, DONT_CARE, 0},
+ {kVWish_2w, 0, kSTSmagic_2w, false, DONT_CARE, 0},
+ {kVDig_2w, 0, kSTSdig_2w, false, DONT_CARE, 0},
+ {kVRude_2w, 0, kSTSrude_2w, false, DONT_CARE, 0},
+ {kVKnock_2w, 0, kSTNoanswer_2w, false, DONT_CARE, 0},
{kVOpen_2w, kNDoor_2w, kSTWontopen_2w, false, DONT_CARE, 0},
{kVUnlock_2w, kNDoor_2w, kSTCantunlock_2w, false, DONT_CARE, 0},
{kVLook_2w, kNDoor_2w, kSTDull_2w, false, DONT_CARE, 0},
{kVLook_2w, kNLight_2w, kSTDull_2w, false, DONT_CARE, 0},
- {kVHello_2w, 0, kSTHi_2w, false, DONT_CARE, 0},
+ {kVHello_2w, 0, kSTHi_2w, false, DONT_CARE, 0},
{kVLook_2w, kNFence_2w, kSTLookover_2w, false, DONT_CARE, 0},
{kVLook_2w, kNWall_2w, kSTLookover_2w, false, DONT_CARE, 0},
{kVLook_2w, kNGardenbits_2w, kSTDull_2w, false, DONT_CARE, 0},
- {kVGive_2w, 0, kSTNothanks_2w, false, DONT_CARE, 0},
+ {kVGive_2w, 0, kSTNothanks_2w, false, DONT_CARE, 0},
{kVLook_2w, kNTree_2w, kSTDull2_2w, false, DONT_CARE, 0},
- {kVFire_2w, 0, kSTFire2_2w, false, DONT_CARE, 0},
- {kVShout_2w, 0, kSTNoanswer_2w, false, DONT_CARE, 0},
- {kVHerring_2w, 0, kSTSherring_2w, false, DONT_CARE, 0},
- {kVUndress_2w, 0, kSTSundress_2w, false, DONT_CARE, 0},
- {kVSit_2w, 0, kSTStired_2w, false, DONT_CARE, 0},
- {kVFeed_2w, 0, kSTNothanks_2w, false, DONT_CARE, 0},
+ {kVFire_2w, 0, kSTFire2_2w, false, DONT_CARE, 0},
+ {kVShout_2w, 0, kSTNoanswer_2w, false, DONT_CARE, 0},
+ {kVHerring_2w, 0, kSTSherring_2w, false, DONT_CARE, 0},
+ {kVUndress_2w, 0, kSTSundress_2w, false, DONT_CARE, 0},
+ {kVSit_2w, 0, kSTStired_2w, false, DONT_CARE, 0},
+ {kVFeed_2w, 0, kSTNothanks_2w, false, DONT_CARE, 0},
{kVRub_2w, kNCatnip_2w, kSTRubcatnip1_2w, false, DONT_CARE, 0},
{kVMakeUseOf_2w, kNScrew_2w, kSTLookScrew_2w, false, DONT_CARE, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen0_desc_2w[] = { // Outside house
{kVLook_2w, 0, kSTWelcome_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen1_desc_2w[] = { // Hall
- {kVLook_2w, 0, kSTLookhall_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTLookhall_2w, true, 0, 0},
{kVLook_2w, kNMaid_2w, kSTTmaid_2w, false, 0, 0},
{kVTalk_2w, kNMaid_2w, kSTChatmaid1_2w, false, 0, 0},
{kVTalk_2w, kNPenny_2w, kSTChatmaid2_2w, false, 0, 0},
@@ -2568,11 +2587,11 @@ background_t screen1_desc_2w[] = { // Hall
{kVOpen_2w, kNDoor_2w, kSTTmaiddoor_2w, false, 0, 0},
{kVUnlock_2w, kNDoor_2w, kSTTmaiddoor_2w, false, 0, 0},
{kVLook_2w, kNDoor_2w, kSTSdoor_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen2_desc_2w[] = { // Bed1
- {kVLook_2w, 0, kSTLookbed1_2w, true, DONT_CARE, 0},
+ {kVLook_2w, 0, kSTLookbed1_2w, true, DONT_CARE, 0},
{kVLook_2w, kNBed_2w, kSTLookbed_2w, false, DONT_CARE, 0},
{kVInto_2w, kNBed_2w, kSTS2bed_2w, false, 0, 0},
{kVRide_2w, kNBed_2w, kSTS2bed_2w, false, 0, 0},
@@ -2586,11 +2605,11 @@ background_t screen2_desc_2w[] = { // Bed1
{kVRest_2w, kNBed_2w, kSTNopurps_2w, false, 1, 0},
{kVUnder_2w, kNBed_2w, kSTSsearch_2w, false, DONT_CARE, 0},
{kVRead_2w, kNBook_2w, kSTNocarry_2w, false, DONT_CARE, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen3_desc_2w[] = { // Bed2
- {kVLook_2w, 0, kSTLookbed2_2w, true , 0, 0},
+ {kVLook_2w, 0, kSTLookbed2_2w, true , 0, 0},
{kVLook_2w, kNBird_2w, kSTParrot_2w, false, 0, 0},
{kVLook_2w, kNPenny_2w, kSTLookpen_2w, false, 0, 0}, // since following cage has synonym "pen"
{kVLook_2w, kNCage_2w, kSTDull_2w, false, 0, 0},
@@ -2608,66 +2627,66 @@ background_t screen3_desc_2w[] = { // Bed2
{kVLook_2w, kNButton_2w, kSTSbutton_2w, false, 0, 0},
{kVPush_2w, kNButton_2w, kSTS3dumb_2w, false, 0, 0},
{kVPush_2w, kNSwitch_2w, kSTS3dumb_2w, false, 0, 0},
- {kVDial_2w, 0, kSTS3phone_2w, false, 0, 4},
+ {kVDial_2w, 0, kSTS3phone_2w, false, 0, 4},
{kVTake_2w, kNPhone_2w, kSTS3phone_2w, false, 0, 4},
{kVUse_2w, kNPhone_2w, kSTS3phone_2w, false, 0, 4},
{kVLift_2w, kNPhone_2w, kSTS3phone_2w, false, 0, 4},
{kVTalk_2w, kNBird_2w, kSTS3bird_2w, false, 0, 5},
- {kVInto_2w, 0, kSTSinto_2w, true, 0, 0},
+ {kVInto_2w, 0, kSTSinto_2w, true, 0, 0},
{kVUnder_2w, kNCupb_2w, kSTSsearch_2w, false, 0, 0},
{kVFeed_2w, kNBird_2w, kSTBirdfull_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen4_desc_2w[] = { // Keyhole
{kVLook_2w, 0, kSTLooklook_2w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen5_desc_2w[] = { // Bed3
- {kVLook_2w, 0, kSTLookbed3_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTLookbed3_2w, true, 0, 0},
{kVLook_2w, kNBlock_2w, kSTLookblocks_2w, false, 0, 0},
{kVPlay_2w, kNBlock_2w, kSTSblock_2w, false, 0, 0},
- {kVBlock_2w, 0, kSTSblock_2w, false, 0, 0},
+ {kVBlock_2w, 0, kSTSblock_2w, false, 0, 0},
{kVLook_2w, kNCage_2w, kSTLookplaypen_2w, false, 0, 0},
{kVInto_2w, kNCage_2w, kSTStoobigtofit_2w, false, 0, 0},
{kVLook_2w, kNWindow_2w, kSTS6garden_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen6_desc_2w[] = { // Kitchen
- {kVLook_2w, 0, kSTLookkitchen_2w, true, DONT_CARE, 0},
+ {kVLook_2w, 0, kSTLookkitchen_2w, true, DONT_CARE, 0},
{kVLook_2w, kNButton_2w, kSTSbutton_2w, false, DONT_CARE, 0},
{kVPush_2w, kNButton_2w, kSTS3dumb_2w, false, DONT_CARE, 0},
{kVLook_2w, kNWindow_2w, kSTS6garden_2w, false, DONT_CARE, 0},
{kVLook_2w, kNUnits_2w, kSTS6dull_2w, false, DONT_CARE, 0},
{kVOpen_2w, kNUnits_2w, kSTS6dull_2w, false, DONT_CARE, 0},
- {kVInto_2w, 0, kSTSinto_2w, true, DONT_CARE, 0},
+ {kVInto_2w, 0, kSTSinto_2w, true, DONT_CARE, 0},
{kVOpen_2w, kNDoor_2w, kSTMorespecific_2w, false, DONT_CARE, 0},
{kVLook_2w, kNDoor_2w, kSTMorespecific_2w, false, DONT_CARE, 0},
{kVTalk_2w, kNCook_2w, kSTTalkcook_2w, false, 1, 0},
{kVLook_2w, kNCook_2w, kSTLookcook_2w, false, 1, 0},
{kVLook_2w, kNKnife_2w, kSTLookknife_2w, false, 1, 0},
{kVTake_2w, kNKnife_2w, kSTTakeknife_2w, false, 1, 0},
- {kVListen_2w, 0, kSTListenkitchen_2w, false, 1, 0},
- {0, 0, 0, false, 0, 0}
+ {kVListen_2w, 0, kSTListenkitchen_2w, false, 1, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen7_desc_2w[] = { // Backdoor
- {kVLook_2w, 0, kSTLookback_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTLookback_2w, true, 0, 0},
{kVLook_2w, kNWindow_2w, kSTLookwin_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen8_desc_2w[] = { // Shed
- {kVLook_2w, 0, kSTLookshed_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTLookshed_2w, true, 0, 0},
{kVLook_2w, kNWindow_2w, kSTLookwin_2w, false, 0, 0},
{kVLook_2w, kNShed_2w, kSTLookatshed_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen9_desc_2w[] = { // In shed
- {kVLook_2w, 0, kSTLookinshed_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTLookinshed_2w, true, 0, 0},
{kVLook_2w, kNWall_2w, kSTS9tools1_2w, false, 0, 0},
{kVLook_2w, kNTools_2w, kSTS9tools1_2w, false, 0, 0},
{kVTake_2w, kNTools_2w, kSTS9tools2_2w, false, 0, 0},
@@ -2678,63 +2697,63 @@ background_t screen9_desc_2w[] = { // In shed
{kVRude_2w, kNGardner_2w, kSTRudeshed_2w, false, 0, 0},
{kVTalk_2w, kNGardner_2w, kSTIgnore_2w, false, 0, 0},
{kVClose_2w, kNDoor_2w, kSTShedclose_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen10_desc_2w[] = { // Venus fly traps
- {kVLook_2w, 0, kSTLookvenus_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTLookvenus_2w, true, 0, 0},
{kVTake_2w, kNMirror_2w, kSTNotmirror_2w, false, 0, 0},
{kVLook_2w, kNFly_2w, kSTLookFly_2w, false, 0, 0},
{kVLook_2w, kNLeaf_2w, kSTLookTrap_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen11_desc_2w[] = { // Gates open
- {kVLook_2w, 0, kSTS11look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS11look_2w, true, 0, 0},
{kVClose_2w, kNDoor_2w, kSTNopurps_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen12_desc_2w[] = { // Gates closed
- {kVLook_2w, 0, kSTS12look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS12look_2w, true, 0, 0},
{kVLook_2w, kNDoor_2w, kSTGates1_2w, false, 0, 0},
{kVOpen_2w, kNDoor_2w, kSTGates1_2w, false, 0, 0},
{kVBreak_2w, kNDoor_2w, kSTGates2_2w, false, 0, 0},
{kVAttack_2w, kNDoor_2w, kSTGates2_2w, false, 0, 0},
{kVUnlock_2w, kNDoor_2w, kSTGates3_2w, false, 0, 0},
{kVUnlock_2w, kNGate_2w, kSTGates3_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen13_desc_2w[] = { // Stream
- {kVLook_2w, 0, kSTS13look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS13look_2w, true, 0, 0},
{kVLook_2w, kNBridge_2w, kSTNospecial_2w, false, 0, 0},
{kVUnder_2w, kNBridge_2w, kSTSsearch_2w, false, 0, 0},
{kVLook_2w, kNWater_2w, kSTDull_2w, false, 0, 0},
{kVThrowit_2w, kNMatches_2w, kSTThrowmatch_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen14_desc_2w[] = { // Zapper
- {kVLook_2w, 0, kSTS14look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS14look_2w, true, 0, 0},
{kVSwitch_2w, kNZapper_2w, kSTNoswitch_2w, false, 0, 0},
{kVWind_2w, kNZapper_2w, kSTNoswitch_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen15_desc_2w[] = { // Mushroom
- {kVLook_2w, 0, kSTS15look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS15look_2w, true, 0, 0},
{kVUse_2w, kNOldman_2w, kSTS15wand2_2w, false, 0, 0},
{kVTalk_2w, kNOldman_2w, kSTNoreply_2w, false, 0, 0},
{kVLook_2w, kNWand_2w, kSTS15wand1_2w, false, 0, 0},
{kVTake_2w, kNWand_2w, kSTS15wand2_2w, false, 0, 0},
{kVSearch_2w, kNOldman_2w, kSTSsearch_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen16_desc_2w[] = { // Well
- {kVLook_2w, 0, kSTS16look_2w, true, 0, 0},
- {kVClimb_2w, 0, kSTTryrope_2w, false, 0, 0},
+ {kVLook_2w, 0, kSTS16look_2w, true, 0, 0},
+ {kVClimb_2w, 0, kSTTryrope_2w, false, 0, 0},
{kVGo_2w, kNWell_2w, kSTTryrope_2w, false, 0, 0},
{kVWind_2w, kNRope_2w, kSTWindwell_2w, false, 0, 0},
{kVTie_2w, kNRope_2w, kSTNopurps_2w, false, 0, 0},
@@ -2745,103 +2764,103 @@ background_t screen16_desc_2w[] = { // Well
{kVWind_2w, kNHandle_2w, kSTWindwell_2w, false, 0, 0},
{kVInto_2w, kNBucket_2w, kSTNosee_2w, false, 0, 0},
{kVInto_2w, kNWell_2w, kSTIntowell_2w, false, 0, 0},
- {kVWish_2w, 0, kSTGetonwithit_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVWish_2w, 0, kSTGetonwithit_2w, false, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen17_desc_2w[] = { // Snakepit
- {kVLook_2w, 0, kSTS17look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS17look_2w, true, 0, 0},
{kVAttack_2w, kNSnake_2w, kSTS17kill_2w, false, 0, 0},
{kVBreak_2w, kNSnake_2w, kSTS17kill_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen18_desc_2w[] = { // Phonebox
- {kVLook_2w, 0, kSTS18look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS18look_2w, true, 0, 0},
{kVLook_2w, kNPhone_2w, kSTS18look_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen19_desc_2w[] = { // Street
- {kVLook_2w, 0, kSTS19look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS19look_2w, true, 0, 0},
{kVLook_2w, kNWall_2w, kSTSgraf_2w, false, 0, 0},
{kVRead_2w, kNWall_2w, kSTSgraf_2w, false, 0, 0},
{kVLook_2w, kNGraf_2w, kSTSgraf_2w, false, 0, 0},
{kVRead_2w, kNGraf_2w, kSTSgraf_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen20_desc_2w[] = { // Kennel
- {kVLook_2w, 0, kSTS20look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS20look_2w, true, 0, 0},
{kVLook_2w, kNWindow_2w, kSTMorespecific_2w, false, 0, 0},
{kVThrowit_2w, kNStick_2w, kSTDonthaveone_2w, false, 0, 0},
{kVStroke_2w, kNDog_2w, kSTStrokedog_2w, false, 0, 0},
{kVTalk_2w, kNDog_2w, kSTStrokedog_2w, false, 0, 0},
- {kVInto_2w, 0, kSTStoobigtofit_2w, false, 0, 0},
+ {kVInto_2w, 0, kSTStoobigtofit_2w, false, 0, 0},
{kVTake_2w, kNStick_2w, kSTThrown_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen21_desc_2w[] = { // Rockroom
- {kVLook_2w, 0, kSTS21look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS21look_2w, true, 0, 0},
{kVClimb_2w, kNRope_2w, kSTNotclose_2w, false, 0, 0},
{kVMove_2w, kNRock_2w, kSTTooheavy_2w, false, 0, 0},
{kVUnder_2w, kNRock_2w, kSTNounder_2w, false, 0, 0},
{kVLift_2w, kNRock_2w, kSTNowayhose_2w, false, 0, 0},
{kVLook_2w, kNRock_2w, kSTDull_2w, false, 0, 0},
{kVTake_2w, kNRock_2w, kSTNowayhose_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen22_desc_2w[] = { // Rockgone
- {kVLook_2w, 0, kSTS22look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS22look_2w, true, 0, 0},
{kVClimb_2w, kNRope_2w, kSTNotclose_2w, false, 0, 0},
{kVLift_2w, kNRock_2w, kSTNopurps_2w, false, 0, 0},
{kVLook_2w, kNRock_2w, kSTDull_2w, false, 0, 0},
{kVTake_2w, kNRock_2w, kSTNopurps_2w, false, 0, 0},
{kVUnder_2w, kNRock_2w, kSTSsearch_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen23_desc_2w[] = { // Threeway
- {kVLook_2w, 0, kSTS23look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS23look_2w, true, 0, 0},
{kVLift_2w, kNRock_2w, kSTNopurps_2w, false, 0, 0},
{kVLook_2w, kNRock_2w, kSTDull_2w, false, 0, 0},
{kVUnder_2w, kNRock_2w, kSTDull2_2w, false, 0, 0},
{kVTake_2w, kNRock_2w, kSTNopurps_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen24_desc_2w[] = { // Lampcave
- {kVLook_2w, 0, kSTS24look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS24look_2w, true, 0, 0},
{kVLift_2w, kNRock_2w, kSTSsearch_2w, false, 0, 0},
{kVLook_2w, kNRock_2w, kSTNospecial_2w, false, 0, 0},
{kVUnder_2w, kNRock_2w, kSTDull2_2w, false, 0, 0},
{kVTake_2w, kNRock_2w, kSTNopurps_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen25_desc_2w[] = { // Chasm
- {kVLook_2w, 0, kSTS25look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS25look_2w, true, 0, 0},
{kVUnder_2w, kNRock_2w, kSTSsearch_2w, false, 0, 0},
{kVLift_2w, kNRock_2w, kSTSsearch_2w, false, 0, 0},
{kVLook_2w, kNRock_2w, kSTDull_2w, false, 0, 0},
{kVTake_2w, kNRock_2w, kSTNopurps_2w, false, 0, 0},
- {kVJump_2w, 0, kSTSnojump_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVJump_2w, 0, kSTSnojump_2w, false, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen26_desc_2w[] = { // Passage
- {kVLook_2w, 0, kSTS26look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS26look_2w, true, 0, 0},
{kVUnder_2w, kNRock_2w, kSTSsearch_2w, false, 0, 0},
{kVLift_2w, kNRock_2w, kSTSsearch_2w, false, 0, 0},
{kVLook_2w, kNRock_2w, kSTDull_2w, false, 0, 0},
{kVTake_2w, kNRock_2w, kSTNopurps_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen27_desc_2w[] = { // genie
- {kVLook_2w, 0, kSTS27look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS27look_2w, true, 0, 0},
{kVUnder_2w, kNRock_2w, kSTSsearch_2w, false, 0, 0},
{kVLift_2w, kNRock_2w, kSTSsearch_2w, false, 0, 0},
{kVLook_2w, kNRock_2w, kSTDull_2w, false, 0, 0},
@@ -2855,57 +2874,57 @@ background_t screen27_desc_2w[] = { // genie
{kVKiss_2w, kNGenie_2w, kSTRudeshed_2w, false, 0, 0},
{kVGive_2w, kNBanana_2w, kSTNobanana_2w, false, 0, 0},
{kVClimb_2w, kNStairs_2w, kSTTrywalk_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen28_desc_2w[] = { // traproom
- {kVLook_2w, 0, kSTS28look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS28look_2w, true, 0, 0},
{kVBreak_2w, kNSafe_2w, kSTNowayhose_2w, false, 0, 0},
{kVLook_2w, kNHole_2w, kSTS28hole_2w, false, 0, 28},
{kVTake_2w, kNMouse_2w, kSTS28mouse_2w, false, 0, 0},
{kVTake_2w, kNMousehole_2w, kSTS28mouse_2w, false, 0, 0},
{kVTake_2w, kNDroppings_2w, kSTSdroppings_2w, false, 0, 0},
{kVUnscrew_2w, kNSafe_2w, kSTMorespecific_2w, false, 0, 0},
- {kVOpen_2w, 0, kSTUnlocksafe_2w, false, 0, 0},
+ {kVOpen_2w, 0, kSTUnlocksafe_2w, false, 0, 0},
{kVUnlock_2w, kNSafe_2w, kSTUnlocksafe_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen29_desc_2w[] = { // Hall 2
{kVLook_2w, 0, kSTLookhall_2w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen30_desc_2w[] = { // Lounge
- {kVLook_2w, 0, kSTS30look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS30look_2w, true, 0, 0},
{kVLook_2w, kNWindow_2w, kSTS6garden_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen31_desc_2w[] = { // parlor
- {kVLook_2w, 0, kSTS31look_2w, true, 0, 0},
- {kVListen_2w, 0, kSTBlah_2w, false, 0, 0},
+ {kVLook_2w, 0, kSTS31look_2w, true, 0, 0},
+ {kVListen_2w, 0, kSTBlah_2w, false, 0, 0},
{kVOpen_2w, kNDoor_2w, kSTMorespecific_2w, false, 0, 0},
{kVLook_2w, kNDoor_2w, kSTMorespecific_2w, false, 0, 0},
{kVLook_2w, kNMaid_2w, kSTLookPMaid_2w, false, 0, 0},
{kVTalk_2w, kNMaid_2w, kSTTalkPMaid_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen32_desc_2w[] = { // catroom
- {kVLook_2w, 0, kSTS32look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS32look_2w, true, 0, 0},
{kVStroke_2w, kNCat_2w, kSTSstrokecat_2w, false, 0, 0},
{kVPlay_2w, kNCat_2w, kSTSplaycat_2w, false, 0, 0},
{kVTalk_2w, kNCat_2w, kSTStalkcat_2w, false, 0, 0},
{kVLook_2w, kNPost_2w, kSTSlookpost_2w, false, 0, 0},
- {kVGive_2w, 0, kSTSgivecat_2w, false, 0, 0},
+ {kVGive_2w, 0, kSTSgivecat_2w, false, 0, 0},
{kVLook_2w, kNWindow_2w, kSTS6garden_2w, false, 0, 0},
{kVRub_2w, kNCatnip_2w, kSTRubcatnip2_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen33_desc_2w[] = { // Boxroom
- {kVLook_2w, 0, kSTS33look_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTS33look_2w, true, 0, 0},
{kVLook_2w, kNDoor_2w, kSTLookboxdoor_2w, false, 0, 0},
{kVOpen_2w, kNDoor_2w, kSTWontopen_2w, false, 0, 0},
{kVRead_2w, kNPaper_2w, kSTReadpaper_2w, false, 0, 29},
@@ -2920,27 +2939,27 @@ background_t screen33_desc_2w[] = { // Boxroom
{kVPush_2w, kNKey_2w, kSTMorespecific_2w, false, 0, 0},
{kVMakeUseOf_2w, kNPencil_2w, kSTUsePencil_2w, false, 0, 0},
{kVScribble_2w, kNPencil_2w, kSTDoCrossword_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen34_desc_2w[] = { // hall3
- {kVLook_2w, 0, kSTLookhall_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTLookhall_2w, true, 0, 0},
{kVLook_2w, kNMirror_2w, kSTLookMirror_2w, false, 0, 0},
{kVTake_2w, kNMirror_2w, kSTNouse_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen35_desc_2w[] = { // Organ
- {kVLook_2w, 0, kSTS35look_2w, true, DONT_CARE, 0},
+ {kVLook_2w, 0, kSTS35look_2w, true, DONT_CARE, 0},
{kVLook_2w, kNOrgan_2w, kSTLookOrgan_2w, false, DONT_CARE, 0},
{kVPlay_2w, kNOrgan_2w, kSTPlayorgan_2w, false, DONT_CARE, 0},
- {kVListen_2w, 0, kSTHearorgan_2w, false, 0, 0},
- {kVListen_2w, 0, kSTHearlaugh_2w, false, 1, 0},
- {0, 0, 0, false, 0, 0}
+ {kVListen_2w, 0, kSTHearorgan_2w, false, 0, 0},
+ {kVListen_2w, 0, kSTHearlaugh_2w, false, 1, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t screen36_desc_2w[] = { // Hestroom
- {kVLook_2w, 0, kSTLookhest_2w, true, 0, 0},
+ {kVLook_2w, 0, kSTLookhest_2w, true, 0, 0},
{kVTake_2w, kNBook_2w, kSTS36book_2w, false, 0, 0},
{kVTake_2w, kNBookcase_2w, kSTS36book_2w, false, 0, 0},
{kVRead_2w, kNBook_2w, kSTS36book_2w, false, 0, 0},
@@ -2948,23 +2967,23 @@ background_t screen36_desc_2w[] = { // Hestroom
{kVLook_2w, kNTable_2w, kSTS36table_2w, false, 0, 0},
{kVTalk_2w, kNHester_2w, kSTTalkhester_2w, false, 0, 0},
{kVLook_2w, kNWindow_2w, kSTS6garden_2w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen37_desc_2w[] = { // Retupmoc
// Screen states: 0: default, 1: Got screwdriver
- {kVLook_2w, 0, kSTS37look_2w, true, DONT_CARE, 0},
+ {kVLook_2w, 0, kSTS37look_2w, true, DONT_CARE, 0},
{kVLift_2w, kNRock_2w, kSTNopurps_2w, false, 0, 0},
{kVLook_2w, kNRock_2w, kSTNospecial_2w, false, 0, 0},
{kVUnder_2w, kNRock_2w, kSTDull2_2w, false, 0, 0},
{kVTalk_2w, kNDoctor_2w, kSTComeHere_2w, false, 0, 0},
{kVTalk_2w, kNDoctor_2w, kSTPleasego_2w, false, 1, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen38_desc_2w[] = { // hall1
{kVLook_2w, 0, kSTS38look_2w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
// Array of ptrs to object_list_t
@@ -2987,138 +3006,138 @@ background_t catchall_3w[] = { // Generally applicable phrases
{kVNaughty_3w, kNPenny_3w, kSTHeadache_3w, false, DONT_CARE, 0},
{kVInto_3w, kNWindow_3w, kSTThruwindow_3w, false, DONT_CARE, 0},
{kVOutof_3w, kNWindow_3w, kSTThruwindow_3w, false, DONT_CARE, 0},
- {kVJump_3w, 0, kSTSjump_3w, false, DONT_CARE, 0},
- {kVGo_3w, 0, kSTTrywalk_3w, false, DONT_CARE, 0},
- {kVInto_3w, 0, kSTTrywalk_3w, false, DONT_CARE, 0},
- {kVClimb_3w, 0, kSTSclimb_3w, false, DONT_CARE, 0},
- {kVShout_3w, 0, kSTNothing_3w, false, DONT_CARE, 0},
- {kVTalk_3w, 0, kSTStalk_3w, false, DONT_CARE, 0},
- {kVSwitch_3w, 0, kSTMorespecific_3w, false, DONT_CARE, 0},
- {kVUse_3w, 0, kSTMorespecific_3w, false, DONT_CARE, 0},
- {kVThrowit_3w, 0, kSTNopurps_3w, false, DONT_CARE, 0},
- {kVRude_3w, 0, kSTSrude_3w, false, DONT_CARE, 0},
- {kVAttack_3w, 0, kSTSattack_3w, false, DONT_CARE, 0},
- {kVBreak_3w, 0, kSTSbreak_3w, false, DONT_CARE, 0},
- {kVListen_3w, 0, kSTQuiet_3w, false, DONT_CARE, 0},
- {kVSmell_3w, 0, kSTAroma_3w, false, DONT_CARE, 0},
- {kVQuery_3w, 0, kSTNoidea_3w, false, DONT_CARE, 0},
+ {kVJump_3w, 0, kSTSjump_3w, false, DONT_CARE, 0},
+ {kVGo_3w, 0, kSTTrywalk_3w, false, DONT_CARE, 0},
+ {kVInto_3w, 0, kSTTrywalk_3w, false, DONT_CARE, 0},
+ {kVClimb_3w, 0, kSTSclimb_3w, false, DONT_CARE, 0},
+ {kVShout_3w, 0, kSTNothing_3w, false, DONT_CARE, 0},
+ {kVTalk_3w, 0, kSTStalk_3w, false, DONT_CARE, 0},
+ {kVSwitch_3w, 0, kSTMorespecific_3w, false, DONT_CARE, 0},
+ {kVUse_3w, 0, kSTMorespecific_3w, false, DONT_CARE, 0},
+ {kVThrowit_3w, 0, kSTNopurps_3w, false, DONT_CARE, 0},
+ {kVRude_3w, 0, kSTSrude_3w, false, DONT_CARE, 0},
+ {kVAttack_3w, 0, kSTSattack_3w, false, DONT_CARE, 0},
+ {kVBreak_3w, 0, kSTSbreak_3w, false, DONT_CARE, 0},
+ {kVListen_3w, 0, kSTQuiet_3w, false, DONT_CARE, 0},
+ {kVSmell_3w, 0, kSTAroma_3w, false, DONT_CARE, 0},
+ {kVQuery_3w, 0, kSTNoidea_3w, false, DONT_CARE, 0},
{kVLook_3w, kNSky_3w, kSTFalling_3w, false, DONT_CARE, 0},
{kVLook_3w, kNWall_3w, kSTDull_3w, false, DONT_CARE, 0},
{kVLook_3w, kNGround_3w, kSTDull_3w, false, DONT_CARE, 0},
- {kVHelp_3w, 0, kSTShelp_3w, false, DONT_CARE, 0},
- {kVMagic_3w, 0, kSTSmagic_3w, false, DONT_CARE, 0},
- {kVWish_3w, 0, kSTSmagic_3w, false, DONT_CARE, 0},
- {kVDig_3w, 0, kSTSdig_3w, false, DONT_CARE, 0},
- {kVNaughty_3w, 0, kSTSnaughty_3w, false, DONT_CARE, 0},
- {kVKnock_3w, 0, kSTNoanswer_3w, false, DONT_CARE, 0},
+ {kVHelp_3w, 0, kSTShelp_3w, false, DONT_CARE, 0},
+ {kVMagic_3w, 0, kSTSmagic_3w, false, DONT_CARE, 0},
+ {kVWish_3w, 0, kSTSmagic_3w, false, DONT_CARE, 0},
+ {kVDig_3w, 0, kSTSdig_3w, false, DONT_CARE, 0},
+ {kVNaughty_3w, 0, kSTSnaughty_3w, false, DONT_CARE, 0},
+ {kVKnock_3w, 0, kSTNoanswer_3w, false, DONT_CARE, 0},
{kVOpen_3w, kNDoor_3w, kSTWontopen_3w, false, DONT_CARE, 0},
{kVUnlock_3w, kNDoor_3w, kSTCantunlock_3w, false, DONT_CARE, 0},
{kVLook_3w, kNDoor_3w, kSTDull_3w, false, DONT_CARE, 0},
- {kVHello_3w, 0, kSTHi_3w, false, DONT_CARE, 0},
- {kVGive_3w, 0, kSTNothanks_3w, false, DONT_CARE, 0},
- {kVShout_3w, 0, kSTNoanswer_3w, false, DONT_CARE, 0},
- {kVUndress_3w, 0, kSTSundress_3w, false, DONT_CARE, 0},
- {kVSit_3w, 0, kSTStired_3w, false, DONT_CARE, 0},
- {kVFeed_3w, 0, kSTNothanks_3w, false, DONT_CARE, 0},
+ {kVHello_3w, 0, kSTHi_3w, false, DONT_CARE, 0},
+ {kVGive_3w, 0, kSTNothanks_3w, false, DONT_CARE, 0},
+ {kVShout_3w, 0, kSTNoanswer_3w, false, DONT_CARE, 0},
+ {kVUndress_3w, 0, kSTSundress_3w, false, DONT_CARE, 0},
+ {kVSit_3w, 0, kSTStired_3w, false, DONT_CARE, 0},
+ {kVFeed_3w, 0, kSTNothanks_3w, false, DONT_CARE, 0},
{kVTake_3w, kNVine_3w, kSTNopurps_3w, false, DONT_CARE, 0},
{kVClimb_3w, kNJungle_3w, kSTNopurps_3w, false, DONT_CARE, 0},
{kVLook_3w, kNJungle_3w, kSTLookjungle_3w, false, DONT_CARE, 0},
{kVPut_3w, kNFire_3w, kSTNopurps_3w, false, DONT_CARE, 0},
- {kVSwim_3w, 0, kSTCantswim_3w, false, DONT_CARE, 0},
+ {kVSwim_3w, 0, kSTCantswim_3w, false, DONT_CARE, 0},
{kVTake_3w, kNMouse_3w, kSTCantcatch_3w, false, DONT_CARE, 0},
{kVLook_3w, kNMouse_3w, kSTNospecial_3w, false, DONT_CARE, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t crash_desc_3w[] = { // At the crash site
- {kVLook_3w, 0, kSTLookcrash_3w, false, 0, 0},
+ {kVLook_3w, 0, kSTLookcrash_3w, false, 0, 0},
{kVRepair_3w, kNPlane_3w, kSTNopurps_3w, false, 0, 0},
{kVFly_3w, kNPlane_3w, kSTNopurps_3w, false, 0, 0},
- {kVInto_3w, 0, kSTMorespecific_3w, true , 0, 0},
+ {kVInto_3w, 0, kSTMorespecific_3w, true , 0, 0},
{kVOpen_3w, kNDoor_3w, kSTOpenplanedoor_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t plane_desc_3w[] = { // Inside the plane
{kVLook_3w, 0, kSTLookplane_3w, true , 0, 0},
{kVSearch_3w, 0, kSTSaylook_3w, false, 0, 0},
{kVInto_3w, 0, kSTYouarein_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t web_desc_3w[] = { // At the spider's web
- {kVLook_3w, 0, kSTLookweb_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookweb_3w, true, 0, 0},
{kVTake_3w, kNNative_3w, kSTTakegirl_3w, false, 0, 0},
{kVLook_3w, kNWeb_3w, kSTLookatweb_3w, false, 0, 0},
{kVTake_3w, kNPenny_3w, kSTTakepenny_3w, false, 0, 0},
{kVTalk_3w, kNPenny_3w, kSTTalkpenny_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t wfall_desc_3w[] = { // Waterfall and stream
- {kVLook_3w, 0, kSTLookwfall_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookwfall_3w, true, 0, 0},
{kVLook_3w, kNWater_3w, kSTLookwfall_3w, false, 0, 0},
{kVCross_3w, kNWater_3w, kSTCantcross_3w, false, 0, 0},
- {kVListen_3w, 0, kSTListenfall_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {kVListen_3w, 0, kSTListenfall_3w, false, 0, 0},
+ {0, 0, 0, false, 0, 0}
};
background_t wfall_b_desc_3w[] = { // Same as above but no water
- {kVLook_3w, 0, kSTLookwfall_b_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookwfall_b_3w, true, 0, 0},
{kVLook_3w, kNWater_3w, kSTLookwfall_b_3w, false, 0, 0},
{kVCross_3w, kNWater_3w, kSTToomuddy_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t wbase_desc_3w[] = { // Base of waterfall
- {kVLook_3w, 0, kSTLookwbase_3w, true , 0, 0},
+ {kVLook_3w, 0, kSTLookwbase_3w, true , 0, 0},
{kVLook_3w, kNWater_3w, kSTLookwbase_3w, false, 0, 0},
{kVCross_3w, kNWater_3w, kSTToomuddy_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t path_ul_desc_3w[] = { // Path at left of spider's web
{kVLook_3w, 0, kSTLookpath_ul_3w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t bridge_desc_3w[] = { // At the bridge
- {kVLook_3w, 0, kSTLookbridge1_3w, true, 0, 0},
- {kVSwing_3w, 0, kSTSwingbridge_3w, false, 0, 0},
+ {kVLook_3w, 0, kSTLookbridge1_3w, true, 0, 0},
+ {kVSwing_3w, 0, kSTSwingbridge_3w, false, 0, 0},
{kVTake_3w, kNVine_3w, kSTGetbridgevines_3w, false, 0, 0},
{kVTie_3w, kNThem_3w, kSTMorespecific_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t bridge2_desc_3w[] = { // At the bridge
{kVLook_3w, 0, kSTLookbridge2_3w, true, 0, 0},
{kVSwing_3w, 0, kSTSwingbridge_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t stream_desc_3w[] = { // stream with vines crossing
{kVLook_3w, 0, kSTLookstream1_3w, true, 0, 0},
{kVSwing_3w, 0, kSTMorespecific_3w, false, 0, 0},
{kVCross_3w, 0, kSTStep1_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t stream2_desc_3w[] = { // Stream with elephant sitting in it
- {kVLook_3w, 0, kSTLookstream2_3w, true, 0, 0},
- {kVSwing_3w, 0, kSTCantswing_3w, false, 0, 0},
+ {kVLook_3w, 0, kSTLookstream2_3w, true, 0, 0},
+ {kVSwing_3w, 0, kSTCantswing_3w, false, 0, 0},
{kVLook_3w, kNElephant_3w, kSTLookele2_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t village_desc_3w[] = { // Long shot of village
- {kVLook_3w, 0, kSTLookvillage_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookvillage_3w, true, 0, 0},
{kVTake_3w, kNFood_3w, kSTTakething_3w, false, 0, 0},
{kVLook_3w, kNFood_3w, kSTTakething_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t hut_out_desc_3w[] = { // Outside witch doctor's hut
- {kVLook_3w, 0, kSTLookhut_out_3w, false, 0, 0},
+ {kVLook_3w, 0, kSTLookhut_out_3w, false, 0, 0},
{kVLook_3w, kNDocbits_3w, kSTLookdocbits_3w, false, 0, 0},
{kVTake_3w, kNDocbits_3w, kSTTakedocbits_3w, false, 0, 0},
{kVLook_3w, kNFire_3w, kSTLookdocbits_3w, false, 0, 0},
@@ -3130,15 +3149,15 @@ background_t hut_out_desc_3w[] = { // Outside witch doctor's hut
{kVSearch_3w, kNWindow_3w, kSTLookinhut_3w, false, 0, 0},
{kVLook_3w, kNWindow_3w, kSTLookinhut_3w, false, 0, 0},
{kVSearch_3w, kNHut_3w, kSTLookinhut_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t hut_in_desc_3w[] = { // Inside hut
// States: 0 imprisoned, 1 doctor incapacitated
- {kVLook_3w, 0, kSTLookhut_in_3w, true, 0, 0},
- {kVLook_3w, 0, kSTLookhut_in2_3w, true, 1, 0},
+ {kVLook_3w, 0, kSTLookhut_in_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookhut_in2_3w, true, 1, 0},
{kVLook_3w, kNDoctor_3w, kSTLookhut_in2_3w, false, 1, 0},
- {kVTake_3w, 0, kSTTakeincage_3w, false, 0, 0},
+ {kVTake_3w, 0, kSTTakeincage_3w, false, 0, 0},
{kVTake_3w, kNDoctor_3w, kSTTakedoctor0_3w, false, 0, 0},
{kVTake_3w, kNDoctor_3w, kSTTakedoctor1_3w, false, 1, 0},
{kVLook_3w, kNDocbits_3w, kSTLookdocbits_3w, false, DONT_CARE, 0},
@@ -3156,7 +3175,7 @@ background_t hut_in_desc_3w[] = { // Inside hut
{kVLook_3w, kNBottles_3w, kSTLookshelfbits2_3w, false, 1, 0},
{kVTake_3w, kNBottles_3w, kSTTakeshelfbits_3w, false, 1, 0},
{kVDrink_3w, kNBottles_3w, kSTTakeshelfbits_3w, false, 1, 0},
- {kVSearch_3w, 0, kSTCantlookin_3w, false, 0, 0},
+ {kVSearch_3w, 0, kSTCantlookin_3w, false, 0, 0},
{kVInto_3w, kNFire_3w, kSTGetinpot_3w, false, 1, 0},
{kVSearch_3w, kNFire_3w, kSTLookinfire_3w, false, 1, 0},
{kVLook_3w, kNFire_3w, kSTLookfire_3w, false, DONT_CARE, 0},
@@ -3173,35 +3192,35 @@ background_t hut_in_desc_3w[] = { // Inside hut
{kVBlow_3w, kNDoctor_3w, kSTMissed_3w, false, DONT_CARE, 0},
{kVUse_3w, kNPipe_3w, kSTMissed_3w, false, DONT_CARE, 0},
{kVClose_3w, kNCdoor_3w, kSTNotclose_3w, false, DONT_CARE, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t garden_desc_3w[] = { // The secret garden
- {kVLook_3w, 0, kSTLookgarden_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookgarden_3w, true, 0, 0},
{kVLook_3w, kNOrchid_3w, kSTLookorchid_3w, false, 0, 0},
{kVTake_3w, kNOrchid_3w, kSTTakeorchid_3w, false, 0, 0},
- {kVCross_3w, 0, kSTCrossgarden_3w, false, 0, 0},
+ {kVCross_3w, 0, kSTCrossgarden_3w, false, 0, 0},
{kVLook_3w, kNWater_3w, kSTLookgarden_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t clifftop_desc_3w[] = { // Top of cliff path
{kVLook_3w, 0, kSTLookclifftop_3w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t oldman_desc_3w[] = { // Old man inside cave
{kVLook_3w, 0, kSTLookoldman_3w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t cliff_desc_3w[] = { // Lower cliff path
{kVLook_3w, 0, kSTLookcliff_3w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t camp_desc_3w[] = { // Camp scene in village
- {kVLook_3w, 0, kSTLookcamp_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookcamp_3w, true, 0, 0},
{kVLook_3w, kNFire_3w, kSTLookhyena_3w, false, 0, 0},
{kVLook_3w, kNPole_3w, kSTLookpole_3w, false, 0, 0},
{kVBehind_3w, kNHut_3w, kSTBehindhut_3w, false, 0, 0},// Must come before look hut
@@ -3209,48 +3228,48 @@ background_t camp_desc_3w[] = { // Camp scene in village
{kVSearch_3w, kNHut_3w, kSTLookintohut_3w, false, 0, 0},
{kVLook_3w, kNHut_3w, kSTLookhut_3w, false, 0, 0},
{kVLook_3w, kNWindow_3w, kSTLookintohut_3w, false, 0, 0},
- {kVEat_3w, 0, kSTEatroast_3w, false, 0, 0},
+ {kVEat_3w, 0, kSTEatroast_3w, false, 0, 0},
{kVTake_3w, kNFood_3w, kSTEatroast_3w, false, 0, 0},
{kVInto_3w, kNFire_3w, kSTIntofire_3w, false, 0, 0},
{kVTake_3w, kNFire_3w, kSTIntofire_3w, false, 0, 0},
{kVTake_3w, kNNative_3w, kSTTakenative_3w, false, 0, 0},
{kVTake_3w, kNPipe_3w, kSTMakeoffer_3w, false, 0, 0},
{kVGive_3w, kNBouillon_3w, kSTNonecarried_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t turn_desc_3w[] = { // Turnaround path
- {kVLook_3w, 0, kSTLookturn_3w, true, DONT_CARE, 0},
+ {kVLook_3w, 0, kSTLookturn_3w, true, DONT_CARE, 0},
{kVUnder_3w, kNRock_3w, kSTUnderrock_3w, false, 0, 0},
{kVLook_3w, kNRock_3w, kSTLookrock_3w, false, 0, 0},
{kVRide_3w, kNRock_3w, kSTOntorock_3w, false, 0, 0},
{kVClimb_3w, kNRock_3w, kSTOntorock_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t slope_desc_3w[] = { // Slope between cliff and stream
{kVLook_3w, 0, kSTLookslope_3w, true, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t path_desc_3w[] = { // Path containing elephant
// States: 0 Elephant present, 1 - Elephant not present
- {kVLook_3w, 0, kSTLookpath2_1_3w, true, 0, 0},
- {kVLook_3w, 0, kSTLookpath2_2_3w, true, 1, 0},
+ {kVLook_3w, 0, kSTLookpath2_1_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookpath2_2_3w, true, 1, 0},
{kVRide_3w, kNElephant_3w, kSTRideelephant_3w, false, 0, 0},
{kVTake_3w, kNElephant_3w, kSTGetelephant_3w, false, 0, 0},
{kVShow_3w, kNMouse_3w, kSTShowmouse_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t cave_desc_3w[] = { // Cave mouth
- {kVLook_3w, 0, kSTLookcave1_3w, true, 0, 0},
- {kVLook_3w, 0, kSTLookcave2_3w, true, 1, 0},
+ {kVLook_3w, 0, kSTLookcave1_3w, true, 0, 0},
+ {kVLook_3w, 0, kSTLookcave2_3w, true, 1, 0},
{kVAttack_3w, kNGhost_3w, kSTAttackghost_3w, false, 0, 0},
{kVBreak_3w, kNGhost_3w, kSTAttackghost_3w, false, 0, 0},
{kVShoot_3w, kNGhost_3w, kSTAttackghost_3w, false, 0, 0},
{kVTake_3w, kNGhost_3w, kSTTakeghost_3w, false, 0, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t bgDummy[] = {
@@ -3268,208 +3287,208 @@ objectList_t backgroundList_3w[] = {
};
background_t catchall_1d[] = { // Generally applicable phrases
- {kVJump_1d, 0, kSTnojump_1d, false, 0, 0},
- {kVGo_1d, 0, kSTtrywalk_1d, false, 0, 0},
- {kVEnter_1d, 0, kSTtrywalk_1d, false, 0, 0},
- {kVClimb_1d, 0, kSTnoclimb_1d, false, 0, 0},
- {kVShout_1d, 0, kSTnothing_1d, false, 0, 0},
- {kVTalk_1d, 0, kSTnotalk_1d, false, 0, 0},
- {kVSwitch_1d, 0, kSTnopurps_1d, false, 0, 0},
- {kVThrow_1d, 0, kSTnopurps_1d, false, 0, 0},
+ {kVJump_1d, 0, kSTnojump_1d, false, 0, 0},
+ {kVGo_1d, 0, kSTtrywalk_1d, false, 0, 0},
+ {kVEnter_1d, 0, kSTtrywalk_1d, false, 0, 0},
+ {kVClimb_1d, 0, kSTnoclimb_1d, false, 0, 0},
+ {kVShout_1d, 0, kSTnothing_1d, false, 0, 0},
+ {kVTalk_1d, 0, kSTnotalk_1d, false, 0, 0},
+ {kVSwitch_1d, 0, kSTnopurps_1d, false, 0, 0},
+ {kVThrow_1d, 0, kSTnopurps_1d, false, 0, 0},
{kVAttack_1d, 0, kSTnoattack_1d, false, 0, 0},
- {kVBreak_1d, 0, kSTnobreak_1d, false, 0, 0},
+ {kVBreak_1d, 0, kSTnobreak_1d, false, 0, 0},
{kVListen_1d, 0, kSTnolisten_1d, false, 0, 0},
- {kVSmell_1d, 0, kSTnosmell_1d, false, 0, 0},
- {kVQuery_1d, 0, kSTnoidea_1d, false, 0, 0},
- {kVLook_1d, kNSky_1d, kSTnolook_1d, false, 0, 0},
- {kVLook_1d, kNWall_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNGround_1d, kSTdull_1d, false, 0, 0},
- {kVHelp_1d, 0, kSTnohelp_1d, false, 0, 0},
- {kVMagic_1d, 0, kSTnomagic_1d, false, 0, 0},
- {kVDig_1d, 0, kSTnodig_1d, false, 0, 0},
- {kVRude_1d, 0, kSTnorude_1d, false, 0, 0},
- {kVKnock_1d, 0, kSTnoknock_1d, false, 0, 0},
- {kVTake_1d, kNPicture_1d, kSTnopurps_1d, false, 0, 0},
+ {kVSmell_1d, 0, kSTnosmell_1d, false, 0, 0},
+ {kVQuery_1d, 0, kSTnoidea_1d, false, 0, 0},
+ {kVLook_1d, kNSky_1d, kSTnolook_1d, false, 0, 0},
+ {kVLook_1d, kNWall_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNGround_1d, kSTdull_1d, false, 0, 0},
+ {kVHelp_1d, 0, kSTnohelp_1d, false, 0, 0},
+ {kVMagic_1d, 0, kSTnomagic_1d, false, 0, 0},
+ {kVDig_1d, 0, kSTnodig_1d, false, 0, 0},
+ {kVRude_1d, 0, kSTnorude_1d, false, 0, 0},
+ {kVKnock_1d, 0, kSTnoknock_1d, false, 0, 0},
+ {kVTake_1d, kNPicture_1d, kSTnopurps_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen0_desc_1d[] = { // Outside house
- {kVLook_1d, kNTree_1d, kSTlooks0tree_1d, false, 0, 0},
- {kVLook_1d, kNFence_1d, kSTlooks0fence_1d, false, 0, 0},
- {kVLook_1d, kNHouse_1d, kSTlooks0house_1d, false, 0, 0},
- {kVLook_1d, kNWindow_1d, kSTlooks0window_1d, false, 0, 0},
- {kVLook_1d, kNRoof_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNMoon_1d, kSTlooks0moon_1d, false, 0, 0},
- {kVEat_1d, kNPkin_1d, kSTeats0pkin_1d, false, 0, 0},
+ {kVLook_1d, kNTree_1d, kSTlooks0tree_1d, false, 0, 0},
+ {kVLook_1d, kNFence_1d, kSTlooks0fence_1d, false, 0, 0},
+ {kVLook_1d, kNHouse_1d, kSTlooks0house_1d, false, 0, 0},
+ {kVLook_1d, kNWindow_1d, kSTlooks0window_1d, false, 0, 0},
+ {kVLook_1d, kNRoof_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNMoon_1d, kSTlooks0moon_1d, false, 0, 0},
+ {kVEat_1d, kNPkin_1d, kSTeats0pkin_1d, false, 0, 0},
{kVUnder_1d, kNCarpet_1d, kSTunders0carpet_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks0_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks0_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen1_desc_1d[] = { // Hall
- {kVLook_1d, kNBat_1d, kSTlooks1bat_1d, false, 0, 0},
+ {kVLook_1d, kNBat_1d, kSTlooks1bat_1d, false, 0, 0},
{kVLook_1d, kNPicture_1d, kSTlooks1picture_1d, false, 0, 0},
- {kVLook_1d, kNTable_1d, kSTlooks1table_1d, false, 0, 0},
- {kVLook_1d, kNCarpet_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNStairs_1d, kSTlooks1stairs_1d, false, 0, 0},
- {kVLook_1d, kNLight_1d, kSTlooks1light_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks1_1d, false, 0, 0},
- {kVListen_1d, 0, kSTlistens1_1d, false, 0, 0},
+ {kVLook_1d, kNTable_1d, kSTlooks1table_1d, false, 0, 0},
+ {kVLook_1d, kNCarpet_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNStairs_1d, kSTlooks1stairs_1d, false, 0, 0},
+ {kVLook_1d, kNLight_1d, kSTlooks1light_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks1_1d, false, 0, 0},
+ {kVListen_1d, 0, kSTlistens1_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen2_desc_1d[] = { // Bedroom 1
- {kVLook_1d, kNBed_1d, kSTlooks2bed_1d, false, 0, 0},
- {kVUnder_1d, kNBed_1d, kSTlooks2bed_1d, false, 0, 0},
- {kVRide_1d, kNBed_1d, kSTrides2bed_1d, false, 0, 0},
- {kVInto_1d, kNBed_1d, kSTrides2bed_1d, false, 0, 0},
- {kVLook_1d, kNWard_1d, kSTlooks2ward_1d, false, 0, 0},
- {kVLook_1d, kNCupb_1d, kSTlooks2cupb_1d, false, 0, 0},
+ {kVLook_1d, kNBed_1d, kSTlooks2bed_1d, false, 0, 0},
+ {kVUnder_1d, kNBed_1d, kSTlooks2bed_1d, false, 0, 0},
+ {kVRide_1d, kNBed_1d, kSTrides2bed_1d, false, 0, 0},
+ {kVInto_1d, kNBed_1d, kSTrides2bed_1d, false, 0, 0},
+ {kVLook_1d, kNWard_1d, kSTlooks2ward_1d, false, 0, 0},
+ {kVLook_1d, kNCupb_1d, kSTlooks2cupb_1d, false, 0, 0},
{kVLook_1d, kNWindow_1d, kSTlooks2window_1d, false, 0, 0},
- {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNFace_1d, kSTlooks2face_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks2_1d, false, 0, 0},
+ {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNFace_1d, kSTlooks2face_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks2_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen3_desc_1d[] = { // Dining room
- {kVLook_1d, kNTable_1d, kSTlooks3table_1d, false, 0, 0},
+ {kVLook_1d, kNTable_1d, kSTlooks3table_1d, false, 0, 0},
{kVLook_1d, kNButler_1d, kSTlooks3butler_1d, false, 0, 0},
- {kVLook_1d, kNPlant_1d, kSTlooks3plant_1d, false, 0, 0},
- {kVLook_1d, kNPicture_1d, kSTlooks3witch_1d, false, 0, 0},
- {kVLook_1d, kNWitch_1d, kSTlooks3witch_1d, false, 0, 0},
+ {kVLook_1d, kNPlant_1d, kSTlooks3plant_1d, false, 0, 0},
+ {kVLook_1d, kNPicture_1d, kSTlooks3witch_1d, false, 0, 0},
+ {kVLook_1d, kNWitch_1d, kSTlooks3witch_1d, false, 0, 0},
{kVLook_1d, kNWindow_1d, kSTlooks3window_1d, false, 0, 0},
- {kVLook_1d, kNFood_1d, kSTlooks3food_1d, false, 0, 0},
- {kVLook_1d, kNMan_1d, kSTlooks3man_1d, false, 0, 0},
- {kVLook_1d, kNCupb_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNWoman_1d, kSTlooks3woman_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks3_1d, false, 0, 0},
- {kVSit_1d, 0, kSTsits3_1d, false, 0, 0},
- {kVTake_1d, kNFood_1d, kSTtakes3food_1d, false, 0, 0},
- {kVEat_1d, 0, kSTtakes3food_1d, false, 0, 0},
- {kVTalk_1d, kNMan_1d, kSTtalks3man_1d, false, 0, 0},
- {kVTalk_1d, kNWoman_1d, kSTtalks3woman_1d, false, 0, 0},
+ {kVLook_1d, kNFood_1d, kSTlooks3food_1d, false, 0, 0},
+ {kVLook_1d, kNMan_1d, kSTlooks3man_1d, false, 0, 0},
+ {kVLook_1d, kNCupb_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNWoman_1d, kSTlooks3woman_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks3_1d, false, 0, 0},
+ {kVSit_1d, 0, kSTsits3_1d, false, 0, 0},
+ {kVTake_1d, kNFood_1d, kSTtakes3food_1d, false, 0, 0},
+ {kVEat_1d, 0, kSTtakes3food_1d, false, 0, 0},
+ {kVTalk_1d, kNMan_1d, kSTtalks3man_1d, false, 0, 0},
+ {kVTalk_1d, kNWoman_1d, kSTtalks3woman_1d, false, 0, 0},
{kVTalk_1d, kNButler_1d, kSTtalkS3butler_1d, false, 0, 0},
- {kVKiss_1d, 0, kSTkisss3_1d, false, 0, 0},
- {kVListen_1d, 0, kSTlistens3_1d, false, 0, 0},
- {kVDrink_1d, 0, kSTdrinks3_1d, false, 0, 0},
+ {kVKiss_1d, 0, kSTkisss3_1d, false, 0, 0},
+ {kVListen_1d, 0, kSTlistens3_1d, false, 0, 0},
+ {kVDrink_1d, 0, kSTdrinks3_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen4_desc_1d[] = { // Bathroom
{kVLook_1d, kNWindow_1d, kSTlooks2window_1d, false, 0, 0},
- {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
{kVLook_1d, kNMirror_1d, kSTlooks4mirror_1d, false, 0, 0},
{kVLook_1d, kNToilet_1d, kSTlooks4toilet_1d, false, 0, 0},
- {kVLook_1d, kNBath_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNSink_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks4_1d, false, 0, 0},
- {kVCrap_1d, 0, kSTcraps4_1d, false, 0, 0},
- {kVSit_1d, 0, kSTsits4_1d, false, 0, 0},
- {kVWash_1d, kNHands_1d, kSTwashs4hands_1d, false, 0, 0},
+ {kVLook_1d, kNBath_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNSink_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks4_1d, false, 0, 0},
+ {kVCrap_1d, 0, kSTcraps4_1d, false, 0, 0},
+ {kVSit_1d, 0, kSTsits4_1d, false, 0, 0},
+ {kVWash_1d, kNHands_1d, kSTwashs4hands_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen5_desc_1d[] = { // Kitchen
- {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNUnits_1d, kSTlooks5units_1d, false, 0, 0},
- {kVOpen_1d, kNUnits_1d, kSTempty_1d, false, 0, 0},
+ {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNUnits_1d, kSTlooks5units_1d, false, 0, 0},
+ {kVOpen_1d, kNUnits_1d, kSTempty_1d, false, 0, 0},
{kVLook_1d, kNWindow_1d, kSTlooks5window_1d, false, 0, 0},
- {kVLook_1d, kNBroom_1d, kSTlooks5broom_1d, false, 0, 0},
- {kVTake_1d, kNBroom_1d, kSTtakes5broom_1d, false, 0, 0},
- {kVRide_1d, kNBroom_1d, kSTrides5broom_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks5_1d, false, 0, 0},
- {kVSweep_1d, 0, kSTsweeps5_1d, false, 0, 0},
- {kVListen_1d, 0, kSTlistens1_1d, false, 0, 0},
+ {kVLook_1d, kNBroom_1d, kSTlooks5broom_1d, false, 0, 0},
+ {kVTake_1d, kNBroom_1d, kSTtakes5broom_1d, false, 0, 0},
+ {kVRide_1d, kNBroom_1d, kSTrides5broom_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks5_1d, false, 0, 0},
+ {kVSweep_1d, 0, kSTsweeps5_1d, false, 0, 0},
+ {kVListen_1d, 0, kSTlistens1_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen6_desc_1d[] = { // Garden
- {kVLook_1d, kNShed_1d, kSTlooks6sched_1d, false, 0, 0},
- {kVLook_1d, kNMoon_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNTree_1d, kSTlooks0tree_1d, false, 0, 0},
- {kVClimb_1d, kNTree_1d, kSTclimbs6tree_1d, false, 0, 0},
+ {kVLook_1d, kNShed_1d, kSTlooks6sched_1d, false, 0, 0},
+ {kVLook_1d, kNMoon_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNTree_1d, kSTlooks0tree_1d, false, 0, 0},
+ {kVClimb_1d, kNTree_1d, kSTclimbs6tree_1d, false, 0, 0},
{kVLook_1d, kNGardenbits_1d, kSTlooks6gardenbits_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks6_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks6_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen7_desc_1d[] = { // Store room
- {kVLook_1d, kNCarpet_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
- {kVUnbolt_1d, kNTrap_1d, kSTunbolts7trap_1d, false, 0, 0},
+ {kVLook_1d, kNCarpet_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
+ {kVUnbolt_1d, kNTrap_1d, kSTunbolts7trap_1d, false, 0, 0},
{kVLook_1d, kNMousehole_1d, kSTlooks7mousehole_1d, false, 0, 0},
{kVTake_1d, kNDroppings_1d, kSTtakes7droppings_1d, false, 0, 0},
- {kVGive_1d, kNChop_1d, kSTchop1_1d, false, 0, 0},
- {kVFeed_1d, kNDog_1d, kSTchop1_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks7_1d, false, 0, 0},
+ {kVGive_1d, kNChop_1d, kSTchop1_1d, false, 0, 0},
+ {kVFeed_1d, kNDog_1d, kSTchop1_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks7_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen8_desc_1d[] = { // Basement
- {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
- {kVLook_1d, kNDoor_1d, kSTlooks8door_1d, false, 0, 0},
- {kVOil_1d, kNDoor_1d, kSToils8door_1d, false, 0, 0},
- {kVPush_1d, kNDoor_1d, kSTpushs8door_1d, false, 0, 0},
- {kVLook_1d, kNRock_1d, kSTlooks8rock_1d, false, 0, 0},
- {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
- {kVAttack_1d, kNDoor_1d, kSTbreaks8door_1d, false, 0, 0},
- {kVBreak_1d, kNDoor_1d, kSTbreaks8door_1d, false, 0, 0},
- {kVOpen_1d, kNDoor_1d, kSTopens8door_1d, false, 0, 0},
- {kVUnlock_1d, kNDoor_1d, kSTunlocks8door_1d, false, 0, 0},
- {kVKnock_1d, kNDoor_1d, kSTknocks8door_1d, false, 0, 0},
+ {kVLook_1d, kNLight_1d, kSTdull_1d, false, 0, 0},
+ {kVLook_1d, kNDoor_1d, kSTlooks8door_1d, false, 0, 0},
+ {kVOil_1d, kNDoor_1d, kSToils8door_1d, false, 0, 0},
+ {kVPush_1d, kNDoor_1d, kSTpushs8door_1d, false, 0, 0},
+ {kVLook_1d, kNRock_1d, kSTlooks8rock_1d, false, 0, 0},
+ {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
+ {kVAttack_1d, kNDoor_1d, kSTbreaks8door_1d, false, 0, 0},
+ {kVBreak_1d, kNDoor_1d, kSTbreaks8door_1d, false, 0, 0},
+ {kVOpen_1d, kNDoor_1d, kSTopens8door_1d, false, 0, 0},
+ {kVUnlock_1d, kNDoor_1d, kSTunlocks8door_1d, false, 0, 0},
+ {kVKnock_1d, kNDoor_1d, kSTknocks8door_1d, false, 0, 0},
{kVTalk_1d, kNPenelope_1d, kSTtalks8penelope_1d, false, 0, 0},
{kVShout_1d, kNPenelope_1d, kSTtalks8penelope_1d, false, 0, 0},
- {kVListen_1d, 0, kSTlistens8_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks8_1d, false, 0, 0},
+ {kVListen_1d, 0, kSTlistens8_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks8_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen9_desc_1d[] = { // Bat cave
- {kVLook_1d, 0, kSTlooks9_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks9_1d, false, 0, 0},
{kVLook_1d, kNRock_1d, kSTlooks9rock_1d, false, 0, 0},
- {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
+ {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen10_desc_1d[] = { // Mummy room
- {kVLook_1d, 0, kSTlooks10_1d, false, 0, 0},
- {kVLook_1d, kNRock_1d, kSTlooks9rock_1d, false, 0, 0},
- {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks10_1d, false, 0, 0},
+ {kVLook_1d, kNRock_1d, kSTlooks9rock_1d, false, 0, 0},
+ {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
{kVLook_1d, kNTomb_1d, kSTlooks10tomb_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen11_desc_1d[] = { // Lake room
- {kVLook_1d, kNRock_1d, kSTlooks9rock_1d, false, 0, 0},
- {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks11_1d, false, 0, 0},
- {kVLakeverbs_1d, 0, kSTlakeverbss11_1d, false, 0, 0},
- {kVDrink_1d, 0, kSTdrinks3_1d, false, 0, 0},
- {kVPlug_1d, 0, kSTplugs11_1d, false, 0, 0},
+ {kVLook_1d, kNRock_1d, kSTlooks9rock_1d, false, 0, 0},
+ {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks11_1d, false, 0, 0},
+ {kVLakeverbs_1d, 0, kSTlakeverbss11_1d, false, 0, 0},
+ {kVDrink_1d, 0, kSTdrinks3_1d, false, 0, 0},
+ {kVPlug_1d, 0, kSTplugs11_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen12_desc_1d[] = { // Dead end
- {kVLook_1d, kNRock_1d, kSTlooks9rock_1d, false, 0, 0},
- {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
- {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
- {kVLook_1d, 0, kSTlooks12_1d, false, 0, 0},
+ {kVLook_1d, kNRock_1d, kSTlooks9rock_1d, false, 0, 0},
+ {kVPush_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVLift_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVMove_1d, kNRock_1d, kSTnowayhose_1d, false, 0, 0},
+ {kVUnder_1d, kNRock_1d, kSTnounder_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks12_1d, false, 0, 0},
{kVTalk_1d, kNGuard_1d, kSTtalks12guard_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
@@ -3483,15 +3502,15 @@ background_t screen14_desc_1d[] = { // The end
};
background_t screen15_desc_1d[] = { // Laboratory
- {kVLook_1d, 0, kSTlooks15_1d, false, 0, 0},
- {kVTalk_1d, kNIgor_1d, kSTtalks15igor_1d, false, 0, 0},
- {kVTalk_1d, kNProf_1d, kSTtalks15prof_1d, false, 0, 0},
+ {kVLook_1d, 0, kSTlooks15_1d, false, 0, 0},
+ {kVTalk_1d, kNIgor_1d, kSTtalks15igor_1d, false, 0, 0},
+ {kVTalk_1d, kNProf_1d, kSTtalks15prof_1d, false, 0, 0},
{kVLook_1d, kNMachinebits_1d, kSTlooks15machinebits_1d, false, 0, 0},
{kVPush_1d, kNMachinebits_1d, kSTpushs15machinebits_1d, false, 0, 0},
- {kVLook_1d, kNTable_1d, kSTlooks15table_1d, false, 0, 0},
- {kVClose_1d, kNDoor_1d, kSTopens15door_1d, false, 0, 0},
- {kVOpen_1d, kNDoor_1d, kSTopens15door_1d, false, 0, 0},
- {kVLook_1d, kNLight_1d, kSTlooks15light_1d, false, 0, 0},
+ {kVLook_1d, kNTable_1d, kSTlooks15table_1d, false, 0, 0},
+ {kVClose_1d, kNDoor_1d, kSTopens15door_1d, false, 0, 0},
+ {kVOpen_1d, kNDoor_1d, kSTopens15door_1d, false, 0, 0},
+ {kVLook_1d, kNLight_1d, kSTlooks15light_1d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
@@ -3514,46 +3533,46 @@ background_t catchall_2d[] = { // Generally applicable phrases
{kVLook_2d, kNPicture_2d, kSTSpicture_2d, false, DONT_CARE, 0},
{kVLook_2d, kNMirror_2d, kSTDull_2d, false, DONT_CARE, 0},
{kVLook_2d, kNTable_2d, kSTNo_on_2d, false, DONT_CARE, 0},
- {kVJump_2d, 0, kSTSjump_2d, false, DONT_CARE, 0},
- {kVGo_2d, 0, kSTTrywalk_2d, false, DONT_CARE, 0},
- {kVInto_2d, 0, kSTTrywalk_2d, false, DONT_CARE, 0},
- {kVClimb_2d, 0, kSTSclimb_2d, false, DONT_CARE, 0},
- {kVShout_2d, 0, kSTNothing_2d, false, DONT_CARE, 0},
- {kVTalk_2d, 0, kSTStalk_2d, false, DONT_CARE, 0},
- {kVSwitch_2d, 0, kSTMorespecific_2d, false, DONT_CARE, 0},
- {kVThrow_2d, 0, kSTNopurps_2d, false, DONT_CARE, 0},
- {kVAttack_2d, 0, kSTSattack_2d, false, DONT_CARE, 0},
- {kVBreak_2d, 0, kSTSbreak_2d, false, DONT_CARE, 0},
- {kVListen_2d, 0, kSTQuiet_2d, false, DONT_CARE, 0},
- {kVSmell_2d, 0, kSTAroma_2d, false, DONT_CARE, 0},
- {kVQuery_2d, 0, kSTNoidea_2d, false, DONT_CARE, 0},
+ {kVJump_2d, 0, kSTSjump_2d, false, DONT_CARE, 0},
+ {kVGo_2d, 0, kSTTrywalk_2d, false, DONT_CARE, 0},
+ {kVInto_2d, 0, kSTTrywalk_2d, false, DONT_CARE, 0},
+ {kVClimb_2d, 0, kSTSclimb_2d, false, DONT_CARE, 0},
+ {kVShout_2d, 0, kSTNothing_2d, false, DONT_CARE, 0},
+ {kVTalk_2d, 0, kSTStalk_2d, false, DONT_CARE, 0},
+ {kVSwitch_2d, 0, kSTMorespecific_2d, false, DONT_CARE, 0},
+ {kVThrow_2d, 0, kSTNopurps_2d, false, DONT_CARE, 0},
+ {kVAttack_2d, 0, kSTSattack_2d, false, DONT_CARE, 0},
+ {kVBreak_2d, 0, kSTSbreak_2d, false, DONT_CARE, 0},
+ {kVListen_2d, 0, kSTQuiet_2d, false, DONT_CARE, 0},
+ {kVSmell_2d, 0, kSTAroma_2d, false, DONT_CARE, 0},
+ {kVQuery_2d, 0, kSTNoidea_2d, false, DONT_CARE, 0},
{kVLook_2d, kNSky_2d, kSTFalling_2d, false, DONT_CARE, 0},
{kVLook_2d, kNWall_2d, kSTDull_2d, false, DONT_CARE, 0},
{kVLook_2d, kNGround_2d, kSTDull_2d, false, DONT_CARE, 0},
- {kVHelp_2d, 0, kSTShelp_2d, false, DONT_CARE, 0},
- {kVMagic_2d, 0, kSTSmagic_2d, false, DONT_CARE, 0},
- {kVWish_2d, 0, kSTSmagic_2d, false, DONT_CARE, 0},
- {kVDig_2d, 0, kSTSdig_2d, false, DONT_CARE, 0},
- {kVRude_2d, 0, kSTSrude_2d, false, DONT_CARE, 0},
- {kVKnock_2d, 0, kSTNoanswer_2d, false, DONT_CARE, 0},
+ {kVHelp_2d, 0, kSTShelp_2d, false, DONT_CARE, 0},
+ {kVMagic_2d, 0, kSTSmagic_2d, false, DONT_CARE, 0},
+ {kVWish_2d, 0, kSTSmagic_2d, false, DONT_CARE, 0},
+ {kVDig_2d, 0, kSTSdig_2d, false, DONT_CARE, 0},
+ {kVRude_2d, 0, kSTSrude_2d, false, DONT_CARE, 0},
+ {kVKnock_2d, 0, kSTNoanswer_2d, false, DONT_CARE, 0},
{kVOpen_2d, kNDoor_2d, kSTWontopen_2d, false, DONT_CARE, 0},
{kVUnlock_2d, kNDoor_2d, kSTCantunlock_2d, false, DONT_CARE, 0},
{kVLook_2d, kNDoor_2d, kSTDull_2d, false, DONT_CARE, 0},
{kVLook_2d, kNLight_2d, kSTDull_2d, false, DONT_CARE, 0},
- {kVHello_2d, 0, kSTHi_2d, false, DONT_CARE, 0},
+ {kVHello_2d, 0, kSTHi_2d, false, DONT_CARE, 0},
{kVLook_2d, kNFence_2d, kSTLookover_2d, false, DONT_CARE, 0},
{kVLook_2d, kNWall_2d, kSTLookover_2d, false, DONT_CARE, 0},
{kVLook_2d, kNGardenbits_2d, kSTDull_2d, false, DONT_CARE, 0},
- {kVGive_2d, 0, kSTNothanks_2d, false, DONT_CARE, 0},
+ {kVGive_2d, 0, kSTNothanks_2d, false, DONT_CARE, 0},
{kVLook_2d, kNTree_2d, kSTDull2_2d, false, DONT_CARE, 0},
- {kVFire_2d, 0, kSTFire2_2d, false, DONT_CARE, 0},
- {kVShout_2d, 0, kSTNoanswer_2d, false, DONT_CARE, 0},
- {kVHerring_2d, 0, kSTSherring_2d, false, DONT_CARE, 0},
- {kVUndress_2d, 0, kSTSundress_2d, false, DONT_CARE, 0},
- {kVSit_2d, 0, kSTStired_2d, false, DONT_CARE, 0},
- {kVFeed_2d, 0, kSTNothanks_2d, false, DONT_CARE, 0},
+ {kVFire_2d, 0, kSTFire2_2d, false, DONT_CARE, 0},
+ {kVShout_2d, 0, kSTNoanswer_2d, false, DONT_CARE, 0},
+ {kVHerring_2d, 0, kSTSherring_2d, false, DONT_CARE, 0},
+ {kVUndress_2d, 0, kSTSundress_2d, false, DONT_CARE, 0},
+ {kVSit_2d, 0, kSTStired_2d, false, DONT_CARE, 0},
+ {kVFeed_2d, 0, kSTNothanks_2d, false, DONT_CARE, 0},
{kVRub_2d, kNCatnip_2d, kSTRubcatnip1_2d, false, DONT_CARE, 0},
- {0, 0, 0, false, 0, 0}
+ {0, 0, 0, false, 0, 0}
};
background_t screen0_desc_2d[] = { // Outside house
@@ -3562,57 +3581,57 @@ background_t screen0_desc_2d[] = { // Outside house
};
background_t screen1_desc_2d[] = { // Hall
- {kVLook_2d, 0, kSTLookhall_2d, true, 0, 0},
- {kVLook_2d, kNMaid_2d, kSTTmaid_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTLookhall_2d, true, 0, 0},
+ {kVLook_2d, kNMaid_2d, kSTTmaid_2d, false, 0, 0},
{kVTalk_2d, kNMaid_2d, kSTChatmaid1_2d, false, 0, 0},
{kVTalk_2d, kNPenny_2d, kSTChatmaid2_2d, false, 0, 0},
{kVKiss_2d, kNMaid_2d, kSTChatmaid3_2d, false, 0, 0},
- {kVRude_2d, kNMaid_2d, kSTRudemaid_2d, false, 0, 0},
+ {kVRude_2d, kNMaid_2d, kSTRudemaid_2d, false, 0, 0},
{kVOpen_2d, kNDoor_2d, kSTTmaiddoor_2d, false, 0, 0},
{kVUnlock_2d, kNDoor_2d, kSTTmaiddoor_2d, false, 0, 0},
- {kVLook_2d, kNDoor_2d, kSTSdoor_2d, false, 0, 0},
+ {kVLook_2d, kNDoor_2d, kSTSdoor_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen2_desc_2d[] = { // Bed1
- {kVLook_2d, 0, kSTLookbed1_2d, true, DONT_CARE, 0},
+ {kVLook_2d, 0, kSTLookbed1_2d, true, DONT_CARE, 0},
{kVLook_2d, kNBed_2d, kSTLookbed_2d, false, DONT_CARE, 0},
- {kVInto_2d, kNBed_2d, kSTS2bed_2d, false, 0, 0},
- {kVRide_2d, kNBed_2d, kSTS2bed_2d, false, 0, 0},
- {kVRest_2d, kNBed_2d, kSTS2bed_2d, false, 0, 0},
- {kVRide_2d, kNPenny_2d, kSTS2bed_2d, false, 0, 0},
- {kVTalk_2d, kNPenny_2d, kSTZzzz_2d, false, 0, 0},
- {kVInto_2d, kNBed_2d, kSTNopurps_2d, false, 1, 0},
- {kVRide_2d, kNBed_2d, kSTNopurps_2d, false, 1, 0},
- {kVRest_2d, kNBed_2d, kSTNopurps_2d, false, 1, 0},
+ {kVInto_2d, kNBed_2d, kSTS2bed_2d, false, 0, 0},
+ {kVRide_2d, kNBed_2d, kSTS2bed_2d, false, 0, 0},
+ {kVRest_2d, kNBed_2d, kSTS2bed_2d, false, 0, 0},
+ {kVRide_2d, kNPenny_2d, kSTS2bed_2d, false, 0, 0},
+ {kVTalk_2d, kNPenny_2d, kSTZzzz_2d, false, 0, 0},
+ {kVInto_2d, kNBed_2d, kSTNopurps_2d, false, 1, 0},
+ {kVRide_2d, kNBed_2d, kSTNopurps_2d, false, 1, 0},
+ {kVRest_2d, kNBed_2d, kSTNopurps_2d, false, 1, 0},
{kVUnder_2d, kNBed_2d, kSTSsearch_2d, false, DONT_CARE, 0},
{kVRead_2d, kNBook_2d, kSTNocarry_2d, false, DONT_CARE, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen3_desc_2d[] = { // Bed2
- {kVLook_2d, 0, kSTLookbed2_2d, true, 0, 0},
- {kVLook_2d, kNBird_2d, kSTParrot_2d, false, 0, 0},
- {kVLook_2d, kNCage_2d, kSTDull_2d, false, 0, 0},
- {kVLook_2d, kNPencil_2d, kSTDull_2d, false, 0, 0},
- {kVLook_2d, kNPhone_2d, kSTDull_2d, false, 0, 0},
- {kVLook_2d, kNPaper_2d, kSTBlotter_2d, false, 0, 0},
- {kVRead_2d, kNPaper_2d, kSTBlotter_2d, false, 0, 0},
- {kVLook_2d, kNChair_2d, kSTDull_2d, false, 0, 0},
- {kVTake_2d, kNPencil_2d, kSTNouse_2d, false, 0, 0},
- {kVTake_2d, kNPaper_2d, kSTNouse_2d, false, 0, 0},
- {kVLook_2d, kNHole_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTLookbed2_2d, true, 0, 0},
+ {kVLook_2d, kNBird_2d, kSTParrot_2d, false, 0, 0},
+ {kVLook_2d, kNCage_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, kNPencil_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, kNPhone_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, kNPaper_2d, kSTBlotter_2d, false, 0, 0},
+ {kVRead_2d, kNPaper_2d, kSTBlotter_2d, false, 0, 0},
+ {kVLook_2d, kNChair_2d, kSTDull_2d, false, 0, 0},
+ {kVTake_2d, kNPencil_2d, kSTNouse_2d, false, 0, 0},
+ {kVTake_2d, kNPaper_2d, kSTNouse_2d, false, 0, 0},
+ {kVLook_2d, kNHole_2d, kSTDull_2d, false, 0, 0},
{kVLook_2d, kNWall_2d, kSTDumbwaiter_2d, false, 0, 0},
- {kVLook_2d, kNButton_2d, kSTSbutton_2d, false, 0, 0},
- {kVPush_2d, kNButton_2d, kSTS3dumb_2d, false, 0, 0},
- {kVDial_2d, 0, kSTS3phone_2d, false, 0, 4},
+ {kVLook_2d, kNButton_2d, kSTSbutton_2d, false, 0, 0},
+ {kVPush_2d, kNButton_2d, kSTS3dumb_2d, false, 0, 0},
+ {kVDial_2d, 0, kSTS3phone_2d, false, 0, 4},
{kVTake_2d, kNPhone_2d, kSTS3phone_2d, false, 0, 4},
{kVUse_2d, kNPhone_2d, kSTS3phone_2d, false, 0, 4},
{kVLift_2d, kNPhone_2d, kSTS3phone_2d, false, 0, 4},
{kVTalk_2d, kNBird_2d, kSTS3bird_2d, false, 0, 5},
- {kVInto_2d, 0, kSTSinto_2d, true, 0, 0},
- {kVUnder_2d, kNCupb_2d, kSTSsearch_2d, false, 0, 0},
- {kVFeed_2d, kNBird_2d, kSTBirdfull_2d, false, 0, 0},
+ {kVInto_2d, 0, kSTSinto_2d, true, 0, 0},
+ {kVUnder_2d, kNCupb_2d, kSTSsearch_2d, false, 0, 0},
+ {kVFeed_2d, kNBird_2d, kSTBirdfull_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
@@ -3623,241 +3642,241 @@ background_t screen4_desc_2d[] = { // Keyhole
};
background_t screen5_desc_2d[] = { // Bed3
- {kVLook_2d, 0, kSTLookbed3_2d, true, 0, 0},
- {kVBlock_2d, 0, kSTSblock_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTLookbed3_2d, true, 0, 0},
+ {kVBlock_2d, 0, kSTSblock_2d, false, 0, 0},
{kVInto_2d, kNCage_2d, kSTStoobigtofit_2d, false, 0, 0},
- {kVLook_2d, kNWindow_2d, kSTS6garden_2d, false, 0, 0},
+ {kVLook_2d, kNWindow_2d, kSTS6garden_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen6_desc_2d[] = { // Kitchen
- {kVLook_2d, 0, kSTLookkitchen_2d, true, DONT_CARE, 0},
+ {kVLook_2d, 0, kSTLookkitchen_2d, true, DONT_CARE, 0},
{kVLook_2d, kNButton_2d, kSTSbutton_2d, false, DONT_CARE, 0},
{kVPush_2d, kNButton_2d, kSTS3dumb_2d, false, DONT_CARE, 0},
{kVLook_2d, kNWindow_2d, kSTS6garden_2d, false, DONT_CARE, 0},
{kVLook_2d, kNUnits_2d, kSTS6dull_2d, false, DONT_CARE, 0},
{kVOpen_2d, kNUnits_2d, kSTS6dull_2d, false, DONT_CARE, 0},
- {kVInto_2d, 0, kSTSinto_2d, true, DONT_CARE, 0},
+ {kVInto_2d, 0, kSTSinto_2d, true, DONT_CARE, 0},
{kVOpen_2d, kNDoor_2d, kSTMorespecific_2d, false, DONT_CARE, 0},
{kVLook_2d, kNDoor_2d, kSTMorespecific_2d, false, DONT_CARE, 0},
- {kVTalk_2d, kNCook_2d, kSTTalkcook_2d, false, 1, 0},
- {kVLook_2d, kNCook_2d, kSTLookcook_2d, false, 1, 0},
- {kVLook_2d, kNKnife_2d, kSTLookknife_2d, false, 1, 0},
- {kVTake_2d, kNKnife_2d, kSTTakeknife_2d, false, 1, 0},
- {kVListen_2d, 0, kSTListenkitchen_2d, false, 1, 0},
+ {kVTalk_2d, kNCook_2d, kSTTalkcook_2d, false, 1, 0},
+ {kVLook_2d, kNCook_2d, kSTLookcook_2d, false, 1, 0},
+ {kVLook_2d, kNKnife_2d, kSTLookknife_2d, false, 1, 0},
+ {kVTake_2d, kNKnife_2d, kSTTakeknife_2d, false, 1, 0},
+ {kVListen_2d, 0, kSTListenkitchen_2d, false, 1, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen7_desc_2d[] = { // Backdoor
- {kVLook_2d, 0, kSTLookback_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTLookback_2d, true, 0, 0},
{kVLook_2d, kNWindow_2d, kSTLookwin_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen8_desc_2d[] = { // Shed
- {kVLook_2d, 0, kSTLookshed_2d, true, 0, 0},
- {kVLook_2d, kNWindow_2d, kSTLookwin_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTLookshed_2d, true, 0, 0},
+ {kVLook_2d, kNWindow_2d, kSTLookwin_2d, false, 0, 0},
{kVLook_2d, kNShed_2d, kSTLookatshed_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen9_desc_2d[] = { // In shed
- {kVLook_2d, 0, kSTLookinshed_2d, true, 0, 0},
- {kVLook_2d, kNWall_2d, kSTS9tools1_2d, false, 0, 0},
- {kVLook_2d, kNTools_2d, kSTS9tools1_2d, false, 0, 0},
- {kVTake_2d, kNTools_2d, kSTS9tools2_2d, false, 0, 0},
- {kVLook_2d, kNBroom_2d, kSTDull_2d, false, 0, 0},
- {kVTake_2d, kNBroom_2d, kSTNouse_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTLookinshed_2d, true, 0, 0},
+ {kVLook_2d, kNWall_2d, kSTS9tools1_2d, false, 0, 0},
+ {kVLook_2d, kNTools_2d, kSTS9tools1_2d, false, 0, 0},
+ {kVTake_2d, kNTools_2d, kSTS9tools2_2d, false, 0, 0},
+ {kVLook_2d, kNBroom_2d, kSTDull_2d, false, 0, 0},
+ {kVTake_2d, kNBroom_2d, kSTNouse_2d, false, 0, 0},
{kVLook_2d, kNTable_2d, kSTSomebuttons_2d, false, 0, 0},
- {kVKiss_2d, kNGardner_2d, kSTMore_2d, false, 0, 0},
- {kVRude_2d, kNGardner_2d, kSTRudeshed_2d, false, 0, 0},
- {kVTalk_2d, kNGardner_2d, kSTIgnore_2d, false, 0, 0},
- {kVClose_2d, kNDoor_2d, kSTShedclose_2d, false, 0, 0},
+ {kVKiss_2d, kNGardner_2d, kSTMore_2d, false, 0, 0},
+ {kVRude_2d, kNGardner_2d, kSTRudeshed_2d, false, 0, 0},
+ {kVTalk_2d, kNGardner_2d, kSTIgnore_2d, false, 0, 0},
+ {kVClose_2d, kNDoor_2d, kSTShedclose_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen10_desc_2d[] = { // Venus fly traps
- {kVLook_2d, 0, kSTLookvenus_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTLookvenus_2d, true, 0, 0},
{kVTake_2d, kNMirror_2d, kSTNotmirror_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen11_desc_2d[] = { // Gates kVOpen_2d,
- {kVLook_2d, 0, kSTS11look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS11look_2d, true, 0, 0},
{kVClose_2d, kNDoor_2d, kSTNopurps_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen12_desc_2d[] = { // Gates closed
- {kVLook_2d, 0, kSTS12look_2d, true, 0, 0},
- {kVOpen_2d, kNDoor_2d, kSTGates1_2d, false, 0, 0},
- {kVBreak_2d, kNDoor_2d, kSTGates2_2d, false, 0, 0},
- {kVAttack_2d, kNDoor_2d, kSTGates2_2d, false, 0, 0},
- {kVUnlock_2d, kNDoor_2d, kSTGates3_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS12look_2d, true, 0, 0},
+ {kVOpen_2d, kNDoor_2d, kSTGates1_2d, false, 0, 0},
+ {kVBreak_2d, kNDoor_2d, kSTGates2_2d, false, 0, 0},
+ {kVAttack_2d, kNDoor_2d, kSTGates2_2d, false, 0, 0},
+ {kVUnlock_2d, kNDoor_2d, kSTGates3_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen13_desc_2d[] = { // Stream
- {kVLook_2d, 0, kSTS13look_2d, true, 0, 0},
- {kVLook_2d, kNBridge_2d, kSTNospecial_2d, false, 0, 0},
- {kVUnder_2d, kNBridge_2d, kSTSsearch_2d, false, 0, 0},
- {kVLook_2d, kNWater_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS13look_2d, true, 0, 0},
+ {kVLook_2d, kNBridge_2d, kSTNospecial_2d, false, 0, 0},
+ {kVUnder_2d, kNBridge_2d, kSTSsearch_2d, false, 0, 0},
+ {kVLook_2d, kNWater_2d, kSTDull_2d, false, 0, 0},
{kVThrow_2d, kNMatches_2d, kSTThrowmatch_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen14_desc_2d[] = { // Zapper
- {kVLook_2d, 0, kSTS14look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS14look_2d, true, 0, 0},
{kVSwitch_2d, kNZapper_2d, kSTNoswitch_2d, false, 0, 0},
{kVWind_2d, kNZapper_2d, kSTNoswitch_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen15_desc_2d[] = { // Mushroom
- {kVLook_2d, 0, kSTS15look_2d, true, 0, 0},
- {kVTalk_2d, kNMan_2d, kSTNoreply_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS15look_2d, true, 0, 0},
+ {kVTalk_2d, kNMan_2d, kSTNoreply_2d, false, 0, 0},
{kVLook_2d, kNWand_2d, kSTS15wand1_2d, false, 0, 0},
{kVTake_2d, kNWand_2d, kSTS15wand2_2d, false, 0, 0},
- {kVSearch_2d, kNMan_2d, kSTSsearch_2d, false, 0, 0},
+ {kVSearch_2d, kNMan_2d, kSTSsearch_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen16_desc_2d[] = { // Well
- {kVLook_2d, 0, kSTS16look_2d, true, 0, 0},
- {kVClimb_2d, 0, kSTTryrope_2d, false, 0, 0},
- {kVGo_2d, kNWell_2d, kSTTryrope_2d, false, 0, 0},
- {kVWind_2d, kNRope_2d, kSTWindwell_2d, false, 0, 0},
- {kVTie_2d, kNRope_2d, kSTNopurps_2d, false, 0, 0},
- {kVTake_2d, kNBucket_2d, kSTNosee_2d, false, 0, 0},
- {kVLook_2d, kNBucket_2d, kSTNosee_2d, false, 0, 0},
- {kVWind_2d, kNBucket_2d, kSTWindwell_2d, false, 0, 0},
- {kVTake_2d, kNWater_2d, kSTNosee_2d, false, 0, 0},
- {kVWind_2d, kNHandle_2d, kSTWindwell_2d, false, 0, 0},
- {kVInto_2d, kNBucket_2d, kSTNosee_2d, false, 0, 0},
- {kVInto_2d, kNWell_2d, kSTIntowell_2d, false, 0, 0},
- {kVWish_2d, 0, kSTGetonwithit_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS16look_2d, true, 0, 0},
+ {kVClimb_2d, 0, kSTTryrope_2d, false, 0, 0},
+ {kVGo_2d, kNWell_2d, kSTTryrope_2d, false, 0, 0},
+ {kVWind_2d, kNRope_2d, kSTWindwell_2d, false, 0, 0},
+ {kVTie_2d, kNRope_2d, kSTNopurps_2d, false, 0, 0},
+ {kVTake_2d, kNBucket_2d, kSTNosee_2d, false, 0, 0},
+ {kVLook_2d, kNBucket_2d, kSTNosee_2d, false, 0, 0},
+ {kVWind_2d, kNBucket_2d, kSTWindwell_2d, false, 0, 0},
+ {kVTake_2d, kNWater_2d, kSTNosee_2d, false, 0, 0},
+ {kVWind_2d, kNHandle_2d, kSTWindwell_2d, false, 0, 0},
+ {kVInto_2d, kNBucket_2d, kSTNosee_2d, false, 0, 0},
+ {kVInto_2d, kNWell_2d, kSTIntowell_2d, false, 0, 0},
+ {kVWish_2d, 0, kSTGetonwithit_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen17_desc_2d[] = { // Snakepit
- {kVLook_2d, 0, kSTS17look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS17look_2d, true, 0, 0},
{kVAttack_2d, kNSnake_2d, kSTS17kill_2d, false, 0, 0},
{kVBreak_2d, kNSnake_2d, kSTS17kill_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen18_desc_2d[] = { // Phonebox
- {kVLook_2d, 0, kSTS18look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS18look_2d, true, 0, 0},
{kVLook_2d, kNPhone_2d, kSTS18look_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen19_desc_2d[] = { // Street
- {kVLook_2d, 0, kSTS19look_2d, true, 0, 0},
- {kVLook_2d, kNWall_2d, kSTSgraf_2d, false, 0, 0},
- {kVRead_2d, kNWall_2d, kSTSgraf_2d, false, 0, 0},
- {kVLook_2d, kNGraf_2d, kSTSgraf_2d, false, 0, 0},
- {kVRead_2d, kNGraf_2d, kSTSgraf_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS19look_2d, true, 0, 0},
+ {kVLook_2d, kNWall_2d, kSTSgraf_2d, false, 0, 0},
+ {kVRead_2d, kNWall_2d, kSTSgraf_2d, false, 0, 0},
+ {kVLook_2d, kNGraf_2d, kSTSgraf_2d, false, 0, 0},
+ {kVRead_2d, kNGraf_2d, kSTSgraf_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen20_desc_2d[] = { // Kennel
- {kVLook_2d, 0, kSTS20look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS20look_2d, true, 0, 0},
{kVLook_2d, kNWindow_2d, kSTMorespecific_2d, false, 0, 0},
- {kVThrow_2d, kNStick_2d, kSTDonthaveone_2d, false, 0, 0},
- {kVStroke_2d, kNDog_2d, kSTStrokedog_2d, false, 0, 0},
- {kVTalk_2d, kNDog_2d, kSTStrokedog_2d, false, 0, 0},
- {kVInto_2d, 0, kSTStoobigtofit_2d, false, 0, 0},
+ {kVThrow_2d, kNStick_2d, kSTDonthaveone_2d, false, 0, 0},
+ {kVStroke_2d, kNDog_2d, kSTStrokedog_2d, false, 0, 0},
+ {kVTalk_2d, kNDog_2d, kSTStrokedog_2d, false, 0, 0},
+ {kVInto_2d, 0, kSTStoobigtofit_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen21_desc_2d[] = { // Rockroom
- {kVLook_2d, 0, kSTS21look_2d, true, 0, 0},
- {kVClimb_2d, kNRope_2d, kSTNotclose_2d, false, 0, 0},
- {kVUnder_2d, kNRock_2d, kSTNounder_2d, false, 0, 0},
- {kVMove_2d, kNRock_2d, kSTTooheavy_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS21look_2d, true, 0, 0},
+ {kVClimb_2d, kNRope_2d, kSTNotclose_2d, false, 0, 0},
+ {kVUnder_2d, kNRock_2d, kSTNounder_2d, false, 0, 0},
+ {kVMove_2d, kNRock_2d, kSTTooheavy_2d, false, 0, 0},
{kVLift_2d, kNRock_2d, kSTNowayhose_2d, false, 0, 0},
- {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
{kVTake_2d, kNRock_2d, kSTNowayhose_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen22_desc_2d[] = { // Rockgone
- {kVLook_2d, 0, kSTS22look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS22look_2d, true, 0, 0},
{kVClimb_2d, kNRope_2d, kSTNotclose_2d, false, 0, 0},
- {kVLift_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
- {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
- {kVTake_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
- {kVUnder_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
+ {kVLift_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
+ {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
+ {kVTake_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
+ {kVUnder_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen23_desc_2d[] = { // Threeway
- {kVLook_2d, 0, kSTS23look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS23look_2d, true, 0, 0},
{kVLift_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
- {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
- {kVUnder_2d, kNRock_2d, kSTDull2_2d, false, 0, 0},
+ {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
+ {kVUnder_2d, kNRock_2d, kSTDull2_2d, false, 0, 0},
{kVTake_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen24_desc_2d[] = { // Lampcave
- {kVLook_2d, 0, kSTS24look_2d, true, 0, 0},
- {kVLift_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS24look_2d, true, 0, 0},
+ {kVLift_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
{kVLook_2d, kNRock_2d, kSTNospecial_2d, false, 0, 0},
- {kVUnder_2d, kNRock_2d, kSTDull2_2d, false, 0, 0},
- {kVTake_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
+ {kVUnder_2d, kNRock_2d, kSTDull2_2d, false, 0, 0},
+ {kVTake_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen25_desc_2d[] = { // Chasm
- {kVLook_2d, 0, kSTS25look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS25look_2d, true, 0, 0},
{kVUnder_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
{kVLift_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
- {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
{kVTake_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
- {kVJump_2d, 0, kSTSnojump_2d, false, 0, 0},
+ {kVJump_2d, 0, kSTSnojump_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen26_desc_2d[] = { // Passage
- {kVLook_2d, 0, kSTS26look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS26look_2d, true, 0, 0},
{kVUnder_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
{kVLift_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
- {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
{kVTake_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen27_desc_2d[] = { // genie
- {kVLook_2d, 0, kSTS27look_2d, true, 0, 0},
- {kVUnder_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
- {kVLift_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
- {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
- {kVLook_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
- {kVOpen_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
- {kVUnscrew_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
- {kVUnlock_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
- {kVPush_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS27look_2d, true, 0, 0},
+ {kVUnder_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
+ {kVLift_2d, kNRock_2d, kSTSsearch_2d, false, 0, 0},
+ {kVLook_2d, kNRock_2d, kSTDull_2d, false, 0, 0},
+ {kVLook_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
+ {kVOpen_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
+ {kVUnscrew_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
+ {kVUnlock_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
+ {kVPush_2d, kNTrap_2d, kSTBudge_2d, false, 0, 0},
{kVTalk_2d, kNGenie_2d, kSTTalkgenie_2d, false, 0, 0},
- {kVRude_2d, kNGenie_2d, kSTRudeshed_2d, false, 0, 0},
- {kVKiss_2d, kNGenie_2d, kSTRudeshed_2d, false, 0, 0},
- {kVGive_2d, kNBanana_2d, kSTNobanana_2d, false, 0, 0},
- {kVClimb_2d, kNStairs_2d, kSTTrywalk_2d, false, 0, 0},
+ {kVRude_2d, kNGenie_2d, kSTRudeshed_2d, false, 0, 0},
+ {kVKiss_2d, kNGenie_2d, kSTRudeshed_2d, false, 0, 0},
+ {kVGive_2d, kNBanana_2d, kSTNobanana_2d, false, 0, 0},
+ {kVClimb_2d, kNStairs_2d, kSTTrywalk_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen28_desc_2d[] = { // traproom
- {kVLook_2d, 0, kSTS28look_2d, true, 0, 0},
- {kVBreak_2d, kNSafe_2d, kSTNowayhose_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS28look_2d, true, 0, 0},
+ {kVBreak_2d, kNSafe_2d, kSTNowayhose_2d, false, 0, 0},
{kVLook_2d, kNHole_2d, kSTS28hole_2d, false, 0, 28},
- {kVTake_2d, kNMouse_2d, kSTS28mouse_2d, false, 0, 0},
- {kVTake_2d, kNDroppings_2d, kSTSdroppings_2d, false, 0, 0},
+ {kVTake_2d, kNMouse_2d, kSTS28mouse_2d, false, 0, 0},
+ {kVTake_2d, kNDroppings_2d, kSTSdroppings_2d, false, 0, 0},
{kVUnscrew_2d, kNSafe_2d, kSTMorespecific_2d, false, 0, 0},
- {kVOpen_2d, 0, kSTUnlocksafe_2d, false, 0, 0},
- {kVUnlock_2d, kNSafe_2d, kSTUnlocksafe_2d, false, 0, 0},
+ {kVOpen_2d, 0, kSTUnlocksafe_2d, false, 0, 0},
+ {kVUnlock_2d, kNSafe_2d, kSTUnlocksafe_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
@@ -3867,78 +3886,78 @@ background_t screen29_desc_2d[] = { // Hall 2
};
background_t screen30_desc_2d[] = { // Lounge
- {kVLook_2d, 0, kSTS30look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS30look_2d, true, 0, 0},
{kVLook_2d, kNWindow_2d, kSTS6garden_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen31_desc_2d[] = { // parlor
- {kVLook_2d, 0, kSTS31look_2d, true, 0, 0},
- {kVListen_2d, 0, kSTBlah_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS31look_2d, true, 0, 0},
+ {kVListen_2d, 0, kSTBlah_2d, false, 0, 0},
{kVOpen_2d, kNDoor_2d, kSTMorespecific_2d, false, 0, 0},
{kVLook_2d, kNDoor_2d, kSTMorespecific_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen32_desc_2d[] = { // catroom
- {kVLook_2d, 0, kSTS32look_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTS32look_2d, true, 0, 0},
{kVStroke_2d, kNCat_2d, kSTSstrokecat_2d, false, 0, 0},
- {kVPlay_2d, kNCat_2d, kSTSplaycat_2d, false, 0, 0},
- {kVTalk_2d, kNCat_2d, kSTStalkcat_2d, false, 0, 0},
- {kVLook_2d, kNPost_2d, kSTSlookpost_2d, false, 0, 0},
- {kVGive_2d, 0, kSTSgivecat_2d, false, 0, 0},
- {kVLook_2d, kNWindow_2d, kSTS6garden_2d, false, 0, 0},
+ {kVPlay_2d, kNCat_2d, kSTSplaycat_2d, false, 0, 0},
+ {kVTalk_2d, kNCat_2d, kSTStalkcat_2d, false, 0, 0},
+ {kVLook_2d, kNPost_2d, kSTSlookpost_2d, false, 0, 0},
+ {kVGive_2d, 0, kSTSgivecat_2d, false, 0, 0},
+ {kVLook_2d, kNWindow_2d, kSTS6garden_2d, false, 0, 0},
{kVRub_2d, kNCatnip_2d, kSTRubcatnip2_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen33_desc_2d[] = { // Boxroom
- {kVLook_2d, 0, kSTS33look_2d, true, 0, 0},
- {kVLook_2d, kNDoor_2d, kSTLookboxdoor_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS33look_2d, true, 0, 0},
+ {kVLook_2d, kNDoor_2d, kSTLookboxdoor_2d, false, 0, 0},
{kVRead_2d, kNPaper_2d, kSTReadpaper_2d, false, 0, 29},
{kVLook_2d, kNPaper_2d, kSTReadpaper_2d, false, 0, 29},
- {kVLook_2d, kNCrate_2d, kSTSlookbox_2d, false, 0, 0},
- {kVInto_2d, kNCrate_2d, kSTSgetinbox_2d, false, 0, 0},
- {kVLook_2d, kNChute_2d, kSTLookchute_2d, false, 0, 0},
- {kVLook_2d, kNHole_2d, kSTLookchute_2d, false, 0, 0},
- {kVClimb_2d, kNChute_2d, kSTUpchute_2d, false, 0, 0},
- {kVLook_2d, kNWall_2d, kSTLookchute_2d, false, 0, 0},
+ {kVLook_2d, kNCrate_2d, kSTSlookbox_2d, false, 0, 0},
+ {kVInto_2d, kNCrate_2d, kSTSgetinbox_2d, false, 0, 0},
+ {kVLook_2d, kNChute_2d, kSTLookchute_2d, false, 0, 0},
+ {kVLook_2d, kNHole_2d, kSTLookchute_2d, false, 0, 0},
+ {kVClimb_2d, kNChute_2d, kSTUpchute_2d, false, 0, 0},
+ {kVLook_2d, kNWall_2d, kSTLookchute_2d, false, 0, 0},
{kVInto_2d, kNDoor_2d, kSTMorespecific_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen34_desc_2d[] = { // hall3
- {kVLook_2d, 0, kSTLookhall_2d, true, 0, 0},
+ {kVLook_2d, 0, kSTLookhall_2d, true, 0, 0},
{kVLook_2d, kNMirror_2d, kSTNospecial_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen35_desc_2d[] = { // Organ
- {kVLook_2d, 0, kSTS35look_2d, true, DONT_CARE, 0},
+ {kVLook_2d, 0, kSTS35look_2d, true, DONT_CARE, 0},
{kVLook_2d, kNOrgan_2d, kSTNospecial_2d, false, DONT_CARE, 0},
{kVPlay_2d, kNOrgan_2d, kSTPlayorgan_2d, false, DONT_CARE, 0},
- {kVListen_2d, 0, kSTHearorgan_2d, false, 0, 0},
- {kVListen_2d, 0, kSTHearlaugh_2d, false, 1, 0},
+ {kVListen_2d, 0, kSTHearorgan_2d, false, 0, 0},
+ {kVListen_2d, 0, kSTHearlaugh_2d, false, 1, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen36_desc_2d[] = { // Hestroom
- {kVLook_2d, 0, kSTLookhest_2d, true, 0, 0},
- {kVTake_2d, kNBook_2d, kSTS36book_2d, false, 0, 0},
- {kVRead_2d, kNBook_2d, kSTS36book_2d, false, 0, 0},
- {kVLook_2d, kNBook_2d, kSTS36book_2d, false, 0, 0},
- {kVLook_2d, kNTable_2d, kSTS36table_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTLookhest_2d, true, 0, 0},
+ {kVTake_2d, kNBook_2d, kSTS36book_2d, false, 0, 0},
+ {kVRead_2d, kNBook_2d, kSTS36book_2d, false, 0, 0},
+ {kVLook_2d, kNBook_2d, kSTS36book_2d, false, 0, 0},
+ {kVLook_2d, kNTable_2d, kSTS36table_2d, false, 0, 0},
{kVTalk_2d, kNHester_2d, kSTTalkhester_2d, false, 0, 0},
- {kVLook_2d, kNWindow_2d, kSTS6garden_2d, false, 0, 0},
+ {kVLook_2d, kNWindow_2d, kSTS6garden_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t screen37_desc_2d[] = { // Retupmoc
- {kVLook_2d, 0, kSTS37look_2d, true, 0, 0},
- {kVLift_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
+ {kVLook_2d, 0, kSTS37look_2d, true, 0, 0},
+ {kVLift_2d, kNRock_2d, kSTNopurps_2d, false, 0, 0},
{kVLook_2d, kNRock_2d, kSTNospecial_2d, false, 0, 0},
- {kVUnder_2d, kNRock_2d, kSTDull2_2d, false, 0, 0},
- {kVTalk_2d, kNDoctor_2d, kSTPleasego_2d, false, 0, 0},
+ {kVUnder_2d, kNRock_2d, kSTDull2_2d, false, 0, 0},
+ {kVTalk_2d, kNDoctor_2d, kSTPleasego_2d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
@@ -3965,68 +3984,68 @@ background_t catchall_3d[] = { // Generally applicable phrases
{kVNaughty_3d, kNPenny_3d, kSTHeadache_3d, false, DONT_CARE, 0},
{kVInto_3d, kNWindow_3d, kSTThruwindow_3d, false, DONT_CARE, 0},
{kVOutof_3d, kNWindow_3d, kSTThruwindow_3d, false, DONT_CARE, 0},
- {kVJump_3d, 0, kSTSjump_3d, false, DONT_CARE, 0},
- {kVGo_3d, 0, kSTTrywalk_3d, false, DONT_CARE, 0},
- {kVInto_3d, 0, kSTTrywalk_3d, false, DONT_CARE, 0},
- {kVClimb_3d, 0, kSTSclimb_3d, false, DONT_CARE, 0},
- {kVShout_3d, 0, kSTNothing_3d, false, DONT_CARE, 0},
- {kVTalk_3d, 0, kSTStalk_3d, false, DONT_CARE, 0},
- {kVSwitch_3d, 0, kSTMorespecific_3d, false, DONT_CARE, 0},
- {kVUse_3d, 0, kSTMorespecific_3d, false, DONT_CARE, 0},
- {kVThrow_3d, 0, kSTNopurps_3d, false, DONT_CARE, 0},
- {kVRude_3d, 0, kSTSrude_3d, false, DONT_CARE, 0},
- {kVAttack_3d, 0, kSTSattack_3d, false, DONT_CARE, 0},
- {kVBreak_3d, 0, kSTSbreak_3d, false, DONT_CARE, 0},
- {kVListen_3d, 0, kSTQuiet_3d, false, DONT_CARE, 0},
- {kVSmell_3d, 0, kSTAroma_3d, false, DONT_CARE, 0},
- {kVQuery_3d, 0, kSTNoidea_3d, false, DONT_CARE, 0},
+ {kVJump_3d, 0, kSTSjump_3d, false, DONT_CARE, 0},
+ {kVGo_3d, 0, kSTTrywalk_3d, false, DONT_CARE, 0},
+ {kVInto_3d, 0, kSTTrywalk_3d, false, DONT_CARE, 0},
+ {kVClimb_3d, 0, kSTSclimb_3d, false, DONT_CARE, 0},
+ {kVShout_3d, 0, kSTNothing_3d, false, DONT_CARE, 0},
+ {kVTalk_3d, 0, kSTStalk_3d, false, DONT_CARE, 0},
+ {kVSwitch_3d, 0, kSTMorespecific_3d, false, DONT_CARE, 0},
+ {kVUse_3d, 0, kSTMorespecific_3d, false, DONT_CARE, 0},
+ {kVThrow_3d, 0, kSTNopurps_3d, false, DONT_CARE, 0},
+ {kVRude_3d, 0, kSTSrude_3d, false, DONT_CARE, 0},
+ {kVAttack_3d, 0, kSTSattack_3d, false, DONT_CARE, 0},
+ {kVBreak_3d, 0, kSTSbreak_3d, false, DONT_CARE, 0},
+ {kVListen_3d, 0, kSTQuiet_3d, false, DONT_CARE, 0},
+ {kVSmell_3d, 0, kSTAroma_3d, false, DONT_CARE, 0},
+ {kVQuery_3d, 0, kSTNoidea_3d, false, DONT_CARE, 0},
{kVLook_3d, kNSky_3d, kSTFalling_3d, false, DONT_CARE, 0},
{kVLook_3d, kNWall_3d, kSTDull_3d, false, DONT_CARE, 0},
{kVLook_3d, kNGround_3d, kSTDull_3d, false, DONT_CARE, 0},
- {kVHelp_3d, 0, kSTShelp_3d, false, DONT_CARE, 0},
- {kVMagic_3d, 0, kSTSmagic_3d, false, DONT_CARE, 0},
- {kVWish_3d, 0, kSTSmagic_3d, false, DONT_CARE, 0},
- {kVDig_3d, 0, kSTSdig_3d, false, DONT_CARE, 0},
- {kVNaughty_3d, 0, kSTSnaughty_3d, false, DONT_CARE, 0},
- {kVKnock_3d, 0, kSTNoanswer_3d, false, DONT_CARE, 0},
+ {kVHelp_3d, 0, kSTShelp_3d, false, DONT_CARE, 0},
+ {kVMagic_3d, 0, kSTSmagic_3d, false, DONT_CARE, 0},
+ {kVWish_3d, 0, kSTSmagic_3d, false, DONT_CARE, 0},
+ {kVDig_3d, 0, kSTSdig_3d, false, DONT_CARE, 0},
+ {kVNaughty_3d, 0, kSTSnaughty_3d, false, DONT_CARE, 0},
+ {kVKnock_3d, 0, kSTNoanswer_3d, false, DONT_CARE, 0},
{kVOpen_3d, kNDoor_3d, kSTWontopen_3d, false, DONT_CARE, 0},
{kVUnlock_3d, kNDoor_3d, kSTCantunlock_3d, false, DONT_CARE, 0},
{kVLook_3d, kNDoor_3d, kSTDull_3d, false, DONT_CARE, 0},
- {kVHello_3d, 0, kSTHi_3d, false, DONT_CARE, 0},
- {kVGive_3d, 0, kSTNothanks_3d, false, DONT_CARE, 0},
- {kVShout_3d, 0, kSTNoanswer_3d, false, DONT_CARE, 0},
- {kVUndress_3d, 0, kSTSundress_3d, false, DONT_CARE, 0},
- {kVSit_3d, 0, kSTStired_3d, false, DONT_CARE, 0},
- {kVFeed_3d, 0, kSTNothanks_3d, false, DONT_CARE, 0},
+ {kVHello_3d, 0, kSTHi_3d, false, DONT_CARE, 0},
+ {kVGive_3d, 0, kSTNothanks_3d, false, DONT_CARE, 0},
+ {kVShout_3d, 0, kSTNoanswer_3d, false, DONT_CARE, 0},
+ {kVUndress_3d, 0, kSTSundress_3d, false, DONT_CARE, 0},
+ {kVSit_3d, 0, kSTStired_3d, false, DONT_CARE, 0},
+ {kVFeed_3d, 0, kSTNothanks_3d, false, DONT_CARE, 0},
{kVTake_3d, kNVine_3d, kSTNopurps_3d, false, DONT_CARE, 0},
{kVClimb_3d, kNJungle_3d, kSTNopurps_3d, false, DONT_CARE, 0},
{kVLook_3d, kNJungle_3d, kSTLookjungle_3d, false, DONT_CARE, 0},
{kVPut_3d, kNFire_3d, kSTNopurps_3d, false, DONT_CARE, 0},
- {kVSwim_3d, 0, kSTCantswim_3d, false, DONT_CARE, 0},
+ {kVSwim_3d, 0, kSTCantswim_3d, false, DONT_CARE, 0},
{kVTake_3d, kNMouse_3d, kSTCantcatch_3d, false, DONT_CARE, 0},
{kVLook_3d, kNMouse_3d, kSTNospecial_3d, false, DONT_CARE, 0},
{0, 0, 0, false, 0, 0}
};
background_t crash_desc_3d[] = { // At the crash site
- {kVLook_3d, 0, kSTLookcrash_3d, false, 0, 0},
- {kVRepair_3d, kNPlane_3d, kSTNopurps_3d, false, 0, 0},
- {kVFly_3d, kNPlane_3d, kSTNopurps_3d, false, 0, 0},
- {kVInto_3d, 0, kSTMorespecific_3d, true, 0, 0},
+ {kVLook_3d, 0, kSTLookcrash_3d, false, 0, 0},
+ {kVRepair_3d, kNPlane_3d, kSTNopurps_3d, false, 0, 0},
+ {kVFly_3d, kNPlane_3d, kSTNopurps_3d, false, 0, 0},
+ {kVInto_3d, 0, kSTMorespecific_3d, true, 0, 0},
{kVOpen_3d, kNDoor_3d, kSTOpenplanedoor_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t plane_desc_3d[] = { // Inside the plane
- {kVLook_3d, 0, kSTLookplane_3d, true, 0, 0},
- {kVSearch_3d, 0, kSTSaylook_3d, false, 0, 0},
- {kVInto_3d, 0, kSTYouarein_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookplane_3d, true, 0, 0},
+ {kVSearch_3d, 0, kSTSaylook_3d, false, 0, 0},
+ {kVInto_3d, 0, kSTYouarein_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t web_desc_3d[] = { // At the spider's web
- {kVLook_3d, 0, kSTLookweb_3d, true, 0, 0},
- {kVTake_3d, kNNative_3d, kSTTakegirl_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookweb_3d, true, 0, 0},
+ {kVTake_3d, kNNative_3d, kSTTakegirl_3d, false, 0, 0},
{kVLook_3d, kNWeb_3d, kSTLookatweb_3d, false, 0, 0},
{kVTake_3d, kNPenny_3d, kSTTakepenny_3d, false, 0, 0},
{kVTalk_3d, kNPenny_3d, kSTTalkpenny_3d, false, 0, 0},
@@ -4034,24 +4053,24 @@ background_t web_desc_3d[] = { // At the spider's web
};
background_t wfall_desc_3d[] = { // Waterfall and stream
- {kVLook_3d, 0, kSTLookwfall_3d, true, 0, 0},
- {kVLook_3d, kNWater_3d, kSTLookwfall_3d, false, 0, 0},
- {kVCross_3d, kNWater_3d, kSTCantcross_3d, false, 0, 0},
- {kVListen_3d, 0, kSTListenfall_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookwfall_3d, true, 0, 0},
+ {kVLook_3d, kNWater_3d, kSTLookwfall_3d, false, 0, 0},
+ {kVCross_3d, kNWater_3d, kSTCantcross_3d, false, 0, 0},
+ {kVListen_3d, 0, kSTListenfall_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t wfall_b_desc_3d[] = { // Same as above but no water
- {kVLook_3d, 0, kSTLookwfall_b_3d, true, 0, 0},
+ {kVLook_3d, 0, kSTLookwfall_b_3d, true, 0, 0},
{kVLook_3d, kNWater_3d, kSTLookwfall_b_3d, false, 0, 0},
- {kVCross_3d, kNWater_3d, kSTToomuddy_3d, false, 0, 0},
+ {kVCross_3d, kNWater_3d, kSTToomuddy_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t wbase_desc_3d[] = { // Base of waterfall
- {kVLook_3d, 0, kSTLookwbase_3d, true, 0, 0},
+ {kVLook_3d, 0, kSTLookwbase_3d, true, 0, 0},
{kVLook_3d, kNWater_3d, kSTLookwbase_3d, false, 0, 0},
- {kVCross_3d, kNWater_3d, kSTToomuddy_3d, false, 0, 0},
+ {kVCross_3d, kNWater_3d, kSTToomuddy_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
@@ -4061,62 +4080,62 @@ background_t path_ul_desc_3d[] = { // Path at left of spider's web
};
background_t bridge_desc_3d[] = { // At the bridge
- {kVLook_3d, 0, kSTLookbridge1_3d, true, 0, 0},
- {kVSwing_3d, 0, kSTSwingbridge_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookbridge1_3d, true, 0, 0},
+ {kVSwing_3d, 0, kSTSwingbridge_3d, false, 0, 0},
{kVTake_3d, kNVine_3d, kSTGetbridgevines_3d, false, 0, 0},
- {kVTie_3d, kNThem_3d, kSTMorespecific_3d, false, 0, 0},
+ {kVTie_3d, kNThem_3d, kSTMorespecific_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t bridge2_desc_3d[] = { // At the bridge
- {kVLook_3d, 0, kSTLookbridge2_3d, true, 0, 0},
+ {kVLook_3d, 0, kSTLookbridge2_3d, true, 0, 0},
{kVSwing_3d, 0, kSTSwingbridge_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t stream_desc_3d[] = { // stream with vines crossing
- {kVLook_3d, 0, kSTLookstream1_3d, true, 0, 0},
+ {kVLook_3d, 0, kSTLookstream1_3d, true, 0, 0},
{kVSwing_3d, 0, kSTMorespecific_3d, false, 0, 0},
- {kVCross_3d, 0, kSTStep1_3d, false, 0, 0},
+ {kVCross_3d, 0, kSTStep1_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t stream2_desc_3d[] = { // Stream with elephant sitting in it
- {kVLook_3d, 0, kSTLookstream2_3d, true, 0, 0},
- {kVSwing_3d, 0, kSTCantswing_3d, false, 0, 0},
- {kVLook_3d, kNElephant_3d, kSTLookele2_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookstream2_3d, true, 0, 0},
+ {kVSwing_3d, 0, kSTCantswing_3d, false, 0, 0},
+ {kVLook_3d, kNElephant_3d, kSTLookele2_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t village_desc_3d[] = { // Long shot of village
- {kVLook_3d, 0, kSTLookvillage_3d, true, 0, 0},
- {kVTake_3d, kNFood_3d, kSTTakething_3d, false, 0, 0},
- {kVLook_3d, kNFood_3d, kSTTakething_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookvillage_3d, true, 0, 0},
+ {kVTake_3d, kNFood_3d, kSTTakething_3d, false, 0, 0},
+ {kVLook_3d, kNFood_3d, kSTTakething_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t hut_out_desc_3d[] = { // Outside witch doctor's hut
- {kVLook_3d, 0, kSTLookhut_out_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookhut_out_3d, false, 0, 0},
{kVLook_3d, kNDocbits_3d, kSTLookdocbits_3d, false, 0, 0},
{kVTake_3d, kNDocbits_3d, kSTTakedocbits_3d, false, 0, 0},
- {kVLook_3d, kNSpider_3d, kSTLookspider_3d, false, 0, 0},
- {kVTake_3d, kNSpider_3d, kSTTakespider_3d, false, 0, 0},
- {kVLook_3d, kNSnake_3d, kSTLooksnake_3d, false, 0, 0},
- {kVTake_3d, kNSnake_3d, kSTTakesnake_3d, false, 0, 0},
- {kVSearch_3d, kNWindow_3d, kSTLookinhut_3d, false, 0, 0},
- {kVLook_3d, kNWindow_3d, kSTLookinhut_3d, false, 0, 0},
- {kVSearch_3d, kNHut_3d, kSTLookinhut_3d, false, 0, 0},
+ {kVLook_3d, kNSpider_3d, kSTLookspider_3d, false, 0, 0},
+ {kVTake_3d, kNSpider_3d, kSTTakespider_3d, false, 0, 0},
+ {kVLook_3d, kNSnake_3d, kSTLooksnake_3d, false, 0, 0},
+ {kVTake_3d, kNSnake_3d, kSTTakesnake_3d, false, 0, 0},
+ {kVSearch_3d, kNWindow_3d, kSTLookinhut_3d, false, 0, 0},
+ {kVLook_3d, kNWindow_3d, kSTLookinhut_3d, false, 0, 0},
+ {kVSearch_3d, kNHut_3d, kSTLookinhut_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t hut_in_desc_3d[] = { // Inside hut
// States: 0 imprisoned_3d, 1 doctor incapacitated
- {kVLook_3d, 0, kSTLookhut_in_3d, true, 0, 0},
- {kVLook_3d, 0, kSTLookhut_in2_3d, true, 1, 0},
- {kVLook_3d, kNDoctor_3d, kSTLookhut_in2_3d, false, 1, 0},
- {kVTake_3d, 0, kSTTakeincage_3d, false, 0, 0},
- {kVTake_3d, kNDoctor_3d, kSTTakedoctor0_3d, false, 0, 0},
- {kVTake_3d, kNDoctor_3d, kSTTakedoctor1_3d, false, 1, 0},
+ {kVLook_3d, 0, kSTLookhut_in_3d, true, 0, 0},
+ {kVLook_3d, 0, kSTLookhut_in2_3d, true, 1, 0},
+ {kVLook_3d, kNDoctor_3d, kSTLookhut_in2_3d, false, 1, 0},
+ {kVTake_3d, 0, kSTTakeincage_3d, false, 0, 0},
+ {kVTake_3d, kNDoctor_3d, kSTTakedoctor0_3d, false, 0, 0},
+ {kVTake_3d, kNDoctor_3d, kSTTakedoctor1_3d, false, 1, 0},
{kVLook_3d, kNDocbits_3d, kSTLookdocbits_3d, false, DONT_CARE, 0},
{kVTake_3d, kNDocbits_3d, kSTTakedocbits_3d, false, DONT_CARE, 0},
{kVLook_3d, kNSpider_3d, kSTLookspider_3d, false, DONT_CARE, 0},
@@ -4124,27 +4143,27 @@ background_t hut_in_desc_3d[] = { // Inside hut
{kVLook_3d, kNSnake_3d, kSTLooksnake_3d, false, DONT_CARE, 0},
{kVTake_3d, kNSnake_3d, kSTTakesnake_3d, false, DONT_CARE, 0},
{kVLook_3d, kNWindow_3d, kSTLookouthut_3d, false, DONT_CARE, 0},
- {kVLook_3d, kNShelfbits_3d, kSTLookshelfbits_3d, false, 0, 0},
- {kVLook_3d, kNShelfbits_3d, kSTLookshelfbits2_3d, false, 1, 0},
- {kVTake_3d, kNShelfbits_3d, kSTTakeshelfbits_3d, false, 1, 0},
- {kVDrink_3d, kNShelfbits_3d, kSTTakeshelfbits_3d, false, 1, 0},
- {kVLook_3d, kNBottles_3d, kSTLookshelfbits_3d, false, 0, 0},
- {kVLook_3d, kNBottles_3d, kSTLookshelfbits2_3d, false, 1, 0},
- {kVTake_3d, kNBottles_3d, kSTTakeshelfbits_3d, false, 1, 0},
- {kVDrink_3d, kNBottles_3d, kSTTakeshelfbits_3d, false, 1, 0},
- {kVSearch_3d, 0, kSTCantlookin_3d, false, 0, 0},
- {kVSearch_3d, kNFire_3d, kSTLookinfire_3d, false, 1, 0},
+ {kVLook_3d, kNShelfbits_3d, kSTLookshelfbits_3d, false, 0, 0},
+ {kVLook_3d, kNShelfbits_3d, kSTLookshelfbits2_3d, false, 1, 0},
+ {kVTake_3d, kNShelfbits_3d, kSTTakeshelfbits_3d, false, 1, 0},
+ {kVDrink_3d, kNShelfbits_3d, kSTTakeshelfbits_3d, false, 1, 0},
+ {kVLook_3d, kNBottles_3d, kSTLookshelfbits_3d, false, 0, 0},
+ {kVLook_3d, kNBottles_3d, kSTLookshelfbits2_3d, false, 1, 0},
+ {kVTake_3d, kNBottles_3d, kSTTakeshelfbits_3d, false, 1, 0},
+ {kVDrink_3d, kNBottles_3d, kSTTakeshelfbits_3d, false, 1, 0},
+ {kVSearch_3d, 0, kSTCantlookin_3d, false, 0, 0},
+ {kVSearch_3d, kNFire_3d, kSTLookinfire_3d, false, 1, 0},
{kVLook_3d, kNFire_3d, kSTLookfire_3d, false, DONT_CARE, 0},
- {kVTalk_3d, kNDoctor_3d, kSTTalkdoc_3d, false, 0, 0},
- {kVTalk_3d, kNDoctor_3d, kSTTalkdoc2_3d, false, 1, 0},
+ {kVTalk_3d, kNDoctor_3d, kSTTalkdoc_3d, false, 0, 0},
+ {kVTalk_3d, kNDoctor_3d, kSTTalkdoc2_3d, false, 1, 0},
{kVSearch_3d, kNMouse_3d, kSTLookinhole_3d, false, DONT_CARE, 0},
{kVTalk_3d, kNMouse_3d, kSTTalkmouse_3d, false, DONT_CARE, 0},
- {kVUnlock_3d, kNCdoor_3d, kSTPicklock_3d, false, 0, 0},
- {kVTake_3d, kNDoorlock_3d, kSTPicklock_3d, false, 0, 0},
+ {kVUnlock_3d, kNCdoor_3d, kSTPicklock_3d, false, 0, 0},
+ {kVTake_3d, kNDoorlock_3d, kSTPicklock_3d, false, 0, 0},
{kVGive_3d, kNMouse_3d, kSTGivemouse_3d, false, DONT_CARE, 0},
{kVThrow_3d, kNCheese_3d, kSTGivemouse_3d, false, DONT_CARE, 0},
- {kVInto_3d, kNFire_3d, kSTGetinpot_3d, false, 1, 0},
- {kVTake_3d, kNNative_3d, kSTTakenative_3d, false, 0, 0},
+ {kVInto_3d, kNFire_3d, kSTGetinpot_3d, false, 1, 0},
+ {kVTake_3d, kNNative_3d, kSTTakenative_3d, false, 0, 0},
{kVShoot_3d, kNDoctor_3d, kSTMissed_3d, false, DONT_CARE, 0},
{kVBlow_3d, kNDoctor_3d, kSTMissed_3d, false, DONT_CARE, 0},
{kVUse_3d, kNPipe_3d, kSTMissed_3d, false, DONT_CARE, 0},
@@ -4153,11 +4172,11 @@ background_t hut_in_desc_3d[] = { // Inside hut
};
background_t garden_desc_3d[] = { // The secret garden
- {kVLook_3d, 0, kSTLookgarden_3d, true, 0, 0},
- {kVLook_3d, kNOrchid_3d, kSTLookorchid_3d, false, 0, 0},
- {kVTake_3d, kNOrchid_3d, kSTTakeorchid_3d, false, 0, 0},
- {kVCross_3d, 0, kSTCrossgarden_3d, false, 0, 0},
- {kVLook_3d, kNWater_3d, kSTLookgarden_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookgarden_3d, true, 0, 0},
+ {kVLook_3d, kNOrchid_3d, kSTLookorchid_3d, false, 0, 0},
+ {kVTake_3d, kNOrchid_3d, kSTTakeorchid_3d, false, 0, 0},
+ {kVCross_3d, 0, kSTCrossgarden_3d, false, 0, 0},
+ {kVLook_3d, kNWater_3d, kSTLookgarden_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
@@ -4177,30 +4196,30 @@ background_t cliff_desc_3d[] = { // Lower cliff path
};
background_t camp_desc_3d[] = { // Camp scene in village
- {kVLook_3d, 0, kSTLookcamp_3d, true, 0, 0},
- {kVLook_3d, kNFire_3d, kSTLookhyena_3d, false, 0, 0},
- {kVLook_3d, kNPole_3d, kSTLookpole_3d, false, 0, 0},
- {kVBehind_3d, kNHut_3d, kSTBehindhut_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookcamp_3d, true, 0, 0},
+ {kVLook_3d, kNFire_3d, kSTLookhyena_3d, false, 0, 0},
+ {kVLook_3d, kNPole_3d, kSTLookpole_3d, false, 0, 0},
+ {kVBehind_3d, kNHut_3d, kSTBehindhut_3d, false, 0, 0},
{kVSearch_3d, kNWindow_3d, kSTLookintohut_3d, false, 0, 0},
{kVSearch_3d, kNHut_3d, kSTLookintohut_3d, false, 0, 0},
- {kVLook_3d, kNHut_3d, kSTLookhut_3d, false, 0, 0},
+ {kVLook_3d, kNHut_3d, kSTLookhut_3d, false, 0, 0},
{kVLook_3d, kNWindow_3d, kSTLookintohut_3d, false, 0, 0},
- {kVEat_3d, 0, kSTEatroast_3d, false, 0, 0},
- {kVTake_3d, kNFood_3d, kSTEatroast_3d, false, 0, 0},
- {kVInto_3d, kNFire_3d, kSTIntofire_3d, false, 0, 0},
- {kVTake_3d, kNFire_3d, kSTIntofire_3d, false, 0, 0},
- {kVTake_3d, kNNative_3d, kSTTakenative_3d, false, 0, 0},
- {kVTake_3d, kNPipe_3d, kSTMakeoffer_3d, false, 0, 0},
+ {kVEat_3d, 0, kSTEatroast_3d, false, 0, 0},
+ {kVTake_3d, kNFood_3d, kSTEatroast_3d, false, 0, 0},
+ {kVInto_3d, kNFire_3d, kSTIntofire_3d, false, 0, 0},
+ {kVTake_3d, kNFire_3d, kSTIntofire_3d, false, 0, 0},
+ {kVTake_3d, kNNative_3d, kSTTakenative_3d, false, 0, 0},
+ {kVTake_3d, kNPipe_3d, kSTMakeoffer_3d, false, 0, 0},
{kVGive_3d, kNBouillon_3d, kSTNonecarried_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
background_t turn_desc_3d[] = { // Turnaround path
- {kVLook_3d, 0, kSTLookturn_3d, true, DONT_CARE, 0},
- {kVUnder_3d, kNRock_3d, kSTUnderrock_3d, false, 0, 0},
- {kVLook_3d, kNRock_3d, kSTLookrock_3d, false, 0, 0},
- {kVRide_3d, kNRock_3d, kSTOntorock_3d, false, 0, 0},
- {kVClimb_3d, kNRock_3d, kSTOntorock_3d, false, 0, 0},
+ {kVLook_3d, 0, kSTLookturn_3d, true, DONT_CARE, 0},
+ {kVUnder_3d, kNRock_3d, kSTUnderrock_3d, false, 0, 0},
+ {kVLook_3d, kNRock_3d, kSTLookrock_3d, false, 0, 0},
+ {kVRide_3d, kNRock_3d, kSTOntorock_3d, false, 0, 0},
+ {kVClimb_3d, kNRock_3d, kSTOntorock_3d, false, 0, 0},
{0, 0, 0, false, 0, 0}
};
@@ -4211,8 +4230,8 @@ background_t slope_desc_3d[] = { // Slope between cliff and stream
background_t path_desc_3d[] = { // Path containing elephant
// States: 0 Elephant present_3d, 1 - Elephant not present
- {kVLook_3d, 0, kSTLookpath2_1_3d, true, 0, 0},
- {kVLook_3d, 0, kSTLookpath2_2_3d, true, 1, 0},
+ {kVLook_3d, 0, kSTLookpath2_1_3d, true, 0, 0},
+ {kVLook_3d, 0, kSTLookpath2_2_3d, true, 1, 0},
{kVRide_3d, kNElephant_3d, kSTRideelephant_3d, false, 0, 0},
{kVTake_3d, kNElephant_3d, kSTGetelephant_3d, false, 0, 0},
{kVShow_3d, kNMouse_3d, kSTShowmouse_3d, false, 0, 0},
@@ -4220,8 +4239,8 @@ background_t path_desc_3d[] = { // Path containing elephant
};
background_t cave_desc_3d[] = { // Cave mouth
- {kVLook_3d, 0, kSTLookcave1_3d, true, 0, 0},
- {kVLook_3d, 0, kSTLookcave2_3d, true, 1, 0},
+ {kVLook_3d, 0, kSTLookcave1_3d, true, 0, 0},
+ {kVLook_3d, 0, kSTLookcave2_3d, true, 1, 0},
{kVAttack_3d, kNGhost_3d, kSTAttackghost_3d, false, 0, 0},
{kVBreak_3d, kNGhost_3d, kSTAttackghost_3d, false, 0, 0},
{kVShoot_3d, kNGhost_3d, kSTAttackghost_3d, false, 0, 0},
@@ -4282,70 +4301,70 @@ byte points_3d[] = {
12, 2
};
-cmd blowdw_1w = {kVBlow_1w, 0, kDTnull, 0, 0, kDTnull, kDTokblow_1w, kALblowdw_1w};
-cmd breakpkin_1w = {kVBreak_1w, 0, kDTnull, 0, 1, kDTnull, kDTokgen_1w, kALpkin_1w};
-cmd brkrope_1w = {kVBreak_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsrbreak_1w, 0};
-cmd closebolt_1w = {kVClose_1w, 0, kDTnull, 2, 1, kDTsclosed_1w, kDTsclosebolt_1w, 0};
-cmd closedoor1_1w = {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, kALclosedoor1_1w};
-cmd closedoor2_1w = {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, 0};
-cmd closedoor3_1w = {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, 0};
-cmd closedoor4_1w = {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, kALclosedoor4_1w};
-cmd closetrap_1w = {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, kALclosetrap_1w};
-cmd closewdoors_1w = {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, kALclosewdoors_1w};
-cmd cutrope_1w = {kVCut_1w, kRknife_1w, kDTrnoknife_1w, 0, 1, kDTsnocut_1w, kDTscut_1w, kALcutrope_1w};
-cmd dropmask_1w = {kVDrop_1w, 0, kDTnull, 0, 0, kDTsworn3_1w, kDTnull, kALdropmask_1w};
-cmd droppkin_1w = {kVDrop_1w, kRpkin_1w, kDTnocgen_1w, 0, 1, kDTnull, kDTnull, kALpkin_1w};
-cmd eatchop_1w = {kVEat_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALeatchop2_1w};
-cmd getchop_1w = {kVTake_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALgetchop_1w};
-cmd getdw_1w = {kVTake_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALcupbdw_1w};
-cmd getinboat_1w = {kVInto_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgetinboat_1w};
-cmd getknife_1w = {kVTake_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALcupbpk_1w};
-cmd getoilcan_1w = {kVTake_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALshedoil_1w};
-cmd getoutboat_1w = {kVOutof_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgetoutboat_1w};
-cmd givegold_1w = {kVGive_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALgold_1w};
-cmd hiderock_1w = {kVHide_1w, 0, kDTnull, 0, 1, kDTsrock_1w, kDTnull, kALrock_1w};
-cmd kickpkin_1w = {kVAttack_1w, 0, kDTnull, 0, 1, kDTnull, kDTokgen_1w, kALpkin_1w};
-cmd knock_1w = {kVKnock_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsNobody_1w, 0};
-cmd lockbolt_1w = {kVLock_1w, 0, kDTnull, 2, 1, kDTsclosed_1w, kDTsclosebolt_1w, 0};
-cmd lockdoor_1w = {kVLock_1w, kRkey_1w, kDTnockey_1w, 1, 0, kDTslock_1w, kDTokgen_1w, kALclosedoor1_1w};
-cmd lookcupb_1w = {kVLook_1w, kRcandle_1w, kDTnoccandle_1w, DONT_CARE, 0, kDTnull, kDTnull, kALlookcupb_1w};
-cmd lookshed_1w = {kVLook_1w, kRcandle_1w, kDTnoccandle_1w, 0, 0, kDTsnoseeoil_1w, kDTsseeoil_1w, kALshedoil_1w};
-cmd movecarp1_1w = {kVMove_1w, 0, kDTnull, 0, 0, kDTnull, kDTsrollrug_1w, kALmovecarp_1w};
-cmd movecarp2_1w = {kVLift_1w, 0, kDTnull, 0, 0, kDTnull, kDTsrollrug_1w, kALmovecarp_1w};
-cmd movecarp3_1w = {kVUnder_1w, 0, kDTnull, 0, 0, kDTnull, kDTsrollrug_1w, kALmovecarp_1w};
-cmd offmask_1w = {kVOff_1w, 0, kDTnull, 1, 0, kDTsworn2_1w, kDTokgen_1w, kALswapmask_1w};
-cmd oilbolt_1w = {kVOil_1w, kRoil_1w, kDTrnooil_1w, 0, 1, kDTsoiled_1w, kDTsoilbolt_1w, 0};
-cmd omattack_1w = {kVAttack_1w, 0, kDTnull, 0, 0, kDTnull, kDTsomattack_1w, 0};
-cmd ombreak_1w = {kVBreak_1w, 0, kDTnull, 0, 0, kDTnull, kDTsomattack_1w, 0};
-cmd omtalk_1w = {kVTalk_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALoldman_1w};
-cmd openbolt_1w = {kVOpen_1w, 0, kDTnull, 1, 2, kDTsstuck_1w, kDTsopenbolt_1w, 0};
-cmd opendoor1_1w = {kVOpen_1w, kRkey_1w, kDTslocked_1w, 0, 1, kDTsopen_1w, kDTsunlock_1w, kALopendoor1_1w};
-cmd opendoor2_1w = {kVOpen_1w, 0, kDTnull, 0, 1, kDTsopen_1w, kDTnull, kALopendoor2_1w};
-cmd opendoor3_1w = {kVOpen_1w, 0, kDTnull, 0, 1, kDTsopen_1w, kDTnull, kALopendoor3_1w};
-cmd opendoor4_1w = {kVOpen_1w, 0, kDTnull, 0, 0, kDTsopen_1w, kDTnull, kALopendoor4_1w};
-cmd openpkin_1w = {kVOpen_1w, 0, kDTnull, 0, 1, kDTnull, kDTsopenpkin_1w, kALpkin_1w};
-cmd opentrap_1w = {kVOpen_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALopentrap_1w};
-cmd openwdoors_1w = {kVOpen_1w, 0, kDTnull, 0, 1, kDTsopen_1w, kDTnull, kALopenwdoors_1w};
-cmd plugbung_1w = {kVPlug_1w, kRbung_1w, kDTnocgen_1w, 0, 1, kDTnull, kDTsplug_1w, kALplugbung_1w};
-cmd pushboat_1w = {kVPush_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALpushboat_1w};
-cmd pushigor_1w = {kVPush_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALigor_1w};
-cmd ruboilcan_1w = {kVRub_1w, 0, kDTnull, 0, 0, kDTnull, kDTsruboil_1w, 0};
-cmd talkdrac_1w = {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkdrac_1w};
-cmd talkfrank_1w = {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkfrank_1w};
-cmd talkgwen_1w = {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkgwen_1w};
-cmd talkhood_1w = {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkhood_1w};
-cmd talkpeahd_1w = {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkpeahd_1w};
-cmd talkslime_1w = {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkslime_1w};
-cmd throwchop_1w = {kVThrowit_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALthrowchop_1w};
-cmd unlkdoor_1w = {kVUnlock_1w, kRkey_1w, kDTnockey_1w, 0, 1, kDTsunlocked_1w, kDTsunlock_1w, kALopendoor1_1w};
-cmd unlock_1w = {kVUnlock_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsUnlocked_1w, 0};
-cmd unlockbolt_1w = {kVUnlock_1w, 0, kDTnull, 1, 2, kDTsstuck_1w, kDTsopenbolt_1w, 0};
-cmd untierope_1w = {kVUntie_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsuntie_1w, 0};
-cmd useboat_1w = {kVMakeUseOf_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALuseboat_1w};
-cmd usemask_1w = {kVMakeUseOf_1w, kRmask_1w, kDTnocgen_1w, DONT_CARE, 0, kDTnull, kDTnull, kALusemask_1w};
-cmd wearmask_1w = {kVWear_1w, kRmask_1w, kDTnocgen_1w, 0, 1, kDTsworn1_1w, kDTokgen_1w, kALswapmask_1w};
-
-cmd emptyCmd = {0, 0, kDTnull, 0, 0, kDTnull, kDTnull, 0};
+#define blowdw_1w {kVBlow_1w, 0, kDTnull, 0, 0, kDTnull, kDTokblow_1w, kALblowdw_1w}
+#define breakpkin_1w {kVBreak_1w, 0, kDTnull, 0, 1, kDTnull, kDTokgen_1w, kALpkin_1w}
+#define brkrope_1w {kVBreak_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsrbreak_1w, 0}
+#define closebolt_1w {kVClose_1w, 0, kDTnull, 2, 1, kDTsclosed_1w, kDTsclosebolt_1w, 0}
+#define closedoor1_1w {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, kALclosedoor1_1w}
+#define closedoor2_1w {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, 0}
+#define closedoor3_1w {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, 0}
+#define closedoor4_1w {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, kALclosedoor4_1w}
+#define closetrap_1w {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, kALclosetrap_1w}
+#define closewdoors_1w {kVClose_1w, 0, kDTnull, 1, 0, kDTsclosed_1w, kDTnull, kALclosewdoors_1w}
+#define cutrope_1w {kVCut_1w, kRknife_1w, kDTrnoknife_1w, 0, 1, kDTsnocut_1w, kDTscut_1w, kALcutrope_1w}
+#define dropmask_1w {kVDrop_1w, 0, kDTnull, 0, 0, kDTsworn3_1w, kDTnull, kALdropmask_1w}
+#define droppkin_1w {kVDrop_1w, kRpkin_1w, kDTnocgen_1w, 0, 1, kDTnull, kDTnull, kALpkin_1w}
+#define eatchop_1w {kVEat_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALeatchop2_1w}
+#define getchop_1w {kVTake_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALgetchop_1w}
+#define getdw_1w {kVTake_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALcupbdw_1w}
+#define getinboat_1w {kVInto_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgetinboat_1w}
+#define getknife_1w {kVTake_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALcupbpk_1w}
+#define getoilcan_1w {kVTake_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALshedoil_1w}
+#define getoutboat_1w {kVOutof_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgetoutboat_1w}
+#define givegold_1w {kVGive_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALgold_1w}
+#define hiderock_1w {kVHide_1w, 0, kDTnull, 0, 1, kDTsrock_1w, kDTnull, kALrock_1w}
+#define kickpkin_1w {kVAttack_1w, 0, kDTnull, 0, 1, kDTnull, kDTokgen_1w, kALpkin_1w}
+#define knock_1w {kVKnock_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsNobody_1w, 0}
+#define lockbolt_1w {kVLock_1w, 0, kDTnull, 2, 1, kDTsclosed_1w, kDTsclosebolt_1w, 0}
+#define lockdoor_1w {kVLock_1w, kRkey_1w, kDTnockey_1w, 1, 0, kDTslock_1w, kDTokgen_1w, kALclosedoor1_1w}
+#define lookcupb_1w {kVLook_1w, kRcandle_1w, kDTnoccandle_1w, DONT_CARE, 0, kDTnull, kDTnull, kALlookcupb_1w}
+#define lookshed_1w {kVLook_1w, kRcandle_1w, kDTnoccandle_1w, 0, 0, kDTsnoseeoil_1w, kDTsseeoil_1w, kALshedoil_1w}
+#define movecarp1_1w {kVMove_1w, 0, kDTnull, 0, 0, kDTnull, kDTsrollrug_1w, kALmovecarp_1w}
+#define movecarp2_1w {kVLift_1w, 0, kDTnull, 0, 0, kDTnull, kDTsrollrug_1w, kALmovecarp_1w}
+#define movecarp3_1w {kVUnder_1w, 0, kDTnull, 0, 0, kDTnull, kDTsrollrug_1w, kALmovecarp_1w}
+#define offmask_1w {kVOff_1w, 0, kDTnull, 1, 0, kDTsworn2_1w, kDTokgen_1w, kALswapmask_1w}
+#define oilbolt_1w {kVOil_1w, kRoil_1w, kDTrnooil_1w, 0, 1, kDTsoiled_1w, kDTsoilbolt_1w, 0}
+#define omattack_1w {kVAttack_1w, 0, kDTnull, 0, 0, kDTnull, kDTsomattack_1w, 0}
+#define ombreak_1w {kVBreak_1w, 0, kDTnull, 0, 0, kDTnull, kDTsomattack_1w, 0}
+#define omtalk_1w {kVTalk_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALoldman_1w}
+#define openbolt_1w {kVOpen_1w, 0, kDTnull, 1, 2, kDTsstuck_1w, kDTsopenbolt_1w, 0}
+#define opendoor1_1w {kVOpen_1w, kRkey_1w, kDTslocked_1w, 0, 1, kDTsopen_1w, kDTsunlock_1w, kALopendoor1_1w}
+#define opendoor2_1w {kVOpen_1w, 0, kDTnull, 0, 1, kDTsopen_1w, kDTnull, kALopendoor2_1w}
+#define opendoor3_1w {kVOpen_1w, 0, kDTnull, 0, 1, kDTsopen_1w, kDTnull, kALopendoor3_1w}
+#define opendoor4_1w {kVOpen_1w, 0, kDTnull, 0, 0, kDTsopen_1w, kDTnull, kALopendoor4_1w}
+#define openpkin_1w {kVOpen_1w, 0, kDTnull, 0, 1, kDTnull, kDTsopenpkin_1w, kALpkin_1w}
+#define opentrap_1w {kVOpen_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALopentrap_1w}
+#define openwdoors_1w {kVOpen_1w, 0, kDTnull, 0, 1, kDTsopen_1w, kDTnull, kALopenwdoors_1w}
+#define plugbung_1w {kVPlug_1w, kRbung_1w, kDTnocgen_1w, 0, 1, kDTnull, kDTsplug_1w, kALplugbung_1w}
+#define pushboat_1w {kVPush_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALpushboat_1w}
+#define pushigor_1w {kVPush_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALigor_1w}
+#define ruboilcan_1w {kVRub_1w, 0, kDTnull, 0, 0, kDTnull, kDTsruboil_1w, 0}
+#define talkdrac_1w {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkdrac_1w}
+#define talkfrank_1w {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkfrank_1w}
+#define talkgwen_1w {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkgwen_1w}
+#define talkhood_1w {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkhood_1w}
+#define talkpeahd_1w {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkpeahd_1w}
+#define talkslime_1w {kVTalk_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALtalkslime_1w}
+#define throwchop_1w {kVThrowit_1w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALthrowchop_1w}
+#define unlkdoor_1w {kVUnlock_1w, kRkey_1w, kDTnockey_1w, 0, 1, kDTsunlocked_1w, kDTsunlock_1w, kALopendoor1_1w}
+#define unlock_1w {kVUnlock_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsUnlocked_1w, 0}
+#define unlockbolt_1w {kVUnlock_1w, 0, kDTnull, 1, 2, kDTsstuck_1w, kDTsopenbolt_1w, 0}
+#define untierope_1w {kVUntie_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsuntie_1w, 0}
+#define useboat_1w {kVMakeUseOf_1w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALuseboat_1w}
+#define usemask_1w {kVMakeUseOf_1w, kRmask_1w, kDTnocgen_1w, DONT_CARE, 0, kDTnull, kDTnull, kALusemask_1w}
+#define wearmask_1w {kVWear_1w, kRmask_1w, kDTnocgen_1w, 0, 1, kDTsworn1_1w, kDTokgen_1w, kALswapmask_1w}
+
+#define emptyCmd {0, 0, kDTnull, 0, 0, kDTnull, kDTnull, 0}
cmd cmdDummy[] = {emptyCmd};
@@ -4388,72 +4407,72 @@ const cmd *cmdList_1w[] = {
shed_1w, slime_1w, trap_1w, ward_1w, whistle_1w
};
-cmd climbdumb_2w = {kVClimb_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALdumb_2w};
-cmd climbrope_2w = {kVClimb_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALclimbrope_2w};
-cmd climbwell_2w = {kVClimb_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALclimbwell_2w};
-cmd closedoor1_2w = {kVClose_2w, 0, kDTnull, 1, 0, kDTsclose_2w, kDTnull, 0};
-cmd closedoor2_2w = {kVClose_2w, 0, kDTnull, 1, 0, kDTsclose_2w, kDTnull, 0};
-cmd closedoor3_2w = {kVClose_2w, 0, kDTnull, 1, 0, kDTsclose_2w, kDTnull, 0};
-cmd closesafe_2w = {kVClose_2w, 0, kDTnull, 1, 0, kDTsclose_2w, kDTokgen_2w, 0};
-cmd dialphone_2w = {kVDial_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALphone_2w};
-cmd doorpencil_2w = {kVMakeUseOf_2w, kRpencil_2w, kDTnocgen_2w, 0, 1, kDTspencil_2w, kDTnull, kALchkpap1_2w};
-cmd dropdynamite_2w = {kVDrop_2w, kRdyn_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALdropdynamite_2w};
-cmd eatbanana_2w = {kVEat_2w, kRbanana_2w, kDTnocgen_2w, 0, 0, kDTnull, kDTnull, kALeatbanana_2w};
-cmd eatcatnip_2w = {kVEat_2w, kRcatnip_2w, kDTnocgen_2w, 0, 0, kDTnopurps_2w, kDTseatnip_2w, 0};
-cmd eatgarlic_2w = {kVEat_2w, kRgarlic_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALgarlic_2w};
-cmd firegun_2w = {kVFire_2w, kRgun_2w, kDTnogun_2w, 0, 1, kDTsempty_2w, kDTnull, kALgun_2w};
-cmd gard1_2w = {kVTalk_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtalkgard_2w};
-cmd gard2_2w = {kVLook_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALlookgard_2w};
-cmd getballoon_2w = {kVTake_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALballoon_2w};
-cmd getbook_2w = {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgetbook_2w};
-cmd getdynamite_2w = {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgetdynamite_2w};
-cmd getletter_2w = {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsgetlet_2w, 0};
-cmd givebanana_2w = {kVGive_2w, kRbanana_2w, kDTnocgen_2w, 0, 0, kDTnull, kDTnull, kALbanana_2w};
-cmd givebell_2w = {kVGive_2w, kRbell_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALgivebel_2w};
-cmd givecatnip_2w = {kVGive_2w, kRcatnip_2w, kDTnocgen_2w, 0, 0, kDTnopurps_2w, kDTscatnip_2w, 0};
-cmd intodumb_2w = {kVInto_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALdumb_2w};
-cmd knock_2w = {kVKnock_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsNobody_2w, 0};
-cmd lightdynamite_2w = {kVStrike_2w, kRmatch_2w, kDTnomatch_2w, DONT_CARE, 0, kDTnull, kDTnull, kALlightdynamite_2w};
-cmd lookcubp_2w = {kVLook_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALphoto_2w};
-cmd lookgarlic_2w = {kVLook_2w, 0, kDTnull, 0, 1, kDTempty_2w, kDTsFindClove_2w, kALgetgarlic_2w};
-cmd lookhole_2w = {kVLook_2w, 0, kDTnull, 0, 0, kDTsDarkHole_2w, kDTnull, kALkeyhole_2w};
-cmd lookkennel_2w = {kVLook_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALlookkennel_2w};
-cmd lookmat_2w = {kVLook_2w, 0, kDTnull, 0, 1, kDTempty_2w, kDTsFindMatch_2w, kALgetmatch_2w};
-cmd opencubp_2w = {kVOpen_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALphoto_2w};
-cmd opendoor1_2w = {kVOpen_2w, 0, kDTnull, 0, 1, kDTsopen1_2w, kDTnull, kALopendoor1_2w};
-cmd opendoor2_2w = {kVOpen_2w, 0, kDTnull, 0, 1, kDTsopen1_2w, kDTnull, kALopendoor2_2w};
-cmd opendoor3_2w = {kVOpen_2w, 0, kDTnull, 0, 1, kDTsopen1_2w, kDTnull, kALopendoor3_2w};
-cmd opendum_2w = {kVOpen_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsopendum_2w, 0};
-cmd opengarlic_2w = {kVOpen_2w, 0, kDTnull, 0, 1, kDTempty_2w, kDTsFindClove_2w, kALgetgarlic_2w};
-cmd openkdoor_2w = {kVOpen_2w, 0, kDTnull, 0, 0, kDTnull, kDTwontopen_2w, 0};
-cmd openlamp_2w = {kVOpen_2w, kRlamp_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTempty_2w, 0};
-cmd openmat_2w = {kVOpen_2w, 0, kDTnull, 0, 1, kDTempty_2w, kDTsFindMatch_2w, kALgetmatch_2w};
-cmd openpdoor_2w = {kVOpen_2w, 0, kDTnull, 0, 0, kDTnull, kDTspdoor_2w, 0};
-cmd opensafe_2w = {kVOpen_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALsafe_2w};
-cmd popballoon_2w = {kVBreak_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALballoon_2w};
-cmd pushblue_2w = {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALworkgates_2w};
-cmd pushbutton_2w = {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsWhichColor_2w, 0};
-cmd pushgreen_2w = {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALbugzapper_2w};
-cmd pushpaper_2w = {kVPush_2w, kRpaper_2w, kDTnocgen_2w, 0, 1, kDTsnopaper_2w, kDTspaper_2w, kALpushpaper_2w};
-cmd pushpencil_2w = {kVPush_2w, kRpencil_2w, kDTnocgen_2w, 0, 0, kDTspencil_2w, kDTnull, kALpushpencil_2w};
-cmd pushred_2w = {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALshedlight_2w};
-cmd pushyellow_2w = {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgatelight_2w};
-cmd readalbum_2w = {kVRead_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTtalbum_2w, 0};
-cmd readletter_2w = {kVRead_2w, 0, kDTnull, 3, 3, kDTsnoread_2w, kDTsread_2w, kALreadlet_2w};
-cmd readwill_2w = {kVRead_2w, kRwill_2w, kDTnocgen_2w, 1, 1, kDTnull, kDTnull, kALwill_2w};
-cmd ringbell_2w = {kVRing_2w, kRbell_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALbell_2w};
-cmd rubcatnip_2w = {kVRub_2w, kRcatnip_2w, kDTnocgen_2w, 0, 0, kDTnopurps_2w, kDTnull, kALcatnip_2w};
-cmd rublamp_2w = {kVRub_2w, kRlamp_2w, kDTnocgen_2w, 0, 0, kDTnopurps_2w, kDTnull, kALlamp_2w};
-cmd serum_2w = {kVDrink_2w, kRserum_2w, kDTnocgen_2w, 0, 1, kDTsnoserum_2w, kDTnull, kALbottle_2w};
-cmd strikematch_2w = {kVStrike_2w, kRmatch_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALstrikematch_2w};
-cmd takepaper_2w = {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtakepaper_2w};
-cmd takephone_2w = {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALphone_2w};
-cmd talkharry_2w = {kVTalk_2w, 0, kDTnull, 0, 1, kDTsharry_2w, kDTnull, kALharry_2w};
-cmd throwstick_2w = {kVThrowit_2w, kRstick_2w, kDTnocgen_2w, 0, 1, kDTnull, kDTnull, kALthrowstick_2w};
-cmd unlock_2w = {kVUnlock_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsUnlocked_2w, 0};
-cmd unlockdum_2w = {kVUnlock_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsunlockdum_2w, 0};
-cmd usedynamite_2w = {kVMakeUseOf_2w, kRmatch_2w, kDTnomatch_2w, DONT_CARE, 0, kDTnull, kDTnull, kALlightdynamite_2w};
-cmd userobot_2w = {kVMakeUseOf_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, 0};
+#define climbdumb_2w {kVClimb_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALdumb_2w}
+#define climbrope_2w {kVClimb_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALclimbrope_2w}
+#define climbwell_2w {kVClimb_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALclimbwell_2w}
+#define closedoor1_2w {kVClose_2w, 0, kDTnull, 1, 0, kDTsclose_2w, kDTnull, 0}
+#define closedoor2_2w {kVClose_2w, 0, kDTnull, 1, 0, kDTsclose_2w, kDTnull, 0}
+#define closedoor3_2w {kVClose_2w, 0, kDTnull, 1, 0, kDTsclose_2w, kDTnull, 0}
+#define closesafe_2w {kVClose_2w, 0, kDTnull, 1, 0, kDTsclose_2w, kDTokgen_2w, 0}
+#define dialphone_2w {kVDial_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALphone_2w}
+#define doorpencil_2w {kVMakeUseOf_2w, kRpencil_2w, kDTnocgen_2w, 0, 1, kDTspencil_2w, kDTnull, kALchkpap1_2w}
+#define dropdynamite_2w {kVDrop_2w, kRdyn_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALdropdynamite_2w}
+#define eatbanana_2w {kVEat_2w, kRbanana_2w, kDTnocgen_2w, 0, 0, kDTnull, kDTnull, kALeatbanana_2w}
+#define eatcatnip_2w {kVEat_2w, kRcatnip_2w, kDTnocgen_2w, 0, 0, kDTnopurps_2w, kDTseatnip_2w, 0}
+#define eatgarlic_2w {kVEat_2w, kRgarlic_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALgarlic_2w}
+#define firegun_2w {kVFire_2w, kRgun_2w, kDTnogun_2w, 0, 1, kDTsempty_2w, kDTnull, kALgun_2w}
+#define gard1_2w {kVTalk_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtalkgard_2w}
+#define gard2_2w {kVLook_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALlookgard_2w}
+#define getballoon_2w {kVTake_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALballoon_2w}
+#define getbook_2w {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgetbook_2w}
+#define getdynamite_2w {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgetdynamite_2w}
+#define getletter_2w {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsgetlet_2w, 0}
+#define givebanana_2w {kVGive_2w, kRbanana_2w, kDTnocgen_2w, 0, 0, kDTnull, kDTnull, kALbanana_2w}
+#define givebell_2w {kVGive_2w, kRbell_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALgivebel_2w}
+#define givecatnip_2w {kVGive_2w, kRcatnip_2w, kDTnocgen_2w, 0, 0, kDTnopurps_2w, kDTscatnip_2w, 0}
+#define intodumb_2w {kVInto_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALdumb_2w}
+#define knock_2w {kVKnock_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsNobody_2w, 0}
+#define lightdynamite_2w {kVStrike_2w, kRmatch_2w, kDTnomatch_2w, DONT_CARE, 0, kDTnull, kDTnull, kALlightdynamite_2w}
+#define lookcubp_2w {kVLook_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALphoto_2w}
+#define lookgarlic_2w {kVLook_2w, 0, kDTnull, 0, 1, kDTempty_2w, kDTsFindClove_2w, kALgetgarlic_2w}
+#define lookhole_2w {kVLook_2w, 0, kDTnull, 0, 0, kDTsDarkHole_2w, kDTnull, kALkeyhole_2w}
+#define lookkennel_2w {kVLook_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALlookkennel_2w}
+#define lookmat_2w {kVLook_2w, 0, kDTnull, 0, 1, kDTempty_2w, kDTsFindMatch_2w, kALgetmatch_2w}
+#define opencubp_2w {kVOpen_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALphoto_2w}
+#define opendoor1_2w {kVOpen_2w, 0, kDTnull, 0, 1, kDTsopen1_2w, kDTnull, kALopendoor1_2w}
+#define opendoor2_2w {kVOpen_2w, 0, kDTnull, 0, 1, kDTsopen1_2w, kDTnull, kALopendoor2_2w}
+#define opendoor3_2w {kVOpen_2w, 0, kDTnull, 0, 1, kDTsopen1_2w, kDTnull, kALopendoor3_2w}
+#define opendum_2w {kVOpen_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsopendum_2w, 0}
+#define opengarlic_2w {kVOpen_2w, 0, kDTnull, 0, 1, kDTempty_2w, kDTsFindClove_2w, kALgetgarlic_2w}
+#define openkdoor_2w {kVOpen_2w, 0, kDTnull, 0, 0, kDTnull, kDTwontopen_2w, 0}
+#define openlamp_2w {kVOpen_2w, kRlamp_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTempty_2w, 0}
+#define openmat_2w {kVOpen_2w, 0, kDTnull, 0, 1, kDTempty_2w, kDTsFindMatch_2w, kALgetmatch_2w}
+#define openpdoor_2w {kVOpen_2w, 0, kDTnull, 0, 0, kDTnull, kDTspdoor_2w, 0}
+#define opensafe_2w {kVOpen_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALsafe_2w}
+#define popballoon_2w {kVBreak_2w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALballoon_2w}
+#define pushblue_2w {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALworkgates_2w}
+#define pushbutton_2w {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsWhichColor_2w, 0}
+#define pushgreen_2w {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALbugzapper_2w}
+#define pushpaper_2w {kVPush_2w, kRpaper_2w, kDTnocgen_2w, 0, 1, kDTsnopaper_2w, kDTspaper_2w, kALpushpaper_2w}
+#define pushpencil_2w {kVPush_2w, kRpencil_2w, kDTnocgen_2w, 0, 0, kDTspencil_2w, kDTnull, kALpushpencil_2w}
+#define pushred_2w {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALshedlight_2w}
+#define pushyellow_2w {kVPush_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgatelight_2w}
+#define readalbum_2w {kVRead_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTtalbum_2w, 0}
+#define readletter_2w {kVRead_2w, 0, kDTnull, 3, 3, kDTsnoread_2w, kDTsread_2w, kALreadlet_2w}
+#define readwill_2w {kVRead_2w, kRwill_2w, kDTnocgen_2w, 1, 1, kDTnull, kDTnull, kALwill_2w}
+#define ringbell_2w {kVRing_2w, kRbell_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALbell_2w}
+#define rubcatnip_2w {kVRub_2w, kRcatnip_2w, kDTnocgen_2w, 0, 0, kDTnopurps_2w, kDTnull, kALcatnip_2w}
+#define rublamp_2w {kVRub_2w, kRlamp_2w, kDTnocgen_2w, 0, 0, kDTnopurps_2w, kDTnull, kALlamp_2w}
+#define serum_2w {kVDrink_2w, kRserum_2w, kDTnocgen_2w, 0, 1, kDTsnoserum_2w, kDTnull, kALbottle_2w}
+#define strikematch_2w {kVStrike_2w, kRmatch_2w, kDTnocgen_2w, DONT_CARE, 0, kDTnull, kDTnull, kALstrikematch_2w}
+#define takepaper_2w {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtakepaper_2w}
+#define takephone_2w {kVTake_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALphone_2w}
+#define talkharry_2w {kVTalk_2w, 0, kDTnull, 0, 1, kDTsharry_2w, kDTnull, kALharry_2w}
+#define throwstick_2w {kVThrowit_2w, kRstick_2w, kDTnocgen_2w, 0, 1, kDTnull, kDTnull, kALthrowstick_2w}
+#define unlock_2w {kVUnlock_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsUnlocked_2w, 0}
+#define unlockdum_2w {kVUnlock_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsunlockdum_2w, 0}
+#define usedynamite_2w {kVMakeUseOf_2w, kRmatch_2w, kDTnomatch_2w, DONT_CARE, 0, kDTnull, kDTnull, kALlightdynamite_2w}
+#define userobot_2w {kVMakeUseOf_2w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, 0}
cmd album_2w[] = {readalbum_2w, emptyCmd};
cmd balloon_2w[] = {popballoon_2w, getballoon_2w, emptyCmd};
@@ -4509,59 +4528,59 @@ const cmd *cmdList_2w[] = {
will_2w, yellow_2w
};
-cmd bell_3w = {kVRing_3w, kRbell_3w, kDTnocgen_3w, DONT_CARE, 0, kDTnull, kDTokbell_3w, 0};
-cmd blow_3w = {kVBlow_3w, kRpipe_3w, kDTnogun_3w, DONT_CARE, 0, kDTnull, kDTnull, kALdart_3w};
-cmd blowdoc_3w = {kVShoot_3w, kRpipe_3w, kDTnogun_3w, DONT_CARE, 0, kDTnull, kDTsblowdoc_3w, 0};
-cmd book_3w = {kVRead_3w, kRbook_3w, kDTnocgen_3w, DONT_CARE, 0, kDTnull, kDTnull, kALreadbook_3w};
-cmd cage1_3w = {kVOpen_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALopencage_3w};
-cmd cage2_3w = {kVClose_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, 0};
-cmd cage3_3w = {kVTake_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtakecage_3w};
-cmd cageuse_3w = {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALusecage_3w};
-cmd candle1_3w = {kVStrike_3w, 0, kDTnull, 0, 1, kDTslit_3w, kDTokgen_3w, 0};
-cmd candle2_3w = {kVDouse_3w, 0, kDTnull, 1, 0, kDTsunlit_3w, kDTokgen_3w, 0};
-cmd cdoor1_3w = {kVOpen_3w, 0, kDTnull, 0, 0, kDTsopen1_3w, kDTnull, kALopendoor_3w};
-cmd cdoor2_3w = {kVClose_3w, 0, kDTnull, 1, 0, kDTsclose_3w, kDTokgen_3w, kALclosedoor_3w};
-cmd cdrinkpool_3w = {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTspool_3w, 0};
-cmd cdrinkstream_3w = {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsstream_3w, 0};
-cmd cexit1_3w = {kVOutof_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALexit_3w};
-cmd cexit2_3w = {kVClimb_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALexit_3w};
-cmd cflask1_3w = {kVFill_3w, 0, kDTnull, 0, 1, kDTsfull_3w, kDTnull, kALfill_3w};
-cmd cflask2_3w = {kVPut_3w, 0, kDTnull, 0, 1, kDTsfull_3w, kDTnull, kALfill_3w};
-cmd cflask3_3w = {kVEmpty_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALempty2_3w};
-cmd cflask4_3w = {kVDrink_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALdrink_3w};
-cmd cflask5_3w = {kVGive_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALflask_3w};
-cmd cheese1_3w = {kVEat_3w, kRcheese_3w, kDTnocgen_3w, 0, 0, kDTnull, kDTnull, kALeatcheese_3w};
-cmd cheese2_3w = {kVDrop_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALdropcheese_3w};
-cmd cheese3_3w = {kVPut_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALdropcheese_3w};
-cmd cheese4_3w = {kVTake_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtakecheese_3w};
-cmd cmake1_3w = {kVMake_3w, 0, kDTnull, 0, 0, kDTsmade_3w, kDTnull, kALmakeclay_3w};
-cmd cmake2_3w = {kVStick_3w, kRpins_3w, kDTnopins_3w, DONT_CARE, 0, kDTnull, kDTnull, kALstick_3w};
-cmd cplane1_3w = {kVClimb_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALplane_3w};
-cmd cplane2_3w = {kVInto_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALplane_3w};
-cmd cplane3_3w = {kVSearch_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALplane_3w};
-cmd crystal_3w = {kVRub_3w, kRcrystal_3w, kDTnocgen_3w, DONT_CARE, 0, kDTnull, kDTnull, kALcrystal_3w};
-cmd csteps1_3w = {kVMakeUseOf_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALsteps_3w};
-cmd cstick1_3w = {kVStick_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALstick_3w};
-cmd cswing1_3w = {kVSwing_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTswinger_3w, kALswing_3w};
-cmd ctalknat_3w = {kVTalk_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtalknat_3w};
-cmd cube1_3w = {kVGive_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgiveb_3w};
-cmd cvine1_3w = {kVMakeUseOf_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALvine_3w};
-cmd cvine2_3w = {kVUntie_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALuntie_vine_3w};
-cmd cvine3_3w = {kVTie_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALvine_3w};
-cmd cwaterfall_3w = {kVLook_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALlookwfall_3w};
-cmd cwaterpool_3w = {kVLook_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTswater_3w, 0};
-cmd cwaterstream_3w = {kVLook_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTswater_3w, 0};
-cmd dart_3w = {kVShoot_3w, kRpipe_3w, kDTnogun_3w, DONT_CARE, 0, kDTnull, kDTnull, kALdart_3w};
-cmd elephant_3w = {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTuelephant_3w, 0};
-cmd ghost1_3w = {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTughost_3w, 0};
-cmd ghost2_3w = {kVExorcise_3w, kRexor_3w, kDTnocex_3w, DONT_CARE, 0, kDTnull, kDTnull, kALexorcise_3w};
-cmd knock_3w = {kVKnock_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsNobody_3w, 0};
-cmd lookrush_3w = {kVBehind_3w, 0, kDTnull, 0, 1, kDTsfoundb_3w, kDTnull, kALfindbook_3w};
-cmd readit_3w = {kVRead_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsread_3w, 0};
-cmd rock1_3w = {kVBehind_3w, 0, kDTnull, 0, 1, kDTsfoundc_3w, kDTsfindc_3w, kALfindcrystal_3w};
-cmd swingc_3w = {kVSwing_3w, 0, kDTnull, 0, 1, kDTsnoswing_3w, kDTswingcave_3w, 0};
-cmd unlock_3w = {kVUnlock_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsUnlocked_3w, 0};
-cmd usedoc_3w = {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtalkdoc_3w};
+#define bell_3w {kVRing_3w, kRbell_3w, kDTnocgen_3w, DONT_CARE, 0, kDTnull, kDTokbell_3w, 0}
+#define blow_3w {kVBlow_3w, kRpipe_3w, kDTnogun_3w, DONT_CARE, 0, kDTnull, kDTnull, kALdart_3w}
+#define blowdoc_3w {kVShoot_3w, kRpipe_3w, kDTnogun_3w, DONT_CARE, 0, kDTnull, kDTsblowdoc_3w, 0}
+#define book_3w {kVRead_3w, kRbook_3w, kDTnocgen_3w, DONT_CARE, 0, kDTnull, kDTnull, kALreadbook_3w}
+#define cage1_3w {kVOpen_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALopencage_3w}
+#define cage2_3w {kVClose_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, 0}
+#define cage3_3w {kVTake_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtakecage_3w}
+#define cageuse_3w {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALusecage_3w}
+#define candle1_3w {kVStrike_3w, 0, kDTnull, 0, 1, kDTslit_3w, kDTokgen_3w, 0}
+#define candle2_3w {kVDouse_3w, 0, kDTnull, 1, 0, kDTsunlit_3w, kDTokgen_3w, 0}
+#define cdoor1_3w {kVOpen_3w, 0, kDTnull, 0, 0, kDTsopen1_3w, kDTnull, kALopendoor_3w}
+#define cdoor2_3w {kVClose_3w, 0, kDTnull, 1, 0, kDTsclose_3w, kDTokgen_3w, kALclosedoor_3w}
+#define cdrinkpool_3w {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTspool_3w, 0}
+#define cdrinkstream_3w {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsstream_3w, 0}
+#define cexit1_3w {kVOutof_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALexit_3w}
+#define cexit2_3w {kVClimb_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALexit_3w}
+#define cflask1_3w {kVFill_3w, 0, kDTnull, 0, 1, kDTsfull_3w, kDTnull, kALfill_3w}
+#define cflask2_3w {kVPut_3w, 0, kDTnull, 0, 1, kDTsfull_3w, kDTnull, kALfill_3w}
+#define cflask3_3w {kVEmpty_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALempty2_3w}
+#define cflask4_3w {kVDrink_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALdrink_3w}
+#define cflask5_3w {kVGive_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALflask_3w}
+#define cheese1_3w {kVEat_3w, kRcheese_3w, kDTnocgen_3w, 0, 0, kDTnull, kDTnull, kALeatcheese_3w}
+#define cheese2_3w {kVDrop_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALdropcheese_3w}
+#define cheese3_3w {kVPut_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALdropcheese_3w}
+#define cheese4_3w {kVTake_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtakecheese_3w}
+#define cmake1_3w {kVMake_3w, 0, kDTnull, 0, 0, kDTsmade_3w, kDTnull, kALmakeclay_3w}
+#define cmake2_3w {kVStick_3w, kRpins_3w, kDTnopins_3w, DONT_CARE, 0, kDTnull, kDTnull, kALstick_3w}
+#define cplane1_3w {kVClimb_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALplane_3w}
+#define cplane2_3w {kVInto_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALplane_3w}
+#define cplane3_3w {kVSearch_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTokgen_3w, kALplane_3w}
+#define crystal_3w {kVRub_3w, kRcrystal_3w, kDTnocgen_3w, DONT_CARE, 0, kDTnull, kDTnull, kALcrystal_3w}
+#define csteps1_3w {kVMakeUseOf_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALsteps_3w}
+#define cstick1_3w {kVStick_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALstick_3w}
+#define cswing1_3w {kVSwing_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTswinger_3w, kALswing_3w}
+#define ctalknat_3w {kVTalk_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtalknat_3w}
+#define cube1_3w {kVGive_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALgiveb_3w}
+#define cvine1_3w {kVMakeUseOf_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALvine_3w}
+#define cvine2_3w {kVUntie_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALuntie_vine_3w}
+#define cvine3_3w {kVTie_3w, 0, kDTnull, 0, 0, kDTnull, kDTnull, kALvine_3w}
+#define cwaterfall_3w {kVLook_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALlookwfall_3w}
+#define cwaterpool_3w {kVLook_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTswater_3w, 0}
+#define cwaterstream_3w {kVLook_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTswater_3w, 0}
+#define dart_3w {kVShoot_3w, kRpipe_3w, kDTnogun_3w, DONT_CARE, 0, kDTnull, kDTnull, kALdart_3w}
+#define elephant_3w {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTuelephant_3w, 0}
+#define ghost1_3w {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTughost_3w, 0}
+#define ghost2_3w {kVExorcise_3w, kRexor_3w, kDTnocex_3w, DONT_CARE, 0, kDTnull, kDTnull, kALexorcise_3w}
+#define knock_3w {kVKnock_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsNobody_3w, 0}
+#define lookrush_3w {kVBehind_3w, 0, kDTnull, 0, 1, kDTsfoundb_3w, kDTnull, kALfindbook_3w}
+#define readit_3w {kVRead_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsread_3w, 0}
+#define rock1_3w {kVBehind_3w, 0, kDTnull, 0, 1, kDTsfoundc_3w, kDTsfindc_3w, kALfindcrystal_3w}
+#define swingc_3w {kVSwing_3w, 0, kDTnull, 0, 1, kDTsnoswing_3w, kDTswingcave_3w, 0}
+#define unlock_3w {kVUnlock_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTsUnlocked_3w, 0}
+#define usedoc_3w {kVMakeUseOf_3w, 0, kDTnull, DONT_CARE, 0, kDTnull, kDTnull, kALtalkdoc_3w}
cmd cbell_3w[] = {bell_3w, emptyCmd};
cmd cbook_3w[] = {book_3w, emptyCmd};
@@ -4601,58 +4620,58 @@ const cmd *cmdList_3w[] = {
cvine_3w, cwfall_3w, cwpool_3w, cwstream_3w
};
-cmd blowdw_1d = {kVBlow_1d, 0, 0, 0, 0, 0, kDTokgen_1d, kALblowdw_1d};
-cmd breakpkin_1d = {kVBreak_1d, 0, 0, 0, 1, 0, kDTokgen_1d, kALpkin_1d};
-cmd brkrope_1d = {kVBreak_1d, 0, 0, DONT_CARE, 0, 0, kDTsrbreak_1d, 0};
-cmd closebolt_1d = {kVClose_1d, 0, 0, 2, 1, kDTsclose_1d, kDTokgen_1d, 0};
-cmd closedoor1_1d = {kVClose_1d, 0, 0, 2, 0, kDTsclose_1d, 0, kALclosedoor1_1d};
-cmd closedoor2_1d = {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, 0, 0};
-cmd closedoor3_1d = {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, 0, 0};
-cmd closedoor4_1d = {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, 0, kALclosedoor4_1d};
-cmd closetrap_1d = {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, kDTokgen_1d, kALclosetrap_1d};
-cmd closewdoors_1d = {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, 0, kALclosewdoors_1d};
-cmd cutrope_1d = {kVCut_1d, kRknife_1d, kDTrnoknife_1d, 0, 1, kDTsnocut_1d, kDTscut_1d, kALcutrope_1d};
-cmd dropmask_1d = {kVDrop_1d, 0, 0, 0, 0, kDTsworn3_1d, 0, kALdropmask_1d};
-cmd droppkin_1d = {kVDrop_1d, kRpkin_1d, kDTnocgen_1d, 0, 1, 0, 0, kALpkin_1d};
-cmd eatchop_1d = {kVEat_1d, 0, 0, 0, 0, 0, 0, kALeatchop_1d};
-cmd getdw_1d = {kVTake_1d, 0, 0, 0, 0, 0, 0, kALcupbdw_1d};
-cmd getinboat_1d = {kVInto_1d, 0, 0, DONT_CARE, 0, 0, 0, kALgetinboat_1d};
-cmd getknife_1d = {kVTake_1d, 0, 0, 0, 0, 0, 0, kALcupbpk_1d};
-cmd getoilcan_1d = {kVTake_1d, 0, 0, 0, 0, 0, 0, kALshedoil_1d};
-cmd getoutboat_1d = {kVOutof_1d, 0, 0, DONT_CARE, 0, 0, 0, kALgetoutboat_1d};
-cmd givegold_1d = {kVGive_1d, 0, 0, 0, 0, 0, 0, kALgold_1d};
-cmd kickpkin_1d = {kVAttack_1d, 0, 0, 0, 1, 0, kDTokgen_1d, kALpkin_1d};
-cmd knock_1d = {kVKnock_1d, 0, 0, DONT_CARE, 0, 0, kDTsknock_1d, 0};
-cmd lockbolt_1d = {kVLock_1d, 0, 0, 2, 1, kDTsclose_1d, kDTokgen_1d, 0};
-cmd lockdoor_1d = {kVLock_1d, kRkey_1d, kDTnockey_1d, 2, 0, kDTslock_1d, kDTokgen_1d, 0};
-cmd lookcupb_1d = {kVLook_1d, kRcandle_1d, kDTnoccandle_1d, DONT_CARE, 0, 0, 0, kALlookcupb_1d};
-cmd lookshed_1d = {kVLook_1d, kRcandle_1d, kDTnoccandle_1d, 0, 0, kDTsnosee_1d, kDTsseeoil_1d, 0};
-cmd movecarp1_1d = {kVMove_1d, 0, 0, 0, 0, 0, kDTokgen_1d, kALmovecarp_1d};
-cmd movecarp2_1d = {kVLift_1d, 0, 0, 0, 0, 0, kDTokgen_1d, kALmovecarp_1d};
-cmd movecarp3_1d = {kVUnder_1d, 0, 0, 0, 0, 0, kDTokgen_1d, kALmovecarp_1d};
-cmd offmask_1d = {kVOff_1d, 0, 0, 1, 0, kDTsworn2_1d, kDTokgen_1d, kALswapmask_1d};
-cmd oilbolt_1d = {kVOil_1d, kRoil_1d, kDTrnooil_1d, 0, 1, kDTsoiled_1d, kDTokgen_1d, 0};
-cmd omattack_1d = {kVAttack_1d, 0, 0, 0, 0, 0, kDTsomattack_1d, 0};
-cmd ombreak_1d = {kVBreak_1d, 0, 0, 0, 0, 0, kDTsomattack_1d, 0};
-cmd omtalk_1d = {kVTalk_1d, 0, 0, DONT_CARE, 0, 0, 0, kALoldman_1d};
-cmd openbolt_1d = {kVOpen_1d, 0, 0, 1, 2, kDTsstuck_1d, kDTokgen_1d, 0};
-cmd opendoor1_1d = {kVOpen_1d, 0, 0, 1, 2, kDTsopen_1d, 0, kALopendoor1_1d};
-cmd opendoor2_1d = {kVOpen_1d, 0, 0, 0, 1, kDTsopen2_1d, 0, kALopendoor2_1d};
-cmd opendoor3_1d = {kVOpen_1d, 0, 0, 0, 1, kDTsopen2_1d, 0, kALopendoor3_1d};
-cmd opendoor4_1d = {kVOpen_1d, 0, 0, 0, 0, kDTsopen2_1d, 0, kALopendoor4_1d};
-cmd openpkin_1d = {kVOpen_1d, 0, 0, 0, 1, 0, kDTokgen_1d, kALpkin_1d};
-cmd opentrap_1d = {kVOpen_1d, 0, 0, 0, 0, 0, 0, kALopentrap_1d};
-cmd openwdoors_1d = {kVOpen_1d, 0, 0, 0, 1, kDTsopen2_1d, 0, kALopenwdoors_1d};
-cmd plugbung_1d = {kVPlug_1d, kRbung_1d, kDTnocgen_1d, 0, 1, 0, kDTokgen_1d, kALplugbung_1d};
-cmd pushboat_1d = {kVPush_1d, 0, 0, DONT_CARE, 0, 0, 0, kALpushboat_1d};
-cmd pushigor_1d = {kVPush_1d, 0, 0, 0, 0, 0, 0, kALigor_1d};
-cmd ruboilcan_1d = {kVRub_1d, 0, 0, 0, 0, 0, kDTsruboil_1d, 0};
-cmd throwchop_1d = {kVThrow_1d, 0, 0, 0, 0, 0, 0, kALthrowchop_1d};
-cmd unlkdoor_1d = {kVUnlock_1d, kRkey_1d, kDTnockey_1d, 0, 1, kDTsunlock_1d, kDTokgen_1d, 0};
-cmd unlock_1d = {kVUnlock_1d, 0, 0, DONT_CARE, 0, 0, kDTsunlock_1d, 0};
-cmd unlockbolt_1d = {kVUnlock_1d, 0, 0, 1, 2, kDTsstuck_1d, kDTokgen_1d, 0};
-cmd untierope_1d = {kVUntie_1d, 0, 0, DONT_CARE, 0, 0, kDTsuntie_1d, 0};
-cmd wearmask_1d = {kVWear_1d, kRmask_1d, kDTnocgen_1d, 0, 1, kDTsworn1_1d, kDTokgen_1d, kALswapmask_1d};
+#define blowdw_1d {kVBlow_1d, 0, 0, 0, 0, 0, kDTokgen_1d, kALblowdw_1d}
+#define breakpkin_1d {kVBreak_1d, 0, 0, 0, 1, 0, kDTokgen_1d, kALpkin_1d}
+#define brkrope_1d {kVBreak_1d, 0, 0, DONT_CARE, 0, 0, kDTsrbreak_1d, 0}
+#define closebolt_1d {kVClose_1d, 0, 0, 2, 1, kDTsclose_1d, kDTokgen_1d, 0}
+#define closedoor1_1d {kVClose_1d, 0, 0, 2, 0, kDTsclose_1d, 0, kALclosedoor1_1d}
+#define closedoor2_1d {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, 0, 0}
+#define closedoor3_1d {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, 0, 0}
+#define closedoor4_1d {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, 0, kALclosedoor4_1d}
+#define closetrap_1d {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, kDTokgen_1d, kALclosetrap_1d}
+#define closewdoors_1d {kVClose_1d, 0, 0, 1, 0, kDTsclose_1d, 0, kALclosewdoors_1d}
+#define cutrope_1d {kVCut_1d, kRknife_1d, kDTrnoknife_1d, 0, 1, kDTsnocut_1d, kDTscut_1d, kALcutrope_1d}
+#define dropmask_1d {kVDrop_1d, 0, 0, 0, 0, kDTsworn3_1d, 0, kALdropmask_1d}
+#define droppkin_1d {kVDrop_1d, kRpkin_1d, kDTnocgen_1d, 0, 1, 0, 0, kALpkin_1d}
+#define eatchop_1d {kVEat_1d, 0, 0, 0, 0, 0, 0, kALeatchop_1d}
+#define getdw_1d {kVTake_1d, 0, 0, 0, 0, 0, 0, kALcupbdw_1d}
+#define getinboat_1d {kVInto_1d, 0, 0, DONT_CARE, 0, 0, 0, kALgetinboat_1d}
+#define getknife_1d {kVTake_1d, 0, 0, 0, 0, 0, 0, kALcupbpk_1d}
+#define getoilcan_1d {kVTake_1d, 0, 0, 0, 0, 0, 0, kALshedoil_1d}
+#define getoutboat_1d {kVOutof_1d, 0, 0, DONT_CARE, 0, 0, 0, kALgetoutboat_1d}
+#define givegold_1d {kVGive_1d, 0, 0, 0, 0, 0, 0, kALgold_1d}
+#define kickpkin_1d {kVAttack_1d, 0, 0, 0, 1, 0, kDTokgen_1d, kALpkin_1d}
+#define knock_1d {kVKnock_1d, 0, 0, DONT_CARE, 0, 0, kDTsknock_1d, 0}
+#define lockbolt_1d {kVLock_1d, 0, 0, 2, 1, kDTsclose_1d, kDTokgen_1d, 0}
+#define lockdoor_1d {kVLock_1d, kRkey_1d, kDTnockey_1d, 2, 0, kDTslock_1d, kDTokgen_1d, 0}
+#define lookcupb_1d {kVLook_1d, kRcandle_1d, kDTnoccandle_1d, DONT_CARE, 0, 0, 0, kALlookcupb_1d}
+#define lookshed_1d {kVLook_1d, kRcandle_1d, kDTnoccandle_1d, 0, 0, kDTsnosee_1d, kDTsseeoil_1d, 0}
+#define movecarp1_1d {kVMove_1d, 0, 0, 0, 0, 0, kDTokgen_1d, kALmovecarp_1d}
+#define movecarp2_1d {kVLift_1d, 0, 0, 0, 0, 0, kDTokgen_1d, kALmovecarp_1d}
+#define movecarp3_1d {kVUnder_1d, 0, 0, 0, 0, 0, kDTokgen_1d, kALmovecarp_1d}
+#define offmask_1d {kVOff_1d, 0, 0, 1, 0, kDTsworn2_1d, kDTokgen_1d, kALswapmask_1d}
+#define oilbolt_1d {kVOil_1d, kRoil_1d, kDTrnooil_1d, 0, 1, kDTsoiled_1d, kDTokgen_1d, 0}
+#define omattack_1d {kVAttack_1d, 0, 0, 0, 0, 0, kDTsomattack_1d, 0}
+#define ombreak_1d {kVBreak_1d, 0, 0, 0, 0, 0, kDTsomattack_1d, 0}
+#define omtalk_1d {kVTalk_1d, 0, 0, DONT_CARE, 0, 0, 0, kALoldman_1d}
+#define openbolt_1d {kVOpen_1d, 0, 0, 1, 2, kDTsstuck_1d, kDTokgen_1d, 0}
+#define opendoor1_1d {kVOpen_1d, 0, 0, 1, 2, kDTsopen_1d, 0, kALopendoor1_1d}
+#define opendoor2_1d {kVOpen_1d, 0, 0, 0, 1, kDTsopen2_1d, 0, kALopendoor2_1d}
+#define opendoor3_1d {kVOpen_1d, 0, 0, 0, 1, kDTsopen2_1d, 0, kALopendoor3_1d}
+#define opendoor4_1d {kVOpen_1d, 0, 0, 0, 0, kDTsopen2_1d, 0, kALopendoor4_1d}
+#define openpkin_1d {kVOpen_1d, 0, 0, 0, 1, 0, kDTokgen_1d, kALpkin_1d}
+#define opentrap_1d {kVOpen_1d, 0, 0, 0, 0, 0, 0, kALopentrap_1d}
+#define openwdoors_1d {kVOpen_1d, 0, 0, 0, 1, kDTsopen2_1d, 0, kALopenwdoors_1d}
+#define plugbung_1d {kVPlug_1d, kRbung_1d, kDTnocgen_1d, 0, 1, 0, kDTokgen_1d, kALplugbung_1d}
+#define pushboat_1d {kVPush_1d, 0, 0, DONT_CARE, 0, 0, 0, kALpushboat_1d}
+#define pushigor_1d {kVPush_1d, 0, 0, 0, 0, 0, 0, kALigor_1d}
+#define ruboilcan_1d {kVRub_1d, 0, 0, 0, 0, 0, kDTsruboil_1d, 0}
+#define throwchop_1d {kVThrow_1d, 0, 0, 0, 0, 0, 0, kALthrowchop_1d}
+#define unlkdoor_1d {kVUnlock_1d, kRkey_1d, kDTnockey_1d, 0, 1, kDTsunlock_1d, kDTokgen_1d, 0}
+#define unlock_1d {kVUnlock_1d, 0, 0, DONT_CARE, 0, 0, kDTsunlock_1d, 0}
+#define unlockbolt_1d {kVUnlock_1d, 0, 0, 1, 2, kDTsstuck_1d, kDTokgen_1d, 0}
+#define untierope_1d {kVUntie_1d, 0, 0, DONT_CARE, 0, 0, kDTsuntie_1d, 0}
+#define wearmask_1d {kVWear_1d, kRmask_1d, kDTnocgen_1d, 0, 1, kDTsworn1_1d, kDTokgen_1d, kALswapmask_1d}
cmd boat_1d[] = {getinboat_1d, getoutboat_1d, pushboat_1d, emptyCmd};
cmd bolt_1d[] = {oilbolt_1d, openbolt_1d, unlockbolt_1d, closebolt_1d, lockbolt_1d, emptyCmd};
@@ -4686,62 +4705,62 @@ const cmd *cmdList_1d[] = {
ward_1d, whistle_1d
};
-cmd climbdumb_2d = {kVClimb_2d, 0, 0, 0, 0, 0, 0, kALdumb_2d};
-cmd climbrope_2d = {kVClimb_2d, 0, 0, DONT_CARE, 0, 0, 0, kALclimbrope_2d};
-cmd climbwell_2d = {kVClimb_2d, 0, 0, DONT_CARE, 0, 0, 0, kALclimbwell_2d};
-cmd closedoor1_2d = {kVClose_2d, 0, 0, 1, 0, kDTsclose_2d, 0, 0};
-cmd closedoor2_2d = {kVClose_2d, 0, 0, 1, 0, kDTsclose_2d, 0, 0};
-cmd closedoor3_2d = {kVClose_2d, 0, 0, 1, 0, kDTsclose_2d, 0, 0};
-cmd closesafe_2d = {kVClose_2d, 0, 0, 1, 0, kDTsclose_2d, kDTokgen_2d, 0};
-cmd dialphone_2d = {kVDial_2d, 0, 0, 1, 1, kDTsdialed_2d, 0, kALphone_2d};
-cmd dropdynamite_2d = {kVDrop_2d, kRdyn_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALdropdynamite_2d};
-cmd eatbanana_2d = {kVEat_2d, kRbanana_2d, kDTnocgen_2d, 0, 0, 0, 0, kALeatbanana_2d};
-cmd eatgarlic_2d = {kVEat_2d, kRgarlic_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALgarlic_2d};
-cmd firegun_2d = {kVFire_2d, kRgun_2d, kDTnogun_2d, 0, 1, kDTsempty_2d, 0, kALgun_2d};
-cmd getballoon_2d = {kVTake_2d, 0, 0, 0, 0, 0, 0, kALballoon_2d};
-cmd getbook_2d = {kVTake_2d, 0, 0, DONT_CARE, 0, 0, 0, kALgetbook_2d};
-cmd getdynamite_2d = {kVTake_2d, 0, 0, DONT_CARE, 0, 0, 0, kALgetdynamite_2d};
-cmd getletter_2d = {kVTake_2d, 0, 0, DONT_CARE, 0, kDTsgetlet_2d, 0, 0};
-cmd givebanana_2d = {kVGive_2d, kRbanana_2d, kDTnocgen_2d, 0, 0, 0, 0, kALbanana_2d};
-cmd givebell_2d = {kVGive_2d, kRbell_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALgivebel_2d};
-cmd givecatnip_2d = {kVGive_2d, kRcatnip_2d, kDTnocgen_2d, 0, 0, kDTnopurps_2d, kDTscatnip_2d, 0};
-cmd intodumb_2d = {kVInto_2d, 0, 0, 0, 0, 0, 0, kALdumb_2d};
-cmd knock_2d = {kVKnock_2d, 0, 0, DONT_CARE, 0, 0, kDTtnoknock_2d, 0};
-cmd lightdynamite_2d = {kVStrike_2d, kRmatch_2d, kDTnomatch_2d, DONT_CARE, 0, 0, 0, kALlightdynamite_2d};
-cmd lookcubp_2d = {kVLook_2d, 0, 0, DONT_CARE, 0, 0, 0, kALphoto_2d};
-cmd lookgarlic_2d = {kVLook_2d, 0, 0, 0, 1, kDTempty_2d, kDTfindclove_2d, kALgetgarlic_2d};
-cmd lookhole_2d = {kVLook_2d, 0, 0, 0, 0, kDTdarkhole_2d, 0, kALkeyhole_2d};
-cmd lookkennel_2d = {kVLook_2d, 0, 0, 0, 0, 0, 0, kALlookkennel_2d};
-cmd lookmat_2d = {kVLook_2d, 0, 0, 0, 1, kDTempty_2d, kDTfindmatch_2d, kALgetmatch_2d};
-cmd lookmatch_2d = {kVLook_2d, 0, 0, DONT_CARE, 0, 0, 0, kALlookmatch_2d};
-cmd opencubp_2d = {kVOpen_2d, 0, 0, DONT_CARE, 0, 0, 0, kALphoto_2d};
-cmd opendoor1_2d = {kVOpen_2d, 0, 0, 0, 1, kDTsopen1_2d, 0, kALopendoor1_2d};
-cmd opendoor2_2d = {kVOpen_2d, 0, 0, 0, 1, kDTsopen1_2d, 0, kALopendoor2_2d};
-cmd opendoor3_2d = {kVOpen_2d, 0, 0, 0, 1, kDTsopen1_2d, 0, kALopendoor3_2d};
-cmd opengarlic_2d = {kVOpen_2d, 0, 0, 0, 1, kDTempty_2d, kDTfindclove_2d, kALgetgarlic_2d};
-cmd openkdoor_2d = {kVOpen_2d, 0, 0, 0, 0, 0, kDTwontopen_2d, 0};
-cmd openlamp_2d = {kVOpen_2d, kRlamp_2d, kDTnocgen_2d, DONT_CARE, 0, 0, kDTempty_2d, 0};
-cmd openmat_2d = {kVOpen_2d, 0, 0, 0, 1, kDTempty_2d, kDTfindmatch_2d, kALgetmatch_2d};
-cmd openpdoor_2d = {kVOpen_2d, 0, 0, 0, 0, 0, kDTspdoor_2d, 0};
-cmd opensafe_2d = {kVOpen_2d, 0, 0, DONT_CARE, 0, 0, 0, kALsafe_2d};
-cmd popballoon_2d = {kVBreak_2d, 0, 0, 0, 0, 0, 0, kALballoon_2d};
-cmd pushblue_2d = {kVPush_2d, 0, 0, DONT_CARE, 0, 0, 0, kALworkgates_2d};
-cmd pushbutton_2d = {kVPush_2d, 0, 0, DONT_CARE, 0, 0, kDTtnopushbutton_2d, 0};
-cmd pushgreen_2d = {kVPush_2d, 0, 0, DONT_CARE, 0, 0, 0, kALbugzapper_2d};
-cmd pushpaper_2d = {kVPush_2d, kRpaper_2d, kDTnocgen_2d, 0, 1, 0, kDTokgen_2d, kALpushpaper_2d};
-cmd pushpencil_2d = {kVPush_2d, kRpencil_2d, kDTnocgen_2d, 0, 0, 0, 0, kALpushpencil_2d};
-cmd pushred_2d = {kVPush_2d, 0, 0, DONT_CARE, 0, 0, 0, kALshedlight_2d};
-cmd pushyellow_2d = {kVPush_2d, 0, 0, DONT_CARE, 0, 0, 0, kALgatelight_2d};
-cmd readletter_2d = {kVRead_2d, 0, 0, 3, 3, kDTsnoread_2d, kDTsread_2d, kALreadlet_2d};
-cmd readwill_2d = {kVRead_2d, kRwill_2d, kDTnocgen_2d, 1, 1, 0, 0, kALwill_2d};
-cmd ringbell_2d = {kVRing_2d, kRbell_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALbell_2d};
-cmd rubcatnip_2d = {kVRub_2d, kRcatnip_2d, kDTnocgen_2d, 0, 0, kDTnopurps_2d, 0, kALcatnip_2d};
-cmd rublamp_2d = {kVRub_2d, kRlamp_2d, kDTnocgen_2d, 0, 0, kDTnopurps_2d, 0, kALlamp_2d};
-cmd serum_2d = {kVDrink_2d, kRserum_2d, kDTnocgen_2d, 0, 1, kDTsnosee_2d, 0, kALbottle_2d};
-cmd strikematch_2d = {kVStrike_2d, kRmatch_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALstrikematch_2d};
-cmd talkharry_2d = {kVTalk_2d, 0, 0, 0, 1, kDTsharry_2d, 0, kALharry_2d};
-cmd throwstick_2d = {kVThrow_2d, kRstick_2d, kDTnocgen_2d, 0, 1, 0, 0, kALthrowstick_2d};
-cmd unlock_2d = {kVUnlock_2d, 0, 0, DONT_CARE, 0, 0, kDTtnounlock_2d, 0};
+#define climbdumb_2d {kVClimb_2d, 0, 0, 0, 0, 0, 0, kALdumb_2d}
+#define climbrope_2d {kVClimb_2d, 0, 0, DONT_CARE, 0, 0, 0, kALclimbrope_2d}
+#define climbwell_2d {kVClimb_2d, 0, 0, DONT_CARE, 0, 0, 0, kALclimbwell_2d}
+#define closedoor1_2d {kVClose_2d, 0, 0, 1, 0, kDTsclose_2d, 0, 0}
+#define closedoor2_2d {kVClose_2d, 0, 0, 1, 0, kDTsclose_2d, 0, 0}
+#define closedoor3_2d {kVClose_2d, 0, 0, 1, 0, kDTsclose_2d, 0, 0}
+#define closesafe_2d {kVClose_2d, 0, 0, 1, 0, kDTsclose_2d, kDTokgen_2d, 0}
+#define dialphone_2d {kVDial_2d, 0, 0, 1, 1, kDTsdialed_2d, 0, kALphone_2d}
+#define dropdynamite_2d {kVDrop_2d, kRdyn_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALdropdynamite_2d}
+#define eatbanana_2d {kVEat_2d, kRbanana_2d, kDTnocgen_2d, 0, 0, 0, 0, kALeatbanana_2d}
+#define eatgarlic_2d {kVEat_2d, kRgarlic_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALgarlic_2d}
+#define firegun_2d {kVFire_2d, kRgun_2d, kDTnogun_2d, 0, 1, kDTsempty_2d, 0, kALgun_2d}
+#define getballoon_2d {kVTake_2d, 0, 0, 0, 0, 0, 0, kALballoon_2d}
+#define getbook_2d {kVTake_2d, 0, 0, DONT_CARE, 0, 0, 0, kALgetbook_2d}
+#define getdynamite_2d {kVTake_2d, 0, 0, DONT_CARE, 0, 0, 0, kALgetdynamite_2d}
+#define getletter_2d {kVTake_2d, 0, 0, DONT_CARE, 0, kDTsgetlet_2d, 0, 0}
+#define givebanana_2d {kVGive_2d, kRbanana_2d, kDTnocgen_2d, 0, 0, 0, 0, kALbanana_2d}
+#define givebell_2d {kVGive_2d, kRbell_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALgivebel_2d}
+#define givecatnip_2d {kVGive_2d, kRcatnip_2d, kDTnocgen_2d, 0, 0, kDTnopurps_2d, kDTscatnip_2d, 0}
+#define intodumb_2d {kVInto_2d, 0, 0, 0, 0, 0, 0, kALdumb_2d}
+#define knock_2d {kVKnock_2d, 0, 0, DONT_CARE, 0, 0, kDTtnoknock_2d, 0}
+#define lightdynamite_2d {kVStrike_2d, kRmatch_2d, kDTnomatch_2d, DONT_CARE, 0, 0, 0, kALlightdynamite_2d}
+#define lookcubp_2d {kVLook_2d, 0, 0, DONT_CARE, 0, 0, 0, kALphoto_2d}
+#define lookgarlic_2d {kVLook_2d, 0, 0, 0, 1, kDTempty_2d, kDTfindclove_2d, kALgetgarlic_2d}
+#define lookhole_2d {kVLook_2d, 0, 0, 0, 0, kDTdarkhole_2d, 0, kALkeyhole_2d}
+#define lookkennel_2d {kVLook_2d, 0, 0, 0, 0, 0, 0, kALlookkennel_2d}
+#define lookmat_2d {kVLook_2d, 0, 0, 0, 1, kDTempty_2d, kDTfindmatch_2d, kALgetmatch_2d}
+#define lookmatch_2d {kVLook_2d, 0, 0, DONT_CARE, 0, 0, 0, kALlookmatch_2d}
+#define opencubp_2d {kVOpen_2d, 0, 0, DONT_CARE, 0, 0, 0, kALphoto_2d}
+#define opendoor1_2d {kVOpen_2d, 0, 0, 0, 1, kDTsopen1_2d, 0, kALopendoor1_2d}
+#define opendoor2_2d {kVOpen_2d, 0, 0, 0, 1, kDTsopen1_2d, 0, kALopendoor2_2d}
+#define opendoor3_2d {kVOpen_2d, 0, 0, 0, 1, kDTsopen1_2d, 0, kALopendoor3_2d}
+#define opengarlic_2d {kVOpen_2d, 0, 0, 0, 1, kDTempty_2d, kDTfindclove_2d, kALgetgarlic_2d}
+#define openkdoor_2d {kVOpen_2d, 0, 0, 0, 0, 0, kDTwontopen_2d, 0}
+#define openlamp_2d {kVOpen_2d, kRlamp_2d, kDTnocgen_2d, DONT_CARE, 0, 0, kDTempty_2d, 0}
+#define openmat_2d {kVOpen_2d, 0, 0, 0, 1, kDTempty_2d, kDTfindmatch_2d, kALgetmatch_2d}
+#define openpdoor_2d {kVOpen_2d, 0, 0, 0, 0, 0, kDTspdoor_2d, 0}
+#define opensafe_2d {kVOpen_2d, 0, 0, DONT_CARE, 0, 0, 0, kALsafe_2d}
+#define popballoon_2d {kVBreak_2d, 0, 0, 0, 0, 0, 0, kALballoon_2d}
+#define pushblue_2d {kVPush_2d, 0, 0, DONT_CARE, 0, 0, 0, kALworkgates_2d}
+#define pushbutton_2d {kVPush_2d, 0, 0, DONT_CARE, 0, 0, kDTtnopushbutton_2d, 0}
+#define pushgreen_2d {kVPush_2d, 0, 0, DONT_CARE, 0, 0, 0, kALbugzapper_2d}
+#define pushpaper_2d {kVPush_2d, kRpaper_2d, kDTnocgen_2d, 0, 1, 0, kDTokgen_2d, kALpushpaper_2d}
+#define pushpencil_2d {kVPush_2d, kRpencil_2d, kDTnocgen_2d, 0, 0, 0, 0, kALpushpencil_2d}
+#define pushred_2d {kVPush_2d, 0, 0, DONT_CARE, 0, 0, 0, kALshedlight_2d}
+#define pushyellow_2d {kVPush_2d, 0, 0, DONT_CARE, 0, 0, 0, kALgatelight_2d}
+#define readletter_2d {kVRead_2d, 0, 0, 3, 3, kDTsnoread_2d, kDTsread_2d, kALreadlet_2d}
+#define readwill_2d {kVRead_2d, kRwill_2d, kDTnocgen_2d, 1, 1, 0, 0, kALwill_2d}
+#define ringbell_2d {kVRing_2d, kRbell_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALbell_2d}
+#define rubcatnip_2d {kVRub_2d, kRcatnip_2d, kDTnocgen_2d, 0, 0, kDTnopurps_2d, 0, kALcatnip_2d}
+#define rublamp_2d {kVRub_2d, kRlamp_2d, kDTnocgen_2d, 0, 0, kDTnopurps_2d, 0, kALlamp_2d}
+#define serum_2d {kVDrink_2d, kRserum_2d, kDTnocgen_2d, 0, 1, kDTsnosee_2d, 0, kALbottle_2d}
+#define strikematch_2d {kVStrike_2d, kRmatch_2d, kDTnocgen_2d, DONT_CARE, 0, 0, 0, kALstrikematch_2d}
+#define talkharry_2d {kVTalk_2d, 0, 0, 0, 1, kDTsharry_2d, 0, kALharry_2d}
+#define throwstick_2d {kVThrow_2d, kRstick_2d, kDTnocgen_2d, 0, 1, 0, 0, kALthrowstick_2d}
+#define unlock_2d {kVUnlock_2d, 0, 0, DONT_CARE, 0, 0, kDTtnounlock_2d, 0}
cmd balloon_2d[] = {popballoon_2d, getballoon_2d, emptyCmd};
cmd banana_2d[] = {givebanana_2d, eatbanana_2d, emptyCmd};
@@ -4792,49 +4811,49 @@ const cmd *cmdList_2d[] = {
well_2d, will_2d, yellow_2d
};
-cmd bell_3d = {kVRing_3d, kRbell_3d, kDTnocgen_3d, DONT_CARE, 0, 0, kDTokbell_3d, 0};
-cmd blow_3d = {kVBlow_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdart_3d};
-cmd book_3d = {kVRead_3d, kRbook_3d, kDTnocgen_3d, DONT_CARE, 0, 0, 0, kALreadbook_3d};
-cmd cage1_3d = {kVOpen_3d, 0, 0, DONT_CARE, 0, 0, 0, kALopencage_3d};
-cmd cage2_3d = {kVClose_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, 0};
-cmd cage3_3d = {kVTake_3d, 0, 0, DONT_CARE, 0, 0, 0, kALtakecage_3d};
-cmd candle1_3d = {kVDouse_3d, 0, 0, 1, 0, kDTsunlit_3d, kDTokgen_3d, 0};
-cmd candle2_3d = {kVStrike_3d, 0, 0, 0, 1, kDTslit_3d, kDTokgen_3d, 0};
-cmd cdoor1_3d = {kVOpen_3d, 0, 0, 0, 0, kDTsopen1_3d, 0, kALopendoor_3d};
-cmd cdoor2_3d = {kVClose_3d, 0, 0, 1, 0, kDTsclose_3d, kDTokgen_3d, kALclosedoor_3d};
-cmd cexit1_3d = {kVOutof_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALexit_3d};
-cmd cexit2_3d = {kVClimb_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALexit_3d};
-cmd cflask1_3d = {kVFill_3d, 0, 0, 0, 1, kDTsfull_3d, 0, kALfill_3d};
-cmd cflask2_3d = {kVPut_3d, 0, 0, 0, 1, kDTsfull_3d, 0, kALfill_3d};
-cmd cflask3_3d = {kVEmpty_3d, 0, 0, DONT_CARE, 0, 0, 0, kALempty_3d};
-cmd cflask4_3d = {kVDrink_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdrink_3d};
-cmd cflask5_3d = {kVGive_3d, 0, 0, DONT_CARE, 0, 0, 0, kALflask_3d};
-cmd cheese1_3d = {kVEat_3d, kRcheese_3d, kDTnocgen_3d, 0, 0, 0, 0, kALeatcheese_3d};
-cmd cheese2_3d = {kVDrop_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdropcheese_3d};
-cmd cheese3_3d = {kVPut_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdropcheese_3d};
-cmd cheese4_3d = {kVTake_3d, 0, 0, DONT_CARE, 0, 0, 0, kALtakecheese_3d};
-cmd cmake1_3d = {kVMake_3d, 0, 0, 0, 0, kDTsmade_3d, 0, kALmakeclay_3d};
-cmd cmake2_3d = {kVStick_3d, kRpins_3d, kDTnopins_3d, DONT_CARE, 0, 0, 0, kALstick_3d};
-cmd cplane1_3d = {kVClimb_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALplane_3d};
-cmd cplane2_3d = {kVInto_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALplane_3d};
-cmd cplane3_3d = {kVSearch_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALplane_3d};
-cmd crystal_3d = {kVRub_3d, kRcrystal_3d, kDTnocgen_3d, DONT_CARE, 0, 0, 0, kALcrystal_3d};
-cmd cstick1_3d = {kVStick_3d, 0, 0, 0, 0, 0, 0, kALstick_3d};
-cmd cswing1_3d = {kVSwing_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALswing_3d};
-cmd ctalknat_3d = {kVTalk_3d, 0, 0, DONT_CARE, 0, 0, 0, kALtalknat_3d};
-cmd cube1_3d = {kVGive_3d, 0, 0, DONT_CARE, 0, 0, 0, kALgiveb_3d};
-cmd cvine1_3d = {kVUntie_3d, 0, 0, 0, 0, 0, 0, kALuntie_vine_3d};
-cmd cvine2_3d = {kVTie_3d, 0, 0, 0, 0, 0, 0, kALvine_3d};
-cmd cwaterfall_3d = {kVLook_3d, 0, 0, DONT_CARE, 0, 0, 0, kALlookwfall_3d};
-cmd cwaterpool_3d = {kVLook_3d, 0, 0, DONT_CARE, 0, 0, kDTdull_3d, 0};
-cmd cwaterstream_3d = {kVLook_3d, 0, 0, DONT_CARE, 0, 0, kDTdull_3d, 0};
-cmd dart_3d = {kVShoot_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdart_3d};
-cmd ghost_3d = {kVExorcise_3d, kRexor_3d, kDTnocex_3d, DONT_CARE, 0, 0, 0, kALexorcise_3d};
-cmd knock_3d = {kVKnock_3d, 0, 0, DONT_CARE, 0, 0, kDTsNobody_3d, 0};
-cmd readit_3d = {kVRead_3d, 0, 0, DONT_CARE, 0, 0, kDTsread_3d, 0};
-cmd rock1_3d = {kVBehind_3d, 0, 0, 0, 1, kDTsfoundc_3d, kDTsfindc_3d, kALfindcrystal_3d};
-cmd swingc_3d = {kVSwing_3d, 0, 0, DONT_CARE, 0, 0, kDTswingcave_3d, 0};
-cmd unlock_3d = {kVUnlock_3d, 0, 0, DONT_CARE, 0, 0, kDTsUnlocked_3d, 0};
+#define bell_3d {kVRing_3d, kRbell_3d, kDTnocgen_3d, DONT_CARE, 0, 0, kDTokbell_3d, 0}
+#define blow_3d {kVBlow_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdart_3d}
+#define book_3d {kVRead_3d, kRbook_3d, kDTnocgen_3d, DONT_CARE, 0, 0, 0, kALreadbook_3d}
+#define cage1_3d {kVOpen_3d, 0, 0, DONT_CARE, 0, 0, 0, kALopencage_3d}
+#define cage2_3d {kVClose_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, 0}
+#define cage3_3d {kVTake_3d, 0, 0, DONT_CARE, 0, 0, 0, kALtakecage_3d}
+#define candle1_3d {kVDouse_3d, 0, 0, 1, 0, kDTsunlit_3d, kDTokgen_3d, 0}
+#define candle2_3d {kVStrike_3d, 0, 0, 0, 1, kDTslit_3d, kDTokgen_3d, 0}
+#define cdoor1_3d {kVOpen_3d, 0, 0, 0, 0, kDTsopen1_3d, 0, kALopendoor_3d}
+#define cdoor2_3d {kVClose_3d, 0, 0, 1, 0, kDTsclose_3d, kDTokgen_3d, kALclosedoor_3d}
+#define cexit1_3d {kVOutof_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALexit_3d}
+#define cexit2_3d {kVClimb_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALexit_3d}
+#define cflask1_3d {kVFill_3d, 0, 0, 0, 1, kDTsfull_3d, 0, kALfill_3d}
+#define cflask2_3d {kVPut_3d, 0, 0, 0, 1, kDTsfull_3d, 0, kALfill_3d}
+#define cflask3_3d {kVEmpty_3d, 0, 0, DONT_CARE, 0, 0, 0, kALempty_3d}
+#define cflask4_3d {kVDrink_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdrink_3d}
+#define cflask5_3d {kVGive_3d, 0, 0, DONT_CARE, 0, 0, 0, kALflask_3d}
+#define cheese1_3d {kVEat_3d, kRcheese_3d, kDTnocgen_3d, 0, 0, 0, 0, kALeatcheese_3d}
+#define cheese2_3d {kVDrop_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdropcheese_3d}
+#define cheese3_3d {kVPut_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdropcheese_3d}
+#define cheese4_3d {kVTake_3d, 0, 0, DONT_CARE, 0, 0, 0, kALtakecheese_3d}
+#define cmake1_3d {kVMake_3d, 0, 0, 0, 0, kDTsmade_3d, 0, kALmakeclay_3d}
+#define cmake2_3d {kVStick_3d, kRpins_3d, kDTnopins_3d, DONT_CARE, 0, 0, 0, kALstick_3d}
+#define cplane1_3d {kVClimb_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALplane_3d}
+#define cplane2_3d {kVInto_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALplane_3d}
+#define cplane3_3d {kVSearch_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALplane_3d}
+#define crystal_3d {kVRub_3d, kRcrystal_3d, kDTnocgen_3d, DONT_CARE, 0, 0, 0, kALcrystal_3d}
+#define cstick1_3d {kVStick_3d, 0, 0, 0, 0, 0, 0, kALstick_3d}
+#define cswing1_3d {kVSwing_3d, 0, 0, DONT_CARE, 0, 0, kDTokgen_3d, kALswing_3d}
+#define ctalknat_3d {kVTalk_3d, 0, 0, DONT_CARE, 0, 0, 0, kALtalknat_3d}
+#define cube1_3d {kVGive_3d, 0, 0, DONT_CARE, 0, 0, 0, kALgiveb_3d}
+#define cvine1_3d {kVUntie_3d, 0, 0, 0, 0, 0, 0, kALuntie_vine_3d}
+#define cvine2_3d {kVTie_3d, 0, 0, 0, 0, 0, 0, kALvine_3d}
+#define cwaterfall_3d {kVLook_3d, 0, 0, DONT_CARE, 0, 0, 0, kALlookwfall_3d}
+#define cwaterpool_3d {kVLook_3d, 0, 0, DONT_CARE, 0, 0, kDTdull_3d, 0}
+#define cwaterstream_3d {kVLook_3d, 0, 0, DONT_CARE, 0, 0, kDTdull_3d, 0}
+#define dart_3d {kVShoot_3d, 0, 0, DONT_CARE, 0, 0, 0, kALdart_3d}
+#define ghost_3d {kVExorcise_3d, kRexor_3d, kDTnocex_3d, DONT_CARE, 0, 0, 0, kALexorcise_3d}
+#define knock_3d {kVKnock_3d, 0, 0, DONT_CARE, 0, 0, kDTsNobody_3d, 0}
+#define readit_3d {kVRead_3d, 0, 0, DONT_CARE, 0, 0, kDTsread_3d, 0}
+#define rock1_3d {kVBehind_3d, 0, 0, 0, 1, kDTsfoundc_3d, kDTsfindc_3d, kALfindcrystal_3d}
+#define swingc_3d {kVSwing_3d, 0, 0, DONT_CARE, 0, 0, kDTswingcave_3d, 0}
+#define unlock_3d {kVUnlock_3d, 0, 0, DONT_CARE, 0, 0, kDTsUnlocked_3d, 0}
cmd cbell_3d[] = {bell_3d, emptyCmd};
cmd cbook_3d[] = {book_3d, emptyCmd};
@@ -4872,22 +4891,22 @@ const cmd *cmdList_3d[] = {
// The following are lists of actions invoked when entering a screen
// They consist of actions which occur no matter which door is entered
// See the list of 'hotspots' and 'Open' cmds for door specific actions
-uint16 s0acts_1w[] = {kALclosedoor1_1w, kALblinkeyes1_1w, kALightning_1w, kALbat_1w, 0}; // House
-uint16 s1acts_1w[] = {kALblinkeyes2_1w, kALridprof_1w, 0}; // Hall
-uint16 s2acts_1w[] = {0}; // Bed1
-uint16 s3acts_1w[] = {kALbut_1w, kALrepredeye_1w, kALreplips_1w, kALreparm_1w, 0}; // dining room
-uint16 s4acts_1w[] = {0}; // Bathroom
-uint16 s5acts_1w[] = {0}; // Kitchen
-uint16 s6acts_1w[] = {0}; // Garden
-uint16 s7acts_1w[] = {kALdog_1w, 0}; // Store room
-uint16 s8acts_1w[] = {kALhelp_1w, 0}; // Basement
-uint16 s9acts_1w[] = {kALbatattack_1w, 0}; // Batcave
-uint16 s10acts_1w[] = {kALmum_1w, 0}; // Mummy room
-uint16 s11acts_1w[] = {0}; // Lake room
-uint16 s12acts_1w[] = {0}; // Dead end
-uint16 s13acts_1w[] = {kALjail_1w, 0}; // Jail
-uint16 s14acts_1w[] = {kALgoodbye_1w, 0}; // The end
-uint16 s15acts_1w[] = {kALlab_1w, kALbox_1w, 0}; // Laboratory
+uint16 s0acts_1w[] = {kALclosedoor1_1w, kALblinkeyes1_1w, kALightning_1w, kALbat_1w, 0}; // House
+uint16 s1acts_1w[] = {kALblinkeyes2_1w, kALridprof_1w, 0}; // Hall
+uint16 s2acts_1w[] = {0}; // Bed1
+uint16 s3acts_1w[] = {kALbut_1w, kALrepredeye_1w, kALreplips_1w, kALreparm_1w, 0}; // dining room
+uint16 s4acts_1w[] = {0}; // Bathroom
+uint16 s5acts_1w[] = {0}; // Kitchen
+uint16 s6acts_1w[] = {0}; // Garden
+uint16 s7acts_1w[] = {kALdog_1w, 0}; // Store room
+uint16 s8acts_1w[] = {kALhelp_1w, 0}; // Basement
+uint16 s9acts_1w[] = {kALbatattack_1w, 0}; // Batcave
+uint16 s10acts_1w[] = {kALmum_1w, 0}; // Mummy room
+uint16 s11acts_1w[] = {0}; // Lake room
+uint16 s12acts_1w[] = {0}; // Dead end
+uint16 s13acts_1w[] = {kALjail_1w, 0}; // Jail
+uint16 s14acts_1w[] = {kALgoodbye_1w, 0}; // The end
+uint16 s15acts_1w[] = {kALlab_1w, kALbox_1w, 0}; // Laboratory
const uint16 *screenActs_1w[] = {
s0acts_1w, s1acts_1w, s2acts_1w, s3acts_1w, s4acts_1w,
@@ -4896,66 +4915,66 @@ const uint16 *screenActs_1w[] = {
s15acts_1w
};
-uint16 s0acts_2w[] = {kALscr01Story_2w, 0}; // House
-uint16 s1acts_2w[] = {kALpenny1_2w, kALmaid_2w, kALheroxy01_2w, 0};// Hall
-uint16 s2acts_2w[] = {kALscr02_2w, 0}; // Bed1
-uint16 s3acts_2w[] = {kALscr03_2w, 0}; // Bed2
-uint16 s4acts_2w[] = {kALscr04_2w, 0}; // Murder
-uint16 s6acts_2w[] = {kALscr06_2w, 0}; // Kitchen
-uint16 s9acts_2w[] = {kALscr09_2w, 0}; // In shed
-uint16 s10acts_2w[] = {kALscr10_2w, 0}; // Venus
-uint16 s14acts_2w[] = {kALscr14_2w, 0}; // Bug attack
-uint16 s15acts_2w[] = {kALscr15_2w, 0}; // Old man
-uint16 s17acts_2w[] = {kALmap0_2w, 0}; // Snakepit
-uint16 s18acts_2w[] = {kALmap1_2w, 0}; // Phonebox
-uint16 s25acts_2w[] = {kALscr25_2w, 0}; // Chasm
-uint16 s29acts_2w[] = {kALscr29_2w, 0}; // Hall2
-uint16 s30acts_2w[] = {kALscr30_2w, 0}; // Lounge
-uint16 s31acts_2w[] = {kALmaidp_2w, 0}; // Parlor
-uint16 s33acts_2w[] = {kALscr33_2w, 0}; // Boxroom
-uint16 s34acts_2w[] = {kALscr34_2w, 0}; // Hall3
-uint16 s35acts_2w[] = {kALscr35_2w, 0}; // Organ
-uint16 s36acts_2w[] = {kALscr36_2w, 0}; // Hestroom
-uint16 s37acts_2w[] = {kALsong3_2w, 0}; // Retupmoc
+uint16 s0acts_2w[] = {kALscr01Story_2w, 0}; // House
+uint16 s1acts_2w[] = {kALpenny1_2w, kALmaid_2w, kALheroxy01_2w, 0}; // Hall
+uint16 s2acts_2w[] = {kALscr02_2w, 0}; // Bed1
+uint16 s3acts_2w[] = {kALscr03_2w, 0}; // Bed2
+uint16 s4acts_2w[] = {kALscr04_2w, 0}; // Murder
+uint16 s6acts_2w[] = {kALscr06_2w, 0}; // Kitchen
+uint16 s9acts_2w[] = {kALscr09_2w, 0}; // In shed
+uint16 s10acts_2w[] = {kALscr10_2w, 0}; // Venus
+uint16 s14acts_2w[] = {kALscr14_2w, 0}; // Bug attack
+uint16 s15acts_2w[] = {kALscr15_2w, 0}; // Old man
+uint16 s17acts_2w[] = {kALmap0_2w, 0}; // Snakepit
+uint16 s18acts_2w[] = {kALmap1_2w, 0}; // Phonebox
+uint16 s25acts_2w[] = {kALscr25_2w, 0}; // Chasm
+uint16 s29acts_2w[] = {kALscr29_2w, 0}; // Hall2
+uint16 s30acts_2w[] = {kALscr30_2w, 0}; // Lounge
+uint16 s31acts_2w[] = {kALmaidp_2w, 0}; // Parlor
+uint16 s33acts_2w[] = {kALscr33_2w, 0}; // Boxroom
+uint16 s34acts_2w[] = {kALscr34_2w, 0}; // Hall3
+uint16 s35acts_2w[] = {kALscr35_2w, 0}; // Organ
+uint16 s36acts_2w[] = {kALscr36_2w, 0}; // Hestroom
+uint16 s37acts_2w[] = {kALsong3_2w, 0}; // Retupmoc
const uint16 *screenActs_2w[] = {
/* 0 */ s0acts_2w, s1acts_2w, s2acts_2w, s3acts_2w, s4acts_2w,
- 0, s6acts_2w, 0, 0, s9acts_2w,
- /* 10 */ s10acts_2w, 0, 0, 0, s14acts_2w,
- s15acts_2w, 0, s17acts_2w, s18acts_2w, 0,
- /* 20 */ 0, 0, 0, 0, 0,
- s25acts_2w, 0, 0, 0, s29acts_2w,
- /* 30 */ s30acts_2w, s31acts_2w, 0, s33acts_2w, s34acts_2w,
- s35acts_2w, s36acts_2w, s37acts_2w, 0, 0,
- /* 40 */ 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- /* 50 */ 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- /* 60 */ 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- /* 70 */ 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- /* 80 */ 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- /* 90 */ 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- /*100 */ 0, 0, 0
+ 0, s6acts_2w, 0, 0, s9acts_2w,
+ /* 10 */ s10acts_2w, 0, 0, 0, s14acts_2w,
+ s15acts_2w, 0, s17acts_2w, s18acts_2w, 0,
+ /* 20 */ 0, 0, 0, 0, 0,
+ s25acts_2w, 0, 0, 0, s29acts_2w,
+ /* 30 */ s30acts_2w, s31acts_2w, 0, s33acts_2w, s34acts_2w,
+ s35acts_2w, s36acts_2w, s37acts_2w, 0, 0,
+ /* 40 */ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* 50 */ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* 60 */ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* 70 */ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* 80 */ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* 90 */ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /*100 */ 0, 0, 0
};
uint16 s0acts_3w[] = {kALcrashStory_3w, kALhorizon_3w, 0}; // Crash site
-uint16 s1acts_3w[] = {kALweb_3w, 0}; // Spider's web
-uint16 s2acts_3w[] = {kALbridgetest_3w, kALbridgetip_3w, 0};// Bridge1
-uint16 s13acts_3w[] = {kALhut_in_3w, kALmouse_3w, 0};// In hut
-uint16 s15acts_3w[] = {kALoldman_3w, kALflash_3w, 0};// Oldman
-uint16 s18acts_3w[] = {kALcamp_3w, 0}; // At camp
-uint16 s19acts_3w[] = {kALsunset_3w, 0}; // Bye bye!
-uint16 s23acts_3w[] = {kALpath_3w, 0}; // Elephant
+uint16 s1acts_3w[] = {kALweb_3w, 0}; // Spider's web
+uint16 s2acts_3w[] = {kALbridgetest_3w, kALbridgetip_3w, 0}; // Bridge1
+uint16 s13acts_3w[] = {kALhut_in_3w, kALmouse_3w, 0}; // In hut
+uint16 s15acts_3w[] = {kALoldman_3w, kALflash_3w, 0}; // Oldman
+uint16 s18acts_3w[] = {kALcamp_3w, 0}; // At camp
+uint16 s19acts_3w[] = {kALsunset_3w, 0}; // Bye bye!
+uint16 s23acts_3w[] = {kALpath_3w, 0}; // Elephant
const uint16 *screenActs_3w[] = {
- /* 0 */ s0acts_3w, s1acts_3w, s2acts_3w, 0, 0,
- 0, 0, 0, 0, 0,
- /* 10 */ 0, 0, 0, s13acts_3w, 0,
- s15acts_3w, 0, 0, s18acts_3w, s19acts_3w,
- /* 20 */ 0, 0, 0, s23acts_3w, 0,
- 0, 0, 0, 0, 0,
+ /* 0 */ s0acts_3w, s1acts_3w, s2acts_3w, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* 10 */ 0, 0, 0, s13acts_3w, 0,
+ s15acts_3w, 0, 0, s18acts_3w, s19acts_3w,
+ /* 20 */ 0, 0, 0, s23acts_3w, 0,
+ 0, 0, 0, 0, 0,
/* 30 */ 0
};
@@ -4984,173 +5003,173 @@ const uint16 *screenActs_1d[] = {
};
-uint16 s0acts_2d[] = {kALscr01_2d, kALsong1_2d, 0}; // House
-uint16 s1acts_2d[] = {kALpenny1_2d, kALmaid_2d, kALheroxy01_2d, 0}; // Hall
-uint16 s2acts_2d[] = {kALscr02_2d, 0}; // Bed1
-uint16 s3acts_2d[] = {kALscr03_2d, 0}; // Bed2
-uint16 s4acts_2d[] = {kALscr04_2d, 0}; // Murder
-uint16 s6acts_2d[] = {kALscr06_2d, 0}; // Kitchen
-uint16 s9acts_2d[] = {kALscr09_2d, 0}; // In shed
-uint16 s10acts_2d[] = {kALscr10_2d, 0}; // Venus
-uint16 s14acts_2d[] = {kALscr14_2d, 0}; // Bug attack
-uint16 s15acts_2d[] = {kALscr15_2d, 0}; // Old man
-uint16 s17acts_2d[] = {kALmap0_2d, 0}; // Snakepit
-uint16 s18acts_2d[] = {kALmap1_2d, 0}; // Phonebox
-uint16 s29acts_2d[] = {kALscr29_2d, 0}; // Hall2
-uint16 s30acts_2d[] = {kALscr30_2d, 0}; // Lounge
-uint16 s31acts_2d[] = {kALmaidp_2d, 0}; // Parlor
-uint16 s33acts_2d[] = {kALscr33_2d, 0}; // Boxroom
-uint16 s34acts_2d[] = {kALscr34_2d, 0}; // Hall3
-uint16 s35acts_2d[] = {kALscr35_2d, 0}; // Organ
-uint16 s36acts_2d[] = {kALscr36_2d, 0}; // Hestroom
-uint16 s37acts_2d[] = {kALsong3_2d, 0}; // Retupmoc
+uint16 s0acts_2d[] = {kALscr01_2d, kALsong1_2d, 0}; // House
+uint16 s1acts_2d[] = {kALpenny1_2d, kALmaid_2d, kALheroxy01_2d, 0}; // Hall
+uint16 s2acts_2d[] = {kALscr02_2d, 0}; // Bed1
+uint16 s3acts_2d[] = {kALscr03_2d, 0}; // Bed2
+uint16 s4acts_2d[] = {kALscr04_2d, 0}; // Murder
+uint16 s6acts_2d[] = {kALscr06_2d, 0}; // Kitchen
+uint16 s9acts_2d[] = {kALscr09_2d, 0}; // In shed
+uint16 s10acts_2d[] = {kALscr10_2d, 0}; // Venus
+uint16 s14acts_2d[] = {kALscr14_2d, 0}; // Bug attack
+uint16 s15acts_2d[] = {kALscr15_2d, 0}; // Old man
+uint16 s17acts_2d[] = {kALmap0_2d, 0}; // Snakepit
+uint16 s18acts_2d[] = {kALmap1_2d, 0}; // Phonebox
+uint16 s29acts_2d[] = {kALscr29_2d, 0}; // Hall2
+uint16 s30acts_2d[] = {kALscr30_2d, 0}; // Lounge
+uint16 s31acts_2d[] = {kALmaidp_2d, 0}; // Parlor
+uint16 s33acts_2d[] = {kALscr33_2d, 0}; // Boxroom
+uint16 s34acts_2d[] = {kALscr34_2d, 0}; // Hall3
+uint16 s35acts_2d[] = {kALscr35_2d, 0}; // Organ
+uint16 s36acts_2d[] = {kALscr36_2d, 0}; // Hestroom
+uint16 s37acts_2d[] = {kALsong3_2d, 0}; // Retupmoc
const uint16 *screenActs_2d[] = {
s0acts_2d, s1acts_2d, s2acts_2d, s3acts_2d, s4acts_2d,
- 0, s6acts_2d, 0, 0, s9acts_2d,
- s10acts_2d, 0, 0, 0, s14acts_2d,
- s15acts_2d, 0, s17acts_2d, s18acts_2d, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, s29acts_2d,
- s30acts_2d, s31acts_2d, 0, s33acts_2d, s34acts_2d,
- s35acts_2d, s36acts_2d, s37acts_2d, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0
-};
-
-uint16 s0acts_3d[] = {kALcrashStory_3d, 0}; // Crash site
-uint16 s1acts_3d[] = {kALweb_3d, 0}; // Spider's web
-uint16 s2acts_3d[] = {kALbridgetip_3d, 0}; // Bridge1
-uint16 s13acts_3d[] = {kALhut_in_3d, kALmouse_3d, 0}; // In hut
-uint16 s15acts_3d[] = {kALoldman_3d, kALflash_3d, 0}; // Oldman
-uint16 s18acts_3d[] = {kALcamp_3d, 0}; // At camp
-uint16 s19acts_3d[] = {kALsunset_3d, 0}; // Bye bye!
-uint16 s23acts_3d[] = {kALpath_3d, 0}; // Elephant
+ 0, s6acts_2d, 0, 0, s9acts_2d,
+ s10acts_2d, 0, 0, 0, s14acts_2d,
+ s15acts_2d, 0, s17acts_2d, s18acts_2d, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, s29acts_2d,
+ s30acts_2d, s31acts_2d, 0, s33acts_2d, s34acts_2d,
+ s35acts_2d, s36acts_2d, s37acts_2d, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0
+};
+
+uint16 s0acts_3d[] = {kALcrashStory_3d, 0}; // Crash site
+uint16 s1acts_3d[] = {kALweb_3d, 0}; // Spider's web
+uint16 s2acts_3d[] = {kALbridgetip_3d, 0}; // Bridge1
+uint16 s13acts_3d[] = {kALhut_in_3d, kALmouse_3d, 0}; // In hut
+uint16 s15acts_3d[] = {kALoldman_3d, kALflash_3d, 0}; // Oldman
+uint16 s18acts_3d[] = {kALcamp_3d, 0}; // At camp
+uint16 s19acts_3d[] = {kALsunset_3d, 0}; // Bye bye!
+uint16 s23acts_3d[] = {kALpath_3d, 0}; // Elephant
const uint16 *screenActs_3d[] = {
- /* 0 */ s0acts_3d, s1acts_3d, s2acts_3d, 0, 0,
- 0, 0, 0, 0, 0,
- /* 10 */ 0, 0, 0, s13acts_3d, 0,
- s15acts_3d, 0, 0, s18acts_3d, s19acts_3d,
- /* 20 */ 0, 0, 0, s23acts_3d, 0,
- 0, 0, 0, 0, 0,
+ /* 0 */ s0acts_3d, s1acts_3d, s2acts_3d, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* 10 */ 0, 0, 0, s13acts_3d, 0,
+ s15acts_3d, 0, 0, s18acts_3d, s19acts_3d,
+ /* 20 */ 0, 0, 0, s23acts_3d, 0,
+ 0, 0, 0, 0, 0,
/* 30 */ 0
};
object_t objects_1w[] = {
//name, description, description_s,path, dx, dy, aptr, seq,seqp, cyc, n,frm,rad,scr,x,y , oldxy,vxy,val,g,cmnd, c, s,ctx,fgb
-{kNHero_1w, kDTthero_1w, 0, USER, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 0, 0, 229, 144, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHero_1w, kDTthero_1w, 0, USER, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 0, 0, 229, 144, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 0: (Outside house)
-{kNDoor_1w, kDTtdoor_1w, 0, AUTO, 0, 0, 0, THING4, INVISIBLE, 1, 4, 4, 16, 0, 26, 131, 90, 90, 0, 0, 0, 1, kCMDdoor1_1w, 0, 0, 0, FLOATING, 29, 175, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNEyes_1w, kDTteyes_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 80, 148, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, 72, 175, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNEyes_1w, kDTteyes_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 59, 78, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, 72, 175, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 95, 55, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNPkin_1w, kDTtpkin_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 10, 0, 20, 168, 90, 90, 0, 0, 2, 7, kCMDpkin_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNKey_1w, kDTtkey_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 5, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFence_1w, 0, 0, AUTO, 193, 37, 0, THING0, INVISIBLE, 0, 0, 0, 30, 0, 69, 161, 127, 145, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 225, 183, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNTree_1w, 0, 0, AUTO, 25, 52, 0, THING0, INVISIBLE, 0, 0, 0, 30, 0, 69, 161, 186, 93, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 190, 183, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_1w, kDTtdoor_1w, 0, AUTO, 0, 0, 0, THING4, INVISIBLE, 1, 4, 4, 16, 0, 26, 131, 90, 90, 0, 0, 0, 1, kCMDdoor1_1w, 0, 0, 0, FLOATING, 29, 175, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNEyes_1w, kDTteyes_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 80, 148, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, 72, 175, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNEyes_1w, kDTteyes_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 59, 78, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, 72, 175, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 95, 55, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNPkin_1w, kDTtpkin_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 10, 0, 20, 168, 90, 90, 0, 0, 2, 7, kCMDpkin_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNKey_1w, kDTtkey_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 5, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFence_1w, 0, 0, AUTO, 193, 37, 0, THING0, INVISIBLE, 0, 0, 0, 30, 0, 69, 161, 127, 145, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 225, 183, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNTree_1w, 0, 0, AUTO, 25, 52, 0, THING0, INVISIBLE, 0, 0, 0, 30, 0, 69, 161, 186, 93, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 190, 183, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 1: (Hall)
-{kNDoor_1w, kDTtdoor_1w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 125, 56, 90, 90, 0, 0, 0, 1, kCMDdoor2_1w, 0, 0, 0, FLOATING, 127, 98, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDoor_1w, kDTtdoor_1w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 208, 56, 90, 90, 0, 0, 0, 1, kCMDdoor3_1w, 0, 0, 0, FLOATING, 210, 98, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNEyes_1w, kDTteyes_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 1, 23, 48, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, 48, 98, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNEyes_1w, kDTteyes_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 1, 7, 93, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, 32, 140, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNBatpic_1w, 0, 0, AUTO, 46, 30, 0, THING0, INVISIBLE, 0, 0, 0, 30, 1, 69, 161, 113, 108, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 110, 160, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNCandle_1w, kDTtcandle_1w, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 30, 1, 176, 131, 90, 90, 0, 0, 3, 7, 0, 0, 0, 0, FLOATING, 164, 165, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNCupb_1w, 0, 0, AUTO, 9, 25, 0, THING0, INVISIBLE, 0, 0, 0, 20, 1, 69, 161, 67, 140, 0, 0, 0, 1, kCMDcupb_1w, 0, 0, 1, FLOATING, 81, 168, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNKnife_1w, kDTtknife_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, 1, 69, 169, 90, 90, 0, 0, 6, 7, kCMDknife_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWhistle_1w, kDTtwhistle_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, 1, 79, 171, 90, 90, 0, 0, 6, 7, kCMDwhistle_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_1w, kDTtdoor_1w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 125, 56, 90, 90, 0, 0, 0, 1, kCMDdoor2_1w, 0, 0, 0, FLOATING, 127, 98, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_1w, kDTtdoor_1w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 208, 56, 90, 90, 0, 0, 0, 1, kCMDdoor3_1w, 0, 0, 0, FLOATING, 210, 98, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNEyes_1w, kDTteyes_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 1, 23, 48, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, 48, 98, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNEyes_1w, kDTteyes_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 1, 7, 93, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, 32, 140, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNBatpic_1w, 0, 0, AUTO, 46, 30, 0, THING0, INVISIBLE, 0, 0, 0, 30, 1, 69, 161, 113, 108, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 110, 160, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNCandle_1w, kDTtcandle_1w, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 30, 1, 176, 131, 90, 90, 0, 0, 3, 7, 0, 0, 0, 0, FLOATING, 164, 165, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNCupb_1w, 0, 0, AUTO, 9, 25, 0, THING0, INVISIBLE, 0, 0, 0, 20, 1, 69, 161, 67, 140, 0, 0, 0, 1, kCMDcupb_1w, 0, 0, 1, FLOATING, 81, 168, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNKnife_1w, kDTtknife_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, 1, 69, 169, 90, 90, 0, 0, 6, 7, kCMDknife_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWhistle_1w, kDTtwhistle_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, 1, 79, 171, 90, 90, 0, 0, 6, 7, kCMDwhistle_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 2: (Bedroom 1)
-{kNWard_1w, kDTtward_1w, 0, AUTO, 46, 51, 0, THING0, INVISIBLE, 1, 4, 4, 30, 2, 172, 113, 150, 58, 0, 0, 0, 1, kCMDward_1w, 0, 0, 0, FLOATING, 168, 117, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNWdoorl_1w, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 2, 150, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWdoorr_1w, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 2, 174, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMask_1w, kDTtmask_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 2, 155, 100, 90, 90, 0, 0, 4, 7, kCMDmask_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMonkey_1w, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 2, 229, 144, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWindow_1w, 0, 0, AUTO, 29, 22, 0, THING0, INVISIBLE, 1, 4, 4, 30, 2, 172, 113, 117, 57, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 136, 116, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNBed_1w, 0, 0, AUTO, 60, 36, 0, THING0, INVISIBLE, 1, 4, 4, 30, 2, 172, 113, 78, 92, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 127, 130, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNWard_1w, kDTtward_1w, 0, AUTO, 46, 51, 0, THING0, INVISIBLE, 1, 4, 4, 30, 2, 172, 113, 150, 58, 0, 0, 0, 1, kCMDward_1w, 0, 0, 0, FLOATING, 168, 117, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNWdoorl_1w, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 2, 150, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWdoorr_1w, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 2, 174, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMask_1w, kDTtmask_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 2, 155, 100, 90, 90, 0, 0, 4, 7, kCMDmask_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMonkey_1w, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 2, 229, 144, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWindow_1w, 0, 0, AUTO, 29, 22, 0, THING0, INVISIBLE, 1, 4, 4, 30, 2, 172, 113, 117, 57, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 136, 116, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBed_1w, 0, 0, AUTO, 60, 36, 0, THING0, INVISIBLE, 1, 4, 4, 30, 2, 172, 113, 78, 92, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 127, 130, Common::KEYCODE_LEFT, 0, 0, 0, 0},
// Screen 3: (Dining room)
-{kNButler_1w, kDTtbutler_1w, 0, AUTO, 0, 0, kALbutler_1w, PERSON, NOT_CYCLING, 0, 0, 0, 20, 3, 70, 78, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNChop_1w, kDTtchop_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 20, 3, 69, 161, 90, 90, 0, 0, 0, 7, kCMDchop_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNRedeyes_1w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, 3, 212, 108, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNLips_1w, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 1, 1, 0, 3, 113, 105, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNArm_1w, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 5, 5, 0, 3, 166, 122, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNHdlshero_1w, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPicture_1w, 0, 0, AUTO, 74, 41, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 172, 113, 122, 52, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 169, 120, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNWindow_1w, 0, 0, AUTO, 41, 50, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 172, 113, 265, 64, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 269, 139, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNCupb_1w, 0, 0, AUTO, 44, 29, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 172, 113, 65, 69, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 78, 124, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNFrank_1w, kDTtfrank_1w, 0, AUTO, 23, 28, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 90, 110, 104, 97, 0, 0, 0, 1, kCMDfrank_1w, 0, 0, 0, FLOATING, 90, 134, Common::KEYCODE_DOWN, 0, 0, 0, 0},
-{kNDracula_1w, kDTtdrac_1w, 0, AUTO, 28, 18, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 130, 110, 135, 107, 0, 0, 0, 1, kCMDdrac_1w, 0, 0, 0, FLOATING, 130, 134, Common::KEYCODE_DOWN, 0, 0, 0, 0},
-{kNGwen_1w, kDTtlady_1w, 0, AUTO, 17, 23, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 160, 110, 174, 97, 0, 0, 0, 1, kCMDgwen_1w, 0, 0, 0, FLOATING, 162, 134, Common::KEYCODE_DOWN, 0, 0, 0, 0},
-{kNHood_1w, kDTthood_1w, 0, AUTO, 35, 26, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 195, 110, 205, 101, 0, 0, 0, 1, kCMDhood_1w, 0, 0, 0, FLOATING, 195, 134, Common::KEYCODE_DOWN, 0, 0, 0, 0},
-{kNSlime_1w, kDTtslime_1w, 0, AUTO, 21, 24, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 75, 140, 88, 113, 0, 0, 0, 1, kCMDslime_1w, 0, 0, 0, FLOATING, 74, 160, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNPeahead_1w, kDTtpeahd_1w, 0, AUTO, 20, 15, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 164, 140, 172, 121, 0, 0, 0, 1, kCMDpeahd_1w, 0, 0, 0, FLOATING, 152, 162, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNFood_1w, 0, 0, AUTO, 19, 10, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 130, 140, 149, 127, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 138, 162, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNPlant_1w, 0, 0, AUTO, 11, 21, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 172, 113, 239, 74, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 230, 125, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNButler_1w, kDTtbutler_1w, 0, AUTO, 0, 0, kALbutler_1w, PERSON, NOT_CYCLING, 0, 0, 0, 20, 3, 70, 78, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNChop_1w, kDTtchop_1w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 20, 3, 69, 161, 90, 90, 0, 0, 0, 7, kCMDchop_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRedeyes_1w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, 3, 212, 108, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNLips_1w, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 1, 1, 0, 3, 113, 105, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNArm_1w, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 5, 5, 0, 3, 166, 122, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHdlshero_1w, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPicture_1w, 0, 0, AUTO, 74, 41, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 172, 113, 122, 52, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 169, 120, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNWindow_1w, 0, 0, AUTO, 41, 50, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 172, 113, 265, 64, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 269, 139, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNCupb_1w, 0, 0, AUTO, 44, 29, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 172, 113, 65, 69, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 78, 124, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNFrank_1w, kDTtfrank_1w, 0, AUTO, 23, 28, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 90, 110, 104, 97, 0, 0, 0, 1, kCMDfrank_1w, 0, 0, 0, FLOATING, 90, 134, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNDracula_1w, kDTtdrac_1w, 0, AUTO, 28, 18, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 130, 110, 135, 107, 0, 0, 0, 1, kCMDdrac_1w, 0, 0, 0, FLOATING, 130, 134, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNGwen_1w, kDTtlady_1w, 0, AUTO, 17, 23, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 160, 110, 174, 97, 0, 0, 0, 1, kCMDgwen_1w, 0, 0, 0, FLOATING, 162, 134, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNHood_1w, kDTthood_1w, 0, AUTO, 35, 26, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 195, 110, 205, 101, 0, 0, 0, 1, kCMDhood_1w, 0, 0, 0, FLOATING, 195, 134, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNSlime_1w, kDTtslime_1w, 0, AUTO, 21, 24, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 75, 140, 88, 113, 0, 0, 0, 1, kCMDslime_1w, 0, 0, 0, FLOATING, 74, 160, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNPeahead_1w, kDTtpeahd_1w, 0, AUTO, 20, 15, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 164, 140, 172, 121, 0, 0, 0, 1, kCMDpeahd_1w, 0, 0, 0, FLOATING, 152, 162, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNFood_1w, 0, 0, AUTO, 19, 10, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 130, 140, 149, 127, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 138, 162, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNPlant_1w, 0, 0, AUTO, 11, 21, 0, THING0, INVISIBLE, 1, 4, 4, 30, 3, 172, 113, 239, 74, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 230, 125, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// Screen 4: (bathroom)
-{kNWindow_1w, 0, 0, AUTO, 31, 27, 0, THING0, INVISIBLE, 1, 4, 4, 30, 4, 172, 113, 153, 61, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 157, 114, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNToilet_1w, 0, 0, AUTO, 32, 17, 0, THING0, INVISIBLE, 1, 4, 4, 30, 4, 172, 113, 101, 113, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 122, 122, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNBath_1w, 0, 0, AUTO, 47, 36, 0, THING0, INVISIBLE, 1, 4, 4, 30, 4, 172, 113, 73, 125, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 119, 156, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNMirror_1w, 0, 0, AUTO, 12, 24, 0, THING0, INVISIBLE, 1, 4, 4, 30, 4, 172, 113, 207, 71, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 180, 127, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNWindow_1w, 0, 0, AUTO, 31, 27, 0, THING0, INVISIBLE, 1, 4, 4, 30, 4, 172, 113, 153, 61, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 157, 114, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNToilet_1w, 0, 0, AUTO, 32, 17, 0, THING0, INVISIBLE, 1, 4, 4, 30, 4, 172, 113, 101, 113, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 122, 122, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNBath_1w, 0, 0, AUTO, 47, 36, 0, THING0, INVISIBLE, 1, 4, 4, 30, 4, 172, 113, 73, 125, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 119, 156, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNMirror_1w, 0, 0, AUTO, 12, 24, 0, THING0, INVISIBLE, 1, 4, 4, 30, 4, 172, 113, 207, 71, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 180, 127, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// Screen 5: (kitchen)
-{kNWindow_1w, 0, 0, AUTO, 66, 35, 0, THING0, INVISIBLE, 1, 4, 4, 30, 5, 172, 113, 107, 76, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 124, 143, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNBroom_1w, 0, 0, AUTO, 19, 51, 0, THING0, INVISIBLE, 1, 4, 4, 30, 5, 172, 113, 280, 114, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 276, 166, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNCupb_1w, 0, 0, AUTO, 159, 29, 0, THING0, INVISIBLE, 1, 4, 4, 30, 5, 172, 113, 50, 112, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 0, 0, 0, 0, 0, 0, 0},
+{kNWindow_1w, 0, 0, AUTO, 66, 35, 0, THING0, INVISIBLE, 1, 4, 4, 30, 5, 172, 113, 107, 76, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 124, 143, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBroom_1w, 0, 0, AUTO, 19, 51, 0, THING0, INVISIBLE, 1, 4, 4, 30, 5, 172, 113, 280, 114, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 276, 166, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNCupb_1w, 0, 0, AUTO, 159, 29, 0, THING0, INVISIBLE, 1, 4, 4, 30, 5, 172, 113, 50, 112, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 0, 0, 0, 0, 0, 0, 0},
// Screen 6: (Garden)
-{kNDoor_1w, kDTtdoor_1w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 6, 226, 58, 90, 90, 0, 0, 0, 1, kCMDdoor4_1w, 0, 0, 0, FLOATING, 224, 104, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNShed_1w, 0, 0, AUTO, 106, 60, 0, THING0, INVISIBLE, 0, 0, 0, 60, 6, 277, 39, 214, 37, 0, 0, 0, 1, kCMDshed_1w, 0, 0, 1, FLOATING, 213, 103, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNOilcan_1w, kDTtoilcan_1w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 40, 6, 240, 65, 90, 90, 0, 0, 4, 1, kCMDoilcan_1w, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNTree_1w, 0, 0, AUTO, 30, 120, 0, THING0, INVISIBLE, 1, 4, 4, 30, 6, 172, 113, 161, 17, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 163, 148, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNShed_1w, 0, 0, AUTO, 25, 40, 0, THING0, INVISIBLE, 1, 4, 4, 30, 6, 172, 113, 226, 58, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 285, 99, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNDoor_1w, kDTtdoor_1w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 6, 226, 58, 90, 90, 0, 0, 0, 1, kCMDdoor4_1w, 0, 0, 0, FLOATING, 224, 104, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNShed_1w, 0, 0, AUTO, 106, 60, 0, THING0, INVISIBLE, 0, 0, 0, 60, 6, 277, 39, 214, 37, 0, 0, 0, 1, kCMDshed_1w, 0, 0, 1, FLOATING, 213, 103, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNOilcan_1w, kDTtoilcan_1w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 40, 6, 240, 65, 90, 90, 0, 0, 4, 1, kCMDoilcan_1w, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNTree_1w, 0, 0, AUTO, 30, 120, 0, THING0, INVISIBLE, 1, 4, 4, 30, 6, 172, 113, 161, 17, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 163, 148, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNShed_1w, 0, 0, AUTO, 25, 40, 0, THING0, INVISIBLE, 1, 4, 4, 30, 6, 172, 113, 226, 58, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 285, 99, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// Screen 7: (Store room)
-{kNDog_1w, kDTtdog_1w, 0, AUTO, 0, 0, kALdoggy_1w, ANIMAL, NOT_CYCLING, 0, 0, 0, -1, 7, 105, 119, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCarpet_1w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 7, 191, 142, 90, 90, 0, 0, 0, 0, kCMDcarpet_1w, 0, 0, 0, BACKGROUND, 234, 153, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNTrap_1w, kDTttrap_1w, 0, AUTO, 0, 0, 0, THING4, INVISIBLE, 0, 2, 2, 20, 7, 216, 140, 90, 90, 0, 0, 0, 1, kCMDtrap_1w, 0, 0, 0, BACKGROUND, 240, 152, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNBolt_1w, kDTtbolt_1w, 0, AUTO, 7, 5, 0, THING0, INVISIBLE, 0, 0, 0, 20, 7, 220, 145, 237, 151, 0, 0, 0, 1, kCMDbolt_1w, 0, 0, 0, BACKGROUND, 240, 152, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNHerodead_1w, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMousehole_1w, 0, 0, AUTO, 7, 8, 0, THING0, INVISIBLE, 1, 4, 4, 30, 7, 172, 113, 52, 148, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 65, 158, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNDog_1w, kDTtdog_1w, 0, AUTO, 0, 0, kALdoggy_1w, ANIMAL, NOT_CYCLING, 0, 0, 0, -1, 7, 105, 119, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCarpet_1w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 7, 191, 142, 90, 90, 0, 0, 0, 0, kCMDcarpet_1w, 0, 0, 0, BACKGROUND, 234, 153, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNTrap_1w, kDTttrap_1w, 0, AUTO, 0, 0, 0, THING4, INVISIBLE, 0, 2, 2, 20, 7, 216, 140, 90, 90, 0, 0, 0, 1, kCMDtrap_1w, 0, 0, 0, BACKGROUND, 240, 152, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNBolt_1w, kDTtbolt_1w, 0, AUTO, 7, 5, 0, THING0, INVISIBLE, 0, 0, 0, 20, 7, 220, 145, 237, 151, 0, 0, 0, 1, kCMDbolt_1w, 0, 0, 0, BACKGROUND, 240, 152, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNHerodead_1w, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMousehole_1w, 0, 0, AUTO, 7, 8, 0, THING0, INVISIBLE, 1, 4, 4, 30, 7, 172, 113, 52, 148, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 65, 158, Common::KEYCODE_LEFT, 0, 0, 0, 0},
// Screen 8: (Basement)
-{kNRock_1w, 0, 0, AUTO, 66, 53, 0, THING0, INVISIBLE, 1, 4, 4, 30, 8, 172, 113, 132, 88, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 123, 149, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNRock_1w, 0, 0, AUTO, 56, 60, 0, THING0, INVISIBLE, 1, 4, 4, 30, 8, 172, 113, 257, 125, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 270, 187, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNRock_1w, 0, 0, AUTO, 25, 91, 0, THING0, INVISIBLE, 1, 4, 4, 30, 8, 172, 113, 0, 102, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 20, 187, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNDoor_1w, 0, 0, AUTO, 30, 57, 0, THING0, INVISIBLE, 1, 4, 4, 30, 8, 172, 113, 207, 84, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 210, 142, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNRock_1w, 0, 0, AUTO, 66, 53, 0, THING0, INVISIBLE, 1, 4, 4, 30, 8, 172, 113, 132, 88, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 123, 149, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNRock_1w, 0, 0, AUTO, 56, 60, 0, THING0, INVISIBLE, 1, 4, 4, 30, 8, 172, 113, 257, 125, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 270, 187, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNRock_1w, 0, 0, AUTO, 25, 91, 0, THING0, INVISIBLE, 1, 4, 4, 30, 8, 172, 113, 0, 102, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 20, 187, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNDoor_1w, 0, 0, AUTO, 30, 57, 0, THING0, INVISIBLE, 1, 4, 4, 30, 8, 172, 113, 207, 84, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 210, 142, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 9: (Batcave)
-{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, kALbats_1w, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, kALbats_1w, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 65, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, kALbats_1w, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, kALbats_1w, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 130, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, kALbats_1w, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, kALbats_1w, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 65, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, kALbats_1w, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1w, kDTtbat_1w, 0, AUTO, 0, 0, kALbats_1w, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 130, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 10: (Mummy room)
-{kNMummy_1w, 0, 0, AUTO, 0, 0, kALmummy_1w, PERSON, NOT_CYCLING, 0, 0, 0, DX, 10, 256, 77, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMdoor, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 10, 258, 55, 90, 90, 0, 0, 0, 1, kCMDdoor4_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGold_1w, kDTtgold_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 10, 208, 152, 90, 90, 0, 0, 10, 7, kCMDgold_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNRock_1w, 0, 0, AUTO, 54, 34, 0, THING0, INVISIBLE, 1, 4, 4, -1, 10, 172, 113, 127, 109, 0, 0, 0, 1, kCMDrock_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMummy_1w, 0, 0, AUTO, 0, 0, kALmummy_1w, PERSON, NOT_CYCLING, 0, 0, 0, DX, 10, 256, 77, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMdoor, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 10, 258, 55, 90, 90, 0, 0, 0, 1, kCMDdoor4_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGold_1w, kDTtgold_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 10, 208, 152, 90, 90, 0, 0, 10, 7, kCMDgold_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRock_1w, 0, 0, AUTO, 54, 34, 0, THING0, INVISIBLE, 1, 4, 4, -1, 10, 172, 113, 127, 109, 0, 0, 0, 1, kCMDrock_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 11: (Lakeroom)
-{kNBoat_1w, kDTtboat_1w, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, 30, 11, 230, 118, 90, 90, 0, 0, 0, 1, kCMDboat_1w, 0, 0, 1, FLOATING, 250, 150, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNRope_1w, kDTtrope_1w, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, 30, 11, 220, 132, 90, 90, 0, 0, 0, 1, kCMDrope_1w, 0, 0, 0, FLOATING, 209, 153, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNOldman_1w, kDTtoldman_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 11, 160, 38, 90, 90, 0, 0, 0, 1, kCMDoldman_1w, 0, 0, 0, FLOATING, 150, 54, Common::KEYCODE_DOWN, 0, 0, 0, 0},
-{kNWhero_1w, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 11, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBoat_1w, kDTtboat_1w, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, 30, 11, 230, 118, 90, 90, 0, 0, 0, 1, kCMDboat_1w, 0, 0, 1, FLOATING, 250, 150, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNRope_1w, kDTtrope_1w, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, 30, 11, 220, 132, 90, 90, 0, 0, 0, 1, kCMDrope_1w, 0, 0, 0, FLOATING, 209, 153, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNOldman_1w, kDTtoldman_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 11, 160, 38, 90, 90, 0, 0, 0, 1, kCMDoldman_1w, 0, 0, 0, FLOATING, 150, 54, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNWhero_1w, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 11, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 12: (Dead end)
-{kNGuard_1w, kDTtguard_1w, 0, AUTO, 0, 0, 0, THING2d, NOT_CYCLING, 0, 0, 0, -1, 12, 147, 38, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 133, 91, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNGuard_1w, kDTtguard_1w, 0, AUTO, 0, 0, 0, THING2d, NOT_CYCLING, 0, 0, 0, -1, 12, 147, 38, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 133, 91, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 15: (Laboratory)
-{kNProf_1w, kDTtprof_1w, 0, AUTO, 0, 0, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 1, 150, 55, 90, 90, DX, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNIgor_1w, kDTtigor_1w, 0, AUTO, 0, 0, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 15, 180, 122, 90, 90, DX, 0, 0, 1, kCMDigor_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBung_1w, kDTtbung_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 14, 15, 75, 145, 90, 90, 0, 0, 11, 7, kCMDbung_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGdoor_1w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 15, 59, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNSpachero_1w, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 15, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFuzyhero_1w, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 15, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNSpark_1w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, 15, 106, 74, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBooth_1w, 0, 0, AUTO, 38, 64, 0, THING0, INVISIBLE, 1, 4, 4, -1, 15, 172, 113, 108, 99, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 124, 154, Common::KEYCODE_DOWN, 0, 0, 0, 0},
-{kNMachinebits_1w, 0, 0, AUTO, 41, 7, 0, THING0, INVISIBLE, 1, 4, 4, 0, 15, 172, 113, 184, 118, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 191, 168, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNMachine_1w, 0, 0, AUTO, 103, 34, 0, THING0, INVISIBLE, 1, 4, 4, 0, 15, 172, 113, 177, 130, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 240, 168, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNTable_1w, 0, 0, AUTO, 44, 11, 0, THING0, INVISIBLE, 1, 4, 4, 0, 15, 172, 113, 49, 137, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 64, 162, Common::KEYCODE_UP, 0, 0, 0, 0}
+{kNProf_1w, kDTtprof_1w, 0, AUTO, 0, 0, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 1, 150, 55, 90, 90, DX, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNIgor_1w, kDTtigor_1w, 0, AUTO, 0, 0, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 15, 180, 122, 90, 90, DX, 0, 0, 1, kCMDigor_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBung_1w, kDTtbung_1w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 14, 15, 75, 145, 90, 90, 0, 0, 11, 7, kCMDbung_1w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGdoor_1w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 15, 59, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSpachero_1w, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 15, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFuzyhero_1w, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 15, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSpark_1w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, 15, 106, 74, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBooth_1w, 0, 0, AUTO, 38, 64, 0, THING0, INVISIBLE, 1, 4, 4, -1, 15, 172, 113, 108, 99, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 124, 154, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNMachinebits_1w, 0, 0, AUTO, 41, 7, 0, THING0, INVISIBLE, 1, 4, 4, 0, 15, 172, 113, 184, 118, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 191, 168, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNMachine_1w, 0, 0, AUTO, 103, 34, 0, THING0, INVISIBLE, 1, 4, 4, 0, 15, 172, 113, 177, 130, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 240, 168, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNTable_1w, 0, 0, AUTO, 44, 11, 0, THING0, INVISIBLE, 1, 4, 4, 0, 15, 172, 113, 49, 137, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 64, 162, Common::KEYCODE_UP, 0, 0, 0, 0}
};
uint16 tmatch_2w[] = {kDTtmatch1_2w, kDTtmatch2_2w, 0};
@@ -5162,174 +5181,174 @@ object_t objects_2w[] = {
// and use dx <> 0 to allow point & click interface to access them.
// viewx: -1 Walk to object, 0 immediate use, else walk to viewx,viewy.
// name,description,description_s,path,dx,dy,aptr,seq,seqp, cyc,n,frm,rad,scr,x,y ,oldxy,vxy,val,g,cmnd,c,s,ctx,fgb
-{kNHero_2w, kDTthero_2w, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 319, 199, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPenny_2w, kDTtpenny_2w, 0, AUTO, 0, 0, 0, PERSON, NOT_CYCLING, 0, 0, 0, -1, 1, 109, 140, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHero_2w, kDTthero_2w, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 319, 199, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPenny_2w, kDTtpenny_2w, 0, AUTO, 0, 0, 0, PERSON, NOT_CYCLING, 0, 0, 0, -1, 1, 109, 140, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 0: (Outside house)
-{kNSmoke_2w, 0, 0, AUTO, 0, 0, 0, THING3, CYCLE_FORWARD, 0, 2, 0, 0, 0, 233, 20, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSmoke_2w, 0, 0, AUTO, 0, 0, 0, THING3, CYCLE_FORWARD, 0, 2, 0, 0, 0, 233, 20, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 1: (Hall)
-{kNDoor_2w, kDTtdoor_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 50, 1, 238, 40, 90, 90, 0, 0, 0, 1, kCMDdoor1_2w, 0, 0, 0, FLOATING, 239, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 26, 42, 0, THING0, INVISIBLE, 0, 0, 0, 50, 1, 80, 40, 80, 40, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 82, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 26, 42, 0, THING0, INVISIBLE, 0, 0, 0, 50, 1, 160, 40, 160, 40, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 162, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNLips_2w, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 0, 1, 186, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNMaid_2w, kDTtmaid_2w, 0, AUTO, 0, 0, 0, PERSON4, NOT_CYCLING, 0, 0, 0, 8, 1, 149, 135, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNHallgo_2w, kDTthallgo_2w, 0, AUTO, 189, 72, 0, THING0, INVISIBLE, 0, 0, 0, -1, 1, 0, 0, 116, 106, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 218, 181, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoor_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 50, 1, 238, 40, 90, 90, 0, 0, 0, 1, kCMDdoor1_2w, 0, 0, 0, FLOATING, 239, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 26, 42, 0, THING0, INVISIBLE, 0, 0, 0, 50, 1, 80, 40, 80, 40, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 82, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 26, 42, 0, THING0, INVISIBLE, 0, 0, 0, 50, 1, 160, 40, 160, 40, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 162, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNLips_2w, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 0, 1, 186, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNMaid_2w, kDTtmaid_2w, 0, AUTO, 0, 0, 0, PERSON4, NOT_CYCLING, 0, 0, 0, 8, 1, 149, 135, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHallgo_2w, kDTthallgo_2w, 0, AUTO, 189, 72, 0, THING0, INVISIBLE, 0, 0, 0, -1, 1, 0, 0, 116, 106, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 218, 181, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 2: (Bedroom 1)
-{kNPennylie_2w, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 2, 24, 177, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
-{kNPenfall_2w, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 10, 2, 24, 177, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBookcase_2w, kDTtbookcase_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 2, 70, 81, 90, 90, 0, 0, 0, 1, kCMDbook_2w, 0, 0, 0, FLOATING, 90, 138, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNBook_2w, kDTtbook_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 10, 2, 90, 140, 90, 90, 0, 0, 0, 1, kCMDbook_2w, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNKeyhole_2w, 0, 0, AUTO, 7, 9, 0, THING0, INVISIBLE, 0, 0, 0, 10, 2, 28, 166, 26, 129, 0, 0, 0, 0, kCMDkeyhole_2w, 0, 0, 0, FLOATING, 35, 166, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNBed_2w, kDTtbed_2w, 0, AUTO, 109, 27, 0, THING0, INVISIBLE, 0, 0, 0, 0, 2, 160, 40, 174, 135, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 214, 136, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNPennylie_2w, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 2, 24, 177, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
+{kNPenfall_2w, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 10, 2, 24, 177, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBookcase_2w, kDTtbookcase_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 2, 70, 81, 90, 90, 0, 0, 0, 1, kCMDbook_2w, 0, 0, 0, FLOATING, 90, 138, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBook_2w, kDTtbook_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 10, 2, 90, 140, 90, 90, 0, 0, 0, 1, kCMDbook_2w, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNKeyhole_2w, 0, 0, AUTO, 7, 9, 0, THING0, INVISIBLE, 0, 0, 0, 10, 2, 28, 166, 26, 129, 0, 0, 0, 0, kCMDkeyhole_2w, 0, 0, 0, FLOATING, 35, 166, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNBed_2w, kDTtbed_2w, 0, AUTO, 109, 27, 0, THING0, INVISIBLE, 0, 0, 0, 0, 2, 160, 40, 174, 135, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 214, 136, Common::KEYCODE_DOWN, 0, 0, 0, 0},
// Screen 3: (Bedroom 2)
-{kNPanel_2w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 3, 189, 91, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNCupb_2w, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 3, 135, 142, 90, 90, 0, 0, 0, 0, kCMDlookdesk_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBird_2w, kDTtbird_2w, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, -1, 3, 186, 100, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FOREGROUND, 192, 157, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNMatches_2w, 0, tmatch_2w, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 30, 255, 78, 30, 90, 90, 0, 0, 5, 15, kCMDmatches_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDumb_2w, kDTtdumb_2w, 0, AUTO, 32, 26, 0, THING0, INVISIBLE, 0, 0, 0, 30, 3, 72, 138, 55, 91, 0, 0, 0, 1, kCMDdumb_2w, 0, 0, 0, FLOATING, 66, 140, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNPhone_2w, 0, 0, AUTO, 16, 7, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 102, 120, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 78, 148, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNBlotpad_2w, 0, 0, AUTO, 41, 10, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 116, 122, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 132, 160, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDrawer_2w, 0, 0, AUTO, 38, 9, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 127, 133, 0, 0, 0, 1, kCMDlookdesk_2w, 0, 0, 0, FLOATING, 139, 158, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNSwitch_2w, 0, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 89, 104, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 74, 141, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNKeyhole_2w, 0, 0, AUTO, 7, 11, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 282, 134, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 260, 170, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNPanel_2w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 3, 189, 91, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNCupb_2w, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 3, 135, 142, 90, 90, 0, 0, 0, 0, kCMDlookdesk_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBird_2w, kDTtbird_2w, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, -1, 3, 186, 100, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FOREGROUND, 192, 157, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNMatches_2w, 0, tmatch_2w, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 30, 255, 78, 30, 90, 90, 0, 0, 5, 15, kCMDmatches_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDumb_2w, kDTtdumb_2w, 0, AUTO, 32, 26, 0, THING0, INVISIBLE, 0, 0, 0, 30, 3, 72, 138, 55, 91, 0, 0, 0, 1, kCMDdumb_2w, 0, 0, 0, FLOATING, 66, 140, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNPhone_2w, 0, 0, AUTO, 16, 7, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 102, 120, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 78, 148, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNBlotpad_2w, 0, 0, AUTO, 41, 10, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 116, 122, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 132, 160, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDrawer_2w, 0, 0, AUTO, 38, 9, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 127, 133, 0, 0, 0, 1, kCMDlookdesk_2w, 0, 0, 0, FLOATING, 139, 158, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNSwitch_2w, 0, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 89, 104, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 74, 141, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNKeyhole_2w, 0, 0, AUTO, 7, 11, 0, THING0, INVISIBLE, 0, 0, 0, 0, 3, 0, 0, 282, 134, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 260, 170, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// Screen 4: (Keyhole)
-{kNMurder_2w, 0, 0, AUTO, 0, 0, 0, THING2e, CYCLE_FORWARD, 1, 2, 16, -1, 4, 141, 76, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMurder_2w, 0, 0, AUTO, 0, 0, 0, THING2e, CYCLE_FORWARD, 1, 2, 16, -1, 4, 141, 76, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 5: (Bed3)
-{kNBalloon_2w, kDTtballoon_2w, 0, WANDER, DX/2, DY/2, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 5, 180, 40, 90, 90, 0, 0, 0, 1, kCMDballoon_2w, 0, 0, 0, FLOATING, 146, 130, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNBlock_2w, 0, 0, AUTO, 18, 10, 0, THING0, INVISIBLE, 0, 0, 0, 0, 5, 0, 0, 175, 131, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 176, 135, Common::KEYCODE_DOWN, 0, 0, 0, 0},
-{kNCage_2w, 0, 0, AUTO, 46, 23, 0, THING0, INVISIBLE, 0, 0, 0, 0, 5, 0, 0, 93, 123, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 96, 150, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 15, 26, 0, THING0, INVISIBLE, 0, 0, 0, 0, 5, 0, 0, 83, 88, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 106, 133, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 31, 21, 0, THING0, INVISIBLE, 0, 0, 0, 0, 5, 0, 0, 133, 85, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 149, 133, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBalloon_2w, kDTtballoon_2w, 0, WANDER, DX/2, DY/2, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 5, 180, 40, 90, 90, 0, 0, 0, 1, kCMDballoon_2w, 0, 0, 0, FLOATING, 146, 130, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBlock_2w, 0, 0, AUTO, 18, 10, 0, THING0, INVISIBLE, 0, 0, 0, 0, 5, 0, 0, 175, 131, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 176, 135, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNCage_2w, 0, 0, AUTO, 46, 23, 0, THING0, INVISIBLE, 0, 0, 0, 0, 5, 0, 0, 93, 123, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 96, 150, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 15, 26, 0, THING0, INVISIBLE, 0, 0, 0, 0, 5, 0, 0, 83, 88, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 106, 133, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 31, 21, 0, THING0, INVISIBLE, 0, 0, 0, 0, 5, 0, 0, 133, 85, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 149, 133, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 6: (Kitchen)
-{kNDumb_2w, kDTtdumb_2w, 0, AUTO, 21, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 6, 35, 152, 26, 99, 0, 0, 0, 1, kCMDdumb_2w, 0, 0, 0, FLOATING, 40, 153, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNCupb_2w, 0, 0, AUTO, 61, 23, 0, THING0, INVISIBLE, 0, 0, 0, 55, 6, 135, 142, 90, 118, 0, 0, 0, 0, kCMDlookcupb_2w, 0, 0, 0, FLOATING, 112, 143, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNGarlic_2w, kDTtgarlic_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 255, 78, 30, 90, 90, 0, 0, 5, 7, kCMDgarlic_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoor_2w, kDTdull_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 6, 290, 196, 90, 90, 0, 0, 0, 0, kCMDkdoor_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 67, 29, 0, THING0, INVISIBLE, 0, 0, 0, 0, 6, 0, 0, 106, 75, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 139, 143, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDumb_2w, kDTtdumb_2w, 0, AUTO, 21, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 6, 35, 152, 26, 99, 0, 0, 0, 1, kCMDdumb_2w, 0, 0, 0, FLOATING, 40, 153, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNCupb_2w, 0, 0, AUTO, 61, 23, 0, THING0, INVISIBLE, 0, 0, 0, 55, 6, 135, 142, 90, 118, 0, 0, 0, 0, kCMDlookcupb_2w, 0, 0, 0, FLOATING, 112, 143, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNGarlic_2w, kDTtgarlic_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 255, 78, 30, 90, 90, 0, 0, 5, 7, kCMDgarlic_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_2w, kDTdull_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 6, 290, 196, 90, 90, 0, 0, 0, 0, kCMDkdoor_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 67, 29, 0, THING0, INVISIBLE, 0, 0, 0, 0, 6, 0, 0, 106, 75, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 139, 143, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 8: (Shed)
-{kNGardner_2w, 0, 0, WANDER, DX, DY, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 8, 250, 90, 90, 90, 0, 0, 0, 1, kCMDlookgard_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGardner_2w, 0, 0, WANDER, DX, DY, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 8, 250, 90, 90, 90, 0, 0, 0, 1, kCMDlookgard_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 9: In shed
-{kNRed_2w, kDTtbutton_2w, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 177, 99, 0, 0, 0, 1, kCMDred_2w, 0, 0, 0, FLOATING, 188, 137, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNYellow_2w, kDTtbutton_2w, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 189, 99, 0, 0, 0, 1, kCMDyellow_2w, 0, 0, 0, FLOATING, 172, 137, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNGreen_2w, kDTtbutton_2w, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 201, 99, 0, 0, 0, 1, kCMDgreen_2w, 0, 0, 0, FLOATING, 184, 137, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNBlue_2w, kDTtbutton_2w, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 215, 99, 0, 0, 0, 1, kCMDblue_2w, 0, 0, 0, FLOATING, 198, 137, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNButton_2w, kDTtbutton_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDbutton_2w, 0, 1, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNShedlight_2w, kDTtslight_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 9, 161, 48, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNTools_2w, 0, 0, AUTO, 33, 21, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 127, 79, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 136, 127, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNRed_2w, kDTtbutton_2w, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 177, 99, 0, 0, 0, 1, kCMDred_2w, 0, 0, 0, FLOATING, 188, 137, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNYellow_2w, kDTtbutton_2w, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 189, 99, 0, 0, 0, 1, kCMDyellow_2w, 0, 0, 0, FLOATING, 172, 137, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNGreen_2w, kDTtbutton_2w, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 201, 99, 0, 0, 0, 1, kCMDgreen_2w, 0, 0, 0, FLOATING, 184, 137, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBlue_2w, kDTtbutton_2w, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 215, 99, 0, 0, 0, 1, kCMDblue_2w, 0, 0, 0, FLOATING, 198, 137, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNButton_2w, kDTtbutton_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDbutton_2w, 0, 1, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNShedlight_2w, kDTtslight_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 9, 161, 48, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNTools_2w, 0, 0, AUTO, 33, 21, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 127, 79, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 136, 127, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 10: Venus fly traps
-{kNMagnify_2w, kDTtmagnify_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 10, 95, 96, 90, 90, 0, 0, 15, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFly_2w, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 48, 60, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFly_2w, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 58, 70, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFly_2w, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 268, 90, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 40, 10, 48, 86, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 41, 103, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 2, 0, 40, 10, 79, 104, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 69, 121, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 40, 10, 71, 141, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 68, 153, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 3, 0, 40, 10, 116, 113, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 99, 132, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 1, 40, 10, 164, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 184, 136, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 2, 0, 40, 10, 185, 83, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 167, 101, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 40, 10, 232, 96, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 223, 116, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 40, 10, 273, 141, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 251, 156, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNMagnify_2w, kDTtmagnify_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 10, 95, 96, 90, 90, 0, 0, 15, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFly_2w, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 48, 60, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFly_2w, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 58, 70, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFly_2w, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 268, 90, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 40, 10, 48, 86, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 41, 103, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 2, 0, 40, 10, 79, 104, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 69, 121, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 40, 10, 71, 141, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 68, 153, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 3, 0, 40, 10, 116, 113, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 99, 132, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 1, 40, 10, 164, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 184, 136, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 2, 0, 40, 10, 185, 83, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 167, 101, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 40, 10, 232, 96, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 223, 116, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNLeaf_2w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 40, 10, 273, 141, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 251, 156, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// Screen 11/12: Gates
-{kNGatelight_2w, kDTtglight_2w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 1, 0, 0, -1, 11, 90, 72, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGate_2w, 0, 0, AUTO, 83, 56, 0, THING0, INVISIBLE, 0, 0, 0, -1, 12, 190, 137, 118, 99, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 152, 157, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNGatelight_2w, kDTtglight_2w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 1, 0, 0, -1, 11, 90, 72, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGate_2w, 0, 0, AUTO, 83, 56, 0, THING0, INVISIBLE, 0, 0, 0, -1, 12, 190, 137, 118, 99, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 152, 157, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 13: Stream
-{kNCatnip_2w, kDTtcatnip_2w, 0, AUTO, 54, 8, 0, THING0, INVISIBLE, 0, 0, 0, -1, 13, 211, 136, 29, 114, 0, 0, 5, 3, kCMDcatnip_2w, 0, 0, 0, FLOATING, 49, 130, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNBridge_2w, kDTtbridge_2w, 0, AUTO, 61, 25, 0, THING0, INVISIBLE, 0, 0, 0, -1, 13, 211, 136, 162, 116, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 218, 124, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNCatnip_2w, kDTtcatnip_2w, 0, AUTO, 54, 8, 0, THING0, INVISIBLE, 0, 0, 0, -1, 13, 211, 136, 29, 114, 0, 0, 5, 3, kCMDcatnip_2w, 0, 0, 0, FLOATING, 49, 130, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBridge_2w, kDTtbridge_2w, 0, AUTO, 61, 25, 0, THING0, INVISIBLE, 0, 0, 0, -1, 13, 211, 136, 162, 116, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 218, 124, Common::KEYCODE_DOWN, 0, 0, 0, 0},
// Screen 14: Zapper
-{kNZapper_2w, kDTtzapper_2w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 1, 0, 0, -1, 14, 134, 46, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNZapper_2w, kDTtzapper_2w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 1, 0, 0, -1, 14, 134, 46, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2w, kDTtbug_2w, 0, AUTO, 0, 0, kALbugs_2w, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 15: Mushroom
-{kNOldman_2w, kDTtoldman_2w, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 1, 0, 0, -1, 15, 126, 77, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNOldman_2w, kDTtoldman_2w, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 1, 0, 0, -1, 15, 126, 77, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 16: Well
-{kNWell_2w, kDTtwell_2w, 0, AUTO, 53, 55, 0, THING0, INVISIBLE, 0, 0, 0, 30, 16, 211, 136, 184, 85, 0, 0, 0, 1, kCMDwell_2w, 0, 0, 0, FLOATING, 242, 131, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNWell_2w, kDTtwell_2w, 0, AUTO, 53, 55, 0, THING0, INVISIBLE, 0, 0, 0, 30, 16, 211, 136, 184, 85, 0, 0, 0, 1, kCMDwell_2w, 0, 0, 0, FLOATING, 242, 131, Common::KEYCODE_LEFT, 0, 0, 0, 0},
// Screen 17: Snakepit
-{kNSnake_2w, kDTtsnake_2w, 0, CHASE2, DX, DY, kALsnake_2w, PERSON2, CYCLE_FORWARD, 0, 0, 0, 25, 17, 165, 95, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSnake_2w, kDTtsnake_2w, 0, CHASE2, DX, DY, kALsnake_2w, PERSON2, CYCLE_FORWARD, 0, 0, 0, 25, 17, 165, 95, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 18: Phonebox
-{kNTardis_2w, kDTttardis_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 18, 21, 74, 90, 90, 0, 0, 0, 1, kCMDtardis_2w, 0, 0, 1, FLOATING, 50, 126, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNTardis_2w, kDTttardis_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 18, 21, 74, 90, 90, 0, 0, 0, 1, kCMDtardis_2w, 0, 0, 1, FLOATING, 50, 126, Common::KEYCODE_LEFT, 0, 0, 0, 0},
// Screen 19: Street
-{kNGraf_2w, 0, 0, AUTO, 34, 14, 0, THING0, INVISIBLE, 0, 0, 0, 50, 19, 21, 74, 134, 102, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 143, 134, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNGraf_2w, 0, 0, AUTO, 34, 14, 0, THING0, INVISIBLE, 0, 0, 0, 50, 19, 21, 74, 134, 102, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 143, 134, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 20: Kennel
-{kNStick_2w, kDTdull_2w, 0, AUTO, 29, 11, 0, THING0, INVISIBLE, 0, 0, 0, 30, 20, 89, 120, 83, 116, 0, 0, 5, 3, kCMDstick_2w, 0, 0, 0, FLOATING, 88, 132, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDynamite_2w, kDTtdynamite_2w, 0, AUTO, 0, 0, 0, THING2a, INVISIBLE, 0, 0, 0, 40, 20, 195, 111, 90, 90, 0, 0, 0, 7, kCMDdynamite_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNKennel_2w, 0, 0, AUTO, 97, 40, 0, THING0, INVISIBLE, 0, 0, 0, 50, 20, 195, 114, 173, 73, 0, 0, 0, 0, kCMDkennel_2w, 0, 0, 0, FLOATING, 160, 113, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNDog_2w, kDTtdog_2w, 0, AUTO, 0, 0, 0, THING2f, CYCLE_FORWARD, 0, 2, 0, 30, 20, 184, 80, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 200, 117, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNStick_2w, kDTdull_2w, 0, AUTO, 29, 11, 0, THING0, INVISIBLE, 0, 0, 0, 30, 20, 89, 120, 83, 116, 0, 0, 5, 3, kCMDstick_2w, 0, 0, 0, FLOATING, 88, 132, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDynamite_2w, kDTtdynamite_2w, 0, AUTO, 0, 0, 0, THING2a, INVISIBLE, 0, 0, 0, 40, 20, 195, 111, 90, 90, 0, 0, 0, 7, kCMDdynamite_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNKennel_2w, 0, 0, AUTO, 97, 40, 0, THING0, INVISIBLE, 0, 0, 0, 50, 20, 195, 114, 173, 73, 0, 0, 0, 0, kCMDkennel_2w, 0, 0, 0, FLOATING, 160, 113, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNDog_2w, kDTtdog_2w, 0, AUTO, 0, 0, 0, THING2f, CYCLE_FORWARD, 0, 2, 0, 30, 20, 184, 80, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 200, 117, Common::KEYCODE_LEFT, 0, 0, 0, 0},
// Screen 21: (Rockroom)
-{kNRock_2w, 0, 0, AUTO, 60, 36, 0, THING0, INVISIBLE, 0, 0, 0, 30, 21, 89, 120, 216, 63, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 254, 102, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNRope_2w, kDTtrope_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 60, 21, 78, 30, 90, 90, 0, 0, 0, 1, kCMDrope_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRock_2w, 0, 0, AUTO, 60, 36, 0, THING0, INVISIBLE, 0, 0, 0, 30, 21, 89, 120, 216, 63, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 254, 102, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNRope_2w, kDTtrope_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 60, 21, 78, 30, 90, 90, 0, 0, 0, 1, kCMDrope_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 22: (Rockgone)
-{kNRope_2w, kDTtrope_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 60, 22, 78, 30, 90, 90, 0, 0, 0, 1, kCMDrope_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRope_2w, kDTtrope_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 60, 22, 78, 30, 90, 90, 0, 0, 0, 1, kCMDrope_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 24: (Lampcave)
-{kNLamp_2w, kDTtlamp_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 24, 78, 115, 90, 90, 0, 0, 10, 7, kCMDlamp_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLamp_2w, kDTtlamp_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 24, 78, 115, 90, 90, 0, 0, 10, 7, kCMDlamp_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 25: (Chasm)
-{kNBanana_2w, kDTtbanana_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 25, 254, 107, 90, 90, 0, 0, 5, 7, kCMDbanana_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNHole_2w, 0, 0, AUTO, 40, 80, 0, THING0, INVISIBLE, 0, 0, 0, 20, 25, 254, 107, 183, 92, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 187, 123, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNBanana_2w, kDTtbanana_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 25, 254, 107, 90, 90, 0, 0, 5, 7, kCMDbanana_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHole_2w, 0, 0, AUTO, 40, 80, 0, THING0, INVISIBLE, 0, 0, 0, 20, 25, 254, 107, 183, 92, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 187, 123, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// Screen 27: (Ladder)
-{kNGenie_2w, kDTtgenie_2w, 0, AUTO, 0, 0, 0, PERSON3, INVISIBLE, 0, 0, 0, 40, 27, 138, 70, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGenie_2w, kDTtgenie_2w, 0, AUTO, 0, 0, 0, PERSON3, INVISIBLE, 0, 0, 0, 40, 27, 138, 70, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 28: (Traproom)
-{kNSafe_2w, kDTtsafe_2w, 0, AUTO, 37, 34, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 104, 110, 0, 0, 0, 1, kCMDsafe_2w, 0, 0, 0, FLOATING, 106, 145, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNWill_2w, kDTtwill_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 90, 90, 0, 0, 5, 7, kCMDwill_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMousehole_2w, 0, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 164, 132, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 153, 146, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 15, 30, 0, THING0, INVISIBLE, 0, 0, 0, -1, 28, 122, 144, 250, 89, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 222, 141, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNSafe_2w, kDTtsafe_2w, 0, AUTO, 37, 34, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 104, 110, 0, 0, 0, 1, kCMDsafe_2w, 0, 0, 0, FLOATING, 106, 145, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNWill_2w, kDTtwill_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 90, 90, 0, 0, 5, 7, kCMDwill_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMousehole_2w, 0, 0, AUTO, 5, 5, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 164, 132, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 153, 146, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 15, 30, 0, THING0, INVISIBLE, 0, 0, 0, -1, 28, 122, 144, 250, 89, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 222, 141, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// Screen 30: (Lounge)
-{kNPicture_2w, 0, 0, AUTO, 35, 31, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 262, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 55, 55, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 163, 86, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 186, 144, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 52, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 89, 86, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 93, 142, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 55, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 23, 89, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 60, 150, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNPlant_2w, 0, 0, AUTO, 19, 51, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 57, 93, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 70, 146, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNPicture_2w, 0, 0, AUTO, 35, 31, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 262, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 55, 55, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 163, 86, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 186, 144, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 52, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 89, 86, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 93, 142, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 55, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 23, 89, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 60, 150, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNPlant_2w, 0, 0, AUTO, 19, 51, 0, THING0, INVISIBLE, 0, 0, 0, 20, 30, 122, 144, 57, 93, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 70, 146, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 31: (Parlor)
-{kNCupb_2w, 0, 0, AUTO, 64, 28, 0, THING0, INVISIBLE, 0, 0, 0, 55, 31, 212, 142, 182, 113, 0, 0, 0, 0, kCMDcupbp_2w, 0, 0, 0, FLOATING, 200, 150, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDoor_2w, kDTdull_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 31, 28, 154, 90, 90, 0, 0, 0, 0, kCMDpdoor_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNAlbum_2w, kDTtalbum_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 255, 212, 142, 90, 90, 0, 0, 5, 1, kCMDalbum_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCupb_2w, 0, 0, AUTO, 64, 28, 0, THING0, INVISIBLE, 0, 0, 0, 55, 31, 212, 142, 182, 113, 0, 0, 0, 0, kCMDcupbp_2w, 0, 0, 0, FLOATING, 200, 150, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTdull_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 31, 28, 154, 90, 90, 0, 0, 0, 0, kCMDpdoor_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNAlbum_2w, kDTtalbum_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 255, 212, 142, 90, 90, 0, 0, 5, 1, kCMDalbum_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 32: (Catroom)
-{kNCat_2w, kDTtcat_2w, 0, AUTO, 0, 0, 0, THING2b, CYCLE_FORWARD, 0, 2, 0, 40, 32, 189, 69, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 171, 117, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 27, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 32, 122, 144, 106, 68, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 113, 118, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 26, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 32, 122, 144, 179, 68, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 189, 118, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNPost_2w, 0, 0, AUTO, 29, 32, 0, THING0, INVISIBLE, 0, 0, 0, 20, 32, 122, 144, 195, 100, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 195, 128, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNCat_2w, kDTtcat_2w, 0, AUTO, 0, 0, 0, THING2b, CYCLE_FORWARD, 0, 2, 0, 40, 32, 189, 69, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 171, 117, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 27, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 32, 122, 144, 106, 68, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 113, 118, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 26, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 32, 122, 144, 179, 68, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 189, 118, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNPost_2w, 0, 0, AUTO, 29, 32, 0, THING0, INVISIBLE, 0, 0, 0, 20, 32, 122, 144, 195, 100, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 195, 128, Common::KEYCODE_DOWN, 0, 0, 0, 0},
// Screen 33: (Boxroom)
-{kNDoor_2w, kDTtbdoor_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 33, 137, 97, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 140, 142, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNPaper_2w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 80, 33, 205, 147, 90, 90, 0, 0, 5, 7, kCMDpaper_2w, 0, 0, 0, BACKGROUND, 188, 159, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNPencil_2w, kDTtpencil_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 40, 33, 205, 163, 90, 90, 0, 0, 5, 7, kCMDpencil_2w, 0, 0, 0, FLOATING, 188, 168, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNChute_2w, 0, 0, AUTO, 12, 21, 0, THING0, INVISIBLE, 0, 0, 0, 20, 33, 122, 144, 73, 107, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 114, 149, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNCrate_2w, 0, 0, AUTO, 48, 28, 0, THING0, INVISIBLE, 0, 0, 0, 20, 33, 122, 144, 68, 133, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 114, 149, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNDoor_2w, kDTtbdoor_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 33, 137, 97, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 140, 142, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNPaper_2w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 80, 33, 205, 147, 90, 90, 0, 0, 5, 7, kCMDpaper_2w, 0, 0, 0, BACKGROUND, 188, 159, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNPencil_2w, kDTtpencil_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 40, 33, 205, 163, 90, 90, 0, 0, 5, 7, kCMDpencil_2w, 0, 0, 0, FLOATING, 188, 168, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNChute_2w, 0, 0, AUTO, 12, 21, 0, THING0, INVISIBLE, 0, 0, 0, 20, 33, 122, 144, 73, 107, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 114, 149, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNCrate_2w, 0, 0, AUTO, 48, 28, 0, THING0, INVISIBLE, 0, 0, 0, 20, 33, 122, 144, 68, 133, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 114, 149, Common::KEYCODE_LEFT, 0, 0, 0, 0},
// Screen 34: (Hall3)
-{kNDoor_2w, kDTtdoor_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 34, 234, 73, 90, 90, 0, 0, 0, 1, kCMDdoor2_2w, 0, 0, 0, FLOATING, 240, 121, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDoor_2w, kDTtdoor_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 34, 103, 73, 90, 90, 0, 0, 0, 1, kCMDdoor3_2w, 0, 0, 0, FLOATING, 107, 121, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 16, 56, 0, THING0, INVISIBLE, 0, 0, 0, 50, 34, 80, 40, 73, 92, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 90, 148, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNMirror_2w, 0, 0, AUTO, 20, 33, 0, THING0, INVISIBLE, 0, 0, 0, 20, 34, 122, 144, 172, 75, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 175, 125, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoor_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 34, 234, 73, 90, 90, 0, 0, 0, 1, kCMDdoor2_2w, 0, 0, 0, FLOATING, 240, 121, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoor_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 34, 103, 73, 90, 90, 0, 0, 0, 1, kCMDdoor3_2w, 0, 0, 0, FLOATING, 107, 121, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 16, 56, 0, THING0, INVISIBLE, 0, 0, 0, 50, 34, 80, 40, 73, 92, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 90, 148, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNMirror_2w, 0, 0, AUTO, 20, 33, 0, THING0, INVISIBLE, 0, 0, 0, 20, 34, 122, 144, 172, 75, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 175, 125, Common::KEYCODE_UP, 0, 0, 0, 0},
// Screen 35: (Organ)
-{kNHarry_2w, kDTtharry_2w, 0, AUTO, DX, DY, 0, THING2f, CYCLE_FORWARD, 0, 2, 0, -1, 35, 188, 84, 90, 90, 0, 0, 0, 1, kCMDharry_2w, 0, 0, 0, FLOATING, 216, 132, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 33, 33, 0, THING0, INVISIBLE, 0, 0, 0, 20, 35, 122, 144, 248, 72, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 251, 134, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNPicture_2w, 0, 0, AUTO, 33, 21, 0, THING0, INVISIBLE, 0, 0, 0, 20, 35, 122, 144, 95, 78, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant_2w, 0, 0, AUTO, 23, 57, 0, THING0, INVISIBLE, 0, 0, 0, 20, 35, 122, 144, 52, 83, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 83, 138, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNOrgan_2w, 0, 0, AUTO, 65, 66, 0, THING0, INVISIBLE, 0, 0, 0, 20, 35, 122, 144, 162, 62, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHarry_2w, kDTtharry_2w, 0, AUTO, DX, DY, 0, THING2f, CYCLE_FORWARD, 0, 2, 0, -1, 35, 188, 84, 90, 90, 0, 0, 0, 1, kCMDharry_2w, 0, 0, 0, FLOATING, 216, 132, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 33, 33, 0, THING0, INVISIBLE, 0, 0, 0, 20, 35, 122, 144, 248, 72, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 251, 134, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNPicture_2w, 0, 0, AUTO, 33, 21, 0, THING0, INVISIBLE, 0, 0, 0, 20, 35, 122, 144, 95, 78, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant_2w, 0, 0, AUTO, 23, 57, 0, THING0, INVISIBLE, 0, 0, 0, 20, 35, 122, 144, 52, 83, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 83, 138, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNOrgan_2w, 0, 0, AUTO, 65, 66, 0, THING0, INVISIBLE, 0, 0, 0, 20, 35, 122, 144, 162, 62, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 36: (Hestroom)
-{kNHester_2w, kDTthester_2w, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 30, 36, 78, 114, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 70, 150, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNLetter_2w, kDTtletter_2w, 0, AUTO, 19, 6, 0, THING0, INVISIBLE, 0, 0, 0, 30, 36, 110, 150, 106, 132, 0, 0, 0, 1, kCMDletter_2w, 0, 0, 0, FLOATING, 98, 151, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNBookcase_2w, 0, 0, AUTO, 69, 62, 0, THING0, INVISIBLE, 0, 0, 0, 20, 36, 122, 144, 179, 81, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 201, 146, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNPicture_2w, 0, 0, AUTO, 23, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 36, 122, 144, 271, 91, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 237, 145, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNPlant_2w, 0, 0, AUTO, 12, 21, 0, THING0, INVISIBLE, 0, 0, 0, 20, 36, 122, 144, 263, 111, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 237, 145, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNWindow_2w, 0, 0, AUTO, 24, 23, 0, THING0, INVISIBLE, 0, 0, 0, 20, 36, 122, 144, 25, 94, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 40, 154, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNHester_2w, kDTthester_2w, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 30, 36, 78, 114, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 70, 150, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNLetter_2w, kDTtletter_2w, 0, AUTO, 19, 6, 0, THING0, INVISIBLE, 0, 0, 0, 30, 36, 110, 150, 106, 132, 0, 0, 0, 1, kCMDletter_2w, 0, 0, 0, FLOATING, 98, 151, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBookcase_2w, 0, 0, AUTO, 69, 62, 0, THING0, INVISIBLE, 0, 0, 0, 20, 36, 122, 144, 179, 81, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 201, 146, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNPicture_2w, 0, 0, AUTO, 23, 24, 0, THING0, INVISIBLE, 0, 0, 0, 20, 36, 122, 144, 271, 91, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 237, 145, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNPlant_2w, 0, 0, AUTO, 12, 21, 0, THING0, INVISIBLE, 0, 0, 0, 20, 36, 122, 144, 263, 111, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 237, 145, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNWindow_2w, 0, 0, AUTO, 24, 23, 0, THING0, INVISIBLE, 0, 0, 0, 20, 36, 122, 144, 25, 94, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 40, 154, Common::KEYCODE_LEFT, 0, 0, 0, 0},
// Screen 37: (Retupmoc)
-{kNDoctor_2w, kDTtdoctor_2w, 0, WANDER, DX, DY, kALdoctor_2w, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 37, 78, 114, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNRobot_2w, 0, trobots_2w, CHASE2, DX, DY, kALrobot_2w, PERSON5, NOT_CYCLING, 0, 0, 0, -1, 37, 78, 114, 90, 90, 0, 0, 0, 9, kCMDrobot_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNScrew_2w, kDTtscrew_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 37, 100, 123, 90, 90, 0, 0, 15, 3, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoctor_2w, kDTtdoctor_2w, 0, WANDER, DX, DY, kALdoctor_2w, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 37, 78, 114, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRobot_2w, 0, trobots_2w, CHASE2, DX, DY, kALrobot_2w, PERSON5, NOT_CYCLING, 0, 0, 0, -1, 37, 78, 114, 90, 90, 0, 0, 0, 9, kCMDrobot_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNScrew_2w, kDTtscrew_2w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 37, 100, 123, 90, 90, 0, 0, 15, 3, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 38: (Hall1 revisited)
-{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 50, 38, 238, 40, 90, 90, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 239, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 26, 42, 0, THING0, INVISIBLE, 0, 0, 0, 50, 38, 80, 40, 80, 40, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 82, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 26, 42, 0, THING0, INVISIBLE, 0, 0, 0, 50, 38, 160, 40, 160, 40, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 162, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNPicture_2w, 0, 0, AUTO, 32, 18, 0, THING0, INVISIBLE, 0, 0, 0, 20, 38, 122, 144, 187, 113, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 200, 158, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNPlant_2w, 0, 0, AUTO, 25, 43, 0, THING0, INVISIBLE, 0, 0, 0, 20, 38, 122, 144, 239, 111, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 219, 157, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 50, 38, 238, 40, 90, 90, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 239, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 26, 42, 0, THING0, INVISIBLE, 0, 0, 0, 50, 38, 80, 40, 80, 40, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 82, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoor_2w, kDTtdoordum_2w, 0, AUTO, 26, 42, 0, THING0, INVISIBLE, 0, 0, 0, 50, 38, 160, 40, 160, 40, 0, 0, 0, 1, kCMDdoordum_2w, 0, 0, 0, FLOATING, 162, 82, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNPicture_2w, 0, 0, AUTO, 32, 18, 0, THING0, INVISIBLE, 0, 0, 0, 20, 38, 122, 144, 187, 113, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 200, 158, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNPlant_2w, 0, 0, AUTO, 25, 43, 0, THING0, INVISIBLE, 0, 0, 0, 20, 38, 122, 144, 239, 111, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 219, 157, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// Misc:
-{kNCook_2w, kDTtcook_2w, 0, AUTO, DX, DY, 0, PERSON, INVISIBLE, 0, 0, 0, 30, 06, 98, 98, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCookb_2w, kDTtcook_2w, 0, AUTO, 0, 0, 0, THING4, CYCLE_FORWARD, 0, 0, 0, 30, 255, 98, 98, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCop_2w, kDTtcop_2w, 0, AUTO, 0, 0, 0, PERSON2, INVISIBLE, 0, 0, 0, 30, 29, 180, 47, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNHorace_2w, kDTthorace_2w, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 30, 34, 215, 76, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBell_2w, kDTtbell_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 15, 149, 109, 90, 90, 0, 0, 5, 7, kCMDbell_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGun_2w, 0, tguns_2w, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 26, 149, 109, 90, 90, 0, 0, 10, 15, kCMDgun_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBottle_2w, kDTtbottle_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 27, 149, 109, 90, 90, 0, 0, 15, 7, kCMDbottle_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCook_2w, kDTtcook_2w, 0, AUTO, DX, DY, 0, PERSON, INVISIBLE, 0, 0, 0, 30, 06, 98, 98, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCookb_2w, kDTtcook_2w, 0, AUTO, 0, 0, 0, THING4, CYCLE_FORWARD, 0, 0, 0, 30, 255, 98, 98, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCop_2w, kDTtcop_2w, 0, AUTO, 0, 0, 0, PERSON2, INVISIBLE, 0, 0, 0, 30, 29, 180, 47, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHorace_2w, kDTthorace_2w, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 30, 34, 215, 76, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBell_2w, kDTtbell_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 15, 149, 109, 90, 90, 0, 0, 5, 7, kCMDbell_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGun_2w, 0, tguns_2w, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 26, 149, 109, 90, 90, 0, 0, 10, 15, kCMDgun_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBottle_2w, kDTtbottle_2w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 27, 149, 109, 90, 90, 0, 0, 15, 7, kCMDbottle_2w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
};
uint16 tflask_3w[] = {kDTtflask1_3w, kDTtflask2_3w, kDTtflask3_3w, 0};// Descriptions depend on flask state
@@ -5341,365 +5360,365 @@ uint16 tcage_3w[] = {kDTtcage1_3w, kDTtcage2_3w, 0};
object_t objects_3w[] = {
//name,description,description_s,path,dx,dy,aptr,SPRITE, cyc, n,frm,rad, scr,x,y ,oldxy,vxy,val,g,cmnd,c,s,ctx,fgb, viewx,viewy,dir
// Common objects // Set Penny state to 3 to avoid story
-{kNHero_3w, kDTthero_3w, 0, USER, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 0, 0, 161, 110, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWhero_3w, kDTthero_3w, 0, USER, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 219, 133, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHero_3w, kDTthero_3w, 0, USER, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 0, 0, 161, 110, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWhero_3w, kDTthero_3w, 0, USER, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 219, 133, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
//#if STORY
-{kNPenny_3w, kDTtpenny_3w, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 0, 109, 110, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPenny_3w, kDTtpenny_3w, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 0, 109, 110, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
//#else
-//{kNPenny_3w, kDTtpenny_3w, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 0, 109, 110, 90, 90, 0, 0, 0, 1, 0, 0, 3, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+//{kNPenny_3w, kDTtpenny_3w, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 0, 109, 110, 90, 90, 0, 0, 0, 1, 0, 0, 3, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
//#endif
-{kNPennylie_3w, kDTtplie_3w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, -1, WEB_3w, 75, 156, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLips_3w, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 0, 0, 186, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNPennylie_3w, kDTtplie_3w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, -1, WEB_3w, 75, 156, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLips_3w, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 0, 0, 186, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
// CRASH site
-{kNPlane_3w, kDTtplane_3w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, CRASH_3w, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcplane_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoor_3w, kDTdull_3w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 80, CRASH_3w, 184, 136, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant1_3w, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 0, CRASH_3w, 132, 165, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
+{kNPlane_3w, kDTtplane_3w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, CRASH_3w, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcplane_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_3w, kDTdull_3w, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 80, CRASH_3w, 184, 136, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant1_3w, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 0, CRASH_3w, 132, 165, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
// INPLANE
-{kNPlane_3w, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, PLANE_3w, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcexit_3w, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWater_3w, kDTtwwater_3w, 0, AUTO, 195, 10, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_3w, 184, 136, 0, 155, 0, 0, 0, 0, kCMDcwfall_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWaterfall_3w, kDTtwwater_3w, 0, AUTO, 57, 131, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_3w, 184, 136, 239, 22, 0, 0, 0, 0, kCMDcwfall_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWater_3w, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_B_3w, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwfall_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWater_3w, kDTtswater_3w, 0, AUTO, 106, 19, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 102, 150, 0, 0, 0, 0, kCMDcwstream_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWater_3w, kDTtswater_3w, 0, AUTO, 195, 9, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 55, 183, 0, 0, 0, 0, kCMDcwstream_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPool_3w, kDTtmwater_3w, 0, AUTO, 87, 34, 0, THING0, INVISIBLE, 0, 0, 0, -1, GARDEN_3w, 184, 136, 112, 129, 0, 0, 0, 0, kCMDcwpool_3w, 0, 0, 0, FLOATING, 155, 170, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNClay_3w, kDTtclay_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 162, 96, 90, 90, 0, 0, 5, 7, kCMDcclay_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNNeedles_3w, kDTtneedles_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 172, 90, 90, 90, 0, 0, 5, 7, kCMDcpins_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNFlask_3w, 0, tflask_3w, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 190, 90, 90, 90, 0, 0, 5, 11, kCMDcflask_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNBouillon_3w, kDTtbouillon_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 185, 94, 90, 90, 0, 0, 5, 7, kCMDcbouillon_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNCheese_3w, kDTtcheese_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 185, 100, 90, 90, 0, 0, 5, 1, kCMDccheese_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNPlane_3w, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, PLANE_3w, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcexit_3w, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWater_3w, kDTtwwater_3w, 0, AUTO, 195, 10, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_3w, 184, 136, 0, 155, 0, 0, 0, 0, kCMDcwfall_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWaterfall_3w, kDTtwwater_3w, 0, AUTO, 57, 131, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_3w, 184, 136, 239, 22, 0, 0, 0, 0, kCMDcwfall_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWater_3w, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_B_3w, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwfall_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWater_3w, kDTtswater_3w, 0, AUTO, 106, 19, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 102, 150, 0, 0, 0, 0, kCMDcwstream_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWater_3w, kDTtswater_3w, 0, AUTO, 195, 9, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 55, 183, 0, 0, 0, 0, kCMDcwstream_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPool_3w, kDTtmwater_3w, 0, AUTO, 87, 34, 0, THING0, INVISIBLE, 0, 0, 0, -1, GARDEN_3w, 184, 136, 112, 129, 0, 0, 0, 0, kCMDcwpool_3w, 0, 0, 0, FLOATING, 155, 170, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNClay_3w, kDTtclay_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 162, 96, 90, 90, 0, 0, 5, 7, kCMDcclay_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNNeedles_3w, kDTtneedles_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 172, 90, 90, 90, 0, 0, 5, 7, kCMDcpins_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNFlask_3w, 0, tflask_3w, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 190, 90, 90, 90, 0, 0, 5, 11, kCMDcflask_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNBouillon_3w, kDTtbouillon_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 185, 94, 90, 90, 0, 0, 5, 7, kCMDcbouillon_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNCheese_3w, kDTtcheese_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3w, 185, 100, 90, 90, 0, 0, 5, 1, kCMDccheese_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
// WEB
-{kNSpider_3w, kDTtspider_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, WEB_3w, 77, 50, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant3_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, WEB_3w, 245, 117, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant4_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, WEB_3w, 285, 90, 91, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSpider_3w, kDTtspider_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, WEB_3w, 77, 50, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant3_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, WEB_3w, 245, 117, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant4_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, WEB_3w, 285, 90, 91, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// BRIDGE
-{kNBlock_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3w, 225, 132, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBlock_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3w, 225, 133, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBlock_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3w, 225, 134, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBlock_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3w, 225, 135, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNVine_3w, kDTtvine_3w, 0, AUTO, 8, 76, 0, THING0, INVISIBLE, 0, 0, 0, -1, BRIDGE_3w, 184, 136, 228, 24, 0, 0, 0, 1, kCMDcvine_3w, 0, 0, 0, FLOATING, 237, 131, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNBlock_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3w, 225, 132, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBlock_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3w, 225, 133, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBlock_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3w, 225, 134, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBlock_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3w, 225, 135, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNVine_3w, kDTtvine_3w, 0, AUTO, 8, 76, 0, THING0, INVISIBLE, 0, 0, 0, -1, BRIDGE_3w, 184, 136, 228, 24, 0, 0, 0, 1, kCMDcvine_3w, 0, 0, 0, FLOATING, 237, 131, Common::KEYCODE_UP, 0, 0, 0, 0},
// STREAM
-{kNVine_3w, kDTtvine_3w, 0, AUTO, 6, 50, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 101, 96, 0, 0, 0, 1, kCMDcswing_3w, 0, 0, 0, FLOATING, 50, 172, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
-{kNVine_3w, kDTtvine_3w, 0, AUTO, 6, 50, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 203, 96, 0, 0, 0, 1, kCMDcswing_3w, 0, 0, 0, FLOATING, 233, 170, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNSwinger_3w, 0, 0, AUTO, 0, 0, 0, PERSON2, INVISIBLE, 0, 0, 0, 0, STREAM_3w, 219, 133, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNSteps_3w, kDTtsteps_3w, 0, AUTO, 153, 15, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 79, 168, 0, 0, 0, 1, kCMDcsteps_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNVine_3w, kDTtvine_3w, 0, AUTO, 6, 50, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 101, 96, 0, 0, 0, 1, kCMDcswing_3w, 0, 0, 0, FLOATING, 50, 172, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNVine_3w, kDTtvine_3w, 0, AUTO, 6, 50, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 203, 96, 0, 0, 0, 1, kCMDcswing_3w, 0, 0, 0, FLOATING, 233, 170, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNSwinger_3w, 0, 0, AUTO, 0, 0, 0, PERSON2, INVISIBLE, 0, 0, 0, 0, STREAM_3w, 219, 133, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSteps_3w, kDTtsteps_3w, 0, AUTO, 153, 15, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3w, 184, 136, 79, 168, 0, 0, 0, 1, kCMDcsteps_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// HUT_IN
-{kNDoctor_3w, kDTtdoctor_3w, 0, WANDER, DX, DY, kALdocgot_3w, PERSON3, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3w, 273, 83, 90, 90, 0, 0, 0, 1, kCMDcdoctor_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoclie_3w, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 30, HUT_IN_3w, 239, 103, 90, 90, 0, 0, 0, 1, kCMDcdoctor_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCdoor_3w, kDTdull_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 40, HUT_IN_3w, 239, 103, 90, 90, 0, 0, 0, 1, kCMDcdoor_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNMouse_3w, kDTtmouse_3w, 0, AUTO, 0, 0, 0, THING2b, INVISIBLE, 0, 0, 0, 30, HUT_IN_3w, 186, 170, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMoushole_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, HUT_IN_3w, 203, 122, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCage_3w, 0, tcage_3w, AUTO, 0, 0, 0, THING2a, NOT_CYCLING, 0, 0, 0, 30, HUT_IN_3w, 156, 121, 90, 90, 0, 0, 1, 13, kCMDccage_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNFire_1_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_OUT_3w, 127, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_1_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_OUT_3w, 172, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_2_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_IN_3w, 30, 145, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_3_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, CAMP_3w, 120, 135, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_3w, 0, 0, AUTO, 42, 54, 0, THING0, INVISIBLE, 0, 0, 0, 50, HUT_IN_3w, 50, 136, 30, 121, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 44, 153, Common::KEYCODE_LEFT, 0, 0, 0, 0},
-{kNWindow_3w, 0, 0, AUTO, 39, 32, 0, THING0, INVISIBLE, 0, 0, 0, 50, HUT_IN_3w, 184, 136, 101, 72, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 111, 148, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNDoctor_3w, kDTtdoctor_3w, 0, WANDER, DX, DY, kALdocgot_3w, PERSON3, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3w, 273, 83, 90, 90, 0, 0, 0, 1, kCMDcdoctor_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoclie_3w, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 30, HUT_IN_3w, 239, 103, 90, 90, 0, 0, 0, 1, kCMDcdoctor_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCdoor_3w, kDTdull_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 40, HUT_IN_3w, 239, 103, 90, 90, 0, 0, 0, 1, kCMDcdoor_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNMouse_3w, kDTtmouse_3w, 0, AUTO, 0, 0, 0, THING2b, INVISIBLE, 0, 0, 0, 30, HUT_IN_3w, 186, 170, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMoushole_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, HUT_IN_3w, 203, 122, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCage_3w, 0, tcage_3w, AUTO, 0, 0, 0, THING2a, NOT_CYCLING, 0, 0, 0, 30, HUT_IN_3w, 156, 121, 90, 90, 0, 0, 1, 13, kCMDccage_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNFire_1_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_OUT_3w, 127, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_1_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_OUT_3w, 172, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_2_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_IN_3w, 30, 145, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_3_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, CAMP_3w, 120, 135, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_3w, 0, 0, AUTO, 42, 54, 0, THING0, INVISIBLE, 0, 0, 0, 50, HUT_IN_3w, 50, 136, 30, 121, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 44, 153, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNWindow_3w, 0, 0, AUTO, 39, 32, 0, THING0, INVISIBLE, 0, 0, 0, 50, HUT_IN_3w, 184, 136, 101, 72, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 111, 148, Common::KEYCODE_UP, 0, 0, 0, 0},
// CAMP
-{kNNat1_3w, kDTtnative_3w, 0, WANDER, DX, 0, 0, PERSON, NOT_CYCLING, 0, 0, 0, -1, CAMP_3w, 130, 105, 90, 90, 0, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNat2_3w, kDTtnative_3w, 0, AUTO, DX, DY, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3w, 17, 97, 90, 90, 4, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNat3_3w, kDTtnative_3w, 0, AUTO, DX, DY, 0, THING2, CYCLE_FORWARD, 0, 16, 0, -1, CAMP_3w, 96, 40, 90, 90, 0, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNatb_3w, kDTtnative_3w, 0, AUTO, DX, DY, 0, THING2, CYCLE_FORWARD, 0, 20, 0, -1, CAMP_3w, 72, 51, 90, 90, 0, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNatg_3w, kDTtnatgirl_3w, 0, AUTO, DX, DY, kALnative_3w, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3w, 28, 101, 90, 90, 3, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPipe_3w, kDTtpipe_3w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, CAMP_3w, 225, 135, 90, 90, 0, 0, 0, 7, kCMDcdart_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNHut_3w, 0, 0, AUTO, 47, 64, 0, THING0, INVISIBLE, 0, 0, 0, 50, CAMP_3w, 184, 136, 0, 42, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 42, 92, Common::KEYCODE_LEFT, 0, 0, 0, 0},
+{kNNat1_3w, kDTtnative_3w, 0, WANDER, DX, 0, 0, PERSON, NOT_CYCLING, 0, 0, 0, -1, CAMP_3w, 130, 105, 90, 90, 0, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNat2_3w, kDTtnative_3w, 0, AUTO, DX, DY, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3w, 17, 97, 90, 90, 4, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNat3_3w, kDTtnative_3w, 0, AUTO, DX, DY, 0, THING2, CYCLE_FORWARD, 0, 16, 0, -1, CAMP_3w, 96, 40, 90, 90, 0, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNatb_3w, kDTtnative_3w, 0, AUTO, DX, DY, 0, THING2, CYCLE_FORWARD, 0, 20, 0, -1, CAMP_3w, 72, 51, 90, 90, 0, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNatg_3w, kDTtnatgirl_3w, 0, AUTO, DX, DY, kALnative_3w, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3w, 28, 101, 90, 90, 3, 0, 0, 1, kCMDcnative_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPipe_3w, kDTtpipe_3w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, CAMP_3w, 225, 135, 90, 90, 0, 0, 0, 7, kCMDcdart_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNHut_3w, 0, 0, AUTO, 47, 64, 0, THING0, INVISIBLE, 0, 0, 0, 50, CAMP_3w, 184, 136, 0, 42, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, 42, 92, Common::KEYCODE_LEFT, 0, 0, 0, 0},
// PATH_2
-{kNElephant_3w, kDTtelephant_3w, 0, AUTO, 0, 0, 0, THING2a, NOT_CYCLING, 0, 4, 0, -1, PATH_3w, 163, 85, 90, 90, 0, 0, 0, 1, kCMDcelephant_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNE_eyes_3w, 0, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, -1, PATH_3w, 194, 102, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNElephant_3w, kDTtelephant_3w, 0, AUTO, 0, 0, 0, THING2a, NOT_CYCLING, 0, 4, 0, -1, PATH_3w, 163, 85, 90, 90, 0, 0, 0, 1, kCMDcelephant_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNE_eyes_3w, 0, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, -1, PATH_3w, 194, 102, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
// Misc
-{kNHero_old_3w, 0, 0, USER, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 161, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNAircraft_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, SUNSET_3w, 250, 116, 90, 90, -2, -1, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNScroll_3w, kDTtscroll_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, CLIFFTOP_3w, 75, 116, 90, 90, 0, 0, 3, 7, kCMDcscroll_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNCrystal_3w, kDTtcrystal_3w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, TURN_3w, 275, 116, 90, 90, 0, 0, 9, 7, kCMDccrystal_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNRock_3w, kDTtrock_3w, 0, AUTO, 93, 55, 0, THING0, INVISIBLE, 0, 0, 0, -1, TURN_3w, 100, 100, 220, 120, 0, 0, 0, 0, kCMDcrock_3w, 0, 0, 0, FLOATING, 220, 169, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
+{kNHero_old_3w, 0, 0, USER, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 161, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNAircraft_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, SUNSET_3w, 250, 116, 90, 90, -2, -1, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNScroll_3w, kDTtscroll_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, CLIFFTOP_3w, 75, 116, 90, 90, 0, 0, 3, 7, kCMDcscroll_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNCrystal_3w, kDTtcrystal_3w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, TURN_3w, 275, 116, 90, 90, 0, 0, 9, 7, kCMDccrystal_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNRock_3w, kDTtrock_3w, 0, AUTO, 93, 55, 0, THING0, INVISIBLE, 0, 0, 0, -1, TURN_3w, 100, 100, 220, 120, 0, 0, 0, 0, kCMDcrock_3w, 0, 0, 0, FLOATING, 220, 169, Common::KEYCODE_RIGHT, 0, 0, 0, 0},
// CAVE etc.
-{kNPlant2_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, CAVE_3w, 27, 160, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
-{kNGhost_3w, kDTtghost_3w, 0, CHASE, DX, DY, 0, THING2c, NOT_CYCLING, 0, 0, 0, -1, CAVE_3w, 121, 86, 90, 90, 0, 0, 0, 1, kCMDcghost_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBell_3w, kDTtbell_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, CLIFF_3w, 202, 152, 90, 90, 0, 0, 2, 7, kCMDcbell_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNBook_3w, kDTtbook_3w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, STREAM_3w, 275, 116, 90, 90, 0, 0, 10, 7, kCMDcbook_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNCandle_3w, kDTtcandle_3w, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 20, 0, 30, HUT_IN_3w, 77, 134, 90, 90, 0, 0, 3, 7, kCMDccandle_3w, 0, 1, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
-{kNVine_3w, kDTtvine_3w, 0, AUTO, 5, 53, 0, THING0, INVISIBLE, 0, 0, 0, -1, CAVE_3w, 184, 136, 116, 80, 0, 0, 0, 1, kCMDcswingc_3w, 0, 0, 0, FLOATING, 114, 139, Common::KEYCODE_UP, 0, 0, 0, 0},
-{kNRush_3w, kDTtrush_3w, 0, AUTO, 40, 18, 0, THING0, INVISIBLE, 0, 0, 0, 60, STREAM_3w, 240, 160, 231, 144, 0, 0, 0, 1, kCMDcrush_3w, 0, 0, 0, FLOATING, 240, 160, Common::KEYCODE_DOWN, 0, 0, 0, 0},
-{kNRush_3w, kDTtrush_3w, 0, AUTO, 40, 18, 0, THING0, INVISIBLE, 0, 0, 0, 60, STREAM2_3w, 240, 160, 231, 144, 0, 0, 0, 1, kCMDcrush_3w, 0, 0, 0, FLOATING, 240, 160, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNPlant2_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, CAVE_3w, 27, 160, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
+{kNGhost_3w, kDTtghost_3w, 0, CHASE, DX, DY, 0, THING2c, NOT_CYCLING, 0, 0, 0, -1, CAVE_3w, 121, 86, 90, 90, 0, 0, 0, 1, kCMDcghost_3w, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBell_3w, kDTtbell_3w, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, CLIFF_3w, 202, 152, 90, 90, 0, 0, 2, 7, kCMDcbell_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNBook_3w, kDTtbook_3w, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, STREAM_3w, 275, 116, 90, 90, 0, 0, 10, 7, kCMDcbook_3w, 0, 0, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNCandle_3w, kDTtcandle_3w, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 20, 0, 30, HUT_IN_3w, 77, 134, 90, 90, 0, 0, 3, 7, kCMDccandle_3w, 0, 1, 0, FLOATING, GO_OBJ, -1, -1, 0, 0, 0, 0},
+{kNVine_3w, kDTtvine_3w, 0, AUTO, 5, 53, 0, THING0, INVISIBLE, 0, 0, 0, -1, CAVE_3w, 184, 136, 116, 80, 0, 0, 0, 1, kCMDcswingc_3w, 0, 0, 0, FLOATING, 114, 139, Common::KEYCODE_UP, 0, 0, 0, 0},
+{kNRush_3w, kDTtrush_3w, 0, AUTO, 40, 18, 0, THING0, INVISIBLE, 0, 0, 0, 60, STREAM_3w, 240, 160, 231, 144, 0, 0, 0, 1, kCMDcrush_3w, 0, 0, 0, FLOATING, 240, 160, Common::KEYCODE_DOWN, 0, 0, 0, 0},
+{kNRush_3w, kDTtrush_3w, 0, AUTO, 40, 18, 0, THING0, INVISIBLE, 0, 0, 0, 60, STREAM2_3w, 240, 160, 231, 144, 0, 0, 0, 1, kCMDcrush_3w, 0, 0, 0, FLOATING, 240, 160, Common::KEYCODE_DOWN, 0, 0, 0, 0},
// OLDMAN (inside cave)
-{kNO_eye_3w, 0, 0, AUTO, 0, 0, 0, THING3, INVISIBLE, 0, 0, 0, 0, OLDMAN_3w, 237, 77, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_4_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, OLDMAN_3w, 65, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMouth_3w, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 0, 0, 0, OLDMAN_3w, 191, 128, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPole_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, CAMP_3w, 126, 35, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant5_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, TURN_3w, 65, 139, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNO_eye_3w, 0, 0, AUTO, 0, 0, 0, THING3, INVISIBLE, 0, 0, 0, 0, OLDMAN_3w, 237, 77, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_4_3w, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, OLDMAN_3w, 65, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMouth_3w, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 0, 0, 0, OLDMAN_3w, 191, 128, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPole_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, CAMP_3w, 126, 35, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant5_3w, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, TURN_3w, 65, 139, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
};
object_t objects_1d[] = {
//name, description, path, dx, dy, aptr, seq, seqp, cyc, n, frm, rad, scr, x, y , oldxy, vxy, val, g, cmnd, c, s, ctx, fgb
-{kNHero_1d, kDTthero_1d, 0, USER, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 0, 0, 229, 144, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHero_1d, kDTthero_1d, 0, USER, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 0, 0, 229, 144, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 0: (Outside house)
-{kNDoor_1d, kDTtdoor_1d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 0, 26, 131, 90, 90, 0, 0, 0, 1, kCMDdoor1_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNEyes_1d, kDTteyes_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 80, 148, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNEyes_1d, kDTteyes_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 59, 78, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 95, 55, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNPkin_1d, kDTtpkin_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 10, 0, 20, 168, 90, 90, 0, 0, 2, 7, kCMDpkin_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNKey_1d, kDTtkey_1d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 5, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_1d, kDTtdoor_1d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 0, 26, 131, 90, 90, 0, 0, 0, 1, kCMDdoor1_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNEyes_1d, kDTteyes_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 80, 148, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNEyes_1d, kDTteyes_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 59, 78, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 0, 95, 55, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNPkin_1d, kDTtpkin_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 10, 0, 20, 168, 90, 90, 0, 0, 2, 7, kCMDpkin_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNKey_1d, kDTtkey_1d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 5, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 1: (Hall)
-{kNDoor_1d, kDTtdoor_1d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 125, 56, 90, 90, 0, 0, 0, 1, kCMDdoor2_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoor_1d, kDTtdoor_1d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 208, 56, 90, 90, 0, 0, 0, 1, kCMDdoor3_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNEyes_1d, kDTteyes_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 1, 23, 48, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNEyes_1d, kDTteyes_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 1, 7, 93, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNCandle_1d, kDTtcandle_1d, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 20, 1, 176, 131, 90, 90, 0, 0, 3, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCupb_1d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 1, 69, 161, 90, 90, 0, 0, 0, 1, kCMDcupb_1d, 0, 0, 1, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNKnife_1d, kDTtknife_1d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 1, 69, 161, 90, 90, 0, 0, 6, 3, kCMDknife_1d, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNWhistle_1d, kDTtwhistle_1d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 1, 69, 161, 90, 90, 0, 0, 6, 3, kCMDwhistle_1d, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_1d, kDTtdoor_1d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 125, 56, 90, 90, 0, 0, 0, 1, kCMDdoor2_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_1d, kDTtdoor_1d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 208, 56, 90, 90, 0, 0, 0, 1, kCMDdoor3_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNEyes_1d, kDTteyes_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 1, 23, 48, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNEyes_1d, kDTteyes_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, 1, 7, 93, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNCandle_1d, kDTtcandle_1d, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 20, 1, 176, 131, 90, 90, 0, 0, 3, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCupb_1d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 1, 69, 161, 90, 90, 0, 0, 0, 1, kCMDcupb_1d, 0, 0, 1, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNKnife_1d, kDTtknife_1d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 1, 69, 161, 90, 90, 0, 0, 6, 3, kCMDknife_1d, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNWhistle_1d, kDTtwhistle_1d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 1, 69, 161, 90, 90, 0, 0, 6, 3, kCMDwhistle_1d, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
// Screen 2: (Bedroom 1)
// Note how wardrobe doors are catered for: The wardrobe has a name but no images,
// the right and left doors have no reference but are cycled by the wardrobe action list
-{kNWard_1d, kDTtward_1d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 1, 4, 4, 30, 2, 172, 113, 90, 90, 0, 0, 0, 1, kCMDward_1d, 0, 0, 1, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNWdoorl_1d, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 2, 150, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWdoorr_1d, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 2, 174, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMask_1d, kDTtmask_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 10, 2, 155, 100, 90, 90, 0, 0, 4, 7, kCMDmask_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMonkey_1d, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 2, 229, 144, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWard_1d, kDTtward_1d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 1, 4, 4, 30, 2, 172, 113, 90, 90, 0, 0, 0, 1, kCMDward_1d, 0, 0, 1, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNWdoorl_1d, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 2, 150, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWdoorr_1d, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 2, 174, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMask_1d, kDTtmask_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 10, 2, 155, 100, 90, 90, 0, 0, 4, 7, kCMDmask_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMonkey_1d, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 2, 229, 144, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 3: (Dining room)
-{kNButler_1d, kDTtbutler_1d, 0, AUTO, 0, 0, kALbutler_1d, PERSON, NOT_CYCLING, 0, 0, 0, DX, 3, 70, 78, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNChop_1d, kDTtchop_1d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 20, 3, 69, 161, 90, 90, 0, 0, 8, 7, kCMDchop_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNRedeyes_1d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, 3, 212, 108, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNLips_1d, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 1, 1, 0, 3, 113, 105, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNArm_1d, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 5, 5, 0, 3, 166, 122, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNHdlshero_1d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 0, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNButler_1d, kDTtbutler_1d, 0, AUTO, 0, 0, kALbutler_1d, PERSON, NOT_CYCLING, 0, 0, 0, DX, 3, 70, 78, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNChop_1d, kDTtchop_1d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 20, 3, 69, 161, 90, 90, 0, 0, 8, 7, kCMDchop_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRedeyes_1d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, 3, 212, 108, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNLips_1d, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 1, 1, 0, 3, 113, 105, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNArm_1d, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 5, 5, 0, 3, 166, 122, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHdlshero_1d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 0, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 6: (Garden)
-{kNDoor_1d, kDTtdoor_1d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 6, 226, 58, 90, 90, 0, 0, 0, 1, kCMDdoor4_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNShed_1d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 60, 6, 277, 39, 90, 90, 0, 0, 0, 1, kCMDshed_1d, 0, 0, 1, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNOilcan_1d, kDTtoilcan_1d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 40, 6, 240, 65, 90, 90, 0, 0, 4, 3, kCMDoilcan_1d, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_1d, kDTtdoor_1d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 6, 226, 58, 90, 90, 0, 0, 0, 1, kCMDdoor4_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNShed_1d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 60, 6, 277, 39, 90, 90, 0, 0, 0, 1, kCMDshed_1d, 0, 0, 1, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNOilcan_1d, kDTtoilcan_1d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 40, 6, 240, 65, 90, 90, 0, 0, 4, 3, kCMDoilcan_1d, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
// Screen 7: (Store room)
-{kNDog_1d, kDTtdog_1d, 0, AUTO, 0, 0, kALdoggy_1d, ANIMAL, NOT_CYCLING, 0, 0, 0, 20, 7, 105, 119, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCarpet_1d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 7, 191, 142, 90, 90, 0, 0, 0, 0, kCMDcarpet_1d, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNTrap_1d, 0, 0, AUTO, 0, 0, 0, THING4, INVISIBLE, 0, 2, 2, 20, 7, 216, 140, 90, 90, 0, 0, 0, 1, kCMDtrap_1d, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNBolt_1d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 7, 220, 145, 90, 90, 0, 0, 0, 1, kCMDbolt_1d, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNHerodead_1d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 0, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDog_1d, kDTtdog_1d, 0, AUTO, 0, 0, kALdoggy_1d, ANIMAL, NOT_CYCLING, 0, 0, 0, 20, 7, 105, 119, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCarpet_1d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 7, 191, 142, 90, 90, 0, 0, 0, 0, kCMDcarpet_1d, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNTrap_1d, 0, 0, AUTO, 0, 0, 0, THING4, INVISIBLE, 0, 2, 2, 20, 7, 216, 140, 90, 90, 0, 0, 0, 1, kCMDtrap_1d, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNBolt_1d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 7, 220, 145, 90, 90, 0, 0, 0, 1, kCMDbolt_1d, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNHerodead_1d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 0, 24, 177, 90, 90, 0, 0, 0, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 9: (Batcave)
-{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, kALbats_1d, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, kALbats_1d, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 65, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, kALbats_1d, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, kALbats_1d, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 130, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, kALbats_1d, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, kALbats_1d, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 65, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, kALbats_1d, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBat_1d, kDTtbat_1d, 0, AUTO, 0, 0, kALbats_1d, THING1, NOT_CYCLING, 0, 0, 0, 16, 9, 55, 130, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 10: (Mummy room)
-{kNMummy_1d, 0, 0, AUTO, 0, 0, kALmummy_1d, PERSON, NOT_CYCLING, 0, 0, 0, DX, 10, 256, 77, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMdoor_1d, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 10, 258, 55, 90, 90, 0, 0, 0, 1, kCMDdoor4_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGold_1d, kDTtgold_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 10, 208, 152, 90, 90, 0, 0, 10, 7, kCMDgold_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMummy_1d, 0, 0, AUTO, 0, 0, kALmummy_1d, PERSON, NOT_CYCLING, 0, 0, 0, DX, 10, 256, 77, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMdoor_1d, 0, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 0, 10, 258, 55, 90, 90, 0, 0, 0, 1, kCMDdoor4_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGold_1d, kDTtgold_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 10, 208, 152, 90, 90, 0, 0, 10, 7, kCMDgold_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 11: (Lakeroom)
-{kNBoat_1d, kDTtboat_1d, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, 30, 11, 230, 118, 90, 90, 0, 0, 0, 1, kCMDboat_1d, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNRope_1d, kDTtrope_1d, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, 30, 11, 220, 132, 90, 90, 0, 0, 0, 1, kCMDrope_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNOldman_1d, kDTtoldman_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 11, 160, 38, 90, 90, 0, 0, 0, 1, kCMDoldman_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWhero_1d, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 11, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBoat_1d, kDTtboat_1d, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, 30, 11, 230, 118, 90, 90, 0, 0, 0, 1, kCMDboat_1d, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRope_1d, kDTtrope_1d, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, 30, 11, 220, 132, 90, 90, 0, 0, 0, 1, kCMDrope_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNOldman_1d, kDTtoldman_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 11, 160, 38, 90, 90, 0, 0, 0, 1, kCMDoldman_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWhero_1d, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 11, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 12: (Dead end)
-{kNGuard_1d, kDTtguard_1d, 0, AUTO, 0, 0, 0, THING2d, NOT_CYCLING, 0, 0, 0, -1, 12, 147, 39, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGuard_1d, kDTtguard_1d, 0, AUTO, 0, 0, 0, THING2d, NOT_CYCLING, 0, 0, 0, -1, 12, 147, 39, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 15: (Laboratory)
-{kNProf_1d, kDTtprof_1d, 0, AUTO, 0, 0, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 1, 150, 55, 90, 90, DX, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNIgor_1d, kDTtigor_1d, 0, AUTO, 0, 0, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 15, 180, 122, 90, 90, DX, 0, 0, 1, kCMDigor_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBung_1d, kDTtbung_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 14, 15, 75, 145, 90, 90, 0, 0, 11, 7, kCMDbung_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGdoor_1d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 15, 59, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNSpachero_1d, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 15, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFuzyhero_1d, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 15, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNArc_1d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, 15, 106, 74, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0}
+{kNProf_1d, kDTtprof_1d, 0, AUTO, 0, 0, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 1, 150, 55, 90, 90, DX, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNIgor_1d, kDTtigor_1d, 0, AUTO, 0, 0, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 15, 180, 122, 90, 90, DX, 0, 0, 1, kCMDigor_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBung_1d, kDTtbung_1d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 14, 15, 75, 145, 90, 90, 0, 0, 11, 7, kCMDbung_1d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGdoor_1d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 15, 59, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSpachero_1d, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 15, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFuzyhero_1d, 0, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 15, 100, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNArc_1d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, 15, 106, 74, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0}
};
object_t objects_2d[] = {
//name,description, path,dx,dy,aptr,seq,seqp, cyc,n,frm,rad,scr,x,y ,oldxy,vxy,val,g,cmnd,c,s,ctx,fgb
-{kNHero_2d, kDTthero_2d, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 319, 199, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPenny_2d, kDTtpenny_2d, 0, AUTO, 0, 0, 0, PERSON, NOT_CYCLING, 0, 0, 0, -1, 1, 109, 140, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHero_2d, kDTthero_2d, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 319, 199, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPenny_2d, kDTtpenny_2d, 0, AUTO, 0, 0, 0, PERSON, NOT_CYCLING, 0, 0, 0, -1, 1, 109, 140, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 0: (Outside house)
-{kNSmoke_2d, 0, 0, AUTO, 0, 0, 0, THING3, CYCLE_FORWARD, 0, 2, 0, 0, 0, 233, 20, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSmoke_2d, 0, 0, AUTO, 0, 0, 0, THING3, CYCLE_FORWARD, 0, 2, 0, 0, 0, 233, 20, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 1: (Hall)
-{kNDoor_2d, kDTtdoor_2d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 238, 40, 90, 90, 0, 0, 0, 1, kCMDdoor1_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLips_2d, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 0, 1, 186, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNMaid_2d, kDTtmaid_2d, 0, AUTO, 0, 0, 0, PERSON4, NOT_CYCLING, 0, 0, 0, 8, 1, 149, 135, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_2d, kDTtdoor_2d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 1, 238, 40, 90, 90, 0, 0, 0, 1, kCMDdoor1_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLips_2d, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 0, 1, 186, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNMaid_2d, kDTtmaid_2d, 0, AUTO, 0, 0, 0, PERSON4, NOT_CYCLING, 0, 0, 0, 8, 1, 149, 135, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 2: (Bedroom 1)
-{kNPennylie_2d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 2, 24, 177, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
-{kNPenfall_2d, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 10, 2, 24, 177, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBookcase_2d, kDTtbookcase_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 2, 70, 81, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBook_2d, kDTtbook_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 10, 2, 90, 140, 90, 90, 0, 0, 0, 1, kCMDbook_2d, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNKeyhole_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 10, 2, 28, 166, 90, 90, 0, 0, 0, 0, kCMDkeyhole_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPennylie_2d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 10, 2, 24, 177, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
+{kNPenfall_2d, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 10, 2, 24, 177, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBookcase_2d, kDTtbookcase_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 2, 70, 81, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBook_2d, kDTtbook_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 10, 2, 90, 140, 90, 90, 0, 0, 0, 1, kCMDbook_2d, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNKeyhole_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 10, 2, 28, 166, 90, 90, 0, 0, 0, 0, kCMDkeyhole_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 3: (Bedroom 2)
-{kNPanel_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 3, 189, 91, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNCupb_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 3, 135, 142, 90, 90, 0, 0, 0, 0, kCMDlookdesk_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBird_2d, kDTtbird_2d, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, -1, 3, 186, 100, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNMatches_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 20, -1, 78, 30, 90, 90, 0, 0, 5, 7, kCMDmatches_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDumb_2d, kDTtdumb_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 3, 72, 138, 90, 90, 0, 0, 0, 1, kCMDdumb_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPanel_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 3, 189, 91, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNCupb_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 3, 135, 142, 90, 90, 0, 0, 0, 0, kCMDlookdesk_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBird_2d, kDTtbird_2d, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, -1, 3, 186, 100, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNMatches_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 20, 255, 78, 30, 90, 90, 0, 0, 5, 7, kCMDmatches_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDumb_2d, kDTtdumb_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 3, 72, 138, 90, 90, 0, 0, 0, 1, kCMDdumb_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 4: (Keyhole)
-{kNMurder_2d, 0, 0, AUTO, 0, 0, 0, THING2e, CYCLE_FORWARD, 1, 2, 16, -1, 4, 141, 76, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMurder_2d, 0, 0, AUTO, 0, 0, 0, THING2e, CYCLE_FORWARD, 1, 2, 16, -1, 4, 141, 76, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 5: (Bed3)
-{kNBalloon_2d, kDTtballoon_2d, 0, WANDER, DX/2, DY/2, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 5, 180, 40, 90, 90, 0, 0, 0, 1, kCMDballoon_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBalloon_2d, kDTtballoon_2d, 0, WANDER, DX/2, DY/2, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 5, 180, 40, 90, 90, 0, 0, 0, 1, kCMDballoon_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 6: (Kitchen)
-{kNDumb_2d, kDTtdumb_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 6, 35, 152, 90, 90, 0, 0, 0, 1, kCMDdumb_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCupb_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 6, 135, 142, 90, 90, 0, 0, 0, 0, kCMDlookcupb_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGarlic_2d, kDTtgarlic_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, -1, 78, 30, 90, 90, 0, 0, 5, 7, kCMDgarlic_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoor_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 6, 290, 196, 90, 90, 0, 0, 0, 0, kCMDkdoor_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDumb_2d, kDTtdumb_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 6, 35, 152, 90, 90, 0, 0, 0, 1, kCMDdumb_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCupb_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 6, 135, 142, 90, 90, 0, 0, 0, 0, kCMDlookcupb_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGarlic_2d, kDTtgarlic_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 255, 78, 30, 90, 90, 0, 0, 5, 7, kCMDgarlic_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 6, 290, 196, 90, 90, 0, 0, 0, 0, kCMDkdoor_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 8: (Shed)
-{kNGardner_2d, kDTtgardner_2d, 0, WANDER, DX, DY, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 8, 250, 90, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGardner_2d, kDTtgardner_2d, 0, WANDER, DX, DY, 0, PERSON2, CYCLE_FORWARD, 0, 0, 0, -1, 8, 250, 90, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 9: In shed
-{kNButton_2d, kDTtbutton_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDbutton_2d, 0, 1, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNRed_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDred_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNYellow_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDyellow_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGreen_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDgreen_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBlue_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDblue_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNShedlight_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 9, 161, 48, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNButton_2d, kDTtbutton_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDbutton_2d, 0, 1, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRed_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDred_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNYellow_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDyellow_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGreen_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDgreen_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBlue_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 9, 190, 137, 90, 90, 0, 0, 0, 1, kCMDblue_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNShedlight_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, -1, 9, 161, 48, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 10: Venus fly traps
-{kNMagnify_2d, kDTtmagnify_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 10, 95, 96, 90, 90, 0, 0, 15, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFly_2d, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 48, 60, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFly_2d, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 58, 70, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFly_2d, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 268, 90, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 20, 10, 48, 86, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 2, 0, 20, 10, 79, 104, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 20, 10, 71, 141, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 3, 0, 20, 10, 116, 113, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 1, 20, 10, 164, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 2, 0, 20, 10, 185, 83, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 20, 10, 232, 96, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 20, 10, 273, 141, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMagnify_2d, kDTtmagnify_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 10, 95, 96, 90, 90, 0, 0, 15, 7, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFly_2d, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 48, 60, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFly_2d, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 58, 70, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFly_2d, 0, 0, WANDER2, DX, DY, 0, THING2, NOT_CYCLING, 0, 1, 0, 20, 10, 268, 90, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 20, 10, 48, 86, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 2, 0, 20, 10, 79, 104, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 20, 10, 71, 141, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 3, 0, 20, 10, 116, 113, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 1, 20, 10, 164, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 2, 0, 20, 10, 185, 83, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 20, 10, 232, 96, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLeaf_2d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 1, 0, 20, 10, 273, 141, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 11: Gates
-{kNGatelight_2d, 0, 0, AUTO, 0, 0, 0, THING1, ALMOST_INVISIBLE, 1, 0, 0, -1, 11, 90, 72, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGatelight_2d, 0, 0, AUTO, 0, 0, 0, THING1, ALMOST_INVISIBLE, 1, 0, 0, -1, 11, 90, 72, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 13: Stream
-{kNCatnip_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, 13, 211, 136, 90, 90, 0, 0, 5, 3, kCMDcatnip_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCatnip_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, 13, 211, 136, 90, 90, 0, 0, 5, 3, kCMDcatnip_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 14: Zapper
-{kNZapper_2d, kDTtzapper_2d, 0, AUTO, 0, 0, 0, THING1, ALMOST_INVISIBLE, 1, 0, 0, -1, 14, 134, 46, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNZapper_2d, kDTtzapper_2d, 0, AUTO, 0, 0, 0, THING1, ALMOST_INVISIBLE, 1, 0, 0, -1, 14, 134, 46, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBug_2d, kDTtbug_2d, 0, AUTO, 0, 0, kALbugs_2d, THING2, CYCLE_FORWARD, 0, 0, 0, 16, 14, 65, 25, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 15: Mushroom
-{kNOldman_2d, kDTtoldman_2d, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 1, 0, 0, -1, 15, 126, 77, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNOldman_2d, kDTtoldman_2d, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 1, 0, 0, -1, 15, 126, 77, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 16: Well
-{kNWell_2d, kDTtwell_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 16, 211, 136, 90, 90, 0, 0, 0, 1, kCMDwell_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWell_2d, kDTtwell_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 16, 211, 136, 90, 90, 0, 0, 0, 1, kCMDwell_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 17: Snakepit
-{kNSnake_2d, kDTtsnake_2d, 0, CHASE2, DX, DY, kALsnake_2d, PERSON2, CYCLE_FORWARD, 0, 0, 0, 16, 17, 165, 95, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSnake_2d, kDTtsnake_2d, 0, CHASE2, DX, DY, kALsnake_2d, PERSON2, CYCLE_FORWARD, 0, 0, 0, 16, 17, 165, 95, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 18: Phonebox
-{kNTardis_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 18, 21, 74, 90, 90, 0, 0, 0, 0, kCMDtardis_2d, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNTardis_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 50, 18, 21, 74, 90, 90, 0, 0, 0, 0, kCMDtardis_2d, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 20: Kennel
-{kNStick_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 20, 89, 120, 90, 90, 0, 0, 5, 3, kCMDstick_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDynamite_2d, kDTtdynamite_2d, 0, AUTO, 0, 0, 0, THING2a, INVISIBLE, 0, 0, 0, 30, 20, 200, 100, 90, 90, 0, 0, 0, 7, kCMDdynamite_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNKennel_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 20, 195, 114, 90, 90, 0, 0, 0, 0, kCMDkennel_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDog_2d, kDTtdog_2d, 0, AUTO, 0, 0, 0, THING2f, CYCLE_FORWARD, 0, 2, 0, 30, 20, 184, 80, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNStick_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 20, 89, 120, 90, 90, 0, 0, 5, 3, kCMDstick_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDynamite_2d, kDTtdynamite_2d, 0, AUTO, 0, 0, 0, THING2a, INVISIBLE, 0, 0, 0, 30, 20, 200, 100, 90, 90, 0, 0, 0, 7, kCMDdynamite_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNKennel_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 20, 195, 114, 90, 90, 0, 0, 0, 0, kCMDkennel_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDog_2d, kDTtdog_2d, 0, AUTO, 0, 0, 0, THING2f, CYCLE_FORWARD, 0, 2, 0, 30, 20, 184, 80, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 21: (Rockroom)
-{kNRope_2d, kDTtrope_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 60, 21, 78, 30, 90, 90, 0, 0, 0, 1, kCMDrope_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRope_2d, kDTtrope_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 60, 21, 78, 30, 90, 90, 0, 0, 0, 1, kCMDrope_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 22: (Rockgone)
-{kNRope_2d, kDTtrope_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 60, 22, 78, 30, 90, 90, 0, 0, 0, 1, kCMDrope_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRope_2d, kDTtrope_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 60, 22, 78, 30, 90, 90, 0, 0, 0, 1, kCMDrope_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 24: (Lampcave)
-{kNLamp_2d, kDTtlamp_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 24, 78, 114, 90, 90, 0, 0, 10, 7, kCMDlamp_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLamp_2d, kDTtlamp_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, 24, 78, 114, 90, 90, 0, 0, 10, 7, kCMDlamp_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 25: (Chasm)
-{kNBanana_2d, kDTtbanana_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 25, 254, 107, 90, 90, 0, 0, 5, 7, kCMDbanana_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBanana_2d, kDTtbanana_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 20, 25, 254, 107, 90, 90, 0, 0, 5, 7, kCMDbanana_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 27: (Ladder)
-{kNGenie_2d, kDTtgenie_2d, 0, AUTO, 0, 0, 0, PERSON3, INVISIBLE, 0, 0, 0, 30, 27, 138, 70, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGenie_2d, kDTtgenie_2d, 0, AUTO, 0, 0, 0, PERSON3, INVISIBLE, 0, 0, 0, 30, 27, 138, 70, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 28: (Traproom)
-{kNSafe_2d, kDTtsafe_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 90, 90, 0, 0, 0, 1, kCMDsafe_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWill_2d, kDTtwill_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 90, 90, 0, 0, 5, 7, kCMDwill_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSafe_2d, kDTtsafe_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 90, 90, 0, 0, 0, 1, kCMDsafe_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWill_2d, kDTtwill_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 28, 122, 144, 90, 90, 0, 0, 5, 7, kCMDwill_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 31: (Parlor)
-{kNCupb_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 31, 212, 142, 90, 90, 0, 0, 0, 0, kCMDcupbp_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoor_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 31, 28, 154, 90, 90, 0, 0, 0, 0, kCMDpdoor_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNAlbum_2d, kDTtalbum_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, -1, 212, 142, 90, 90, 0, 0, 5, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCupb_2d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 31, 212, 142, 90, 90, 0, 0, 0, 0, kCMDcupbp_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 31, 28, 154, 90, 90, 0, 0, 0, 0, kCMDpdoor_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNAlbum_2d, kDTtalbum_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 55, 255, 212, 142, 90, 90, 0, 0, 5, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 32: (Catroom)
-{kNCat_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING2b, CYCLE_FORWARD, 0, 2, 0, 40, 32, 189, 69, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCat_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING2b, CYCLE_FORWARD, 0, 2, 0, 40, 32, 189, 69, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 33: (Boxroom)
-{kNDoor_2d, kDTtbdoor_2d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 33, 137, 97, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPaper_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 20, 33, 205, 147, 90, 90, 0, 0, 5, 7, kCMDpaper_2d, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
-{kNPencil_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 20, 33, 205, 163, 90, 90, 0, 0, 5, 7, kCMDpencil_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_2d, kDTtbdoor_2d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 33, 137, 97, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPaper_2d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 20, 33, 205, 147, 90, 90, 0, 0, 5, 7, kCMDpaper_2d, 0, 0, 0, BACKGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNPencil_2d, kDTdull_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 1, 0, 0, 20, 33, 205, 163, 90, 90, 0, 0, 5, 7, kCMDpencil_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 34: (Hall3)
-{kNDoor_2d, kDTtdoor_2d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 34, 234, 73, 90, 90, 0, 0, 0, 1, kCMDdoor2_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoor_2d, kDTtdoor_2d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 34, 103, 73, 90, 90, 0, 0, 0, 1, kCMDdoor3_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_2d, kDTtdoor_2d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 34, 234, 73, 90, 90, 0, 0, 0, 1, kCMDdoor2_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_2d, kDTtdoor_2d, 0, AUTO, 0, 0, 0, THING4, NOT_CYCLING, 1, 4, 4, 16, 34, 103, 73, 90, 90, 0, 0, 0, 1, kCMDdoor3_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 35: (Organ)
-{kNHarry_2d, kDTtharry_2d, 0, AUTO, DX, DY, 0, THING2g, CYCLE_FORWARD, 0, 2, 0, -1, 35, 188, 84, 90, 90, 0, 0, 0, 1, kCMDharry_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHarry_2d, kDTtharry_2d, 0, AUTO, DX, DY, 0, THING2g, CYCLE_FORWARD, 0, 2, 0, -1, 35, 188, 84, 90, 90, 0, 0, 0, 1, kCMDharry_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 36: (Hestroom)
-{kNHester_2d, kDTthester_2d, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 30, 36, 78, 114, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLetter_2d, kDTtletter_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 36, 110, 150, 90, 90, 0, 0, 0, 1, kCMDletter_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHester_2d, kDTthester_2d, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 30, 36, 78, 114, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLetter_2d, kDTtletter_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 30, 36, 110, 150, 90, 90, 0, 0, 0, 1, kCMDletter_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Screen 37: (Retupmoc)
-{kNDoctor_2d, kDTtdoctor_2d, 0, WANDER, DX, DY, kALdoctor_2d, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 37, 78, 114, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDalek_2d, kDTtdalek_2d, 0, CHASE2, DX, DY, kALdalek_2d, PERSON5, NOT_CYCLING, 0, 0, 0, -1, 37, 78, 114, 90, 90, 0, 0, 0, 1, kCMDgun_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNScrew_2d, kDTtscrew_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 37, 100, 123, 90, 90, 0, 0, 15, 3, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoctor_2d, kDTtdoctor_2d, 0, WANDER, DX, DY, kALdoctor_2d, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 37, 78, 114, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDalek_2d, kDTtdalek_2d, 0, CHASE2, DX, DY, kALdalek_2d, PERSON5, NOT_CYCLING, 0, 0, 0, -1, 37, 78, 114, 90, 90, 0, 0, 0, 1, kCMDgun_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNScrew_2d, kDTtscrew_2d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 20, 37, 100, 123, 90, 90, 0, 0, 15, 3, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// Misc:
-{kNCook_2d, kDTtcook_2d, 0, AUTO, DX, DY, 0, PERSON, INVISIBLE, 0, 0, 0, 30, 06, 98, 98, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCookb_2d, kDTtcook_2d, 0, AUTO, 0, 0, 0, THING4, CYCLE_FORWARD, 0, 0, 0, 30, -1, 98, 98, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCop_2d, kDTtcop_2d, 0, AUTO, 0, 0, 0, PERSON2, INVISIBLE, 0, 0, 0, 30, 29, 180, 47, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNHorace_2d, kDTthorace_2d, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 30, 34, 215, 76, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBell_2d, kDTtbell_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 15, 149, 109, 90, 90, 0, 0, 5, 7, kCMDbell_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNGun_2d, kDTtgun_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 26, 149, 109, 90, 90, 0, 0, 10, 7, kCMDgun_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBottle_2d, kDTtbottle_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 27, 149, 109, 90, 90, 0, 0, 15, 7, kCMDbottle_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCook_2d, kDTtcook_2d, 0, AUTO, DX, DY, 0, PERSON, INVISIBLE, 0, 0, 0, 30, 06, 98, 98, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCookb_2d, kDTtcook_2d, 0, AUTO, 0, 0, 0, THING4, CYCLE_FORWARD, 0, 0, 0, 30, 255, 98, 98, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCop_2d, kDTtcop_2d, 0, AUTO, 0, 0, 0, PERSON2, INVISIBLE, 0, 0, 0, 30, 29, 180, 47, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHorace_2d, kDTthorace_2d, 0, AUTO, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 30, 34, 215, 76, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBell_2d, kDTtbell_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 15, 149, 109, 90, 90, 0, 0, 5, 7, kCMDbell_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNGun_2d, kDTtgun_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 26, 149, 109, 90, 90, 0, 0, 10, 7, kCMDgun_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBottle_2d, kDTtbottle_2d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, MAZE_SCREEN + 27, 149, 109, 90, 90, 0, 0, 15, 7, kCMDbottle_2d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
};
object_t objects_3d[] = {
//name,description,path,dx,dy,aptr,SPRITE, cyc, n,frm,rad, scr,x,y ,oldxy,vxy,val,g,cmnd,c,s,ctx,fgb
// Common objects // Set Penny state to 3 to avoid story
-{kNHero_3d, kDTthero_3d, 0, USER, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 0, 0, 161, 110, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWhero_3d, kDTthero_3d, 0, USER, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 219, 133, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHero_3d, kDTthero_3d, 0, USER, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, 0, 0, 161, 110, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWhero_3d, kDTthero_3d, 0, USER, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 219, 133, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
//#if NO_STORY
-//{kNPenny_3d, kDTtpenny_3d, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 0, 109, 110, 90, 90, 0, 0, 0, 1, 0, 0, 3, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+//{kNPenny_3d, kDTtpenny_3d, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 0, 109, 110, 90, 90, 0, 0, 0, 1, 0, 0, 3, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
//#else
-{kNPenny_3d, kDTtpenny_3d, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 0, 109, 110, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPenny_3d, kDTtpenny_3d, 0, AUTO, 0, 0, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, 0, 109, 110, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
//#endif
-{kNPennylie_3d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, -1, WEB_3d, 75, 156, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNLips_3d, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 0, 0, 186, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNPennylie_3d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, -1, WEB_3d, 75, 156, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNLips_3d, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 0, 0, 186, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
// CRASH site
-{kNPlane_3d, kDTtplane_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, CRASH_3d, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcplane_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoor_3d, kDTdull_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 80, CRASH_3d, 184, 136, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant1_3d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 0, CRASH_3d, 132, 165, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
+{kNPlane_3d, kDTtplane_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, CRASH_3d, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcplane_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoor_3d, kDTdull_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, 80, CRASH_3d, 184, 136, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant1_3d, 0, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 0, CRASH_3d, 132, 165, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
// INPLANE
-{kNPlane_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, PLANE_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcexit_3d, 0, 0, 1,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWater_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwfall_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWater_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_B_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwfall_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWater_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwstream_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNWater_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, GARDEN_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwpool_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNClay_3d, kDTtclay_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 162, 96, 90, 90, 0, 0, 5, 7, kCMDcclay_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNeedles_3d, kDTtneedles_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 172, 90, 90, 90, 0, 0, 5, 7, kCMDcpins_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFlask_3d, kDTtflask_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 190, 90, 90, 90, 0, 0, 5, 7, kCMDcflask_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBouillon_3d, kDTtbouillon_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 185, 94, 90, 90, 0, 0, 5, 7, kCMDcbouillon_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCheese_3d, kDTtcheese_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 185, 100, 90, 90, 0, 0, 5, 1, kCMDccheese_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlane_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, PLANE_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcexit_3d, 0, 0, 1, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWater_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwfall_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWater_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, WFALL_B_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwfall_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWater_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwstream_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNWater_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, GARDEN_3d, 184, 136, 90, 90, 0, 0, 0, 0, kCMDcwpool_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNClay_3d, kDTtclay_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 162, 96, 90, 90, 0, 0, 5, 7, kCMDcclay_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNeedles_3d, kDTtneedles_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 172, 90, 90, 90, 0, 0, 5, 7, kCMDcpins_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFlask_3d, kDTtflask_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 190, 90, 90, 90, 0, 0, 5, 7, kCMDcflask_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBouillon_3d, kDTtbouillon_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 185, 94, 90, 90, 0, 0, 5, 7, kCMDcbouillon_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCheese_3d, kDTtcheese_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, PLANE_3d, 185, 100, 90, 90, 0, 0, 5, 1, kCMDccheese_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// WEB
-{kNSpider_3d, kDTtspider_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, WEB_3d, 77, 50, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant3_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, WEB_3d, 245, 117, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant4_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, WEB_3d, 285, 90, 91, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSpider_3d, kDTtspider_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, WEB_3d, 77, 50, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant3_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, WEB_3d, 245, 117, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant4_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, WEB_3d, 285, 90, 91, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// BRIDGE
-{kNBlock_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3d, 225, 133, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBlock_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3d, 225, 134, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBlock_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3d, 225, 135, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNVine_3d, kDTtvine_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, BRIDGE_3d, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcvine_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBlock_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3d, 225, 133, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBlock_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3d, 225, 134, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBlock_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, BRIDGE_3d, 225, 135, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNVine_3d, kDTtvine_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, BRIDGE_3d, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcvine_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// STREAM
-{kNVine_3d, kDTtvine_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3d, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcswing_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNSwinger_3d, 0, 0, AUTO, 0, 0, 0, PERSON2, INVISIBLE, 0, 0, 0, 0, STREAM_3d, 219, 133, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNVine_3d, kDTtvine_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, STREAM_3d, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcswing_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNSwinger_3d, 0, 0, AUTO, 0, 0, 0, PERSON2, INVISIBLE, 0, 0, 0, 0, STREAM_3d, 219, 133, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// HUT_IN
-{kNDoctor_3d, kDTtdoctor_3d, 0, WANDER, DX, DY, kALdocgot_3d, PERSON3, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3d, 273, 83, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNDoclie_3d, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 30, HUT_IN_3d, 239, 103, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCdoor_3d, kDTdull_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 40, HUT_IN_3d, 239, 103, 90, 90, 0, 0, 0, 1, kCMDcdoor_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMouse_3d, kDTtmouse_3d, 0, AUTO, 0, 0, 0, THING2b, INVISIBLE, 0, 0, 0, 30, HUT_IN_3d, 186, 170, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMoushole_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, HUT_IN_3d, 203, 122, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCage_3d, kDTtcage_3d, 0, AUTO, 0, 0, 0, THING2a, NOT_CYCLING, 0, 0, 0, 30, HUT_IN_3d, 156, 121, 90, 90, 0, 0, 1, 5, kCMDccage_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_1_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_OUT_3d, 127, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_1_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_OUT_3d, 172, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_2_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_IN_3d, 30, 145, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_3_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, CAMP_3d, 120, 135, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoctor_3d, kDTtdoctor_3d, 0, WANDER, DX, DY, kALdocgot_3d, PERSON3, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3d, 273, 83, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNDoclie_3d, 0, 0, AUTO, 0, 0, 0, THING2, INVISIBLE, 0, 0, 0, 30, HUT_IN_3d, 239, 103, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCdoor_3d, kDTdull_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 40, HUT_IN_3d, 239, 103, 90, 90, 0, 0, 0, 1, kCMDcdoor_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMouse_3d, kDTtmouse_3d, 0, AUTO, 0, 0, 0, THING2b, INVISIBLE, 0, 0, 0, 30, HUT_IN_3d, 186, 170, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMoushole_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, HUT_IN_3d, 203, 122, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCage_3d, kDTtcage_3d, 0, AUTO, 0, 0, 0, THING2a, NOT_CYCLING, 0, 0, 0, 30, HUT_IN_3d, 156, 121, 90, 90, 0, 0, 1, 5, kCMDccage_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_1_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_OUT_3d, 127, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_1_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_OUT_3d, 172, 100, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_2_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, HUT_IN_3d, 30, 145, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_3_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, CAMP_3d, 120, 135, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// CAMP
-{kNNat1_3d, kDTtnative_3d, 0, WANDER, DX, 0, 0, PERSON, NOT_CYCLING, 0, 0, 0, -1, CAMP_3d, 130, 105, 90, 90, 0, 0, 0, 1, kCMDcnative_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNat2_3d, kDTtnative_3d, 0, AUTO, DX, DY, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3d, 17, 97, 90, 90, 4, 0, 0, 1, kCMDcnative_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNat3_3d, kDTtnative_3d, 0, AUTO, DX, DY, 0, THING2, CYCLE_FORWARD, 0, 16, 0, -1, CAMP_3d, 96, 40, 90, 90, 0, 0, 0, 1, kCMDcnative_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNatb_3d, kDTtnative_3d, 0, AUTO, DX, DY, 0, THING2, CYCLE_FORWARD, 0, 20, 0, -1, CAMP_3d, 72, 51, 90, 90, 0, 0, 0, 1, kCMDcnative_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNNatg_3d, kDTtnatgirl_3d, 0, AUTO, DX, DY, kALnative_3d, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3d, 28, 101, 90, 90, 3, 0, 0, 1, kCMDcnative_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPipe_3d, kDTtpipe_3d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, CAMP_3d, 225, 135, 90, 90, 0, 0, 0, 7, kCMDcdart_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNat1_3d, kDTtnative_3d, 0, WANDER, DX, 0, 0, PERSON, NOT_CYCLING, 0, 0, 0, -1, CAMP_3d, 130, 105, 90, 90, 0, 0, 0, 1, kCMDcnative_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNat2_3d, kDTtnative_3d, 0, AUTO, DX, DY, 0, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3d, 17, 97, 90, 90, 4, 0, 0, 1, kCMDcnative_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNat3_3d, kDTtnative_3d, 0, AUTO, DX, DY, 0, THING2, CYCLE_FORWARD, 0, 16, 0, -1, CAMP_3d, 96, 40, 90, 90, 0, 0, 0, 1, kCMDcnative_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNatb_3d, kDTtnative_3d, 0, AUTO, DX, DY, 0, THING2, CYCLE_FORWARD, 0, 20, 0, -1, CAMP_3d, 72, 51, 90, 90, 0, 0, 0, 1, kCMDcnative_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNNatg_3d, kDTtnatgirl_3d, 0, AUTO, DX, DY, kALnative_3d, PERSON, CYCLE_FORWARD, 0, 0, 0, -1, CAMP_3d, 28, 101, 90, 90, 3, 0, 0, 1, kCMDcnative_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPipe_3d, kDTtpipe_3d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, CAMP_3d, 225, 135, 90, 90, 0, 0, 0, 7, kCMDcdart_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// PATH_2
-{kNElephant_3d, kDTtelephant_3d, 0, AUTO, 0, 0, 0, THING2a, NOT_CYCLING, 0, 4, 0, -1, PATH_3d, 163, 85, 90, 90, 0, 0, 0, 1, kCMDcdart_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNE_eyes_3d, 0, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, -1, PATH_3d, 194, 102, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
+{kNElephant_3d, kDTtelephant_3d, 0, AUTO, 0, 0, 0, THING2a, NOT_CYCLING, 0, 4, 0, -1, PATH_3d, 163, 85, 90, 90, 0, 0, 0, 1, kCMDcdart_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNE_eyes_3d, 0, 0, AUTO, 0, 0, 0, THING2c, NOT_CYCLING, 0, 0, 0, -1, PATH_3d, 194, 102, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FOREGROUND, -1, -1, -1, 0, 0, 0, 0},
// Misc
-{kNHero_old_3d, 0, 0, USER, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 161, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNAircraft_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, SUNSET_3d, 275, 116, 90, 90, -2, -1, 0, 1, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNScroll_3d, kDTtscroll_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, CLIFFTOP_3d, 75, 116, 90, 90, 0, 0, 3, 7, kCMDcscroll_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCrystal_3d, kDTtcrystal_3d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, TURN_3d, 275, 116, 90, 90, 0, 0, 9, 7, kCMDccrystal_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNRock_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, TURN_3d, 100, 100, 90, 90, 0, 0, 0, 0, kCMDcrock_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNHero_old_3d, 0, 0, USER, 0, 0, 0, PERSON, INVISIBLE, 0, 0, 0, 0, 0, 161, 120, 90, 90, 0, 0, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNAircraft_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, -1, SUNSET_3d, 275, 116, 90, 90, -2, -1, 0, 1, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNScroll_3d, kDTtscroll_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, CLIFFTOP_3d, 75, 116, 90, 90, 0, 0, 3, 7, kCMDcscroll_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCrystal_3d, kDTtcrystal_3d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, TURN_3d, 275, 116, 90, 90, 0, 0, 9, 7, kCMDccrystal_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNRock_3d, 0, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, TURN_3d, 100, 100, 90, 90, 0, 0, 0, 0, kCMDcrock_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// CAVE etc.
-{kNPlant2_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, CAVE_3d, 27, 160, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,OVEROVL, -1, -1, -1, 0, 0, 0, 0},
-{kNGhost_3d, kDTtghost_3d, 0, CHASE, DX, DY, 0, THING2c, NOT_CYCLING, 0, 0, 0, -1, CAVE_3d, 121, 86, 90, 90, 0, 0, 0, 1, kCMDcghost_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBell_3d, kDTtbell_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, CLIFF_3d, 202, 152, 90, 90, 0, 0, 2, 7, kCMDcbell_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNBook_3d, kDTtbook_3d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, STREAM_3d, 275, 116, 90, 90, 0, 0, 10, 7, kCMDcbook_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNCandle_3d, kDTtcandle_3d, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 20, 0, 30, HUT_IN_3d, 77, 134, 90, 90, 0, 0, 3, 7, kCMDccandle_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNVine_3d, kDTtvine_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, CAVE_3d, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcswingc_3d, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant2_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, CAVE_3d, 27, 160, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, OVEROVL, -1, -1, -1, 0, 0, 0, 0},
+{kNGhost_3d, kDTtghost_3d, 0, CHASE, DX, DY, 0, THING2c, NOT_CYCLING, 0, 0, 0, -1, CAVE_3d, 121, 86, 90, 90, 0, 0, 0, 1, kCMDcghost_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBell_3d, kDTtbell_3d, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 30, CLIFF_3d, 202, 152, 90, 90, 0, 0, 2, 7, kCMDcbell_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNBook_3d, kDTtbook_3d, 0, AUTO, 0, 0, 0, THING1, INVISIBLE, 0, 0, 0, 30, STREAM_3d, 275, 116, 90, 90, 0, 0, 10, 7, kCMDcbook_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNCandle_3d, kDTtcandle_3d, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 20, 0, 30, HUT_IN_3d, 77, 134, 90, 90, 0, 0, 3, 7, kCMDccandle_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNVine_3d, kDTtvine_3d, 0, AUTO, 0, 0, 0, THING0, INVISIBLE, 0, 0, 0, -1, CAVE_3d, 184, 136, 90, 90, 0, 0, 0, 1, kCMDcswingc_3d, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
// OLDMAN (inside cave)
-{kNO_eye_3d, 0, 0, AUTO, 0, 0, 0, THING3, INVISIBLE, 0, 0, 0, 0, OLDMAN_3d, 237, 77, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNFire_4_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, OLDMAN_3d, 65, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNMouth_3d, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 0, 0, 0, OLDMAN_3d, 191, 128, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPole_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, CAMP_3d, 126, 35, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
-{kNPlant5_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, TURN_3d, 65, 139, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0,FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNO_eye_3d, 0, 0, AUTO, 0, 0, 0, THING3, INVISIBLE, 0, 0, 0, 0, OLDMAN_3d, 237, 77, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNFire_4_3d, 0, 0, AUTO, 0, 0, 0, THING2, CYCLE_FORWARD, 0, 0, 0, 0, OLDMAN_3d, 65, 56, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNMouth_3d, 0, 0, AUTO, 0, 0, 0, THING2, NOT_CYCLING, 0, 0, 0, 0, OLDMAN_3d, 191, 128, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPole_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, CAMP_3d, 126, 35, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
+{kNPlant5_3d, 0, 0, AUTO, 0, 0, 0, THING1, NOT_CYCLING, 0, 0, 0, 0, TURN_3d, 65, 139, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, FLOATING, -1, -1, -1, 0, 0, 0, 0},
};
// Hugo 1 Win
@@ -5715,137 +5734,137 @@ int openrep_1w[] = {kSTsopenr_1w, -1};
// Action lists (suffix with 0)
// These are the various actions, referred to in the command lists and/or
// referenced directly as part of screen actions
-act0 areplight_1w = {ASCHEDULE, 11 * NORMAL_TPS, kALightning_1w};
-act0 arepeye_1w = {ASCHEDULE, 8 * NORMAL_TPS, kALblinkeyes1_1w};
-act0 arepbat_1w = {ASCHEDULE, 12 * NORMAL_TPS, kALbat_1w};
-act0 arepeye2_1w = {ASCHEDULE, 8 * NORMAL_TPS, kALblinkeyes2_1w};
-act0 arepredeye_1w = {ASCHEDULE, 6 * NORMAL_TPS, kALrepredeye_1w};
-act0 areplips_1w = {ASCHEDULE, 4 * NORMAL_TPS, kALreplips_1w};
-act0 areparm_1w = {ASCHEDULE, 5 * NORMAL_TPS, kALreparm_1w};
-act0 adead_1w = {ASCHEDULE, 0, kALdead_1w};
-act0 arepbata_1w = {ASCHEDULE, 3 * NORMAL_TPS, kALbatrep_1w};
-act0 ajailrep_1w = {ASCHEDULE, 4, kALjailrep_1w};
-act0 aend_1w = {ASCHEDULE, 4 * NORMAL_TPS, kALend_1w};
-act0 arepbox_1w = {ASCHEDULE, NORMAL_TPS, kALbox_1w};
-act0 aweird_1w = {ASCHEDULE, 16, kALweird_1w};
-act0 acycle_1w = {ASCHEDULE, 0, kALcycle_1w};
-
-act1 aopendoor1a_1w = {START_OBJ, NORMAL_TPS, DOOR1_1w, 1, CYCLE_FORWARD};
-act1 aclosedoor1_1w = {START_OBJ, NORMAL_TPS, DOOR1_1w, 1, CYCLE_BACKWARD};
-act1 ablink1a_1w = {START_OBJ, 0, EYES1_1w, 0, INVISIBLE};
-act1 ablink1b_1w = {START_OBJ, 1, EYES1_1w, 0, NOT_CYCLING};
-act1 ablink1c_1w = {START_OBJ, 2, EYES1_1w, 0, INVISIBLE};
-act1 ablink1d_1w = {START_OBJ, 3, EYES1_1w, 0, NOT_CYCLING};
-act1 ablink2a_1w = {START_OBJ, 3 * NORMAL_TPS, EYES2_1w, 0, INVISIBLE};
-act1 ablink2b_1w = {START_OBJ, 3 * NORMAL_TPS + 1, EYES2_1w, 0, NOT_CYCLING};
-act1 ablink2c_1w = {START_OBJ, 3 * NORMAL_TPS + 2, EYES2_1w, 0, INVISIBLE};
-act1 ablink2d_1w = {START_OBJ, 3 * NORMAL_TPS + 3, EYES2_1w, 0, NOT_CYCLING};
-act1 aridpkin_1w = {START_OBJ, 0, PKIN_1w, 0, INVISIBLE};
-act1 ashowkey_1w = {START_OBJ, 0, KEY_1w, 0, NOT_CYCLING};
-act1 aridprof_1w = {START_OBJ, 130 / DX, PROF_1w, 0, INVISIBLE};
-act1 aopendoor2_1w = {START_OBJ, 0, DOOR2_1w, 1, CYCLE_FORWARD};
-act1 aopendoor3_1w = {START_OBJ, 0, DOOR3_1w, 1, CYCLE_FORWARD};
-act1 ablink3a_1w = {START_OBJ, 0, EYES3_1w, 0, INVISIBLE};
-act1 ablink3b_1w = {START_OBJ, 1, EYES3_1w, 0, NOT_CYCLING};
-act1 ablink3c_1w = {START_OBJ, 2, EYES3_1w, 0, INVISIBLE};
-act1 ablink3d_1w = {START_OBJ, 3, EYES3_1w, 0, NOT_CYCLING};
-act1 ablink4a_1w = {START_OBJ, 3 * NORMAL_TPS, EYES4_1w, 0, INVISIBLE};
-act1 ablink4b_1w = {START_OBJ, 3 * NORMAL_TPS + 1, EYES4_1w, 0, NOT_CYCLING};
-act1 ablink4c_1w = {START_OBJ, 3 * NORMAL_TPS + 2, EYES4_1w, 0, INVISIBLE};
-act1 ablink4d_1w = {START_OBJ, 3 * NORMAL_TPS + 3, EYES4_1w, 0, NOT_CYCLING};
-act1 a115b_1w = {START_OBJ, 0, MASK_1w, 0, NOT_CYCLING};
-act1 acupknife_1w = {START_OBJ, 0, KNIFE_1w, 0, NOT_CYCLING};
-act1 acupwhist_1w = {START_OBJ, 0, WHISTLE_1w, 0, NOT_CYCLING};
-act1 aopenwdoorl_1w = {START_OBJ, NORMAL_TPS, WDOORL_1w, 1, CYCLE_FORWARD};
-act1 aopenwdoorr_1w = {START_OBJ, NORMAL_TPS, WDOORR_1w, 1, CYCLE_FORWARD};
-act1 aopenwd1_1w = {START_OBJ, NORMAL_TPS, MASK_1w, 1, NOT_CYCLING};
-act1 aclosewdoorl_1w = {START_OBJ, NORMAL_TPS, WDOORL_1w, 1, CYCLE_BACKWARD};
-act1 aclosewdoorr_1w = {START_OBJ, NORMAL_TPS, WDOORR_1w, 1, CYCLE_BACKWARD};
-act1 abut1_1w = {START_OBJ, 4 * NORMAL_TPS, BUTLER_1w, 0, CYCLE_FORWARD};
-act1 abut6d_1w = {START_OBJ, 7, HERO, 0, INVISIBLE};
-act1 abut6f_1w = {START_OBJ, 7, HDLSHERO_1w, 0, NOT_CYCLING};
-act1 ashowchop_1w = {START_OBJ, 0, CHOP_1w, 0, NOT_CYCLING};
-act1 aridchop_1w = {START_OBJ, 0, CHOP_1w, 0, INVISIBLE};
-act1 adogcyc_1w = {START_OBJ, 0, DOG_1w, 0, CYCLE_FORWARD};
-act1 ablink5a_1w = {START_OBJ, 0, REDEYES_1w, 0, INVISIBLE};
-act1 ablink5b_1w = {START_OBJ, 1, REDEYES_1w, 0, NOT_CYCLING};
-act1 ablink5c_1w = {START_OBJ, 2, REDEYES_1w, 0, INVISIBLE};
-act1 ablink5d_1w = {START_OBJ, 3, REDEYES_1w, 0, NOT_CYCLING};
-act1 alips_1w = {START_OBJ, 0, LIPS_1w, 6, CYCLE_FORWARD};
-act1 aarm_1w = {START_OBJ, 0, ARM_1w, 3, CYCLE_BACKWARD};
-act1 aopendoor4_1w = {START_OBJ, 0, DOOR4_1w, 1, CYCLE_FORWARD};
-act1 aclosedoor4_1w = {START_OBJ, 0, DOOR4_1w, 1, CYCLE_BACKWARD};
-act1 adog1_1w = {START_OBJ, 0, DOG_1w, 0, CYCLE_FORWARD};
-act1 adead1_1w = {START_OBJ, 0, HERO, 0, INVISIBLE};
-act1 adead3_1w = {START_OBJ, 0, HERODEAD_1w, 0, NOT_CYCLING};
-act1 amovecarp1_1w = {START_OBJ, 0, CARPET_1w, 0, INVISIBLE};
-act1 amovecarp2_1w = {START_OBJ, 0, TRAP_1w, 0, NOT_CYCLING};
-act1 aopentrap_1w = {START_OBJ, NORMAL_TPS, TRAP_1w, 1, CYCLE_FORWARD};
-act1 aclosetrap_1w = {START_OBJ, NORMAL_TPS, TRAP_1w, 1, CYCLE_BACKWARD};
-act1 amdoor1_1w = {START_OBJ, NORMAL_TPS, MDOOR_1w, 1, CYCLE_FORWARD};
-act1 amdoor2_1w = {START_OBJ, 3 * NORMAL_TPS, MDOOR_1w, 0, INVISIBLE};
-act1 amum1_1w = {START_OBJ, 2 * NORMAL_TPS, MUMMY_1w, 0, CYCLE_FORWARD};
-act1 arock2_1w = {START_OBJ, 0, HERO, 0, CYCLE_FORWARD};
-act1 arock7_1w = {START_OBJ, 20, HERO, 0, NOT_CYCLING};
-act1 arock9_1w = {START_OBJ, 40, HERO, 0, CYCLE_FORWARD};
-act1 arock14_1w = {START_OBJ, 55, HERO, 0, NOT_CYCLING};
-act1 abin2_1w = {START_OBJ, 0, HERO, 0, INVISIBLE};
-act1 aridbung_1w = {START_OBJ, 0, BUNG_1w, 0, INVISIBLE};
-act1 about2_1w = {START_OBJ, 0, HERO, 0, NOT_CYCLING};
-act1 ajail2_1w = {START_OBJ, 0, HERO, 0, CYCLE_FORWARD};
-act1 atheend1_1w = {START_OBJ, 5 * NORMAL_TPS, HERO, 0, INVISIBLE};
-act1 aguardgo2_1w = {START_OBJ, 0, GUARD_1w, 0, CYCLE_FORWARD};
-act1 alab5_1w = {START_OBJ, 0, PROF_1w, 0, CYCLE_FORWARD};
-act1 alab8_1w = {START_OBJ, 12, PROF_1w, 0, NOT_CYCLING};
-act1 alab9_1w = {START_OBJ, 16, IGOR_1w, 0, NOT_CYCLING};
-act1 abox10_1w = {START_OBJ, 38, PROF_1w, 0, CYCLE_FORWARD};
-act1 abox11_1w = {START_OBJ, 73, PROF_1w, 0, INVISIBLE};
-
-act2 abatxy_1w = {INIT_OBJXY, 0, BAT_1w, 95, 55};
-act2 aheroxy01_1w = {INIT_OBJXY, 0, HERO, 106, 130};
-act2 aheroxy12_1w = {INIT_OBJXY, 12, HERO, 169, 87};
-act2 aheroxy14_1w = {INIT_OBJXY, 12, HERO, 135, 115};
-act2 aheroxy10_1w = {INIT_OBJXY, 0, HERO, 33, 134};
-act2 aheroxy13_1w = {INIT_OBJXY, 0, HERO, 40, 127};
-act2 aheroxy15_1w = {INIT_OBJXY, 0, HERO, 250, 120};
-act2 ahchase2_1w = {INIT_OBJXY, 5 * NORMAL_TPS, DOG_1w, 280, 137};
-act2 akchase2_1w = {INIT_OBJXY, 5 * NORMAL_TPS, DOG_1w, 30, 120};
-act2 a115d_1w = {INIT_OBJXY, 0, MASK_1w, 236, 91};
-act2 aheroxy115_1w = {INIT_OBJXY, 1, HERO, 27, 130};
-act2 aheroxy21_1w = {INIT_OBJXY, 0, HERO, 130, 56};
-act2 achopxy_1w = {INIT_OBJXY, 0, CHOP_1w, 51, 155};
-act2 aheroxy31_1w = {INIT_OBJXY, 0, HERO, 263, 126};
-act2 aheroxy35_1w = {INIT_OBJXY, 0, HERO, 253, 96};
-act2 aheroxy41_1w = {INIT_OBJXY, 0, HERO, 200, 56};
-act2 aheroxy51_1w = {INIT_OBJXY, 0, HERO, 200, 110};
-act2 aheroxy53_1w = {INIT_OBJXY, 0, HERO, 50, 90};
-act2 aheroxy56_1w = {INIT_OBJXY, 0, HERO, 260, 140};
-act2 aheroxy57_1w = {INIT_OBJXY, 0, HERO, 245, 107};
-act2 aheroxy65_1w = {INIT_OBJXY, 0, HERO, 215, 96};
-act2 aheroxy75_1w = {INIT_OBJXY, 0, HERO, 25, 105};
-act2 adog4_1w = {INIT_OBJXY, 0, DOG_1w, 105, 119};
-act2 aheroxy78_1w = {INIT_OBJXY, NORMAL_TPS + 12, HERO, 80, 42};
-act2 aheroxy89_1w = {INIT_OBJXY, 0, HERO, 276, 135};
-act2 aheroxy87_1w = {INIT_OBJXY, 0, HERO, 235, 108};
-act2 aheroxy910_1w = {INIT_OBJXY, 0, HERO, 50, 132};
-act2 aheroxy98_1w = {INIT_OBJXY, 0, HERO, 130, 120};
-act2 abata1c_1w = {INIT_OBJXY, 0, BAT2_1w, 65, 25};
-act2 abata2c_1w = {INIT_OBJXY, 0, BAT3_1w, 55, 65};
-act2 abata3c_1w = {INIT_OBJXY, 0, BAT4_1w, 50, 120};
-act2 abata4c_1w = {INIT_OBJXY, 0, BAT5_1w, 55, 130};
-act2 aheroxy109_1w = {INIT_OBJXY, 0, HERO, 96, 105};
-act2 aheroxy1011_1w = {INIT_OBJXY, 0, HERO, 76, 130};
-act2 aheroxy1110_1w = {INIT_OBJXY, 0, HERO, 261, 77};
-act2 aheroxy1112_1w = {INIT_OBJXY, 0, HERO, 216, 134};
-act2 aherofar_1w = {INIT_OBJXY, 0, HERO, 142, 25};
-act2 aheronear_1w = {INIT_OBJXY, 0, HERO, 230, 132};
-act2 aheroxy1213_1w = {INIT_OBJXY, 0, HERO, 131, 110};
-act2 aguardgo1_1w = {INIT_OBJXY, 0, GUARD_1w, 137, 39};
-act2 aheroxy1211_1w = {INIT_OBJXY, 0, HERO, 291, 42};
-act2 aheroxy151_1w = {INIT_OBJXY, 0, HERO, 245, 55};
-act2 alab2_1w = {INIT_OBJXY, 0, PROF_1w, 100, 130};
-act2 abox4a_1w = {INIT_OBJXY, 20, HERO, 124, 122};
-act2 aigor12_1w = {INIT_OBJXY, 30, HERO, 116, 112};
+act0 areplight_1w = {ASCHEDULE, 11 * NORMAL_TPS_v2d, kALightning_1w};
+act0 arepeye_1w = {ASCHEDULE, 8 * NORMAL_TPS_v2d, kALblinkeyes1_1w};
+act0 arepbat_1w = {ASCHEDULE, 12 * NORMAL_TPS_v2d, kALbat_1w};
+act0 arepeye2_1w = {ASCHEDULE, 8 * NORMAL_TPS_v2d, kALblinkeyes2_1w};
+act0 arepredeye_1w = {ASCHEDULE, 6 * NORMAL_TPS_v2d, kALrepredeye_1w};
+act0 areplips_1w = {ASCHEDULE, 4 * NORMAL_TPS_v2d, kALreplips_1w};
+act0 areparm_1w = {ASCHEDULE, 5 * NORMAL_TPS_v2d, kALreparm_1w};
+act0 adead_1w = {ASCHEDULE, 0, kALdead_1w};
+act0 arepbata_1w = {ASCHEDULE, 3 * NORMAL_TPS_v2d, kALbatrep_1w};
+act0 ajailrep_1w = {ASCHEDULE, 4, kALjailrep_1w};
+act0 aend_1w = {ASCHEDULE, 4 * NORMAL_TPS_v2d, kALend_1w};
+act0 arepbox_1w = {ASCHEDULE, NORMAL_TPS_v2d, kALbox_1w};
+act0 aweird_1w = {ASCHEDULE, 16, kALweird_1w};
+act0 acycle_1w = {ASCHEDULE, 0, kALcycle_1w};
+
+act1 aopendoor1a_1w = {START_OBJ, NORMAL_TPS_v2d, DOOR1_1w, 1, CYCLE_FORWARD};
+act1 aclosedoor1_1w = {START_OBJ, NORMAL_TPS_v2d, DOOR1_1w, 1, CYCLE_BACKWARD};
+act1 ablink1a_1w = {START_OBJ, 0, EYES1_1w, 0, INVISIBLE};
+act1 ablink1b_1w = {START_OBJ, 1, EYES1_1w, 0, NOT_CYCLING};
+act1 ablink1c_1w = {START_OBJ, 2, EYES1_1w, 0, INVISIBLE};
+act1 ablink1d_1w = {START_OBJ, 3, EYES1_1w, 0, NOT_CYCLING};
+act1 ablink2a_1w = {START_OBJ, 3 * NORMAL_TPS_v2d, EYES2_1w, 0, INVISIBLE};
+act1 ablink2b_1w = {START_OBJ, 3 * NORMAL_TPS_v2d + 1, EYES2_1w, 0, NOT_CYCLING};
+act1 ablink2c_1w = {START_OBJ, 3 * NORMAL_TPS_v2d + 2, EYES2_1w, 0, INVISIBLE};
+act1 ablink2d_1w = {START_OBJ, 3 * NORMAL_TPS_v2d + 3, EYES2_1w, 0, NOT_CYCLING};
+act1 aridpkin_1w = {START_OBJ, 0, PKIN_1w, 0, INVISIBLE};
+act1 ashowkey_1w = {START_OBJ, 0, KEY_1w, 0, NOT_CYCLING};
+act1 aridprof_1w = {START_OBJ, 130 / DX, PROF_1w, 0, INVISIBLE};
+act1 aopendoor2_1w = {START_OBJ, 0, DOOR2_1w, 1, CYCLE_FORWARD};
+act1 aopendoor3_1w = {START_OBJ, 0, DOOR3_1w, 1, CYCLE_FORWARD};
+act1 ablink3a_1w = {START_OBJ, 0, EYES3_1w, 0, INVISIBLE};
+act1 ablink3b_1w = {START_OBJ, 1, EYES3_1w, 0, NOT_CYCLING};
+act1 ablink3c_1w = {START_OBJ, 2, EYES3_1w, 0, INVISIBLE};
+act1 ablink3d_1w = {START_OBJ, 3, EYES3_1w, 0, NOT_CYCLING};
+act1 ablink4a_1w = {START_OBJ, 3 * NORMAL_TPS_v2d, EYES4_1w, 0, INVISIBLE};
+act1 ablink4b_1w = {START_OBJ, 3 * NORMAL_TPS_v2d + 1, EYES4_1w, 0, NOT_CYCLING};
+act1 ablink4c_1w = {START_OBJ, 3 * NORMAL_TPS_v2d + 2, EYES4_1w, 0, INVISIBLE};
+act1 ablink4d_1w = {START_OBJ, 3 * NORMAL_TPS_v2d + 3, EYES4_1w, 0, NOT_CYCLING};
+act1 a115b_1w = {START_OBJ, 0, MASK_1w, 0, NOT_CYCLING};
+act1 acupknife_1w = {START_OBJ, 0, KNIFE_1w, 0, NOT_CYCLING};
+act1 acupwhist_1w = {START_OBJ, 0, WHISTLE_1w, 0, NOT_CYCLING};
+act1 aopenwdoorl_1w = {START_OBJ, NORMAL_TPS_v2d, WDOORL_1w, 1, CYCLE_FORWARD};
+act1 aopenwdoorr_1w = {START_OBJ, NORMAL_TPS_v2d, WDOORR_1w, 1, CYCLE_FORWARD};
+act1 aopenwd1_1w = {START_OBJ, NORMAL_TPS_v2d, MASK_1w, 1, NOT_CYCLING};
+act1 aclosewdoorl_1w = {START_OBJ, NORMAL_TPS_v2d, WDOORL_1w, 1, CYCLE_BACKWARD};
+act1 aclosewdoorr_1w = {START_OBJ, NORMAL_TPS_v2d, WDOORR_1w, 1, CYCLE_BACKWARD};
+act1 abut1_1w = {START_OBJ, 4 * NORMAL_TPS_v2d, BUTLER_1w, 0, CYCLE_FORWARD};
+act1 abut6d_1w = {START_OBJ, 7, HERO, 0, INVISIBLE};
+act1 abut6f_1w = {START_OBJ, 7, HDLSHERO_1w, 0, NOT_CYCLING};
+act1 ashowchop_1w = {START_OBJ, 0, CHOP_1w, 0, NOT_CYCLING};
+act1 aridchop_1w = {START_OBJ, 0, CHOP_1w, 0, INVISIBLE};
+act1 adogcyc_1w = {START_OBJ, 0, DOG_1w, 0, CYCLE_FORWARD};
+act1 ablink5a_1w = {START_OBJ, 0, REDEYES_1w, 0, INVISIBLE};
+act1 ablink5b_1w = {START_OBJ, 1, REDEYES_1w, 0, NOT_CYCLING};
+act1 ablink5c_1w = {START_OBJ, 2, REDEYES_1w, 0, INVISIBLE};
+act1 ablink5d_1w = {START_OBJ, 3, REDEYES_1w, 0, NOT_CYCLING};
+act1 alips_1w = {START_OBJ, 0, LIPS_1w, 6, CYCLE_FORWARD};
+act1 aarm_1w = {START_OBJ, 0, ARM_1w, 3, CYCLE_BACKWARD};
+act1 aopendoor4_1w = {START_OBJ, 0, DOOR4_1w, 1, CYCLE_FORWARD};
+act1 aclosedoor4_1w = {START_OBJ, 0, DOOR4_1w, 1, CYCLE_BACKWARD};
+act1 adog1_1w = {START_OBJ, 0, DOG_1w, 0, CYCLE_FORWARD};
+act1 adead1_1w = {START_OBJ, 0, HERO, 0, INVISIBLE};
+act1 adead3_1w = {START_OBJ, 0, HERODEAD_1w, 0, NOT_CYCLING};
+act1 amovecarp1_1w = {START_OBJ, 0, CARPET_1w, 0, INVISIBLE};
+act1 amovecarp2_1w = {START_OBJ, 0, TRAP_1w, 0, NOT_CYCLING};
+act1 aopentrap_1w = {START_OBJ, NORMAL_TPS_v2d, TRAP_1w, 1, CYCLE_FORWARD};
+act1 aclosetrap_1w = {START_OBJ, NORMAL_TPS_v2d, TRAP_1w, 1, CYCLE_BACKWARD};
+act1 amdoor1_1w = {START_OBJ, NORMAL_TPS_v2d, MDOOR_1w, 1, CYCLE_FORWARD};
+act1 amdoor2_1w = {START_OBJ, 3 * NORMAL_TPS_v2d, MDOOR_1w, 0, INVISIBLE};
+act1 amum1_1w = {START_OBJ, 2 * NORMAL_TPS_v2d, MUMMY_1w, 0, CYCLE_FORWARD};
+act1 arock2_1w = {START_OBJ, 0, HERO, 0, CYCLE_FORWARD};
+act1 arock7_1w = {START_OBJ, 20, HERO, 0, NOT_CYCLING};
+act1 arock9_1w = {START_OBJ, 40, HERO, 0, CYCLE_FORWARD};
+act1 arock14_1w = {START_OBJ, 55, HERO, 0, NOT_CYCLING};
+act1 abin2_1w = {START_OBJ, 0, HERO, 0, INVISIBLE};
+act1 aridbung_1w = {START_OBJ, 0, BUNG_1w, 0, INVISIBLE};
+act1 about2_1w = {START_OBJ, 0, HERO, 0, NOT_CYCLING};
+act1 ajail2_1w = {START_OBJ, 0, HERO, 0, CYCLE_FORWARD};
+act1 atheend1_1w = {START_OBJ, 5 * NORMAL_TPS_v2d, HERO, 0, INVISIBLE};
+act1 aguardgo2_1w = {START_OBJ, 0, GUARD_1w, 0, CYCLE_FORWARD};
+act1 alab5_1w = {START_OBJ, 0, PROF_1w, 0, CYCLE_FORWARD};
+act1 alab8_1w = {START_OBJ, 12, PROF_1w, 0, NOT_CYCLING};
+act1 alab9_1w = {START_OBJ, 16, IGOR_1w, 0, NOT_CYCLING};
+act1 abox10_1w = {START_OBJ, 38, PROF_1w, 0, CYCLE_FORWARD};
+act1 abox11_1w = {START_OBJ, 73, PROF_1w, 0, INVISIBLE};
+
+act2 abatxy_1w = {INIT_OBJXY, 0, BAT_1w, 95, 55};
+act2 aheroxy01_1w = {INIT_OBJXY, 0, HERO, 106, 130};
+act2 aheroxy12_1w = {INIT_OBJXY, 12, HERO, 169, 87};
+act2 aheroxy14_1w = {INIT_OBJXY, 12, HERO, 135, 115};
+act2 aheroxy10_1w = {INIT_OBJXY, 0, HERO, 33, 134};
+act2 aheroxy13_1w = {INIT_OBJXY, 0, HERO, 40, 127};
+act2 aheroxy15_1w = {INIT_OBJXY, 0, HERO, 250, 120};
+act2 ahchase2_1w = {INIT_OBJXY, 5 * NORMAL_TPS_v2d, DOG_1w, 280, 137};
+act2 akchase2_1w = {INIT_OBJXY, 5 * NORMAL_TPS_v2d, DOG_1w, 30, 120};
+act2 a115d_1w = {INIT_OBJXY, 0, MASK_1w, 236, 91};
+act2 aheroxy115_1w = {INIT_OBJXY, 1, HERO, 27, 130};
+act2 aheroxy21_1w = {INIT_OBJXY, 0, HERO, 130, 56};
+act2 achopxy_1w = {INIT_OBJXY, 0, CHOP_1w, 51, 155};
+act2 aheroxy31_1w = {INIT_OBJXY, 0, HERO, 263, 126};
+act2 aheroxy35_1w = {INIT_OBJXY, 0, HERO, 253, 96};
+act2 aheroxy41_1w = {INIT_OBJXY, 0, HERO, 200, 56};
+act2 aheroxy51_1w = {INIT_OBJXY, 0, HERO, 200, 110};
+act2 aheroxy53_1w = {INIT_OBJXY, 0, HERO, 50, 90};
+act2 aheroxy56_1w = {INIT_OBJXY, 0, HERO, 260, 140};
+act2 aheroxy57_1w = {INIT_OBJXY, 0, HERO, 245, 107};
+act2 aheroxy65_1w = {INIT_OBJXY, 0, HERO, 215, 96};
+act2 aheroxy75_1w = {INIT_OBJXY, 0, HERO, 25, 105};
+act2 adog4_1w = {INIT_OBJXY, 0, DOG_1w, 105, 119};
+act2 aheroxy78_1w = {INIT_OBJXY, NORMAL_TPS_v2d + 12, HERO, 80, 42};
+act2 aheroxy89_1w = {INIT_OBJXY, 0, HERO, 276, 135};
+act2 aheroxy87_1w = {INIT_OBJXY, 0, HERO, 235, 108};
+act2 aheroxy910_1w = {INIT_OBJXY, 0, HERO, 50, 132};
+act2 aheroxy98_1w = {INIT_OBJXY, 0, HERO, 130, 120};
+act2 abata1c_1w = {INIT_OBJXY, 0, BAT2_1w, 65, 25};
+act2 abata2c_1w = {INIT_OBJXY, 0, BAT3_1w, 55, 65};
+act2 abata3c_1w = {INIT_OBJXY, 0, BAT4_1w, 50, 120};
+act2 abata4c_1w = {INIT_OBJXY, 0, BAT5_1w, 55, 130};
+act2 aheroxy109_1w = {INIT_OBJXY, 0, HERO, 96, 105};
+act2 aheroxy1011_1w = {INIT_OBJXY, 0, HERO, 76, 130};
+act2 aheroxy1110_1w = {INIT_OBJXY, 0, HERO, 261, 77};
+act2 aheroxy1112_1w = {INIT_OBJXY, 0, HERO, 216, 134};
+act2 aherofar_1w = {INIT_OBJXY, 0, HERO, 142, 25};
+act2 aheronear_1w = {INIT_OBJXY, 0, HERO, 230, 132};
+act2 aheroxy1213_1w = {INIT_OBJXY, 0, HERO, 131, 110};
+act2 aguardgo1_1w = {INIT_OBJXY, 0, GUARD_1w, 137, 39};
+act2 aheroxy1211_1w = {INIT_OBJXY, 0, HERO, 291, 42};
+act2 aheroxy151_1w = {INIT_OBJXY, 0, HERO, 245, 55};
+act2 alab2_1w = {INIT_OBJXY, 0, PROF_1w, 100, 130};
+act2 abox4a_1w = {INIT_OBJXY, 20, HERO, 124, 122};
+act2 aigor12_1w = {INIT_OBJXY, 30, HERO, 116, 112};
act3 aopenp_1w = {PROMPT, 0, kSTsopenp_1w, openrep_1w, kALopenyes_1w, kALopenno_1w, false};
act3 amanq1_1w = {PROMPT, 0, kSTsq1_1w, rep1_1w, kALrepyes1_1w, kALrepno1_1w, false};
@@ -5869,44 +5888,44 @@ act4 abg6_1w = {BKGD_COLOR, 10, _LIGHTMAGENTA};
act4 abg7_1w = {BKGD_COLOR, 12, _LIGHTRED};
act4 abg8_1w = {BKGD_COLOR, 14, _BLACK};
-act5 aopendoor1b_1w = {INIT_OBJVXY, 0, HERO, DX, -DY};
-act5 abatvxy1_1w = {INIT_OBJVXY, 0, BAT_1w, 2, -2};
-act5 abatvxy2_1w = {INIT_OBJVXY, 20, BAT_1w, -1, 1};
-act5 abatvxy3_1w = {INIT_OBJVXY, 40, BAT_1w, -1, -1};
-act5 abatvxy4_1w = {INIT_OBJVXY, 50, BAT_1w, -5, 0};
-act5 abatvxy5_1w = {INIT_OBJVXY, 60, BAT_1w, 0, 0};
-act5 astophero_1w = {INIT_OBJVXY, 0, HERO, 0, 0};
-act5 abutvxy1_1w = {INIT_OBJVXY, 4 * NORMAL_TPS, BUTLER_1w, DX - 2, 0};
-act5 adead4_1w = {INIT_OBJVXY, 0, HERO, 0, 0};
-act5 arock4_1w = {INIT_OBJVXY, 0, HERO, DX, 0};
-act5 arock6_1w = {INIT_OBJVXY, 11, HERO, 0, -DY};
-act5 arock8_1w = {INIT_OBJVXY, 20, HERO, 0, 0};
-act5 arock11_1w = {INIT_OBJVXY, 40, HERO, 0, -DY};
-act5 arock13_1w = {INIT_OBJVXY, 44, HERO, 0, DY};
-act5 arock15_1w = {INIT_OBJVXY, 55, HERO, 0, 0};
-act5 ahin2_1w = {INIT_OBJVXY, 0, HERO, 0, 0};
-act5 aboatvxy1_1w = {INIT_OBJVXY, 0, BOAT_1w, 0, -2};
-act5 aboatvxy2_1w = {INIT_OBJVXY, 10, BOAT_1w, -5, 0};
-act5 aboatvxy3_1w = {INIT_OBJVXY, 20, BOAT_1w, 2, 0};
-act5 aboatvxy4_1w = {INIT_OBJVXY, 50, BOAT_1w, 1, -1};
-act5 aboatvxy5_1w = {INIT_OBJVXY, 60, BOAT_1w, -2, -3};
-act5 aboatvxy6_1w = {INIT_OBJVXY, 70, BOAT_1w, -3, 0};
-act5 aboatvxy7_1w = {INIT_OBJVXY, 100, BOAT_1w, 0, -3};
-act5 aboatvxy8_1w = {INIT_OBJVXY, 104, BOAT_1w, -1, -1};
-act5 aboatvxy9_1w = {INIT_OBJVXY, 107, BOAT_1w, 0, 0};
-act5 aboatvxy10_1w = {INIT_OBJVXY, 0, BOAT_1w, 9, 7};
-act5 aboatvxy11_1w = {INIT_OBJVXY, 3, BOAT_1w, 0, 0};
-act5 aboatvxy12_1w = {INIT_OBJVXY, 10, BOAT_1w, 1, 1};
-act5 aguardgo4_1w = {INIT_OBJVXY, 0, GUARD_1w, -DX, 0};
-act5 alab3_1w = {INIT_OBJVXY, 0, PROF_1w, DX, 0};
-act5 alab6_1w = {INIT_OBJVXY, 12, PROF_1w, 0, 0};
-act5 alab7_1w = {INIT_OBJVXY, 16, IGOR_1w, 0, 0};
-act5 abox0_1w = {INIT_OBJVXY, 0, GDOOR_1w, 6, 0};
-act5 abox1_1w = {INIT_OBJVXY, 9, GDOOR_1w, 0, 0};
-act5 abox7_1w = {INIT_OBJVXY, 50, GDOOR_1w, -6, 0};
-act5 abox8_1w = {INIT_OBJVXY, 57, GDOOR_1w, 0, 0};
-act5 abox8a_1w = {INIT_OBJVXY, 56, GDOOR_1w, 0, 0};
-act5 abox9_1w = {INIT_OBJVXY, 38, PROF_1w, -DX, 0};
+act5 aopendoor1b_1w = {INIT_OBJVXY, 0, HERO, DX, -DY};
+act5 abatvxy1_1w = {INIT_OBJVXY, 0, BAT_1w, 2, -2};
+act5 abatvxy2_1w = {INIT_OBJVXY, 20, BAT_1w, -1, 1};
+act5 abatvxy3_1w = {INIT_OBJVXY, 40, BAT_1w, -1, -1};
+act5 abatvxy4_1w = {INIT_OBJVXY, 50, BAT_1w, -5, 0};
+act5 abatvxy5_1w = {INIT_OBJVXY, 60, BAT_1w, 0, 0};
+act5 astophero_1w = {INIT_OBJVXY, 0, HERO, 0, 0};
+act5 abutvxy1_1w = {INIT_OBJVXY, 4 * NORMAL_TPS_v2d, BUTLER_1w, DX - 2, 0};
+act5 adead4_1w = {INIT_OBJVXY, 0, HERO, 0, 0};
+act5 arock4_1w = {INIT_OBJVXY, 0, HERO, DX, 0};
+act5 arock6_1w = {INIT_OBJVXY, 11, HERO, 0, -DY};
+act5 arock8_1w = {INIT_OBJVXY, 20, HERO, 0, 0};
+act5 arock11_1w = {INIT_OBJVXY, 40, HERO, 0, -DY};
+act5 arock13_1w = {INIT_OBJVXY, 44, HERO, 0, DY};
+act5 arock15_1w = {INIT_OBJVXY, 55, HERO, 0, 0};
+act5 ahin2_1w = {INIT_OBJVXY, 0, HERO, 0, 0};
+act5 aboatvxy1_1w = {INIT_OBJVXY, 0, BOAT_1w, 0, -2};
+act5 aboatvxy2_1w = {INIT_OBJVXY, 10, BOAT_1w, -5, 0};
+act5 aboatvxy3_1w = {INIT_OBJVXY, 20, BOAT_1w, 2, 0};
+act5 aboatvxy4_1w = {INIT_OBJVXY, 50, BOAT_1w, 1, -1};
+act5 aboatvxy5_1w = {INIT_OBJVXY, 60, BOAT_1w, -2, -3};
+act5 aboatvxy6_1w = {INIT_OBJVXY, 70, BOAT_1w, -3, 0};
+act5 aboatvxy7_1w = {INIT_OBJVXY, 100, BOAT_1w, 0, -3};
+act5 aboatvxy8_1w = {INIT_OBJVXY, 104, BOAT_1w, -1, -1};
+act5 aboatvxy9_1w = {INIT_OBJVXY, 107, BOAT_1w, 0, 0};
+act5 aboatvxy10_1w = {INIT_OBJVXY, 0, BOAT_1w, 9, 7};
+act5 aboatvxy11_1w = {INIT_OBJVXY, 3, BOAT_1w, 0, 0};
+act5 aboatvxy12_1w = {INIT_OBJVXY, 10, BOAT_1w, 1, 1};
+act5 aguardgo4_1w = {INIT_OBJVXY, 0, GUARD_1w, -DX, 0};
+act5 alab3_1w = {INIT_OBJVXY, 0, PROF_1w, DX, 0};
+act5 alab6_1w = {INIT_OBJVXY, 12, PROF_1w, 0, 0};
+act5 alab7_1w = {INIT_OBJVXY, 16, IGOR_1w, 0, 0};
+act5 abox0_1w = {INIT_OBJVXY, 0, GDOOR_1w, 6, 0};
+act5 abox1_1w = {INIT_OBJVXY, 9, GDOOR_1w, 0, 0};
+act5 abox7_1w = {INIT_OBJVXY, 50, GDOOR_1w, -6, 0};
+act5 abox8_1w = {INIT_OBJVXY, 57, GDOOR_1w, 0, 0};
+act5 abox8a_1w = {INIT_OBJVXY, 56, GDOOR_1w, 0, 0};
+act5 abox9_1w = {INIT_OBJVXY, 38, PROF_1w, -DX, 0};
act6 adroppkin_1w = {INIT_CARRY, 0, PKIN_1w, false};
act6 a115c_1w = {INIT_CARRY, 0, MASK_1w, false};
@@ -5916,97 +5935,97 @@ act6 adropchop_1w = {INIT_CARRY, 0, CHOP_1w, false};
act6 ashedoil3_1w = {INIT_CARRY, 0, OILCAN_1w, true};
act6 adropbung_1w = {INIT_CARRY, 0, BUNG_1w, false};
-act7 amovekey_1w = {INIT_HF_COORD, 0, KEY_1w};
-act7 ahchase1_1w = {INIT_HF_COORD, 5 * NORMAL_TPS, DOG_1w};
-act7 akchase1_1w = {INIT_HF_COORD, 5 * NORMAL_TPS, DOG_1w};
+act7 amovekey_1w = {INIT_HF_COORD, 0, KEY_1w};
+act7 ahchase1_1w = {INIT_HF_COORD, 5 * NORMAL_TPS_v2d, DOG_1w};
+act7 akchase1_1w = {INIT_HF_COORD, 5 * NORMAL_TPS_v2d, DOG_1w};
// Those two actions were defined as act11 with a type set to INIT_HF_COORD
-act7 adog3_1w = {INIT_HF_COORD, 0, DOG_1w};
-act7 alab1_1w = {INIT_HF_COORD, 0, PROF_1w};
-
-act8 ascr01_1w = {NEW_SCREEN, 0, 1};
-act8 ascr12_1w = {NEW_SCREEN, 12, 2};
-act8 ascr14_1w = {NEW_SCREEN, 12, 4};
-act8 ascr10_1w = {NEW_SCREEN, 0, 0};
-act8 ascr13_1w = {NEW_SCREEN, 0, 3};
-act8 ascr15_1w = {NEW_SCREEN, 0, 5};
-act8 ascr115_1w = {NEW_SCREEN, 1, 15};
-act8 ascr21_1w = {NEW_SCREEN, 0, 1};
-act8 ascr31_1w = {NEW_SCREEN, 0, 1};
-act8 ascr35_1w = {NEW_SCREEN, 0, 5};
-act8 ascr41_1w = {NEW_SCREEN, 0, 1};
-act8 ascr51_1w = {NEW_SCREEN, 0, 1};
-act8 ascr53_1w = {NEW_SCREEN, 0, 3};
-act8 ascr56_1w = {NEW_SCREEN, 0, 6};
-act8 ascr57_1w = {NEW_SCREEN, 0, 7};
-act8 ascr65_1w = {NEW_SCREEN, 0, 5};
-act8 ascr75_1w = {NEW_SCREEN, 0, 5};
-act8 aopen78_1w = {NEW_SCREEN, NORMAL_TPS + 12, 8};
-act8 ascr89_1w = {NEW_SCREEN, 0, 9};
-act8 ascr87_1w = {NEW_SCREEN, 0, 7};
-act8 ascr910_1w = {NEW_SCREEN, 0, 10};
-act8 ascr98_1w = {NEW_SCREEN, 0, 8};
-act8 ascr109_1w = {NEW_SCREEN, 0, 9};
-act8 ascr1011_1w = {NEW_SCREEN, 0, 11};
-act8 ascr1110_1w = {NEW_SCREEN, 0, 10};
-act8 ascr1112_1w = {NEW_SCREEN, 0, 12};
-act8 ascr1213_1w = {NEW_SCREEN, 0, 13};
-act8 atheend2_1w = {NEW_SCREEN, 5 * NORMAL_TPS, 14};
-act8 ascr1211_1w = {NEW_SCREEN, 0, 11};
-act8 ascr151_1w = {NEW_SCREEN, 0, 1};
-
-act9 ast12_1w = {INIT_OBJSTATE, 12, DOOR2_1w, 0};
-act9 ast14_1w = {INIT_OBJSTATE, 12, DOOR3_1w, 0};
-act9 ast01_1w = {INIT_OBJSTATE, 0, DOOR1_1w, 0};
-act9 adef8_1w = {INIT_OBJSTATE, 0, WHISTLE_1w, 1};
-act9 a115g_1w = {INIT_OBJSTATE, 0, MASK_1w, 0};
-act9 aopenwd2_1w = {INIT_OBJSTATE, 0, WDOORL_1w, 1};
-act9 aworn_1w = {INIT_OBJSTATE, 0, MASK_1w, 1};
-act9 aremoved_1w = {INIT_OBJSTATE, 0, MASK_1w, 0};
-act9 abut4a_1w = {INIT_OBJSTATE, 0, BUTLER_1w, 1};
-act9 abut7a_1w = {INIT_OBJSTATE, 0, BUTLER_1w, 1};
-act9 abut10_1w = {INIT_OBJSTATE, 10 * NORMAL_TPS, BUTLER_1w, 0};
-act9 astatedoor4_1w = {INIT_OBJSTATE, 0, DOOR4_1w, 1};
-act9 ashedoil2_1w = {INIT_OBJSTATE, 0, SHED_1w, 1};
-act9 ast78_1w = {INIT_OBJSTATE, NORMAL_TPS + 12, TRAP_1w, 0};
-act9 ahin1_1w = {INIT_OBJSTATE, 0, HERO, 1};
-act9 ahout_1w = {INIT_OBJSTATE, 0, HERO, 0};
-act9 aboatmov_1w = {INIT_OBJSTATE, 0, BOAT_1w, 2};
-act9 aboatfar_1w = {INIT_OBJSTATE, 107, BOAT_1w, 1};
-act9 aboatnear_1w = {INIT_OBJSTATE, 13, BOAT_1w, 0};
-act9 aompass_1w = {INIT_OBJSTATE, 0, OLDMAN_1w, 1};
-act9 abox12_1w = {INIT_OBJSTATE, 0, GDOOR_1w, 1};
-act9 aigor33_1w = {INIT_OBJSTATE, 0, GDOOR_1w, 4};
-act9 aigor23_1w = {INIT_OBJSTATE, 0, GDOOR_1w, 3};
-act9 aigor14_1w = {INIT_OBJSTATE, 0, GDOOR_1w, 2};
-
-act10 ahchase3_1w = {INIT_PATH, 5 * NORMAL_TPS, DOG_1w, CHASE, DX * 2, DY * 2};
-act10 akchase3_1w = {INIT_PATH, 5 * NORMAL_TPS, DOG_1w, CHASE, DX * 2, DY * 2};
-act10 adef2_1w = {INIT_PATH, NORMAL_TPS, BAT2_1w, WANDER, DX, DY};
-act10 adef3_1w = {INIT_PATH, NORMAL_TPS, BAT3_1w, WANDER, DX, DY};
-act10 adef4_1w = {INIT_PATH, NORMAL_TPS, BAT4_1w, WANDER, DX, DY};
-act10 adef5_1w = {INIT_PATH, NORMAL_TPS, BAT5_1w, WANDER, DX, DY};
-act10 abut2_1w = {INIT_PATH, 8 * NORMAL_TPS, BUTLER_1w, CHASE, DX - 2, DY - 2};
-act10 abut3_1w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
-act10 abut8_1w = {INIT_PATH, 0, BUTLER_1w, WANDER, DX - 2, DY - 2};
-act10 abut9_1w = {INIT_PATH, 0, HERO, USER, 0, 0};
-act10 adog2_1w = {INIT_PATH, 0, DOG_1w, CHASE, DX * 2, DY * 2};
-act10 abata1a_1w = {INIT_PATH, 0, BAT2_1w, CHASE, DX * 2, DY * 2};
-act10 abata1b_1w = {INIT_PATH, 7, BAT2_1w, WANDER, DX, DY};
-act10 abata2a_1w = {INIT_PATH, 0, BAT3_1w, CHASE, DX * 2, DY * 2};
-act10 abata2b_1w = {INIT_PATH, 6, BAT3_1w, WANDER, DX, DY};
-act10 abata3a_1w = {INIT_PATH, 0, BAT4_1w, CHASE, DX * 2, DY * 2};
-act10 abata3b_1w = {INIT_PATH, 5, BAT4_1w, WANDER, DX, DY};
-act10 abata4a_1w = {INIT_PATH, 0, BAT5_1w, CHASE, DX * 2, DY * 2};
-act10 abata4b_1w = {INIT_PATH, 4, BAT5_1w, WANDER, DX, DY};
-act10 amum2_1w = {INIT_PATH, 3 * NORMAL_TPS, MUMMY_1w, CHASE, DX * 2, DY * 2};
-act10 arock1_1w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
-act10 arock16_1w = {INIT_PATH, 55, HERO, USER, 0, 0};
-act10 abin3_1w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
-act10 about3_1w = {INIT_PATH, 0, HERO, USER, 0, 0};
-act10 ajail1_1w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
-act10 alab14_1w = {INIT_PATH, 40, IGOR_1w, WANDER, DX, 0};
-act10 acyc1_1w = {INIT_PATH, 0, HERO, QUIET, 0, 0};
-act10 acyc2_1w = {INIT_PATH, 57, HERO, USER, 0, 0};
+act7 adog3_1w = {INIT_HF_COORD, 0, DOG_1w};
+act7 alab1_1w = {INIT_HF_COORD, 0, PROF_1w};
+
+act8 ascr01_1w = {NEW_SCREEN, 0, 1};
+act8 ascr12_1w = {NEW_SCREEN, 12, 2};
+act8 ascr14_1w = {NEW_SCREEN, 12, 4};
+act8 ascr10_1w = {NEW_SCREEN, 0, 0};
+act8 ascr13_1w = {NEW_SCREEN, 0, 3};
+act8 ascr15_1w = {NEW_SCREEN, 0, 5};
+act8 ascr115_1w = {NEW_SCREEN, 1, 15};
+act8 ascr21_1w = {NEW_SCREEN, 0, 1};
+act8 ascr31_1w = {NEW_SCREEN, 0, 1};
+act8 ascr35_1w = {NEW_SCREEN, 0, 5};
+act8 ascr41_1w = {NEW_SCREEN, 0, 1};
+act8 ascr51_1w = {NEW_SCREEN, 0, 1};
+act8 ascr53_1w = {NEW_SCREEN, 0, 3};
+act8 ascr56_1w = {NEW_SCREEN, 0, 6};
+act8 ascr57_1w = {NEW_SCREEN, 0, 7};
+act8 ascr65_1w = {NEW_SCREEN, 0, 5};
+act8 ascr75_1w = {NEW_SCREEN, 0, 5};
+act8 aopen78_1w = {NEW_SCREEN, NORMAL_TPS_v2d + 12, 8};
+act8 ascr89_1w = {NEW_SCREEN, 0, 9};
+act8 ascr87_1w = {NEW_SCREEN, 0, 7};
+act8 ascr910_1w = {NEW_SCREEN, 0, 10};
+act8 ascr98_1w = {NEW_SCREEN, 0, 8};
+act8 ascr109_1w = {NEW_SCREEN, 0, 9};
+act8 ascr1011_1w = {NEW_SCREEN, 0, 11};
+act8 ascr1110_1w = {NEW_SCREEN, 0, 10};
+act8 ascr1112_1w = {NEW_SCREEN, 0, 12};
+act8 ascr1213_1w = {NEW_SCREEN, 0, 13};
+act8 atheend2_1w = {NEW_SCREEN, 5 * NORMAL_TPS_v2d, 14};
+act8 ascr1211_1w = {NEW_SCREEN, 0, 11};
+act8 ascr151_1w = {NEW_SCREEN, 0, 1};
+
+act9 ast12_1w = {INIT_OBJSTATE, 12, DOOR2_1w, 0};
+act9 ast14_1w = {INIT_OBJSTATE, 12, DOOR3_1w, 0};
+act9 ast01_1w = {INIT_OBJSTATE, 0, DOOR1_1w, 0};
+act9 adef8_1w = {INIT_OBJSTATE, 0, WHISTLE_1w, 1};
+act9 a115g_1w = {INIT_OBJSTATE, 0, MASK_1w, 0};
+act9 aopenwd2_1w = {INIT_OBJSTATE, 0, WDOORL_1w, 1};
+act9 aworn_1w = {INIT_OBJSTATE, 0, MASK_1w, 1};
+act9 aremoved_1w = {INIT_OBJSTATE, 0, MASK_1w, 0};
+act9 abut4a_1w = {INIT_OBJSTATE, 0, BUTLER_1w, 1};
+act9 abut7a_1w = {INIT_OBJSTATE, 0, BUTLER_1w, 1};
+act9 abut10_1w = {INIT_OBJSTATE, 10 * NORMAL_TPS_v2d, BUTLER_1w, 0};
+act9 astatedoor4_1w = {INIT_OBJSTATE, 0, DOOR4_1w, 1};
+act9 ashedoil2_1w = {INIT_OBJSTATE, 0, SHED_1w, 1};
+act9 ast78_1w = {INIT_OBJSTATE, NORMAL_TPS_v2d + 12, TRAP_1w, 0};
+act9 ahin1_1w = {INIT_OBJSTATE, 0, HERO, 1};
+act9 ahout_1w = {INIT_OBJSTATE, 0, HERO, 0};
+act9 aboatmov_1w = {INIT_OBJSTATE, 0, BOAT_1w, 2};
+act9 aboatfar_1w = {INIT_OBJSTATE, 107, BOAT_1w, 1};
+act9 aboatnear_1w = {INIT_OBJSTATE, 13, BOAT_1w, 0};
+act9 aompass_1w = {INIT_OBJSTATE, 0, OLDMAN_1w, 1};
+act9 abox12_1w = {INIT_OBJSTATE, 0, GDOOR_1w, 1};
+act9 aigor33_1w = {INIT_OBJSTATE, 0, GDOOR_1w, 4};
+act9 aigor23_1w = {INIT_OBJSTATE, 0, GDOOR_1w, 3};
+act9 aigor14_1w = {INIT_OBJSTATE, 0, GDOOR_1w, 2};
+
+act10 ahchase3_1w = {INIT_PATH, 5 * NORMAL_TPS_v2d, DOG_1w, CHASE, DX * 2, DY * 2};
+act10 akchase3_1w = {INIT_PATH, 5 * NORMAL_TPS_v2d, DOG_1w, CHASE, DX * 2, DY * 2};
+act10 adef2_1w = {INIT_PATH, NORMAL_TPS_v2d, BAT2_1w, WANDER, DX, DY};
+act10 adef3_1w = {INIT_PATH, NORMAL_TPS_v2d, BAT3_1w, WANDER, DX, DY};
+act10 adef4_1w = {INIT_PATH, NORMAL_TPS_v2d, BAT4_1w, WANDER, DX, DY};
+act10 adef5_1w = {INIT_PATH, NORMAL_TPS_v2d, BAT5_1w, WANDER, DX, DY};
+act10 abut2_1w = {INIT_PATH, 8 * NORMAL_TPS_v2d, BUTLER_1w, CHASE, DX - 2, DY - 2};
+act10 abut3_1w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
+act10 abut8_1w = {INIT_PATH, 0, BUTLER_1w, WANDER, DX - 2, DY - 2};
+act10 abut9_1w = {INIT_PATH, 0, HERO, USER, 0, 0};
+act10 adog2_1w = {INIT_PATH, 0, DOG_1w, CHASE, DX * 2, DY * 2};
+act10 abata1a_1w = {INIT_PATH, 0, BAT2_1w, CHASE, DX * 2, DY * 2};
+act10 abata1b_1w = {INIT_PATH, 7, BAT2_1w, WANDER, DX, DY};
+act10 abata2a_1w = {INIT_PATH, 0, BAT3_1w, CHASE, DX * 2, DY * 2};
+act10 abata2b_1w = {INIT_PATH, 6, BAT3_1w, WANDER, DX, DY};
+act10 abata3a_1w = {INIT_PATH, 0, BAT4_1w, CHASE, DX * 2, DY * 2};
+act10 abata3b_1w = {INIT_PATH, 5, BAT4_1w, WANDER, DX, DY};
+act10 abata4a_1w = {INIT_PATH, 0, BAT5_1w, CHASE, DX * 2, DY * 2};
+act10 abata4b_1w = {INIT_PATH, 4, BAT5_1w, WANDER, DX, DY};
+act10 amum2_1w = {INIT_PATH, 3 * NORMAL_TPS_v2d, MUMMY_1w, CHASE, DX * 2, DY * 2};
+act10 arock1_1w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
+act10 arock16_1w = {INIT_PATH, 55, HERO, USER, 0, 0};
+act10 abin3_1w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
+act10 about3_1w = {INIT_PATH, 0, HERO, USER, 0, 0};
+act10 ajail1_1w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
+act10 alab14_1w = {INIT_PATH, 40, IGOR_1w, WANDER, DX, 0};
+act10 acyc1_1w = {INIT_PATH, 0, HERO, QUIET, 0, 0};
+act10 acyc2_1w = {INIT_PATH, 57, HERO, USER, 0, 0};
act11 atcup2_1w = {COND_R, 0, CUPBOARD_1w, 2, kALcuptxt2_1w, kALcuptxt3_1w};
act11 atcup1_1w = {COND_R, 0, CUPBOARD_1w, 1, kALcuptxt1_1w, kALlookcupb2_1w};
@@ -6040,93 +6059,93 @@ act11 aichk2_1w = {COND_R, 0, GDOOR_1w, 2, kALigor2_1w,
act11 aichk1_1w = {COND_R, 0, GDOOR_1w, 1, kALigor1_1w, kALichk2_1w};
act11 aichk0_1w = {COND_R, 0, GDOOR_1w, 0, kALigor0_1w, kALichk1_1w};
-act12 apbreak_1w = {TEXT, 0, kSTspbreak_1w};
-act12 acuptxt0_1w = {TEXT, 0, kSTsseepkdw_1w};
-act12 acuptxt1_1w = {TEXT, 0, kSTsseedw_1w};
-act12 acuptxt2_1w = {TEXT, 0, kSTsseepk_1w};
-act12 acuptxt3_1w = {TEXT, 0, kSTesnosee_1w};
-act12 adwwhy_1w = {TEXT, 0, kSTsWonder_1w};
-act12 ablowt_1w = {TEXT, 3 * NORMAL_TPS, kSTsBlowWhistle_1w};
-act12 adef6_1w = {TEXT, NORMAL_TPS, kSTsdefbat1_1w};
-act12 adef7_1w = {TEXT, 3 * NORMAL_TPS, kSTsdefbat2_1w};
-act12 anought_1w = {TEXT, NORMAL_TPS, kSTsNothing_1w};
-act12 a115e_1w = {TEXT, 0, kSTsDropMask_1w};
-act12 aweartext_1w = {TEXT, 0, kSTWearMask_1w};
-act12 aremovetext_1w = {TEXT, 0, kSTRemoveMask_1w};
-act12 abut6a_1w = {TEXT, 0, kSTsButSniff_1w};
-act12 abut6b_1w = {TEXT, 3, kSTsButChop_1w};
-act12 abut6c_1w = {TEXT, 6, kSTsButHead_1w};
-act12 abut9a_1w = {TEXT, NORMAL_TPS / 3, kSTsButEnjoy_1w};
-act12 abut9b_1w = {TEXT, NORMAL_TPS / 3 + 1, kSTsButTake_1w};
-act12 abut11_1w = {TEXT, NORMAL_TPS / 3, kSTsButLater_1w};
-act12 aeatchop_1w = {TEXT, 0, kSTsEatChop_1w};
-act12 achopfail_1w = {TEXT, 0, kSTesthrown_1w};
-act12 achopthrown_1w = {TEXT, 5 * NORMAL_TPS, kSTsDogEat_1w};
-act12 atalk1a_1w = {TEXT, 0, kSTAskFrank_1w};
-act12 atalk1b_1w = {TEXT, 0, kSTRepFrank_1w};
-act12 atalk2a_1w = {TEXT, 0, kSTAskDrac_1w};
-act12 atalk2b_1w = {TEXT, 0, kSTRepDrac_1w};
-act12 atalk3a_1w = {TEXT, 0, kSTAskGwen_1w};
-act12 atalk3b_1w = {TEXT, 0, kSTRepGwen_1w};
-act12 atalk4a_1w = {TEXT, 0, kSTAskFriar_1w};
-act12 atalk4b_1w = {TEXT, 0, kSTRepFriar_1w};
-act12 atalk5a_1w = {TEXT, 0, kSTAskSlime_1w};
-act12 atalk5b_1w = {TEXT, 0, kSTRepSlime_1w};
-act12 atalk6a_1w = {TEXT, 0, kSTAskPea_1w};
-act12 atalk6b_1w = {TEXT, 0, kSTRepPea_1w};
-act12 anoopen_1w = {TEXT, 0, kSTsWrongCombo_1w};
-act12 aopen4_1w = {TEXT, 0, kSTsRightCombo_1w};
-act12 ashedoil1_1w = {TEXT, 0, kSTsTakeOil_1w};
-act12 adoggy_1w = {TEXT, 0, kSTsDogEatHero_1w};
-act12 at78a_1w = {TEXT, 0, kSTsTossMask_1w};
-act12 aopenfail_1w = {TEXT, 0, kSTsTrapBolted_1w};
-act12 ahelps1_1w = {TEXT, 0, kSTsBaseHelp1_1w};
-act12 anohelp_1w = {TEXT, 0, kSTsNoHelp_1w};
-act12 ahelps2_1w = {TEXT, 0, kSTsBaseHelp2_1w};
-act12 abat5a_1w = {TEXT, 0, kSTsGotcher_1w};
-act12 abat5b_1w = {TEXT, 0, kSTsBatGot_1w};
-act12 amum3_1w = {TEXT, 0, kSTsGotcher_1w};
-act12 amum4_1w = {TEXT, 0, kSTsMummyGot_1w};
-act12 abin0_1w = {TEXT, 0, kSTsEnterBoat_1w};
-act12 abung1_1w = {TEXT, 0, kSTsBoatHole_1w};
-act12 ahout1_1w = {TEXT, 0, kSTsExitBoat_1w};
-act12 anodeboat_1w = {TEXT, 0, kSTsManBlock_1w};
-act12 amoving_1w = {TEXT, 0, kSTsShutup_1w};
-act12 anotcut_1w = {TEXT, 0, kSTsBoatTied_1w};
-act12 arepyep_1w = {TEXT, 0, kSTsCorrect_1w};
-act12 arepnop_1w = {TEXT, 0, kSTsIncorrect_1w};
-act12 amans1_1w = {TEXT, 0, kSTsDoomed1_1w};
-act12 arepno5_1w = {TEXT, 0, kSTsDoomed2_1w};
-act12 arepyep2_1w = {TEXT, 0, kSTsContinue_1w};
-act12 amans3_1w = {TEXT, 0, kSTsOldMan1_1w};
-act12 amans4_1w = {TEXT, 0, kSTsOldMan2_1w};
-act12 amans5_1w = {TEXT, 0, kSTsOldMan3_1w};
-act12 amans6_1w = {TEXT, 0, kSTsOldMan4_1w};
-act12 amans7_1w = {TEXT, 0, kSTsOldMan5_1w};
-act12 ajails1_1w = {TEXT, 0, kSTsCongrats_1w};
-act12 ajails2_1w = {TEXT, 0, kSTsRescued1_1w};
-act12 ajails3_1w = {TEXT, 0, kSTsRescued2_1w};
-act12 ajails4_1w = {TEXT, 0, kSTsRescued3_1w};
-act12 agive1_1w = {TEXT, 0, kSTsGuard1_1w};
-act12 agive2_1w = {TEXT, 0, kSTsGuard2_1w};
-act12 anogive_1w = {TEXT, 0, kSTsNoGive_1w};
-act12 bye1_1w = {TEXT, 2 * NORMAL_TPS, kSTsKissy_1w};
-act12 bye2_1w = {TEXT, 3 * NORMAL_TPS, kSTsGoodbye_1w};
-act12 admsg3_1w = {TEXT, 0, kSTsGrip_1w};
-act12 admsg2_1w = {TEXT, 0, kSTsCoordinate_1w};
-act12 admsg1_1w = {TEXT, 0, kSTsReach_1w};
-act12 alab12_1w = {TEXT, 24, kSTsProf1_1w};
-act12 alab13_1w = {TEXT, 24, kSTsProf2_1w};
-act12 abox2_1w = {TEXT, 16, kSTsProf3_1w};
-act12 abox3_1w = {TEXT, 16, kSTsIgorRed_1w};
-act12 abox5_1w = {TEXT, 38, kSTsProfUpset_1w};
-act12 abox6_1w = {TEXT, 44, kSTsProfRetires_1w};
-act12 ainorm_1w = {TEXT, 0, kSTsIgorRefuses_1w};
-act12 aigor22_1w = {TEXT, 0, kSTsIgorGreen_1w};
-act12 aigor13_1w = {TEXT, 0, kSTsIgorYellow_1w};
-act12 aigor32_1w = {TEXT, 0, kSTsIgorBlue_1w};
-act12 aigor0_1w = {TEXT, 0, kSTsIgorNo_1w};
-act12 agobox_1w = {TEXT, 0, kSTsIgorBox_1w};
+act12 apbreak_1w = {TEXT, 0, kSTspbreak_1w};
+act12 acuptxt0_1w = {TEXT, 0, kSTsseepkdw_1w};
+act12 acuptxt1_1w = {TEXT, 0, kSTsseedw_1w};
+act12 acuptxt2_1w = {TEXT, 0, kSTsseepk_1w};
+act12 acuptxt3_1w = {TEXT, 0, kSTesnosee_1w};
+act12 adwwhy_1w = {TEXT, 0, kSTsWonder_1w};
+act12 ablowt_1w = {TEXT, 3 * NORMAL_TPS_v2d, kSTsBlowWhistle_1w};
+act12 adef6_1w = {TEXT, NORMAL_TPS_v2d, kSTsdefbat1_1w};
+act12 adef7_1w = {TEXT, 3 * NORMAL_TPS_v2d, kSTsdefbat2_1w};
+act12 anought_1w = {TEXT, NORMAL_TPS_v2d, kSTsNothing_1w};
+act12 a115e_1w = {TEXT, 0, kSTsDropMask_1w};
+act12 aweartext_1w = {TEXT, 0, kSTWearMask_1w};
+act12 aremovetext_1w = {TEXT, 0, kSTRemoveMask_1w};
+act12 abut6a_1w = {TEXT, 0, kSTsButSniff_1w};
+act12 abut6b_1w = {TEXT, 3, kSTsButChop_1w};
+act12 abut6c_1w = {TEXT, 6, kSTsButHead_1w};
+act12 abut9a_1w = {TEXT, NORMAL_TPS_v2d / 3, kSTsButEnjoy_1w};
+act12 abut9b_1w = {TEXT, NORMAL_TPS_v2d / 3 + 1, kSTsButTake_1w};
+act12 abut11_1w = {TEXT, NORMAL_TPS_v2d / 3, kSTsButLater_1w};
+act12 aeatchop_1w = {TEXT, 0, kSTsEatChop_1w};
+act12 achopfail_1w = {TEXT, 0, kSTesthrown_1w};
+act12 achopthrown_1w = {TEXT, 5 * NORMAL_TPS_v2d, kSTsDogEat_1w};
+act12 atalk1a_1w = {TEXT, 0, kSTAskFrank_1w};
+act12 atalk1b_1w = {TEXT, 0, kSTRepFrank_1w};
+act12 atalk2a_1w = {TEXT, 0, kSTAskDrac_1w};
+act12 atalk2b_1w = {TEXT, 0, kSTRepDrac_1w};
+act12 atalk3a_1w = {TEXT, 0, kSTAskGwen_1w};
+act12 atalk3b_1w = {TEXT, 0, kSTRepGwen_1w};
+act12 atalk4a_1w = {TEXT, 0, kSTAskFriar_1w};
+act12 atalk4b_1w = {TEXT, 0, kSTRepFriar_1w};
+act12 atalk5a_1w = {TEXT, 0, kSTAskSlime_1w};
+act12 atalk5b_1w = {TEXT, 0, kSTRepSlime_1w};
+act12 atalk6a_1w = {TEXT, 0, kSTAskPea_1w};
+act12 atalk6b_1w = {TEXT, 0, kSTRepPea_1w};
+act12 anoopen_1w = {TEXT, 0, kSTsWrongCombo_1w};
+act12 aopen4_1w = {TEXT, 0, kSTsRightCombo_1w};
+act12 ashedoil1_1w = {TEXT, 0, kSTsTakeOil_1w};
+act12 adoggy_1w = {TEXT, 0, kSTsDogEatHero_1w};
+act12 at78a_1w = {TEXT, 0, kSTsTossMask_1w};
+act12 aopenfail_1w = {TEXT, 0, kSTsTrapBolted_1w};
+act12 ahelps1_1w = {TEXT, 0, kSTsBaseHelp1_1w};
+act12 anohelp_1w = {TEXT, 0, kSTsNoHelp_1w};
+act12 ahelps2_1w = {TEXT, 0, kSTsBaseHelp2_1w};
+act12 abat5a_1w = {TEXT, 0, kSTsGotcher_1w};
+act12 abat5b_1w = {TEXT, 0, kSTsBatGot_1w};
+act12 amum3_1w = {TEXT, 0, kSTsGotcher_1w};
+act12 amum4_1w = {TEXT, 0, kSTsMummyGot_1w};
+act12 abin0_1w = {TEXT, 0, kSTsEnterBoat_1w};
+act12 abung1_1w = {TEXT, 0, kSTsBoatHole_1w};
+act12 ahout1_1w = {TEXT, 0, kSTsExitBoat_1w};
+act12 anodeboat_1w = {TEXT, 0, kSTsManBlock_1w};
+act12 amoving_1w = {TEXT, 0, kSTsShutup_1w};
+act12 anotcut_1w = {TEXT, 0, kSTsBoatTied_1w};
+act12 arepyep_1w = {TEXT, 0, kSTsCorrect_1w};
+act12 arepnop_1w = {TEXT, 0, kSTsIncorrect_1w};
+act12 amans1_1w = {TEXT, 0, kSTsDoomed1_1w};
+act12 arepno5_1w = {TEXT, 0, kSTsDoomed2_1w};
+act12 arepyep2_1w = {TEXT, 0, kSTsContinue_1w};
+act12 amans3_1w = {TEXT, 0, kSTsOldMan1_1w};
+act12 amans4_1w = {TEXT, 0, kSTsOldMan2_1w};
+act12 amans5_1w = {TEXT, 0, kSTsOldMan3_1w};
+act12 amans6_1w = {TEXT, 0, kSTsOldMan4_1w};
+act12 amans7_1w = {TEXT, 0, kSTsOldMan5_1w};
+act12 ajails1_1w = {TEXT, 0, kSTsCongrats_1w};
+act12 ajails2_1w = {TEXT, 0, kSTsRescued1_1w};
+act12 ajails3_1w = {TEXT, 0, kSTsRescued2_1w};
+act12 ajails4_1w = {TEXT, 0, kSTsRescued3_1w};
+act12 agive1_1w = {TEXT, 0, kSTsGuard1_1w};
+act12 agive2_1w = {TEXT, 0, kSTsGuard2_1w};
+act12 anogive_1w = {TEXT, 0, kSTsNoGive_1w};
+act12 bye1_1w = {TEXT, 2 * NORMAL_TPS_v2d, kSTsKissy_1w};
+act12 bye2_1w = {TEXT, 3 * NORMAL_TPS_v2d, kSTsGoodbye_1w};
+act12 admsg3_1w = {TEXT, 0, kSTsGrip_1w};
+act12 admsg2_1w = {TEXT, 0, kSTsCoordinate_1w};
+act12 admsg1_1w = {TEXT, 0, kSTsReach_1w};
+act12 alab12_1w = {TEXT, 24, kSTsProf1_1w};
+act12 alab13_1w = {TEXT, 24, kSTsProf2_1w};
+act12 abox2_1w = {TEXT, 16, kSTsProf3_1w};
+act12 abox3_1w = {TEXT, 16, kSTsIgorRed_1w};
+act12 abox5_1w = {TEXT, 38, kSTsProfUpset_1w};
+act12 abox6_1w = {TEXT, 44, kSTsProfRetires_1w};
+act12 ainorm_1w = {TEXT, 0, kSTsIgorRefuses_1w};
+act12 aigor22_1w = {TEXT, 0, kSTsIgorGreen_1w};
+act12 aigor13_1w = {TEXT, 0, kSTsIgorYellow_1w};
+act12 aigor32_1w = {TEXT, 0, kSTsIgorBlue_1w};
+act12 aigor0_1w = {TEXT, 0, kSTsIgorNo_1w};
+act12 agobox_1w = {TEXT, 0, kSTsIgorBox_1w};
act13 aswapmask_1w = {SWAP_IMAGES, 0, HERO, MONKEY_1w};
act13 aswaphero_1w = {SWAP_IMAGES, 0, HERO, WHERO_1w};
@@ -6147,40 +6166,40 @@ act14 achkscr_1w = {COND_SCR, 0, HERO, 12, kALgive_1w, kALnogive_1w};
act15 adogchop_1w = {AUTOPILOT, 0, DOG_1w, CHOP_1w, DX + 2, DY * 2};
-act16 aclosedoor2_1w = {INIT_OBJ_SEQ, 12, DOOR2_1w, 0};
-act16 aclosedoor3_1w = {INIT_OBJ_SEQ, 12, DOOR3_1w, 0};
-act16 adogseq_1w = {INIT_OBJ_SEQ, 0, DOG_1w, 1};
-act16 adogseq2_1w = {INIT_OBJ_SEQ, 4 * NORMAL_TPS, DOG_1w, 2};
-act16 adog5_1w = {INIT_OBJ_SEQ, 0, DOG_1w, 0};
-act16 at78c_1w = {INIT_OBJ_SEQ, NORMAL_TPS + 12, TRAP_1w, 0};
-act16 arock3_1w = {INIT_OBJ_SEQ, 0, HERO, RIGHT};
-act16 arock5_1w = {INIT_OBJ_SEQ, 11, HERO, _UP};
-act16 arock10_1w = {INIT_OBJ_SEQ, 40, HERO, _UP};
-act16 arock12_1w = {INIT_OBJ_SEQ, 44, HERO, DOWN};
-act16 acutrope_1w = {INIT_OBJ_SEQ, 0, ROPE_1w, 1};
-act16 abin1_1w = {INIT_OBJ_SEQ, 0, BOAT_1w, 1};
-act16 about1_1w = {INIT_OBJ_SEQ, 0, BOAT_1w, 0};
-act16 ajail3_1w = {INIT_OBJ_SEQ, 0, HERO, 0};
-act16 ajail4_1w = {INIT_OBJ_SEQ, 2, HERO, 1};
-act16 aguardgo3_1w = {INIT_OBJ_SEQ, 0, GUARD_1w, 1};
-act16 aturnguard_1w = {INIT_OBJ_SEQ, 2 * NORMAL_TPS, GUARD_1w, 0};
-act16 alab4_1w = {INIT_OBJ_SEQ, 0, PROF_1w, 0};
-act16 alab10_1w = {INIT_OBJ_SEQ, 14, PROF_1w, 1};
-act16 alab11_1w = {INIT_OBJ_SEQ, 18, IGOR_1w, 1};
+act16 aclosedoor2_1w = {INIT_OBJ_SEQ, 12, DOOR2_1w, 0};
+act16 aclosedoor3_1w = {INIT_OBJ_SEQ, 12, DOOR3_1w, 0};
+act16 adogseq_1w = {INIT_OBJ_SEQ, 0, DOG_1w, 1};
+act16 adogseq2_1w = {INIT_OBJ_SEQ, 4 * NORMAL_TPS_v2d, DOG_1w, 2};
+act16 adog5_1w = {INIT_OBJ_SEQ, 0, DOG_1w, 0};
+act16 at78c_1w = {INIT_OBJ_SEQ, NORMAL_TPS_v2d + 12, TRAP_1w, 0};
+act16 arock3_1w = {INIT_OBJ_SEQ, 0, HERO, RIGHT};
+act16 arock5_1w = {INIT_OBJ_SEQ, 11, HERO, _UP};
+act16 arock10_1w = {INIT_OBJ_SEQ, 40, HERO, _UP};
+act16 arock12_1w = {INIT_OBJ_SEQ, 44, HERO, DOWN};
+act16 acutrope_1w = {INIT_OBJ_SEQ, 0, ROPE_1w, 1};
+act16 abin1_1w = {INIT_OBJ_SEQ, 0, BOAT_1w, 1};
+act16 about1_1w = {INIT_OBJ_SEQ, 0, BOAT_1w, 0};
+act16 ajail3_1w = {INIT_OBJ_SEQ, 0, HERO, 0};
+act16 ajail4_1w = {INIT_OBJ_SEQ, 2, HERO, 1};
+act16 aguardgo3_1w = {INIT_OBJ_SEQ, 0, GUARD_1w, 1};
+act16 aturnguard_1w = {INIT_OBJ_SEQ, 2 * NORMAL_TPS_v2d, GUARD_1w, 0};
+act16 alab4_1w = {INIT_OBJ_SEQ, 0, PROF_1w, 0};
+act16 alab10_1w = {INIT_OBJ_SEQ, 14, PROF_1w, 1};
+act16 alab11_1w = {INIT_OBJ_SEQ, 18, IGOR_1w, 1};
act17 acupbpk_1w = {SET_STATE_BITS, 0, CUPBOARD_1w, 1};
act17 acupbdw_1w = {SET_STATE_BITS, 0, CUPBOARD_1w, 2};
-act20 adef1_1w = {DEL_EVENTS, 1 * NORMAL_TPS, ASCHEDULE};
+act20 adef1_1w = {DEL_EVENTS, 1 * NORMAL_TPS_v2d, ASCHEDULE};
act21 abut6g_1w = {GAMEOVER, 7};
act21 adead5_1w = {GAMEOVER, 0};
// Those two were act7, with a type set to INIT_HH_COORD
-act22 abut6e_1w = {INIT_HH_COORD, 7, HDLSHERO_1w};
-act22 adead2_1w = {INIT_HH_COORD, 0, HERODEAD_1w};
+act22 abut6e_1w = {INIT_HH_COORD, 7, HDLSHERO_1w};
+act22 adead2_1w = {INIT_HH_COORD, 0, HERODEAD_1w};
-act23 bye3_1w = {EXIT, 4 * NORMAL_TPS};
+act23 bye3_1w = {EXIT, 4 * NORMAL_TPS_v2d};
act24 abonus12_1w = {BONUS, 0, 12};
act24 abonus1_1w = {BONUS, 0, 1};
@@ -6196,26 +6215,26 @@ act24 abonus8_1w = {BONUS, 0, 8};
// The following was defined as a act27 with a type set to BONUS
act24 abut7b_1w = {BONUS, 0, 10};
-act25 achkdoor_1w = {COND_BOX, 2 * NORMAL_TPS, HERO, 25, 173, 40, 175, kALgoinside_1w, 0};
-act25 achkbbox_1w = {COND_BOX, 0, HERO, 100, 153, 144, 160, kALbbox_1w, 0};
-act25 aichkbox_1w = {COND_BOX, 0, HERO, 100, 153, 144, 163, kALichk0_1w, kALgobox_1w};
-
-act26 acreak_1w = {SOUND, 0, DOOR_CREAK_1w};
-act26 abatsnd_1w = {SOUND, 50, BAT_FLUTTER_1w};
-act26 adooropen_1w = {SOUND, 0, DOOR_OPEN_1w};
-act26 ahchase4_1w = {SOUND, 5 * NORMAL_TPS, DOG_BARK_1w};
-act26 abutsnd_1w = {SOUND, 3, BUTLER_GOTCHER_1w};
-act26 abut6h_1w = {SOUND, 7, T_TRACK10};
-act26 amunch_1w = {SOUND, 0, MUNCH_1w};
-act26 afork_1w = {SOUND, 1 * NORMAL_TPS, FORK_BANG_1w};
-act26 asong3_1w = {SOUND, 0, DOG_BARK_1w};
-act26 afuneral_1w = {SOUND, 0, T_TRACK10};
-act26 abatgot_1w = {SOUND, 0, BAT_FLUTTER_1w};
-act26 asong2_1w = {SOUND, 3 * NORMAL_TPS, MUMMY_CHASE_1w};
-act26 amumgot_1w = {SOUND, 0, MUMMY_GOTCHER_1w};
-act26 asplash_1w = {SOUND, 0, SPLASH_1w};
-act26 afinale_1w = {SOUND, 0, T_TRACK1};
-act26 abgsnd_1w = {SOUND, 0, MACHINE_NOISE_1w};
+act25 achkdoor_1w = {COND_BOX, 2 * NORMAL_TPS_v2d, HERO, 25, 173, 40, 175, kALgoinside_1w, 0};
+act25 achkbbox_1w = {COND_BOX, 0, HERO, 100, 153, 144, 160, kALbbox_1w, 0};
+act25 aichkbox_1w = {COND_BOX, 0, HERO, 100, 153, 144, 163, kALichk0_1w, kALgobox_1w};
+
+act26 acreak_1w = {SOUND, 0, DOOR_CREAK_1w};
+act26 abatsnd_1w = {SOUND, 50, BAT_FLUTTER_1w};
+act26 adooropen_1w = {SOUND, 0, DOOR_OPEN_1w};
+act26 ahchase4_1w = {SOUND, 5 * NORMAL_TPS_v2d, DOG_BARK_1w};
+act26 abutsnd_1w = {SOUND, 3, BUTLER_GOTCHER_1w};
+act26 abut6h_1w = {SOUND, 7, T_TRACK10};
+act26 amunch_1w = {SOUND, 0, MUNCH_1w};
+act26 afork_1w = {SOUND, 1 * NORMAL_TPS_v2d, FORK_BANG_1w};
+act26 asong3_1w = {SOUND, 0, DOG_BARK_1w};
+act26 afuneral_1w = {SOUND, 0, T_TRACK10};
+act26 abatgot_1w = {SOUND, 0, BAT_FLUTTER_1w};
+act26 asong2_1w = {SOUND, 3 * NORMAL_TPS_v2d, MUMMY_CHASE_1w};
+act26 amumgot_1w = {SOUND, 0, MUMMY_GOTCHER_1w};
+act26 asplash_1w = {SOUND, 0, SPLASH_1w};
+act26 afinale_1w = {SOUND, 0, T_TRACK1};
+act26 abgsnd_1w = {SOUND, 0, MACHINE_NOISE_1w};
act27 ashedoil4_1w = {ADD_SCORE, 0, OILCAN_1w};
@@ -6224,11 +6243,11 @@ act28 a115f_1w = {SUB_SCORE, 0, MASK_1w};
act29 achkmask_1w = {COND_CARRY, 0, MASK_1w, kALputmask_1w, 0};
act29 achkmask2_1w = {COND_CARRY, 0, MASK_1w, kALridmask_1w, 0};
-act43 abut4_1w = {YESNO, 0, kSTsbut1_1w, kALbutyes_1w, kALbutno_1w};
-act43 achopprompt_1w = {YESNO, 0, kSTsChopPrompt_1w, kALeatchop_1w, 0};
-act43 ahelp1_1w = {YESNO, 4 * 60 * NORMAL_TPS, kSTshelpp1_1w, kALhelpy_1w, kALhelpn_1w};
-act43 ahelp2_1w = {YESNO, 5 * 60 * NORMAL_TPS, kSTshelpp2_1w, kALhelpy2_1w, kALhelpn_1w};
-act43 achkboat2_1w = {YESNO, 0, kSTsBoatAsk_1w, kALpushboat_1w, kALgetoutboat_1w};
+act43 abut4_1w = {YESNO, 0, kSTsbut1_1w, kALbutyes_1w, kALbutno_1w};
+act43 achopprompt_1w = {YESNO, 0, kSTsChopPrompt_1w, kALeatchop_1w, 0};
+act43 ahelp1_1w = {YESNO, 4 * 60 * NORMAL_TPS_v2d, kSTshelpp1_1w, kALhelpy_1w, kALhelpn_1w};
+act43 ahelp2_1w = {YESNO, 5 * 60 * NORMAL_TPS_v2d, kSTshelpp2_1w, kALhelpy2_1w, kALhelpn_1w};
+act43 achkboat2_1w = {YESNO, 0, kSTsBoatAsk_1w, kALpushboat_1w, kALgetoutboat_1w};
act47 aviewfar_1w = {INIT_VIEW, 107, BOAT_1w, 140, 55, Common::KEYCODE_DOWN};
act47 aviewnear_1w = {INIT_VIEW, 13, BOAT_1w, 250, 150, Common::KEYCODE_UP};
@@ -6452,15 +6471,15 @@ actList actListArr_1w[] = {
int dialrsp_2w[] = {kSTSdial2_2w, -1};
int whorsp_2w[] = {kSTNobody_2w, kSTNo_one1_2w, kSTNo_one2_2w, kSTSharry_2w, -1};
-act0 arepchk_2w = {ASCHEDULE, 4, kALscr25_2w};
-act0 aclimax_2w = {ASCHEDULE, 20, kALclimax_2w};
-act0 aclue09_2w = {ASCHEDULE, 200 * NORMAL_TPS, kALchkc09_2w};
-act0 ahdrink10_2w = {ASCHEDULE, 72, kALhfaint_2w};
-act0 aschedbut_2w = {ASCHEDULE, 30, kALschedbut_2w};
-act0 arepbuga_2w = {ASCHEDULE, 3 * NORMAL_TPS, kALbugrep1_2w};
-act0 arepbugf_2w = {ASCHEDULE, 2 * NORMAL_TPS, kALbugrep2_2w};
-act0 arepblah_2w = {ASCHEDULE, 12 * NORMAL_TPS, kALblah_2w};
-act0 arepmsg1_2w = {ASCHEDULE, 120 * NORMAL_TPS, kALrepmsg1_2w};
+act0 arepchk_2w = {ASCHEDULE, 4, kALscr25_2w};
+act0 aclimax_2w = {ASCHEDULE, 20, kALclimax_2w};
+act0 aclue09_2w = {ASCHEDULE, 200 * NORMAL_TPS_v2d, kALchkc09_2w};
+act0 ahdrink10_2w = {ASCHEDULE, 72, kALhfaint_2w};
+act0 aschedbut_2w = {ASCHEDULE, 30, kALschedbut_2w};
+act0 arepbuga_2w = {ASCHEDULE, 3 * NORMAL_TPS_v2d, kALbugrep1_2w};
+act0 arepbugf_2w = {ASCHEDULE, 2 * NORMAL_TPS_v2d, kALbugrep2_2w};
+act0 arepblah_2w = {ASCHEDULE, 12 * NORMAL_TPS_v2d, kALblah_2w};
+act0 arepmsg1_2w = {ASCHEDULE, 120 * NORMAL_TPS_v2d, kALrepmsg1_2w};
act1 aback1_2w = {START_OBJ, 0, CAT_2w, 0, INVISIBLE};
act1 aback2_2w = {START_OBJ, 2, CAT_2w, 0, NOT_CYCLING};
@@ -6816,7 +6835,7 @@ act8 ascr0203_2w = {NEW_SCREEN, 40, 3};
act8 ascr11maze_2w = {NEW_SCREEN, 0, MAZE_SCREEN + 59};// Enter maze
act8 ascr3435_2w = {NEW_SCREEN, DOORDELAY, 35}; // Goto to organ
act8 ascr3436_2w = {NEW_SCREEN, DOORDELAY, 36}; // Goto to hestroom
-act8 ascrmaze_2w = {NEW_SCREEN, 0, 11}; // Maze exit to gatesopn
+act8 ascrmaze_2w = {NEW_SCREEN, 0, 11}; // Maze exit to gatesopn
act8 ascr01_2w = {NEW_SCREEN, STORYDELAY + 10, 1};
act8 askip5_2w = {NEW_SCREEN, 0, 3};
@@ -6954,195 +6973,195 @@ act11 achkmaid_2w = {COND_R, 0, MAID_2w, 0, kALmaidx_2w, kALblah_2w}
act11 achkstate0_2w = {COND_R, 0, BOOK_2w, 0, kALhugone_2w, kALchkstate1_2w};
act11 achkstate1_2w = {COND_R, 0, BOOK_2w, 1, kALhole_2w, kALpengone_2w};
-act12 alookbrg_2w = {TEXT, 0, kSTLookBridge_2w};
-act12 astuck1_2w = {TEXT, 0, kSTDoorStuck_2w};
-act12 atalkg_2w = {TEXT, 0, kSTIgnore_2w};
-act12 aball4_2w = {TEXT, 2, kSTBalloon1_2w};
-act12 aball5_2w = {TEXT, 2, kSTBalloon2_2w};
-act12 aball6_2w = {TEXT, 2, kSTBalloon3_2w};
-act12 abanana1_2w = {TEXT, 0, kSTBanana1_2w};
-act12 abanana3_2w = {TEXT, 0, kSTBanana2_2w};
-act12 abell_2w = {TEXT, 0, kSTBell1_2w};
-act12 abell1_2w = {TEXT, 8, kSTMaid7_2w};
-act12 abite2_2w = {TEXT, 0, kSTSnake5_2w};
-act12 ablah_2w = {TEXT, 8, kSTBlah_2w};
-act12 aboom_2w = {TEXT, 0, kSTDyn4_2w};
-act12 acallp2_2w = {TEXT, 0, kSTCall1_2w};
-act12 acallp3_2w = {TEXT, 0, kSTCall2_2w};
-act12 acallp4_2w = {TEXT, 0, kSTCall3_2w};
-act12 acallp5_2w = {TEXT, 0, kSTCall4_2w};
-act12 acallp6_2w = {TEXT, 0, kSTCall5_2w};
-act12 acallp7_2w = {TEXT, 0, kSTCall6_2w};
-act12 acantpush_2w = {TEXT, 0, kSTPush1_2w};
-act12 acat1_2w = {TEXT, 0, kSTCat3_2w};
-act12 acat4_2w = {TEXT, 0, kSTMaid8_2w};
-act12 achasm1_2w = {TEXT, 12, kSTChasm1_2w};
-act12 acheat1_2w = {TEXT, 0, kSTScheat1_2w};
-act12 acheat2_2w = {TEXT, 0, kSTScheat2_2w};
-act12 aclimax1_2w = {TEXT, 0, kSTSclimax1_2w};
-act12 aclimax2_2w = {TEXT, 8, kSTSclimax2_2w};
-act12 aclimax3_2w = {TEXT, 80, kSTSclimax3_2w};
-act12 aclimax4_2w = {TEXT, 80, kSTSclimax4_2w};
-act12 aclimax5_2w = {TEXT, 80, kSTSclimax5_2w};
-act12 aclimax6_2w = {TEXT, 80, kSTSclimax6_2w};
-act12 aclue09a_2w = {TEXT, 0, kSTSclue09a_2w};
-act12 aclue09b_2w = {TEXT, 0, kSTSclue09b_2w};
-act12 aclue09c_2w = {TEXT, 0, kSTSclue09c_2w};
-act12 acomb1_2w = {TEXT, 0, kSTScomb1_2w};
-act12 acomb2_2w = {TEXT, 0, kSTScomb2_2w};
-act12 acook1_2w = {TEXT, 8, kSTCook1_2w};
-act12 acook2_2w = {TEXT, 8, kSTCook2_2w};
-act12 acook3_2w = {TEXT, 8, kSTCook3_2w};
-act12 acook4_2w = {TEXT, 24, kSTCook4_2w};
-act12 acook5_2w = {TEXT, 24, kSTCook5_2w};
-act12 adialed_2w = {TEXT, 0, kSTSdialed_2w};
-act12 adidnt1_2w = {TEXT, 0, kSTSdidnt1_2w};
-act12 adidnt2_2w = {TEXT, 0, kSTSdidnt2_2w};
-act12 adog1_2w = {TEXT, 0, kSTDyn2_2w};
-act12 adone1_2w = {TEXT, 10, kSTSdone1_2w};
-act12 adone13_2w = {TEXT, 50, kSTSdone5_2w};
-act12 adone14_2w = {TEXT, 50, kSTSdone6_2w};
-act12 adone15_2w = {TEXT, 50, kSTSdone7_2w};
-act12 adone2_2w = {TEXT, 10, kSTSdone2_2w};
-act12 adone3_2w = {TEXT, 10, kSTSdone3_2w};
-act12 adone4_2w = {TEXT, 10, kSTSdone4_2w};
-act12 adraught_2w = {TEXT, 5 * 60 * NORMAL_TPS, kSTDraught_2w};
-act12 adropdyn2_2w = {TEXT, 0, kSTDyn3_2w};
-act12 adumb12_2w = {TEXT, 0, kSTDumb2_2w};
-act12 adumb2_2w = {TEXT, 0, kSTDumb1_2w};
-act12 adyn1_2w = {TEXT, 0, kSTDyn1_2w};
-act12 aeatban_2w = {TEXT, 0, kSTSeatbanana_2w};
-act12 aeatgarl1_2w = {TEXT, 0, kSTSgarl1_2w};
-act12 aeatgarl2_2w = {TEXT, 0, kSTSgarl2_2w};
-act12 aexplainb_2w = {TEXT, 0, kSTSexplainb_2w};
-act12 aext1_2w = {TEXT, 0, kSTSrobot1_2w};
-act12 aext2_2w = {TEXT, 0, kSTSrobot2_2w};
-act12 aext3_2w = {TEXT, 0, kSTSrobot3_2w};
-act12 agard10_2w = {TEXT, 300, kSTSgard6_2w};
-act12 agard5_2w = {TEXT, 20, kSTSgard1_2w};
-act12 agard6_2w = {TEXT, 30, kSTSgard2_2w};
-act12 agard7_2w = {TEXT, 40, kSTSgard3_2w};
-act12 agard8_2w = {TEXT, 90, kSTSgard4_2w};
-act12 agard9_2w = {TEXT, 100, kSTSgard5_2w};
-act12 agenie1_2w = {TEXT, 0, kSTRub2_2w};
-act12 agiveb3_2w = {TEXT, 0, kSTCat2_2w};
-act12 aglook1_2w = {TEXT, 0, kSTGardInShed_2w};
-act12 aglook2_2w = {TEXT, 0, kSTGardShed_2w};
-act12 agotwill_2w = {TEXT, 0, kSTGotWill_2w};
-act12 ahdrink11_2w = {TEXT, 82, kSTHest4_2w};
-act12 ahdrink12_2w = {TEXT, 84, kSTSay1_2w};
-act12 ahdrink13_2w = {TEXT, 84, kSTSay2_2w};
-act12 ahdrink2_2w = {TEXT, 0, kSTHest1_2w};
-act12 ahdrink8_2w = {TEXT, 72, kSTHest2_2w};
-act12 ahdrink9_2w = {TEXT, 72, kSTHest3_2w};
-act12 ahest12_2w = {TEXT, 8, kSTHest6_2w};
-act12 ahest13_2w = {TEXT, 12, kSTHest7_2w};
-act12 ahest14_2w = {TEXT, 16, kSTHest8_2w};
-act12 ahest15_2w = {TEXT, 50, kSTHest9_2w};
-act12 ahestd2_2w = {TEXT, 0, kSTHest5_2w};
-act12 ahnod1_2w = {TEXT, 0, kSTNod1_2w};
-act12 ahnod2_2w = {TEXT, 0, kSTSay1_2w};
-act12 ahnod3_2w = {TEXT, 0, kSTSay2_2w};
-act12 akaboom1_2w = {TEXT, 0, kSTDyn5_2w};
-act12 amat5_2w = {TEXT, 0, kSTMatch4_2w};
-act12 amissed2_2w = {TEXT, 0, kSTFire1_2w};
-act12 amissed3_2w = {TEXT, 0, kSTFire2_2w};
-act12 amurd4_2w = {TEXT, 10, kSTArgue1_2w};
-act12 anobang_2w = {TEXT, 0, kSTDyn7_2w};
-act12 anobang2_2w = {TEXT, 0, kSTDyn6_2w};
-act12 anobell_2w = {TEXT, 8, kSTBell2_2w};
-act12 anogenie_2w = {TEXT, 0, kSTRub1_2w};
-act12 anoreply_2w = {TEXT, 0, kSTBrrr_2w};
-act12 anotrap_2w = {TEXT, 0, kSTTrap1_2w};
-act12 aom1_2w = {TEXT, 8, kSTSom1_2w};
-act12 aom10_2w = {TEXT, 50, kSTSom4_2w};
-act12 aom11_2w = {TEXT, 50, kSTSom5_2w};
-act12 aom12_2w = {TEXT, 50, kSTSom6_2w};
-act12 aom13_2w = {TEXT, 54, kSTSom7_2w};
-act12 aom14_2w = {TEXT, 54, kSTSom8_2w};
-act12 aom5_2w = {TEXT, 16, kSTSom2_2w};
-act12 aom6_2w = {TEXT, 20, kSTSom3_2w};
-act12 aom9_2w = {TEXT, 40, kSTSom3a_2w};
-act12 apen1_2w = {TEXT, 0, kSTSpen1_2w};
-act12 apen2_2w = {TEXT, 0, kSTSpen2_2w};
-act12 apen3_2w = {TEXT, 0, kSTSpen3_2w};
-act12 aphoto4_2w = {TEXT, 0, kSTSphoto_2w};
-act12 aphoto6_2w = {TEXT, 0, kSTSphoto1_2w};
-act12 apois1_2w = {TEXT, 0, kSTSnake1_2w};
-act12 apois2_2w = {TEXT, 0, kSTSnake2_2w};
-act12 apois3_2w = {TEXT, 0, kSTSnake3_2w};
-act12 apois4_2w = {TEXT, 0, kSTSnake4_2w};
-act12 aridkey2_2w = {TEXT, 0, kSTSridkey_2w};
-act12 arobot1_2w = {TEXT, 0, kSTFire3_2w};
-act12 arok_2w = {TEXT, 0, kSTWell1_2w};
-act12 arumbling_2w = {TEXT, 0, kSTRumble_2w};
-act12 arup_2w = {TEXT, 0, kSTDyn8_2w};
-act12 asafe1_2w = {TEXT, 0, kSTSsafe1_2w};
-act12 ascr31_2w = {TEXT, 0, kSTLock1_2w};
-act12 aserum1_2w = {TEXT, 0, kSTSserum1_2w};
-act12 aserum2_2w = {TEXT, 0, kSTSserum2_2w};
-act12 asilly_2w = {TEXT, 0, kSTDyn9_2w};
-act12 asniff_2w = {TEXT, 0, kSTCat1_2w};
-act12 asoggy_2w = {TEXT, 0, kSTMatch1_2w};
-act12 asonic1_2w = {TEXT, 0, kSTSsonic1_2w};
-act12 asonic2_2w = {TEXT, 0, kSTSsonic2_2w};
-act12 asonic3_2w = {TEXT, 0, kSTSsonic3_2w};
-act12 asonic4_2w = {TEXT, 0, kSTSsonic4_2w};
-act12 astick1_2w = {TEXT, 0, kSTWeee_2w};
-act12 astrike_2w = {TEXT, 0, kSTMatch2_2w};
-act12 astung_2w = {TEXT, 0, kSTStung_2w};
-act12 awarn_2w = {TEXT, 8, kSTSwarn_2w};
-act12 awarnz_2w = {TEXT, 8, kSTSwarnz_2w};
-act12 awho1_2w = {TEXT, 0, kSTTard1_2w};
-act12 awho2_2w = {TEXT, 0, kSTTard2_2w};
-act12 awill1_2w = {TEXT, 0, kSTSwill1_2w};
-act12 awill2_2w = {TEXT, 0, kSTSwill2_2w};
-act12 awill3_2w = {TEXT, 0, kSTSwill3_2w};
-act12 awill4_2w = {TEXT, 0, kSTSwill4_2w};
-act12 abell2_2w = {TEXT, 16, kSTMaid6_2w};
-act12 abug5a_2w = {TEXT, 0, kSTStingeroo_2w};
-act12 abug5b_2w = {TEXT, 0, kSTSbug5b_2w};
-act12 aclick_2w = {TEXT, 0, kSTClick_2w};
-act12 aempty_2w = {TEXT, 0, kSTEmpty_2w};
-act12 afaint1_2w = {TEXT, 5, kSTSfaint1_2w};
-act12 afaint10_2w = {TEXT, 35, kSTSfaint4_2w};
-act12 afaint5_2w = {TEXT, 20, kSTSfaint2_2w};
-act12 afaint9_2w = {TEXT, 35, kSTSfaint3_2w};
-act12 agone10_2w = {TEXT, 115, kSTSgone6_2w};
-act12 agone11_2w = {TEXT, 115, kSTSgone7_2w};
-act12 agone5_2w = {TEXT, 0, kSTSgone1_2w};
-act12 agone6_2w = {TEXT, 34, kSTSgone2_2w};
-act12 agone7_2w = {TEXT, 70, kSTSgone3_2w};
-act12 agone8_2w = {TEXT, 90, kSTSgone4_2w};
-act12 agone9_2w = {TEXT, 115, kSTSgone5_2w};
-act12 aharry3_2w = {TEXT, 4, kSTOrgan1_2w};
-act12 aharry4_2w = {TEXT, 4, kSTOrgan2_2w};
-act12 aharry5_2w = {TEXT, 4, kSTOrgan3_2w};
-act12 aharry7_2w = {TEXT, 8, kSTOrgan4_2w};
-act12 ahole_2w = {TEXT, 0, kSTFirst2_2w};
-act12 akeyhole1_2w = {TEXT, 0, kSTHole1_2w};
-act12 alie1_2w = {TEXT, 13, kSTTired_2w};
-act12 alie2_2w = {TEXT, 18, kSTTired2_2w};
-act12 amaid10_2w = {TEXT, 90 * NORMAL_TPS, kSTSmaid1_8_2w};
-act12 amaid11_2w = {TEXT, 99 * NORMAL_TPS, kSTSmaid1_9_2w};
-act12 amaid12_2w = {TEXT, 0, kSTSmaid1_10_2w};
-act12 amaid3_2w = {TEXT, 4, kSTSmaid1_1_2w};
-act12 amaid4_2w = {TEXT, 17, kSTSmaid1_2_2w};
-act12 amaid5_2w = {TEXT, 17, kSTSmaid1_3_2w};
-act12 amaid6_2w = {TEXT, 17, kSTSmaid1_4_2w};
-act12 amaid7_2w = {TEXT, 30, kSTSmaid1_5_2w};
-act12 amaid8_2w = {TEXT, 30 * NORMAL_TPS, kSTSmaid1_6_2w};
-act12 amaid9_2w = {TEXT, 60 * NORMAL_TPS, kSTSmaid1_7_2w};
-act12 amaidp3_2w = {TEXT, 8, kSTMaid1_2w};
-act12 amaidp4_2w = {TEXT, 8, kSTMaid2_2w};
-act12 amaidp5_2w = {TEXT, 8, kSTMaid3_2w};
-act12 amaidp7_2w = {TEXT, 12, kSTMaid4_2w};
-act12 amaidp8_2w = {TEXT, 12, kSTMaid5_2w};
-act12 anocarry_2w = {TEXT, 0, kSTNocarry_2w};
-act12 anopurps_2w = {TEXT, 0, kSTNopurps_2w};
-act12 aok_2w = {TEXT, 0, kSTOkgen_2w};
-act12 ascr21_2w = {TEXT, 0, kSTSfirst_2w};
-act12 astory_2w = {TEXT, STORYDELAY, kSTStory_2w};
+act12 alookbrg_2w = {TEXT, 0, kSTLookBridge_2w};
+act12 astuck1_2w = {TEXT, 0, kSTDoorStuck_2w};
+act12 atalkg_2w = {TEXT, 0, kSTIgnore_2w};
+act12 aball4_2w = {TEXT, 2, kSTBalloon1_2w};
+act12 aball5_2w = {TEXT, 2, kSTBalloon2_2w};
+act12 aball6_2w = {TEXT, 2, kSTBalloon3_2w};
+act12 abanana1_2w = {TEXT, 0, kSTBanana1_2w};
+act12 abanana3_2w = {TEXT, 0, kSTBanana2_2w};
+act12 abell_2w = {TEXT, 0, kSTBell1_2w};
+act12 abell1_2w = {TEXT, 8, kSTMaid7_2w};
+act12 abite2_2w = {TEXT, 0, kSTSnake5_2w};
+act12 ablah_2w = {TEXT, 8, kSTBlah_2w};
+act12 aboom_2w = {TEXT, 0, kSTDyn4_2w};
+act12 acallp2_2w = {TEXT, 0, kSTCall1_2w};
+act12 acallp3_2w = {TEXT, 0, kSTCall2_2w};
+act12 acallp4_2w = {TEXT, 0, kSTCall3_2w};
+act12 acallp5_2w = {TEXT, 0, kSTCall4_2w};
+act12 acallp6_2w = {TEXT, 0, kSTCall5_2w};
+act12 acallp7_2w = {TEXT, 0, kSTCall6_2w};
+act12 acantpush_2w = {TEXT, 0, kSTPush1_2w};
+act12 acat1_2w = {TEXT, 0, kSTCat3_2w};
+act12 acat4_2w = {TEXT, 0, kSTMaid8_2w};
+act12 achasm1_2w = {TEXT, 12, kSTChasm1_2w};
+act12 acheat1_2w = {TEXT, 0, kSTScheat1_2w};
+act12 acheat2_2w = {TEXT, 0, kSTScheat2_2w};
+act12 aclimax1_2w = {TEXT, 0, kSTSclimax1_2w};
+act12 aclimax2_2w = {TEXT, 8, kSTSclimax2_2w};
+act12 aclimax3_2w = {TEXT, 80, kSTSclimax3_2w};
+act12 aclimax4_2w = {TEXT, 80, kSTSclimax4_2w};
+act12 aclimax5_2w = {TEXT, 80, kSTSclimax5_2w};
+act12 aclimax6_2w = {TEXT, 80, kSTSclimax6_2w};
+act12 aclue09a_2w = {TEXT, 0, kSTSclue09a_2w};
+act12 aclue09b_2w = {TEXT, 0, kSTSclue09b_2w};
+act12 aclue09c_2w = {TEXT, 0, kSTSclue09c_2w};
+act12 acomb1_2w = {TEXT, 0, kSTScomb1_2w};
+act12 acomb2_2w = {TEXT, 0, kSTScomb2_2w};
+act12 acook1_2w = {TEXT, 8, kSTCook1_2w};
+act12 acook2_2w = {TEXT, 8, kSTCook2_2w};
+act12 acook3_2w = {TEXT, 8, kSTCook3_2w};
+act12 acook4_2w = {TEXT, 24, kSTCook4_2w};
+act12 acook5_2w = {TEXT, 24, kSTCook5_2w};
+act12 adialed_2w = {TEXT, 0, kSTSdialed_2w};
+act12 adidnt1_2w = {TEXT, 0, kSTSdidnt1_2w};
+act12 adidnt2_2w = {TEXT, 0, kSTSdidnt2_2w};
+act12 adog1_2w = {TEXT, 0, kSTDyn2_2w};
+act12 adone1_2w = {TEXT, 10, kSTSdone1_2w};
+act12 adone13_2w = {TEXT, 50, kSTSdone5_2w};
+act12 adone14_2w = {TEXT, 50, kSTSdone6_2w};
+act12 adone15_2w = {TEXT, 50, kSTSdone7_2w};
+act12 adone2_2w = {TEXT, 10, kSTSdone2_2w};
+act12 adone3_2w = {TEXT, 10, kSTSdone3_2w};
+act12 adone4_2w = {TEXT, 10, kSTSdone4_2w};
+act12 adraught_2w = {TEXT, 5 * 60 * NORMAL_TPS_v2d, kSTDraught_2w};
+act12 adropdyn2_2w = {TEXT, 0, kSTDyn3_2w};
+act12 adumb12_2w = {TEXT, 0, kSTDumb2_2w};
+act12 adumb2_2w = {TEXT, 0, kSTDumb1_2w};
+act12 adyn1_2w = {TEXT, 0, kSTDyn1_2w};
+act12 aeatban_2w = {TEXT, 0, kSTSeatbanana_2w};
+act12 aeatgarl1_2w = {TEXT, 0, kSTSgarl1_2w};
+act12 aeatgarl2_2w = {TEXT, 0, kSTSgarl2_2w};
+act12 aexplainb_2w = {TEXT, 0, kSTSexplainb_2w};
+act12 aext1_2w = {TEXT, 0, kSTSrobot1_2w};
+act12 aext2_2w = {TEXT, 0, kSTSrobot2_2w};
+act12 aext3_2w = {TEXT, 0, kSTSrobot3_2w};
+act12 agard10_2w = {TEXT, 300, kSTSgard6_2w};
+act12 agard5_2w = {TEXT, 20, kSTSgard1_2w};
+act12 agard6_2w = {TEXT, 30, kSTSgard2_2w};
+act12 agard7_2w = {TEXT, 40, kSTSgard3_2w};
+act12 agard8_2w = {TEXT, 90, kSTSgard4_2w};
+act12 agard9_2w = {TEXT, 100, kSTSgard5_2w};
+act12 agenie1_2w = {TEXT, 0, kSTRub2_2w};
+act12 agiveb3_2w = {TEXT, 0, kSTCat2_2w};
+act12 aglook1_2w = {TEXT, 0, kSTGardInShed_2w};
+act12 aglook2_2w = {TEXT, 0, kSTGardShed_2w};
+act12 agotwill_2w = {TEXT, 0, kSTGotWill_2w};
+act12 ahdrink11_2w = {TEXT, 82, kSTHest4_2w};
+act12 ahdrink12_2w = {TEXT, 84, kSTSay1_2w};
+act12 ahdrink13_2w = {TEXT, 84, kSTSay2_2w};
+act12 ahdrink2_2w = {TEXT, 0, kSTHest1_2w};
+act12 ahdrink8_2w = {TEXT, 72, kSTHest2_2w};
+act12 ahdrink9_2w = {TEXT, 72, kSTHest3_2w};
+act12 ahest12_2w = {TEXT, 8, kSTHest6_2w};
+act12 ahest13_2w = {TEXT, 12, kSTHest7_2w};
+act12 ahest14_2w = {TEXT, 16, kSTHest8_2w};
+act12 ahest15_2w = {TEXT, 50, kSTHest9_2w};
+act12 ahestd2_2w = {TEXT, 0, kSTHest5_2w};
+act12 ahnod1_2w = {TEXT, 0, kSTNod1_2w};
+act12 ahnod2_2w = {TEXT, 0, kSTSay1_2w};
+act12 ahnod3_2w = {TEXT, 0, kSTSay2_2w};
+act12 akaboom1_2w = {TEXT, 0, kSTDyn5_2w};
+act12 amat5_2w = {TEXT, 0, kSTMatch4_2w};
+act12 amissed2_2w = {TEXT, 0, kSTFire1_2w};
+act12 amissed3_2w = {TEXT, 0, kSTFire2_2w};
+act12 amurd4_2w = {TEXT, 10, kSTArgue1_2w};
+act12 anobang_2w = {TEXT, 0, kSTDyn7_2w};
+act12 anobang2_2w = {TEXT, 0, kSTDyn6_2w};
+act12 anobell_2w = {TEXT, 8, kSTBell2_2w};
+act12 anogenie_2w = {TEXT, 0, kSTRub1_2w};
+act12 anoreply_2w = {TEXT, 0, kSTBrrr_2w};
+act12 anotrap_2w = {TEXT, 0, kSTTrap1_2w};
+act12 aom1_2w = {TEXT, 8, kSTSom1_2w};
+act12 aom10_2w = {TEXT, 50, kSTSom4_2w};
+act12 aom11_2w = {TEXT, 50, kSTSom5_2w};
+act12 aom12_2w = {TEXT, 50, kSTSom6_2w};
+act12 aom13_2w = {TEXT, 54, kSTSom7_2w};
+act12 aom14_2w = {TEXT, 54, kSTSom8_2w};
+act12 aom5_2w = {TEXT, 16, kSTSom2_2w};
+act12 aom6_2w = {TEXT, 20, kSTSom3_2w};
+act12 aom9_2w = {TEXT, 40, kSTSom3a_2w};
+act12 apen1_2w = {TEXT, 0, kSTSpen1_2w};
+act12 apen2_2w = {TEXT, 0, kSTSpen2_2w};
+act12 apen3_2w = {TEXT, 0, kSTSpen3_2w};
+act12 aphoto4_2w = {TEXT, 0, kSTSphoto_2w};
+act12 aphoto6_2w = {TEXT, 0, kSTSphoto1_2w};
+act12 apois1_2w = {TEXT, 0, kSTSnake1_2w};
+act12 apois2_2w = {TEXT, 0, kSTSnake2_2w};
+act12 apois3_2w = {TEXT, 0, kSTSnake3_2w};
+act12 apois4_2w = {TEXT, 0, kSTSnake4_2w};
+act12 aridkey2_2w = {TEXT, 0, kSTSridkey_2w};
+act12 arobot1_2w = {TEXT, 0, kSTFire3_2w};
+act12 arok_2w = {TEXT, 0, kSTWell1_2w};
+act12 arumbling_2w = {TEXT, 0, kSTRumble_2w};
+act12 arup_2w = {TEXT, 0, kSTDyn8_2w};
+act12 asafe1_2w = {TEXT, 0, kSTSsafe1_2w};
+act12 ascr31_2w = {TEXT, 0, kSTLock1_2w};
+act12 aserum1_2w = {TEXT, 0, kSTSserum1_2w};
+act12 aserum2_2w = {TEXT, 0, kSTSserum2_2w};
+act12 asilly_2w = {TEXT, 0, kSTDyn9_2w};
+act12 asniff_2w = {TEXT, 0, kSTCat1_2w};
+act12 asoggy_2w = {TEXT, 0, kSTMatch1_2w};
+act12 asonic1_2w = {TEXT, 0, kSTSsonic1_2w};
+act12 asonic2_2w = {TEXT, 0, kSTSsonic2_2w};
+act12 asonic3_2w = {TEXT, 0, kSTSsonic3_2w};
+act12 asonic4_2w = {TEXT, 0, kSTSsonic4_2w};
+act12 astick1_2w = {TEXT, 0, kSTWeee_2w};
+act12 astrike_2w = {TEXT, 0, kSTMatch2_2w};
+act12 astung_2w = {TEXT, 0, kSTStung_2w};
+act12 awarn_2w = {TEXT, 8, kSTSwarn_2w};
+act12 awarnz_2w = {TEXT, 8, kSTSwarnz_2w};
+act12 awho1_2w = {TEXT, 0, kSTTard1_2w};
+act12 awho2_2w = {TEXT, 0, kSTTard2_2w};
+act12 awill1_2w = {TEXT, 0, kSTSwill1_2w};
+act12 awill2_2w = {TEXT, 0, kSTSwill2_2w};
+act12 awill3_2w = {TEXT, 0, kSTSwill3_2w};
+act12 awill4_2w = {TEXT, 0, kSTSwill4_2w};
+act12 abell2_2w = {TEXT, 16, kSTMaid6_2w};
+act12 abug5a_2w = {TEXT, 0, kSTStingeroo_2w};
+act12 abug5b_2w = {TEXT, 0, kSTSbug5b_2w};
+act12 aclick_2w = {TEXT, 0, kSTClick_2w};
+act12 aempty_2w = {TEXT, 0, kSTEmpty_2w};
+act12 afaint1_2w = {TEXT, 5, kSTSfaint1_2w};
+act12 afaint10_2w = {TEXT, 35, kSTSfaint4_2w};
+act12 afaint5_2w = {TEXT, 20, kSTSfaint2_2w};
+act12 afaint9_2w = {TEXT, 35, kSTSfaint3_2w};
+act12 agone10_2w = {TEXT, 115, kSTSgone6_2w};
+act12 agone11_2w = {TEXT, 115, kSTSgone7_2w};
+act12 agone5_2w = {TEXT, 0, kSTSgone1_2w};
+act12 agone6_2w = {TEXT, 34, kSTSgone2_2w};
+act12 agone7_2w = {TEXT, 70, kSTSgone3_2w};
+act12 agone8_2w = {TEXT, 90, kSTSgone4_2w};
+act12 agone9_2w = {TEXT, 115, kSTSgone5_2w};
+act12 aharry3_2w = {TEXT, 4, kSTOrgan1_2w};
+act12 aharry4_2w = {TEXT, 4, kSTOrgan2_2w};
+act12 aharry5_2w = {TEXT, 4, kSTOrgan3_2w};
+act12 aharry7_2w = {TEXT, 8, kSTOrgan4_2w};
+act12 ahole_2w = {TEXT, 0, kSTFirst2_2w};
+act12 akeyhole1_2w = {TEXT, 0, kSTHole1_2w};
+act12 alie1_2w = {TEXT, 13, kSTTired_2w};
+act12 alie2_2w = {TEXT, 18, kSTTired2_2w};
+act12 amaid10_2w = {TEXT, 90 * NORMAL_TPS_v2d, kSTSmaid1_8_2w};
+act12 amaid11_2w = {TEXT, 99 * NORMAL_TPS_v2d, kSTSmaid1_9_2w};
+act12 amaid12_2w = {TEXT, 0, kSTSmaid1_10_2w};
+act12 amaid3_2w = {TEXT, 4, kSTSmaid1_1_2w};
+act12 amaid4_2w = {TEXT, 17, kSTSmaid1_2_2w};
+act12 amaid5_2w = {TEXT, 17, kSTSmaid1_3_2w};
+act12 amaid6_2w = {TEXT, 17, kSTSmaid1_4_2w};
+act12 amaid7_2w = {TEXT, 30, kSTSmaid1_5_2w};
+act12 amaid8_2w = {TEXT, 30 * NORMAL_TPS_v2d, kSTSmaid1_6_2w};
+act12 amaid9_2w = {TEXT, 60 * NORMAL_TPS_v2d, kSTSmaid1_7_2w};
+act12 amaidp3_2w = {TEXT, 8, kSTMaid1_2w};
+act12 amaidp4_2w = {TEXT, 8, kSTMaid2_2w};
+act12 amaidp5_2w = {TEXT, 8, kSTMaid3_2w};
+act12 amaidp7_2w = {TEXT, 12, kSTMaid4_2w};
+act12 amaidp8_2w = {TEXT, 12, kSTMaid5_2w};
+act12 anocarry_2w = {TEXT, 0, kSTNocarry_2w};
+act12 anopurps_2w = {TEXT, 0, kSTNopurps_2w};
+act12 aok_2w = {TEXT, 0, kSTOkgen_2w};
+act12 ascr21_2w = {TEXT, 0, kSTSfirst_2w};
+act12 astory_2w = {TEXT, STORYDELAY, kSTStory_2w};
act13 ascr33b_2w = {SWAP_IMAGES, 4, HERO, PENNY_2w};
act13 aswaphero_2w = {SWAP_IMAGES, 120, HERO, PENNY_2w};
@@ -7250,7 +7269,7 @@ act19 achkgates_2w = {TEST_STATE_BITS, 2, BUTTON_2w, 16, kALswgates_2w, kALru
act19 achkglight_2w = {TEST_STATE_BITS, 2, BUTTON_2w, 2, kALglightoff_2w, kALglighton_2w};
act19 achkgo_2w = {TEST_STATE_BITS, 0, BUTTON_2w, 32, kALgoopen_2w, kALgoclosed_2w};
act19 achkslight_2w = {TEST_STATE_BITS, 2, BUTTON_2w, 1, kALslightoff_2w, kALslighton_2w};
-act19 achksong_2w = {TEST_STATE_BITS, 0, COP_2w, 8, 0, kALsong4_2w};
+act19 achksong_2w = {TEST_STATE_BITS, 0, COP_2w, 8, 0, kALsong4_2w};
act19 achkzapper_2w = {TEST_STATE_BITS, 2, BUTTON_2w, 4, kALswzapper_2w, kALclick_2w};
act19 aswgates_2w = {TEST_STATE_BITS, 2, BUTTON_2w, 32, kALgatescls_2w, kALgatesopn_2w};
act19 aswzapper_2w = {TEST_STATE_BITS, 2, BUTTON_2w, 8, kALzapperoff_2w, kALzapperon_2w};
@@ -7365,14 +7384,14 @@ act33 amaidc11_2w = {INIT_SCREEN, 30, MAID_2w, 31};
act33 amaidc2_2w = {INIT_SCREEN, 8, MAID_2w, 32};
act33 amaidp1_2w = {INIT_SCREEN, 0, MAID_2w, 31};
-act34 abang1_2w = {AGSCHEDULE, 6 * NORMAL_TPS, kALbang2_2w};
-act34 abite3_2w = {AGSCHEDULE, 60 * NORMAL_TPS, kALpois1_2w};
-act34 abite4_2w = {AGSCHEDULE, 200 * NORMAL_TPS, kALpois2_2w};
-act34 abite5_2w = {AGSCHEDULE, 290 * NORMAL_TPS, kALpois3_2w};
-act34 abite6_2w = {AGSCHEDULE, 300 * NORMAL_TPS, kALpois4_2w};
-act34 acat3_2w = {AGSCHEDULE, 8 * NORMAL_TPS, kALchkcarry_2w};
-act34 akaboom2_2w = {AGSCHEDULE, 1, kALkaboom3_2w};
-act34 amaidb6_2w = {AGSCHEDULE, 8 * NORMAL_TPS, kALmaidbk_2w};
+act34 abang1_2w = {AGSCHEDULE, 6 * NORMAL_TPS_v2d, kALbang2_2w};
+act34 abite3_2w = {AGSCHEDULE, 60 * NORMAL_TPS_v2d, kALpois1_2w};
+act34 abite4_2w = {AGSCHEDULE, 200 * NORMAL_TPS_v2d, kALpois2_2w};
+act34 abite5_2w = {AGSCHEDULE, 290 * NORMAL_TPS_v2d, kALpois3_2w};
+act34 abite6_2w = {AGSCHEDULE, 300 * NORMAL_TPS_v2d, kALpois4_2w};
+act34 acat3_2w = {AGSCHEDULE, 8 * NORMAL_TPS_v2d, kALchkcarry_2w};
+act34 akaboom2_2w = {AGSCHEDULE, 1, kALkaboom3_2w};
+act34 amaidb6_2w = {AGSCHEDULE, 8 * NORMAL_TPS_v2d, kALmaidbk_2w};
act35 amap0_2w = {REMAPPAL, 0, _TLIGHTMAGENTA, _TLIGHTMAGENTA};
act35 amap1_2w = {REMAPPAL, 0, _TLIGHTMAGENTA, _TBLACK};
@@ -8006,50 +8025,50 @@ act8 ascr_wfall_clf_3w = {NEW_SCREEN, 0, CLIFF_3w};
act8 ascr_wfallb_wbase_3w = {NEW_SCREEN, 0, WBASE_3w};
act8 aweb23_3w = {NEW_SCREEN, 117, CRASH_3w};
-act9 abrg_msg2_3w = {INIT_OBJSTATE, 0, VINE_3w, 1};
-act9 acageempty_3w = {INIT_OBJSTATE, 0, CAGE_3w, 0};
-act9 acamp0a_3w = {INIT_OBJSTATE, 4, NAT2_3w, 0};
-act9 acom0b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 1};
-act9 acom1b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 2};
-act9 acom2b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 3};
-act9 acom3b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 4};
-act9 acom4b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 5};
-act9 acom5b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 6};
-act9 acom6b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 7};
-act9 acom7b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 8};
-act9 acom8b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 9};
-act9 adart1_3w = {INIT_OBJSTATE, 0, BLOWPIPE_3w, 1};
-act9 adn_3w = {INIT_OBJSTATE, 0, HERO, 0};
-act9 adrink_3w = {INIT_OBJSTATE, 0, FLASK_3w, 0};
-act9 adropcheese3_3w = {INIT_OBJSTATE, 0, CHEESE_3w, 1};
-act9 aelewoken_3w = {INIT_OBJSTATE, 0, ELEPHANT_3w, 0};
-act9 aemptyflask_3w = {INIT_OBJSTATE, 0, FLASK_3w, 0};
-act9 aendaction_3w = {INIT_OBJSTATE, DARTTIME + 30, E_EYES_3w, 0};
-act9 aenter1_3w = {INIT_OBJSTATE, 0, MOUSE_3w, 2};
-act9 aenter9_3w = {INIT_OBJSTATE, 0, CAGE_3w, 1};
-act9 aex7_3w = {INIT_OBJSTATE, 0, GHOST_3w, 1};
-act9 aex9_3w = {INIT_OBJSTATE, 0, VINE3_3w, 1};
-act9 afillmagic3_3w = {INIT_OBJSTATE, 0, FLASK_3w, 2};
-act9 afillord2_3w = {INIT_OBJSTATE, 0, FLASK_3w, 1};
-act9 afindb1_3w = {INIT_OBJSTATE, 0, BOOK_3w, 1};
-act9 agive3_3w = {INIT_OBJSTATE, 0, NAT1_3w, 10};
-act9 agot1_3w = {INIT_OBJSTATE, 0, DOCTOR_3w, 1};
-act9 ahelp2_3w = {INIT_OBJSTATE, 0, HERO, 1};
-act9 ahole5a_3w = {INIT_OBJSTATE, 0, MOUSE_3w, 1};
-act9 ahole5b_3w = {INIT_OBJSTATE, 0, MOUSE_3w, 0};
-act9 amakeclay2_3w = {INIT_OBJSTATE, 0, CLAY_3w, 1};
-act9 amission1_3w = {INIT_OBJSTATE, 0, PENNY_3w, 2};
-act9 amousefree_3w = {INIT_OBJSTATE, 0, MOUSE_3w, 3};
-act9 aoldstate_3w = {INIT_OBJSTATE, 0, MOUTH_3w, 1};
-act9 aopen2_3w = {INIT_OBJSTATE, 0, CDOOR_3w, 1};
-act9 apause0_3w = {INIT_OBJSTATE, 3 * NORMAL_TPS, NAT2_3w, 0};
-act9 apause1_3w = {INIT_OBJSTATE, 0, NAT2_3w, 1};
-act9 astartaction_3w = {INIT_OBJSTATE, 0, E_EYES_3w, 1};
-act9 astick3_3w = {INIT_OBJSTATE, 0, DOCTOR_3w, 2};
-act9 atakecheese1_3w = {INIT_OBJSTATE, 0, CHEESE_3w, 0};
-act9 aup_3w = {INIT_OBJSTATE, 0, HERO, 1};
-act9 avine7_3w = {INIT_OBJSTATE, 0, BLOCK1_3w, 1};
-act9 aweb1_3w = {INIT_OBJSTATE, 0, PENNY_3w, 1};
+act9 abrg_msg2_3w = {INIT_OBJSTATE, 0, VINE_3w, 1};
+act9 acageempty_3w = {INIT_OBJSTATE, 0, CAGE_3w, 0};
+act9 acamp0a_3w = {INIT_OBJSTATE, 4, NAT2_3w, 0};
+act9 acom0b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 1};
+act9 acom1b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 2};
+act9 acom2b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 3};
+act9 acom3b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 4};
+act9 acom4b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 5};
+act9 acom5b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 6};
+act9 acom6b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 7};
+act9 acom7b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 8};
+act9 acom8b_3w = {INIT_OBJSTATE, 0, NAT1_3w, 9};
+act9 adart1_3w = {INIT_OBJSTATE, 0, BLOWPIPE_3w, 1};
+act9 adn_3w = {INIT_OBJSTATE, 0, HERO, 0};
+act9 adrink_3w = {INIT_OBJSTATE, 0, FLASK_3w, 0};
+act9 adropcheese3_3w = {INIT_OBJSTATE, 0, CHEESE_3w, 1};
+act9 aelewoken_3w = {INIT_OBJSTATE, 0, ELEPHANT_3w, 0};
+act9 aemptyflask_3w = {INIT_OBJSTATE, 0, FLASK_3w, 0};
+act9 aendaction_3w = {INIT_OBJSTATE, DARTTIME + 30, E_EYES_3w, 0};
+act9 aenter1_3w = {INIT_OBJSTATE, 0, MOUSE_3w, 2};
+act9 aenter9_3w = {INIT_OBJSTATE, 0, CAGE_3w, 1};
+act9 aex7_3w = {INIT_OBJSTATE, 0, GHOST_3w, 1};
+act9 aex9_3w = {INIT_OBJSTATE, 0, VINE3_3w, 1};
+act9 afillmagic3_3w = {INIT_OBJSTATE, 0, FLASK_3w, 2};
+act9 afillord2_3w = {INIT_OBJSTATE, 0, FLASK_3w, 1};
+act9 afindb1_3w = {INIT_OBJSTATE, 0, BOOK_3w, 1};
+act9 agive3_3w = {INIT_OBJSTATE, 0, NAT1_3w, 10};
+act9 agot1_3w = {INIT_OBJSTATE, 0, DOCTOR_3w, 1};
+act9 ahelp2_3w = {INIT_OBJSTATE, 0, HERO, 1};
+act9 ahole5a_3w = {INIT_OBJSTATE, 0, MOUSE_3w, 1};
+act9 ahole5b_3w = {INIT_OBJSTATE, 0, MOUSE_3w, 0};
+act9 amakeclay2_3w = {INIT_OBJSTATE, 0, CLAY_3w, 1};
+act9 amission1_3w = {INIT_OBJSTATE, 0, PENNY_3w, 2};
+act9 amousefree_3w = {INIT_OBJSTATE, 0, MOUSE_3w, 3};
+act9 aoldstate_3w = {INIT_OBJSTATE, 0, MOUTH_3w, 1};
+act9 aopen2_3w = {INIT_OBJSTATE, 0, CDOOR_3w, 1};
+act9 apause0_3w = {INIT_OBJSTATE, 3 * NORMAL_TPS_v2d, NAT2_3w, 0};
+act9 apause1_3w = {INIT_OBJSTATE, 0, NAT2_3w, 1};
+act9 astartaction_3w = {INIT_OBJSTATE, 0, E_EYES_3w, 1};
+act9 astick3_3w = {INIT_OBJSTATE, 0, DOCTOR_3w, 2};
+act9 atakecheese1_3w = {INIT_OBJSTATE, 0, CHEESE_3w, 0};
+act9 aup_3w = {INIT_OBJSTATE, 0, HERO, 1};
+act9 avine7_3w = {INIT_OBJSTATE, 0, BLOCK1_3w, 1};
+act9 aweb1_3w = {INIT_OBJSTATE, 0, PENNY_3w, 1};
act10 acamp1a_3w = {INIT_PATH, 0, NAT2_3w, AUTO, 0, 0};
act10 acamp1b_3w = {INIT_PATH, 0, NATG_3w, AUTO, 0, 0};
@@ -8072,62 +8091,62 @@ act10 adisable_3w = {INIT_PATH, 0, HERO, AUTO, 0, 0};
act10 aenable_3w = {INIT_PATH, 0, HERO, USER, 0, 0};
act10 aquiet_3w = {INIT_PATH, 0, HERO, QUIET, 0, 0};
-act11 aactiontest1_3w = {COND_R, 0, E_EYES_3w, 1, 0, kALoktoleave1_3w};
-act11 aactiontest2_3w = {COND_R, 0, E_EYES_3w, 1, 0, kALoktoleave2_3w};
-act11 ablktest_3w = {COND_R, 0, BLOCK1_3w, 0, kALblk1_3w, 0};
-act11 abrgmsgtest_3w = {COND_R, 0, VINE_3w, 0, kALbrg_clftop_msg_3w, kALbrg_clftop1_3w};
-act11 abrgtest_3w = {COND_R, 0, VINE_3w, 0, kALbrg_ok_3w, kALbrg_down_3w};
-act11 abridgetest_3w = {COND_R, 0, BLOCK1_3w, 0, kALbridge_3w, 0};
-act11 acagetest_3w = {COND_R, 0, MOUSE_3w, 2, 0, kALpostest_3w};
-act11 acagetest1_3w = {COND_R, 0, MOUSE_3w, 2, kALcagetest2_3w, kALok_3w};
-act11 acagetest5_3w = {COND_R, 0, MOUSE_3w, 2, kALcageprompt_3w, kALmousegone_3w};
-act11 acamptest_3w = {COND_R, 0, NAT1_3w, 0, kALcampers_3w, kALchase_3w};
-act11 acavetest_3w = {COND_R, 0, GHOST_3w, 0, kALspirit_3w, kALcave_man_3w};
-act11 acrashtest1_3w = {COND_R, 0, PENNY_3w, 0, kALcrashed_3w, kALcrashtest2_3w};
-act11 acrashtest2_3w = {COND_R, 0, PENNY_3w, 1, kALcryhelp_3w, 0};
-act11 adartedtest_3w = {COND_R, 0, BLOWPIPE_3w, 0, kALdodart_3w, kALdarted_3w};
-act11 adoctest_3w = {COND_R, 0, DOCTOR_3w, 0, kALdoc_3w, 0};
-act11 adrinktest_3w = {COND_R, 0, FLASK_3w, 0, kALdrinkno_3w, kALdrinkyes_3w};
-act11 aeletest1_3w = {COND_R, 0, ELEPHANT_3w, 1, kALele_sleep_3w, kALeletest2_3w};
-act11 aeletest2_3w = {COND_R, 0, ELEPHANT_3w, 0, kALeleblink_3w, 0};
-act11 aemptytest1_3w = {COND_R, 0, FLASK_3w, 2, kALemptymagic_3w, kALemptytest2_3w};
-act11 aemptytest2_3w = {COND_R, 0, FLASK_3w, 1, kALemptyord_3w, kALdrinkno_3w};
-act11 aentertest1_3w = {COND_R, 0, CHEESE_3w, 1, kALentertest2_3w, 0};
-act11 aentertest2_3w = {COND_R, 0, MOUSE_3w, 0, kALentertest3_3w, 0};
-act11 aexotest1_3w = {COND_R, 0, GHOST_3w, 0, kALexotest2_3w, kALexordone_3w};
-act11 afindbtest_3w = {COND_R, 0, BOOK_3w, 0, kALfindit_3w, 0};
-act11 aflasktest2_3w = {COND_R, 0, FLASK_3w, 2, kALremedy_3w, kALflasktest3_3w};
-act11 aflasktest3_3w = {COND_R, 0, FLASK_3w, 1, kALnoremedy_3w, kALrefuseflask_3w};
-act11 agettest2_3w = {COND_R, 0, DOCTOR_3w, 0, kALgot_3w, 0};
-act11 agivetest_3w = {COND_R, 0, NAT1_3w, 10, kALrefuse_3w, kALgive_3w};
-act11 ahoriz1_3w = {COND_R, 0, HERO, 0, kALup_3w, 0};
-act11 ahoriz2_3w = {COND_R, 0, HERO, 1, kALdn_3w, 0};
-act11 anat0_3w = {COND_R, 0, NAT1_3w, 0, kALcom0_3w, kALnat1_3w};
-act11 anat1_3w = {COND_R, 0, NAT1_3w, 1, kALcom1_3w, kALnat2_3w};
-act11 anat2_3w = {COND_R, 0, NAT1_3w, 2, kALcom2_3w, kALnat3_3w};
-act11 anat3_3w = {COND_R, 0, NAT1_3w, 3, kALcom3_3w, kALnat4_3w};
-act11 anat4_3w = {COND_R, 0, NAT1_3w, 4, kALcom4_3w, kALnat5_3w};
-act11 anat5_3w = {COND_R, 0, NAT1_3w, 5, kALcom5_3w, kALnat6_3w};
-act11 anat6_3w = {COND_R, 0, NAT1_3w, 6, kALcom6_3w, kALnat7_3w};
-act11 anat7_3w = {COND_R, 0, NAT1_3w, 7, kALcom7_3w, kALnat8_3w};
-act11 anat8_3w = {COND_R, 0, NAT1_3w, 8, kALcom8_3w, 0};
-act11 aold5_3w = {COND_R, 0, FLASK_3w, 2, kALold6_3w, kALwrong_3w};
-act11 aoldmantest_3w = {COND_R, 0, MOUTH_3w, 0, kALoldfirst_3w, kALoldsubseq_3w};
-act11 aopentest_3w = {COND_R, 0, DOCTOR_3w, 1, kALprod_3w, kALopencdoor_3w};
-act11 apausetest_3w = {COND_R, 0, NAT2_3w, 1, 0, kALcomment_3w};
-act11 apostest_3w = {COND_R, 0, MOUSE_3w, 0, kALmousel_3w, kALmouser_3w};
-act11 aspirittest_3w = {COND_R, 0, GHOST_3w, 0, kALwarn_3w, 0};
-act11 asticktest1_3w = {COND_R, 0, DOCTOR_3w, 2, kALstuckpin_3w, kALsticktest2_3w};
-act11 asticktest2_3w = {COND_R, 0, CLAY_3w, 1, kALstickpin_3w, kALnostickpin_3w};
-act11 ataketest1_3w = {COND_R, 0, MOUSE_3w, 2, kALtakeit_3w, kALcanttake_3w};
-act11 ataketest2_3w = {COND_R, 0, MOUSE_3w, 3, kALtakeit_3w, kALtaketest1_3w};
-act11 atalktest1_3w = {COND_R, 0, NAT1_3w, 9, kALnat9_3w, kALnative_3w};
-act11 atdtest_3w = {COND_R, 0, DOCTOR_3w, 2, kALtalkdoc2_3w, kALtalkdoc1_3w};
-act11 atiptest_3w = {COND_R, 60 * NORMAL_TPS, BLOCK1_3w, 0, kALbtipprompt_3w, 0};
-act11 auntietest_3w = {COND_R, 0, BLOCK1_3w, 0, kALnottied_3w, kALuntie_3w};
-act11 avinetest_3w = {COND_R, 0, BLOCK1_3w, 0, kALtievine_3w, kALtied_3w};
-act11 awebtest1_3w = {COND_R, 0, PENNY_3w, 0, kALspider_3w, kALwebtest2_3w};
-act11 awebtest2_3w = {COND_R, 0, PENNY_3w, 1, kALmission_3w, kALreturn_3w};
+act11 aactiontest1_3w = {COND_R, 0, E_EYES_3w, 1, 0, kALoktoleave1_3w};
+act11 aactiontest2_3w = {COND_R, 0, E_EYES_3w, 1, 0, kALoktoleave2_3w};
+act11 ablktest_3w = {COND_R, 0, BLOCK1_3w, 0, kALblk1_3w, 0};
+act11 abrgmsgtest_3w = {COND_R, 0, VINE_3w, 0, kALbrg_clftop_msg_3w, kALbrg_clftop1_3w};
+act11 abrgtest_3w = {COND_R, 0, VINE_3w, 0, kALbrg_ok_3w, kALbrg_down_3w};
+act11 abridgetest_3w = {COND_R, 0, BLOCK1_3w, 0, kALbridge_3w, 0};
+act11 acagetest_3w = {COND_R, 0, MOUSE_3w, 2, 0, kALpostest_3w};
+act11 acagetest1_3w = {COND_R, 0, MOUSE_3w, 2, kALcagetest2_3w, kALok_3w};
+act11 acagetest5_3w = {COND_R, 0, MOUSE_3w, 2, kALcageprompt_3w, kALmousegone_3w};
+act11 acamptest_3w = {COND_R, 0, NAT1_3w, 0, kALcampers_3w, kALchase_3w};
+act11 acavetest_3w = {COND_R, 0, GHOST_3w, 0, kALspirit_3w, kALcave_man_3w};
+act11 acrashtest1_3w = {COND_R, 0, PENNY_3w, 0, kALcrashed_3w, kALcrashtest2_3w};
+act11 acrashtest2_3w = {COND_R, 0, PENNY_3w, 1, kALcryhelp_3w, 0};
+act11 adartedtest_3w = {COND_R, 0, BLOWPIPE_3w, 0, kALdodart_3w, kALdarted_3w};
+act11 adoctest_3w = {COND_R, 0, DOCTOR_3w, 0, kALdoc_3w, 0};
+act11 adrinktest_3w = {COND_R, 0, FLASK_3w, 0, kALdrinkno_3w, kALdrinkyes_3w};
+act11 aeletest1_3w = {COND_R, 0, ELEPHANT_3w, 1, kALele_sleep_3w, kALeletest2_3w};
+act11 aeletest2_3w = {COND_R, 0, ELEPHANT_3w, 0, kALeleblink_3w, 0};
+act11 aemptytest1_3w = {COND_R, 0, FLASK_3w, 2, kALemptymagic_3w, kALemptytest2_3w};
+act11 aemptytest2_3w = {COND_R, 0, FLASK_3w, 1, kALemptyord_3w, kALdrinkno_3w};
+act11 aentertest1_3w = {COND_R, 0, CHEESE_3w, 1, kALentertest2_3w, 0};
+act11 aentertest2_3w = {COND_R, 0, MOUSE_3w, 0, kALentertest3_3w, 0};
+act11 aexotest1_3w = {COND_R, 0, GHOST_3w, 0, kALexotest2_3w, kALexordone_3w};
+act11 afindbtest_3w = {COND_R, 0, BOOK_3w, 0, kALfindit_3w, 0};
+act11 aflasktest2_3w = {COND_R, 0, FLASK_3w, 2, kALremedy_3w, kALflasktest3_3w};
+act11 aflasktest3_3w = {COND_R, 0, FLASK_3w, 1, kALnoremedy_3w, kALrefuseflask_3w};
+act11 agettest2_3w = {COND_R, 0, DOCTOR_3w, 0, kALgot_3w, 0};
+act11 agivetest_3w = {COND_R, 0, NAT1_3w, 10, kALrefuse_3w, kALgive_3w};
+act11 ahoriz1_3w = {COND_R, 0, HERO, 0, kALup_3w, 0};
+act11 ahoriz2_3w = {COND_R, 0, HERO, 1, kALdn_3w, 0};
+act11 anat0_3w = {COND_R, 0, NAT1_3w, 0, kALcom0_3w, kALnat1_3w};
+act11 anat1_3w = {COND_R, 0, NAT1_3w, 1, kALcom1_3w, kALnat2_3w};
+act11 anat2_3w = {COND_R, 0, NAT1_3w, 2, kALcom2_3w, kALnat3_3w};
+act11 anat3_3w = {COND_R, 0, NAT1_3w, 3, kALcom3_3w, kALnat4_3w};
+act11 anat4_3w = {COND_R, 0, NAT1_3w, 4, kALcom4_3w, kALnat5_3w};
+act11 anat5_3w = {COND_R, 0, NAT1_3w, 5, kALcom5_3w, kALnat6_3w};
+act11 anat6_3w = {COND_R, 0, NAT1_3w, 6, kALcom6_3w, kALnat7_3w};
+act11 anat7_3w = {COND_R, 0, NAT1_3w, 7, kALcom7_3w, kALnat8_3w};
+act11 anat8_3w = {COND_R, 0, NAT1_3w, 8, kALcom8_3w, 0};
+act11 aold5_3w = {COND_R, 0, FLASK_3w, 2, kALold6_3w, kALwrong_3w};
+act11 aoldmantest_3w = {COND_R, 0, MOUTH_3w, 0, kALoldfirst_3w, kALoldsubseq_3w};
+act11 aopentest_3w = {COND_R, 0, DOCTOR_3w, 1, kALprod_3w, kALopencdoor_3w};
+act11 apausetest_3w = {COND_R, 0, NAT2_3w, 1, 0, kALcomment_3w};
+act11 apostest_3w = {COND_R, 0, MOUSE_3w, 0, kALmousel_3w, kALmouser_3w};
+act11 aspirittest_3w = {COND_R, 0, GHOST_3w, 0, kALwarn_3w, 0};
+act11 asticktest1_3w = {COND_R, 0, DOCTOR_3w, 2, kALstuckpin_3w, kALsticktest2_3w};
+act11 asticktest2_3w = {COND_R, 0, CLAY_3w, 1, kALstickpin_3w, kALnostickpin_3w};
+act11 ataketest1_3w = {COND_R, 0, MOUSE_3w, 2, kALtakeit_3w, kALcanttake_3w};
+act11 ataketest2_3w = {COND_R, 0, MOUSE_3w, 3, kALtakeit_3w, kALtaketest1_3w};
+act11 atalktest1_3w = {COND_R, 0, NAT1_3w, 9, kALnat9_3w, kALnative_3w};
+act11 atdtest_3w = {COND_R, 0, DOCTOR_3w, 2, kALtalkdoc2_3w, kALtalkdoc1_3w};
+act11 atiptest_3w = {COND_R, 60 * NORMAL_TPS_v2d, BLOCK1_3w, 0, kALbtipprompt_3w, 0};
+act11 auntietest_3w = {COND_R, 0, BLOCK1_3w, 0, kALnottied_3w, kALuntie_3w};
+act11 avinetest_3w = {COND_R, 0, BLOCK1_3w, 0, kALtievine_3w, kALtied_3w};
+act11 awebtest1_3w = {COND_R, 0, PENNY_3w, 0, kALspider_3w, kALwebtest2_3w};
+act11 awebtest2_3w = {COND_R, 0, PENNY_3w, 1, kALmission_3w, kALreturn_3w};
act12 ablk1_3w = {TEXT, 0, kSTBlk1_3w};
act12 abook1_3w = {TEXT, 0, kSTBook1_3w};
@@ -8781,138 +8800,138 @@ int repbut2_1d[] = {kSTsbut2_1d, -1};
int repopen_1d[] = {kSTsopenr_1d, -1};
// Hugo 1 DOS
-act0 aend_1d = {ASCHEDULE, 4 * NORMAL_TPS, kALend_1d};
-act0 ajailrep_1d = {ASCHEDULE, 4, kALjailrep_1d};
-act0 acycle_1d = {ASCHEDULE, 0, kALcycle_1d};
-act0 areparm_1d = {ASCHEDULE, 5 * NORMAL_TPS, kALreparm_1d};
-act0 arepbat_1d = {ASCHEDULE, 12 * NORMAL_TPS, kALbat_1d};
-act0 arepbata_1d = {ASCHEDULE, 3 * NORMAL_TPS, kALbatrep_1d};
-act0 arepeye_1d = {ASCHEDULE, 8 * NORMAL_TPS, kALblinkeyes1_1d};
-act0 arepeye2_1d = {ASCHEDULE, 8 * NORMAL_TPS, kALblinkeyes2_1d};
-act0 areplight_1d = {ASCHEDULE, 11 * NORMAL_TPS, kALightning_1d};
-act0 areplips_1d = {ASCHEDULE, 4 * NORMAL_TPS, kALreplips_1d};
-act0 arepredeye_1d = {ASCHEDULE, 6 * NORMAL_TPS, kALrepredeye_1d};
-act0 aweird_1d = {ASCHEDULE, 16, kALweird_1d};
-
-act1 aridchop_1d = {START_OBJ, 0, CHOP_1d, 0, ALMOST_INVISIBLE};
-act1 ashowchop_1d = {START_OBJ, 0, CHOP_1d, 0, NOT_CYCLING};
-act1 a115b_1d = {START_OBJ, 0, MASK_1d, 0, NOT_CYCLING};
-act1 abin2_1d = {START_OBJ, 0, HERO, 0, ALMOST_INVISIBLE};
-act1 about2_1d = {START_OBJ, 0, HERO, 0, NOT_CYCLING};
-act1 abox10_1d = {START_OBJ, 38, PROF_1d, 0, CYCLE_FORWARD};
-act1 abox11_1d = {START_OBJ, 73, PROF_1d, 0, ALMOST_INVISIBLE};
-act1 abut6d_1d = {START_OBJ, 7, HERO, 0, ALMOST_INVISIBLE};
-act1 abut6f_1d = {START_OBJ, 7, HDLSHERO_1d, 0, NOT_CYCLING};
-act1 aclosetrap_1d = {START_OBJ, 1 * NORMAL_TPS, TRAP_1d, 1, CYCLE_BACKWARD};
-act1 adogcyc_1d = {START_OBJ, 0, DOG_1d, 0, CYCLE_FORWARD};
-act1 adoggy1_1d = {START_OBJ, 0, HERO, 0, ALMOST_INVISIBLE};
-act1 adoggy3_1d = {START_OBJ, 0, HERODEAD_1d, 0, NOT_CYCLING};
-act1 aguardgo1_1d = {START_OBJ, 0, GUARD_1d, 0, CYCLE_FORWARD};
-act1 ajail2_1d = {START_OBJ, 0, HERO, 0, CYCLE_FORWARD};
-act1 alab5_1d = {START_OBJ, 0, PROF_1d, 0, CYCLE_FORWARD};
-act1 alab8_1d = {START_OBJ, 12, PROF_1d, 0, NOT_CYCLING};
-act1 alab9_1d = {START_OBJ, 16, IGOR_1d, 0, NOT_CYCLING};
-act1 aopentrap_1d = {START_OBJ, 1 * NORMAL_TPS, TRAP_1d, 1, CYCLE_FORWARD};
-act1 aridbung_1d = {START_OBJ, 0, BUNG_1d, 0, ALMOST_INVISIBLE};
-act1 atheend1_1d = {START_OBJ, 5 * NORMAL_TPS, HERO, 0, ALMOST_INVISIBLE};
-act1 aarm_1d = {START_OBJ, 0, ARM_1d, 3, CYCLE_BACKWARD};
-act1 ablink1a_1d = {START_OBJ, 0, EYES1_1d, 0, ALMOST_INVISIBLE};
-act1 ablink1b_1d = {START_OBJ, 1, EYES1_1d, 0, NOT_CYCLING};
-act1 ablink1c_1d = {START_OBJ, 2, EYES1_1d, 0, ALMOST_INVISIBLE};
-act1 ablink1d_1d = {START_OBJ, 3, EYES1_1d, 0, NOT_CYCLING};
-act1 ablink2a_1d = {START_OBJ, 3 * NORMAL_TPS + 0, EYES2_1d, 0, ALMOST_INVISIBLE};
-act1 ablink2b_1d = {START_OBJ, 3 * NORMAL_TPS + 1, EYES2_1d, 0, NOT_CYCLING};
-act1 ablink2c_1d = {START_OBJ, 3 * NORMAL_TPS + 2, EYES2_1d, 0, ALMOST_INVISIBLE};
-act1 ablink2d_1d = {START_OBJ, 3 * NORMAL_TPS + 3, EYES2_1d, 0, NOT_CYCLING};
-act1 ablink3a_1d = {START_OBJ, 0, EYES3_1d, 0, ALMOST_INVISIBLE};
-act1 ablink3b_1d = {START_OBJ, 1, EYES3_1d, 0, NOT_CYCLING};
-act1 ablink3c_1d = {START_OBJ, 2, EYES3_1d, 0, ALMOST_INVISIBLE};
-act1 ablink3d_1d = {START_OBJ, 3, EYES3_1d, 0, NOT_CYCLING};
-act1 ablink4a_1d = {START_OBJ, 3 * NORMAL_TPS + 0, EYES4_1d, 0, ALMOST_INVISIBLE};
-act1 ablink4b_1d = {START_OBJ, 3 * NORMAL_TPS + 1, EYES4_1d, 0, NOT_CYCLING};
-act1 ablink4c_1d = {START_OBJ, 3 * NORMAL_TPS + 2, EYES4_1d, 0, ALMOST_INVISIBLE};
-act1 ablink4d_1d = {START_OBJ, 3 * NORMAL_TPS + 3, EYES4_1d, 0, NOT_CYCLING};
-act1 ablink5a_1d = {START_OBJ, 0, REDEYES_1d, 0, ALMOST_INVISIBLE};
-act1 ablink5b_1d = {START_OBJ, 1, REDEYES_1d, 0, NOT_CYCLING};
-act1 ablink5c_1d = {START_OBJ, 2, REDEYES_1d, 0, ALMOST_INVISIBLE};
-act1 ablink5d_1d = {START_OBJ, 3, REDEYES_1d, 0, NOT_CYCLING};
-act1 abut1_1d = {START_OBJ, 4 * NORMAL_TPS, BUTLER_1d, 0, CYCLE_FORWARD};
-act1 aclosedoor1_1d = {START_OBJ, 1 * NORMAL_TPS, DOOR1_1d, 1, CYCLE_BACKWARD};
-act1 aclosedoor4_1d = {START_OBJ, 1 * NORMAL_TPS, DOOR4_1d, 1, CYCLE_BACKWARD};
-act1 aclosewdoorl_1d = {START_OBJ, 1 * NORMAL_TPS, WDOORL_1d, 1, CYCLE_BACKWARD};
-act1 aclosewdoorr_1d = {START_OBJ, 1 * NORMAL_TPS, WDOORR_1d, 1, CYCLE_BACKWARD};
-act1 adog1_1d = {START_OBJ, 0, DOG_1d, 0, CYCLE_FORWARD};
-act1 alips_1d = {START_OBJ, 0, LIPS_1d, 6, CYCLE_FORWARD};
-act1 amdoor1_1d = {START_OBJ, 1 * NORMAL_TPS, MDOOR_1d, 1, CYCLE_FORWARD};
-act1 amovecarp1_1d = {START_OBJ, 0, CARPET_1d, 0, ALMOST_INVISIBLE};
-act1 amovecarp2_1d = {START_OBJ, 0, TRAP_1d, 0, NOT_CYCLING};
-act1 amum1_1d = {START_OBJ, 2 * NORMAL_TPS, MUMMY_1d, 0, CYCLE_FORWARD};
-act1 aopendoor1_1d = {START_OBJ, 1 * NORMAL_TPS, DOOR1_1d, 1, CYCLE_FORWARD};
-act1 aopendoor2_1d = {START_OBJ, 1 * NORMAL_TPS, DOOR2_1d, 1, CYCLE_FORWARD};
-act1 aopendoor3_1d = {START_OBJ, 1 * NORMAL_TPS, DOOR3_1d, 1, CYCLE_FORWARD};
-act1 aopendoor4_1d = {START_OBJ, 1 * NORMAL_TPS, DOOR4_1d, 1, CYCLE_FORWARD};
-act1 aopenwdoorl_1d = {START_OBJ, 1 * NORMAL_TPS, WDOORL_1d, 1, CYCLE_FORWARD};
-act1 aopenwdoorr_1d = {START_OBJ, 1 * NORMAL_TPS, WDOORR_1d, 1, CYCLE_FORWARD};
-act1 aridpkin_1d = {START_OBJ, 0, PKIN_1d, 0, ALMOST_INVISIBLE};
-act1 aridprof_1d = {START_OBJ, 130 / DX, PROF_1d, 0, ALMOST_INVISIBLE};
-act1 ashowkey_1d = {START_OBJ, 0, KEY_1d, 0, NOT_CYCLING};
-
-act2 achopxy_1d = {INIT_OBJXY, 0, CHOP_1d, 51, 155};
-act2 aigor12_1d = {INIT_OBJXY, 30, HERO, 116, 112};
-act2 a115d_1d = {INIT_OBJXY, 0, MASK_1d, 240, 88};
-act2 abata1c_1d = {INIT_OBJXY, 0, BAT2_1d, 65, 25};
-act2 abata2c_1d = {INIT_OBJXY, 0, BAT3_1d, 55, 65};
-act2 abata3c_1d = {INIT_OBJXY, 0, BAT4_1d, 50, 120};
-act2 abata4c_1d = {INIT_OBJXY, 0, BAT5_1d, 55, 130};
-act2 abox4a_1d = {INIT_OBJXY, 20, HERO, 124, 122};
-act2 adog4_1d = {INIT_OBJXY, 0, DOG_1d, 105, 119};
-act2 aheroxy78_1d = {INIT_OBJXY, 1 * NORMAL_TPS + 12, HERO, 80, 42};
-act2 alab2_1d = {INIT_OBJXY, 0, PROF_1d, 100, 130};
-act2 abatxy_1d = {INIT_OBJXY, 0, BAT_1d, 95, 55};
-act2 ahchase2_1d = {INIT_OBJXY, 5 * NORMAL_TPS, DOG_1d, 280, 137};
-act2 aherofar_1d = {INIT_OBJXY, 0, HERO, 142, 25};
-act2 aheronear_1d = {INIT_OBJXY, 0, HERO, 230, 132};
-act2 aheroxy01_1d = {INIT_OBJXY, 0, HERO, 106, 130};
-act2 aheroxy10_1d = {INIT_OBJXY, 0, HERO, 33, 134};
-act2 aheroxy1011_1d = {INIT_OBJXY, 0, HERO, 76, 130};
-act2 aheroxy109_1d = {INIT_OBJXY, 0, HERO, 96, 105};
-act2 aheroxy1110_1d = {INIT_OBJXY, 0, HERO, 261, 77};
-act2 aheroxy1112_1d = {INIT_OBJXY, 0, HERO, 216, 134};
-act2 aheroxy115_1d = {INIT_OBJXY, 1, HERO, 27, 130};
-act2 aheroxy12_1d = {INIT_OBJXY, 1 * NORMAL_TPS + 12, HERO, 169, 90};
-act2 aheroxy1211_1d = {INIT_OBJXY, 0, HERO, 291, 42};
-act2 aheroxy1213_1d = {INIT_OBJXY, 0, HERO, 131, 110};
-act2 aheroxy13_1d = {INIT_OBJXY, 0, HERO, 40, 127};
-act2 aheroxy14_1d = {INIT_OBJXY, 1 * NORMAL_TPS + 12, HERO, 135, 115};
-act2 aheroxy15_1d = {INIT_OBJXY, 0, HERO, 270, 120};
-act2 aheroxy151_1d = {INIT_OBJXY, 0, HERO, 240, 55};
-act2 aheroxy21_1d = {INIT_OBJXY, 0, HERO, 130, 56};
-act2 aheroxy31_1d = {INIT_OBJXY, 0, HERO, 263, 126};
-act2 aheroxy35_1d = {INIT_OBJXY, 0, HERO, 253, 96};
-act2 aheroxy41_1d = {INIT_OBJXY, 0, HERO, 200, 56};
-act2 aheroxy51_1d = {INIT_OBJXY, 0, HERO, 200, 110};
-act2 aheroxy53_1d = {INIT_OBJXY, 0, HERO, 50, 90};
-act2 aheroxy56_1d = {INIT_OBJXY, 0, HERO, 290, 140};
-act2 aheroxy57_1d = {INIT_OBJXY, 0, HERO, 255, 107};
-act2 aheroxy65_1d = {INIT_OBJXY, 0, HERO, 215, 96};
-act2 aheroxy75_1d = {INIT_OBJXY, 0, HERO, 20, 110};
-act2 aheroxy87_1d = {INIT_OBJXY, 0, HERO, 235, 108};
-act2 aheroxy89_1d = {INIT_OBJXY, 0, HERO, 276, 135};
-act2 aheroxy910_1d = {INIT_OBJXY, 0, HERO, 50, 132};
-act2 aheroxy98_1d = {INIT_OBJXY, 0, HERO, 130, 120};
-act2 akchase2_1d = {INIT_OBJXY, 5 * NORMAL_TPS, DOG_1d, 30, 120};
-
-act3 abut4_1d = {PROMPT, 0, kSTsbut1_1d, repbut2_1d, kALbutyes_1d, kALbutno_1d, false};
-act3 ahelp1_1d = {PROMPT, 4 * 60 * NORMAL_TPS, kSTshelpp1_1d, repbut2_1d, kALhelpy_1d, kALhelpn_1d, false};
-act3 ahelp2_1d = {PROMPT, 5 * 60 * NORMAL_TPS, kSTshelpp2_1d, repbut2_1d, kALhelpy2_1d, kALhelpn_1d, false};
-act3 amanq1_1d = {PROMPT, 0, kSTsq1_1d, rep1_1d, kALrepyes1_1d, kALrepno1_1d, true};
-act3 amanq2_1d = {PROMPT, 0, kSTsq2_1d, rep2_1d, kALrepyes2_1d, kALrepno1_1d, true};
-act3 amanq3_1d = {PROMPT, 0, kSTsq3_1d, rep3_1d, kALrepyes3_1d, kALrepno1_1d, true};
-act3 amanq4_1d = {PROMPT, 0, kSTsq4_1d, rep4_1d, kALrepyes4_1d, kALrepno1_1d, true};
-act3 amanq5_1d = {PROMPT, 0, kSTsq5_1d, rep5_1d, kALrepyes5_1d, kALrepno1_1d, true};
-act3 amanq6_1d = {PROMPT, 0, kSTsq6_1d, rep6_1d, kALrepyes6_1d, kALrepno1_1d, true};
-act3 amanq7_1d = {PROMPT, 0, kSTsq7_1d, repbut2_1d, kALrepyes7_1d, kALrepno3_1d, false};
-act3 aopenp_1d = {PROMPT, 0, kSTsopenp_1d, repopen_1d, kALopenyes_1d, kALopenno_1d, false};
+act0 aend_1d = {ASCHEDULE, 4 * NORMAL_TPS_v1d, kALend_1d};
+act0 ajailrep_1d = {ASCHEDULE, 4, kALjailrep_1d};
+act0 acycle_1d = {ASCHEDULE, 0, kALcycle_1d};
+act0 areparm_1d = {ASCHEDULE, 5 * NORMAL_TPS_v1d, kALreparm_1d};
+act0 arepbat_1d = {ASCHEDULE, 12 * NORMAL_TPS_v1d, kALbat_1d};
+act0 arepbata_1d = {ASCHEDULE, 3 * NORMAL_TPS_v1d, kALbatrep_1d};
+act0 arepeye_1d = {ASCHEDULE, 8 * NORMAL_TPS_v1d, kALblinkeyes1_1d};
+act0 arepeye2_1d = {ASCHEDULE, 8 * NORMAL_TPS_v1d, kALblinkeyes2_1d};
+act0 areplight_1d = {ASCHEDULE, 11 * NORMAL_TPS_v1d, kALightning_1d};
+act0 areplips_1d = {ASCHEDULE, 4 * NORMAL_TPS_v1d, kALreplips_1d};
+act0 arepredeye_1d = {ASCHEDULE, 6 * NORMAL_TPS_v1d, kALrepredeye_1d};
+act0 aweird_1d = {ASCHEDULE, 16, kALweird_1d};
+
+act1 aridchop_1d = {START_OBJ, 0, CHOP_1d, 0, ALMOST_INVISIBLE};
+act1 ashowchop_1d = {START_OBJ, 0, CHOP_1d, 0, NOT_CYCLING};
+act1 a115b_1d = {START_OBJ, 0, MASK_1d, 0, NOT_CYCLING};
+act1 abin2_1d = {START_OBJ, 0, HERO, 0, ALMOST_INVISIBLE};
+act1 about2_1d = {START_OBJ, 0, HERO, 0, NOT_CYCLING};
+act1 abox10_1d = {START_OBJ, 38, PROF_1d, 0, CYCLE_FORWARD};
+act1 abox11_1d = {START_OBJ, 73, PROF_1d, 0, ALMOST_INVISIBLE};
+act1 abut6d_1d = {START_OBJ, 7, HERO, 0, ALMOST_INVISIBLE};
+act1 abut6f_1d = {START_OBJ, 7, HDLSHERO_1d, 0, NOT_CYCLING};
+act1 aclosetrap_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, TRAP_1d, 1, CYCLE_BACKWARD};
+act1 adogcyc_1d = {START_OBJ, 0, DOG_1d, 0, CYCLE_FORWARD};
+act1 adoggy1_1d = {START_OBJ, 0, HERO, 0, ALMOST_INVISIBLE};
+act1 adoggy3_1d = {START_OBJ, 0, HERODEAD_1d, 0, NOT_CYCLING};
+act1 aguardgo1_1d = {START_OBJ, 0, GUARD_1d, 0, CYCLE_FORWARD};
+act1 ajail2_1d = {START_OBJ, 0, HERO, 0, CYCLE_FORWARD};
+act1 alab5_1d = {START_OBJ, 0, PROF_1d, 0, CYCLE_FORWARD};
+act1 alab8_1d = {START_OBJ, 12, PROF_1d, 0, NOT_CYCLING};
+act1 alab9_1d = {START_OBJ, 16, IGOR_1d, 0, NOT_CYCLING};
+act1 aopentrap_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, TRAP_1d, 1, CYCLE_FORWARD};
+act1 aridbung_1d = {START_OBJ, 0, BUNG_1d, 0, ALMOST_INVISIBLE};
+act1 atheend1_1d = {START_OBJ, 5 * NORMAL_TPS_v1d, HERO, 0, ALMOST_INVISIBLE};
+act1 aarm_1d = {START_OBJ, 0, ARM_1d, 3, CYCLE_BACKWARD};
+act1 ablink1a_1d = {START_OBJ, 0, EYES1_1d, 0, ALMOST_INVISIBLE};
+act1 ablink1b_1d = {START_OBJ, 1, EYES1_1d, 0, NOT_CYCLING};
+act1 ablink1c_1d = {START_OBJ, 2, EYES1_1d, 0, ALMOST_INVISIBLE};
+act1 ablink1d_1d = {START_OBJ, 3, EYES1_1d, 0, NOT_CYCLING};
+act1 ablink2a_1d = {START_OBJ, 3 * NORMAL_TPS_v1d + 0, EYES2_1d, 0, ALMOST_INVISIBLE};
+act1 ablink2b_1d = {START_OBJ, 3 * NORMAL_TPS_v1d + 1, EYES2_1d, 0, NOT_CYCLING};
+act1 ablink2c_1d = {START_OBJ, 3 * NORMAL_TPS_v1d + 2, EYES2_1d, 0, ALMOST_INVISIBLE};
+act1 ablink2d_1d = {START_OBJ, 3 * NORMAL_TPS_v1d + 3, EYES2_1d, 0, NOT_CYCLING};
+act1 ablink3a_1d = {START_OBJ, 0, EYES3_1d, 0, ALMOST_INVISIBLE};
+act1 ablink3b_1d = {START_OBJ, 1, EYES3_1d, 0, NOT_CYCLING};
+act1 ablink3c_1d = {START_OBJ, 2, EYES3_1d, 0, ALMOST_INVISIBLE};
+act1 ablink3d_1d = {START_OBJ, 3, EYES3_1d, 0, NOT_CYCLING};
+act1 ablink4a_1d = {START_OBJ, 3 * NORMAL_TPS_v1d + 0, EYES4_1d, 0, ALMOST_INVISIBLE};
+act1 ablink4b_1d = {START_OBJ, 3 * NORMAL_TPS_v1d + 1, EYES4_1d, 0, NOT_CYCLING};
+act1 ablink4c_1d = {START_OBJ, 3 * NORMAL_TPS_v1d + 2, EYES4_1d, 0, ALMOST_INVISIBLE};
+act1 ablink4d_1d = {START_OBJ, 3 * NORMAL_TPS_v1d + 3, EYES4_1d, 0, NOT_CYCLING};
+act1 ablink5a_1d = {START_OBJ, 0, REDEYES_1d, 0, ALMOST_INVISIBLE};
+act1 ablink5b_1d = {START_OBJ, 1, REDEYES_1d, 0, NOT_CYCLING};
+act1 ablink5c_1d = {START_OBJ, 2, REDEYES_1d, 0, ALMOST_INVISIBLE};
+act1 ablink5d_1d = {START_OBJ, 3, REDEYES_1d, 0, NOT_CYCLING};
+act1 abut1_1d = {START_OBJ, 4 * NORMAL_TPS_v1d, BUTLER_1d, 0, CYCLE_FORWARD};
+act1 aclosedoor1_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, DOOR1_1d, 1, CYCLE_BACKWARD};
+act1 aclosedoor4_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, DOOR4_1d, 1, CYCLE_BACKWARD};
+act1 aclosewdoorl_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, WDOORL_1d, 1, CYCLE_BACKWARD};
+act1 aclosewdoorr_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, WDOORR_1d, 1, CYCLE_BACKWARD};
+act1 adog1_1d = {START_OBJ, 0, DOG_1d, 0, CYCLE_FORWARD};
+act1 alips_1d = {START_OBJ, 0, LIPS_1d, 6, CYCLE_FORWARD};
+act1 amdoor1_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, MDOOR_1d, 1, CYCLE_FORWARD};
+act1 amovecarp1_1d = {START_OBJ, 0, CARPET_1d, 0, ALMOST_INVISIBLE};
+act1 amovecarp2_1d = {START_OBJ, 0, TRAP_1d, 0, NOT_CYCLING};
+act1 amum1_1d = {START_OBJ, 2 * NORMAL_TPS_v1d, MUMMY_1d, 0, CYCLE_FORWARD};
+act1 aopendoor1_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, DOOR1_1d, 1, CYCLE_FORWARD};
+act1 aopendoor2_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, DOOR2_1d, 1, CYCLE_FORWARD};
+act1 aopendoor3_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, DOOR3_1d, 1, CYCLE_FORWARD};
+act1 aopendoor4_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, DOOR4_1d, 1, CYCLE_FORWARD};
+act1 aopenwdoorl_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, WDOORL_1d, 1, CYCLE_FORWARD};
+act1 aopenwdoorr_1d = {START_OBJ, 1 * NORMAL_TPS_v1d, WDOORR_1d, 1, CYCLE_FORWARD};
+act1 aridpkin_1d = {START_OBJ, 0, PKIN_1d, 0, ALMOST_INVISIBLE};
+act1 aridprof_1d = {START_OBJ, 130 / DX, PROF_1d, 0, ALMOST_INVISIBLE};
+act1 ashowkey_1d = {START_OBJ, 0, KEY_1d, 0, NOT_CYCLING};
+
+act2 achopxy_1d = {INIT_OBJXY, 0, CHOP_1d, 51, 155};
+act2 aigor12_1d = {INIT_OBJXY, 30, HERO, 116, 112};
+act2 a115d_1d = {INIT_OBJXY, 0, MASK_1d, 240, 88};
+act2 abata1c_1d = {INIT_OBJXY, 0, BAT2_1d, 65, 25};
+act2 abata2c_1d = {INIT_OBJXY, 0, BAT3_1d, 55, 65};
+act2 abata3c_1d = {INIT_OBJXY, 0, BAT4_1d, 50, 120};
+act2 abata4c_1d = {INIT_OBJXY, 0, BAT5_1d, 55, 130};
+act2 abox4a_1d = {INIT_OBJXY, 20, HERO, 124, 122};
+act2 adog4_1d = {INIT_OBJXY, 0, DOG_1d, 105, 119};
+act2 aheroxy78_1d = {INIT_OBJXY, 1 * NORMAL_TPS_v1d + 12, HERO, 80, 42};
+act2 alab2_1d = {INIT_OBJXY, 0, PROF_1d, 100, 130};
+act2 abatxy_1d = {INIT_OBJXY, 0, BAT_1d, 95, 55};
+act2 ahchase2_1d = {INIT_OBJXY, 5 * NORMAL_TPS_v1d, DOG_1d, 280, 137};
+act2 aherofar_1d = {INIT_OBJXY, 0, HERO, 142, 25};
+act2 aheronear_1d = {INIT_OBJXY, 0, HERO, 230, 132};
+act2 aheroxy01_1d = {INIT_OBJXY, 0, HERO, 106, 130};
+act2 aheroxy10_1d = {INIT_OBJXY, 0, HERO, 33, 134};
+act2 aheroxy1011_1d = {INIT_OBJXY, 0, HERO, 76, 130};
+act2 aheroxy109_1d = {INIT_OBJXY, 0, HERO, 96, 105};
+act2 aheroxy1110_1d = {INIT_OBJXY, 0, HERO, 261, 77};
+act2 aheroxy1112_1d = {INIT_OBJXY, 0, HERO, 216, 134};
+act2 aheroxy115_1d = {INIT_OBJXY, 1, HERO, 27, 130};
+act2 aheroxy12_1d = {INIT_OBJXY, 1 * NORMAL_TPS_v1d + 12, HERO, 169, 90};
+act2 aheroxy1211_1d = {INIT_OBJXY, 0, HERO, 291, 42};
+act2 aheroxy1213_1d = {INIT_OBJXY, 0, HERO, 131, 110};
+act2 aheroxy13_1d = {INIT_OBJXY, 0, HERO, 40, 127};
+act2 aheroxy14_1d = {INIT_OBJXY, 1 * NORMAL_TPS_v1d + 12, HERO, 135, 115};
+act2 aheroxy15_1d = {INIT_OBJXY, 0, HERO, 270, 120};
+act2 aheroxy151_1d = {INIT_OBJXY, 0, HERO, 240, 55};
+act2 aheroxy21_1d = {INIT_OBJXY, 0, HERO, 130, 56};
+act2 aheroxy31_1d = {INIT_OBJXY, 0, HERO, 263, 126};
+act2 aheroxy35_1d = {INIT_OBJXY, 0, HERO, 253, 96};
+act2 aheroxy41_1d = {INIT_OBJXY, 0, HERO, 200, 56};
+act2 aheroxy51_1d = {INIT_OBJXY, 0, HERO, 200, 110};
+act2 aheroxy53_1d = {INIT_OBJXY, 0, HERO, 50, 90};
+act2 aheroxy56_1d = {INIT_OBJXY, 0, HERO, 290, 140};
+act2 aheroxy57_1d = {INIT_OBJXY, 0, HERO, 255, 107};
+act2 aheroxy65_1d = {INIT_OBJXY, 0, HERO, 215, 96};
+act2 aheroxy75_1d = {INIT_OBJXY, 0, HERO, 20, 110};
+act2 aheroxy87_1d = {INIT_OBJXY, 0, HERO, 235, 108};
+act2 aheroxy89_1d = {INIT_OBJXY, 0, HERO, 276, 135};
+act2 aheroxy910_1d = {INIT_OBJXY, 0, HERO, 50, 132};
+act2 aheroxy98_1d = {INIT_OBJXY, 0, HERO, 130, 120};
+act2 akchase2_1d = {INIT_OBJXY, 5 * NORMAL_TPS_v1d, DOG_1d, 30, 120};
+
+act3 abut4_1d = {PROMPT, 0, kSTsbut1_1d, repbut2_1d, kALbutyes_1d, kALbutno_1d, false};
+act3 ahelp1_1d = {PROMPT, 4 * 60 * NORMAL_TPS_v1d, kSTshelpp1_1d, repbut2_1d, kALhelpy_1d, kALhelpn_1d, false};
+act3 ahelp2_1d = {PROMPT, 5 * 60 * NORMAL_TPS_v1d, kSTshelpp2_1d, repbut2_1d, kALhelpy2_1d, kALhelpn_1d, false};
+act3 amanq1_1d = {PROMPT, 0, kSTsq1_1d, rep1_1d, kALrepyes1_1d, kALrepno1_1d, true};
+act3 amanq2_1d = {PROMPT, 0, kSTsq2_1d, rep2_1d, kALrepyes2_1d, kALrepno1_1d, true};
+act3 amanq3_1d = {PROMPT, 0, kSTsq3_1d, rep3_1d, kALrepyes3_1d, kALrepno1_1d, true};
+act3 amanq4_1d = {PROMPT, 0, kSTsq4_1d, rep4_1d, kALrepyes4_1d, kALrepno1_1d, true};
+act3 amanq5_1d = {PROMPT, 0, kSTsq5_1d, rep5_1d, kALrepyes5_1d, kALrepno1_1d, true};
+act3 amanq6_1d = {PROMPT, 0, kSTsq6_1d, rep6_1d, kALrepyes6_1d, kALrepno1_1d, true};
+act3 amanq7_1d = {PROMPT, 0, kSTsq7_1d, repbut2_1d, kALrepyes7_1d, kALrepno3_1d, false};
+act3 aopenp_1d = {PROMPT, 0, kSTsopenp_1d, repopen_1d, kALopenyes_1d, kALopenno_1d, false};
act4 abg1_1d = {BKGD_COLOR, 0, _LIGHTYELLOW};
act4 abg2_1d = {BKGD_COLOR, 2, _LIGHTMAGENTA};
@@ -8927,36 +8946,36 @@ act4 abk2_1d = {BKGD_COLOR, 2, _BLUE};
act4 abknorm1_1d = {BKGD_COLOR, 0, _BLACK};
act4 abknorm2_1d = {BKGD_COLOR, 3, _BLACK};
-act5 abox0_1d = {INIT_OBJVXY, 0, GDOOR_1d, 6, 0};
-act5 abox1_1d = {INIT_OBJVXY, 9, GDOOR_1d, 0, 0};
-act5 abox7_1d = {INIT_OBJVXY, 50, GDOOR_1d, -6, 0};
-act5 abox8_1d = {INIT_OBJVXY, 57, GDOOR_1d, 0, 0};
-act5 abox9_1d = {INIT_OBJVXY, 38, PROF_1d, -DX, 0};
-act5 adoggy5_1d = {INIT_OBJVXY, 0, HERO, 0, 0};
-act5 aguardgo3_1d = {INIT_OBJVXY, 0, GUARD_1d, -DX, 0};
-act5 ahin2_1d = {INIT_OBJVXY, 0, HERO, 0, 0}; // Stop hero!
-act5 alab3_1d = {INIT_OBJVXY, 0, PROF_1d, DX, 0};
-act5 alab6_1d = {INIT_OBJVXY, 12, PROF_1d, 0, 0};
-act5 alab7_1d = {INIT_OBJVXY, 16, IGOR_1d, 0, 0};
-act5 abatvxy1_1d = {INIT_OBJVXY, 0, BAT_1d, 2, -2};
-act5 abatvxy2_1d = {INIT_OBJVXY, 20, BAT_1d, -1, 1};
-act5 abatvxy3_1d = {INIT_OBJVXY, 40, BAT_1d, -1, -1};
-act5 abatvxy4_1d = {INIT_OBJVXY, 50, BAT_1d, -5, 0};
-act5 abatvxy5_1d = {INIT_OBJVXY, 60, BAT_1d, 0, 0};
-act5 aboatvxy1_1d = {INIT_OBJVXY, 0, BOAT_1w, 0, -2};
-act5 aboatvxy10_1d = {INIT_OBJVXY, 0, BOAT_1w, 9, 7};
-act5 aboatvxy11_1d = {INIT_OBJVXY, 3, BOAT_1w, 0, 0};
-act5 aboatvxy12_1d = {INIT_OBJVXY, 10, BOAT_1w, 1, 1};
-act5 aboatvxy2_1d = {INIT_OBJVXY, 10, BOAT_1w, -5, 0};
-act5 aboatvxy3_1d = {INIT_OBJVXY, 20, BOAT_1w, 2, 0};
-act5 aboatvxy4_1d = {INIT_OBJVXY, 50, BOAT_1w, 1, -1};
-act5 aboatvxy5_1d = {INIT_OBJVXY, 60, BOAT_1w, -2, -3};
-act5 aboatvxy6_1d = {INIT_OBJVXY, 70, BOAT_1w, -3, 0};
-act5 aboatvxy7_1d = {INIT_OBJVXY, 100, BOAT_1w, 0, -3};
-act5 aboatvxy8_1d = {INIT_OBJVXY, 104, BOAT_1w, -1, -1};
-act5 aboatvxy9_1d = {INIT_OBJVXY, 107, BOAT_1w, 0, 0};
-act5 abutvxy1_1d = {INIT_OBJVXY, 4 * NORMAL_TPS, BUTLER_1d, DX - 2, 0};
-act5 astophero_1d = {INIT_OBJVXY, 0, HERO, 0, 0}; // Stop hero!
+act5 abox0_1d = {INIT_OBJVXY, 0, GDOOR_1d, 6, 0};
+act5 abox1_1d = {INIT_OBJVXY, 9, GDOOR_1d, 0, 0};
+act5 abox7_1d = {INIT_OBJVXY, 50, GDOOR_1d, -6, 0};
+act5 abox8_1d = {INIT_OBJVXY, 57, GDOOR_1d, 0, 0};
+act5 abox9_1d = {INIT_OBJVXY, 38, PROF_1d, -DX, 0};
+act5 adoggy5_1d = {INIT_OBJVXY, 0, HERO, 0, 0};
+act5 aguardgo3_1d = {INIT_OBJVXY, 0, GUARD_1d, -DX, 0};
+act5 ahin2_1d = {INIT_OBJVXY, 0, HERO, 0, 0}; // Stop hero!
+act5 alab3_1d = {INIT_OBJVXY, 0, PROF_1d, DX, 0};
+act5 alab6_1d = {INIT_OBJVXY, 12, PROF_1d, 0, 0};
+act5 alab7_1d = {INIT_OBJVXY, 16, IGOR_1d, 0, 0};
+act5 abatvxy1_1d = {INIT_OBJVXY, 0, BAT_1d, 2, -2};
+act5 abatvxy2_1d = {INIT_OBJVXY, 20, BAT_1d, -1, 1};
+act5 abatvxy3_1d = {INIT_OBJVXY, 40, BAT_1d, -1, -1};
+act5 abatvxy4_1d = {INIT_OBJVXY, 50, BAT_1d, -5, 0};
+act5 abatvxy5_1d = {INIT_OBJVXY, 60, BAT_1d, 0, 0};
+act5 aboatvxy1_1d = {INIT_OBJVXY, 0, BOAT_1w, 0, -2};
+act5 aboatvxy10_1d = {INIT_OBJVXY, 0, BOAT_1w, 9, 7};
+act5 aboatvxy11_1d = {INIT_OBJVXY, 3, BOAT_1w, 0, 0};
+act5 aboatvxy12_1d = {INIT_OBJVXY, 10, BOAT_1w, 1, 1};
+act5 aboatvxy2_1d = {INIT_OBJVXY, 10, BOAT_1w, -5, 0};
+act5 aboatvxy3_1d = {INIT_OBJVXY, 20, BOAT_1w, 2, 0};
+act5 aboatvxy4_1d = {INIT_OBJVXY, 50, BOAT_1w, 1, -1};
+act5 aboatvxy5_1d = {INIT_OBJVXY, 60, BOAT_1w, -2, -3};
+act5 aboatvxy6_1d = {INIT_OBJVXY, 70, BOAT_1w, -3, 0};
+act5 aboatvxy7_1d = {INIT_OBJVXY, 100, BOAT_1w, 0, -3};
+act5 aboatvxy8_1d = {INIT_OBJVXY, 104, BOAT_1w, -1, -1};
+act5 aboatvxy9_1d = {INIT_OBJVXY, 107, BOAT_1w, 0, 0};
+act5 abutvxy1_1d = {INIT_OBJVXY, 4 * NORMAL_TPS_v1d, BUTLER_1d, DX - 2, 0};
+act5 astophero_1d = {INIT_OBJVXY, 0, HERO, 0, 0}; // Stop hero!
act6 adropchop_1d = {INIT_CARRY, 0, CHOP_1d, false};
act6 a115c_1d = {INIT_CARRY, 0, MASK_1d, false};
@@ -8965,19 +8984,19 @@ act6 adropbung_1d = {INIT_CARRY, 0, BUNG_1d, false};
act6 adropmask_1d = {INIT_CARRY, 0, MASK_1d, false};
act6 adroppkin_1d = {INIT_CARRY, 0, PKIN_1d, false};
-act7 abut6e_1d = {INIT_HH_COORD, 7, HDLSHERO_1d}; // Remove hero's head
-act7 adoggy2_1d = {INIT_HH_COORD, 0, HERODEAD_1d};
-act7 ahchase1_1d = {INIT_HF_COORD, 5 * NORMAL_TPS, DOG_1d};// Set screen to hero's
-act7 akchase1_1d = {INIT_HF_COORD, 5 * NORMAL_TPS, DOG_1d}; // Set screen to hero's
-act7 amovekey_1d = {INIT_HF_COORD, 0, KEY_1d}; // Move key to hero's coords
+act7 abut6e_1d = {INIT_HH_COORD, 7, HDLSHERO_1d}; // Remove hero's head
+act7 adoggy2_1d = {INIT_HH_COORD, 0, HERODEAD_1d};
+act7 ahchase1_1d = {INIT_HF_COORD, 5 * NORMAL_TPS_v1d, DOG_1d}; // Set screen to hero's
+act7 akchase1_1d = {INIT_HF_COORD, 5 * NORMAL_TPS_v1d, DOG_1d}; // Set screen to hero's
+act7 amovekey_1d = {INIT_HF_COORD, 0, KEY_1d}; // Move key to hero's coords
// Those two were originally defined as act11, but with the type INIT_HF_COORD
// They are now defined as act7 to silence GCC warnings.
-act7 adog3_1d = {INIT_HF_COORD, 0, DOG_1d}; // Set correct screen
-act7 alab1_1d = {INIT_HF_COORD, 0, PROF_1d}; // Set correct screen
+act7 adog3_1d = {INIT_HF_COORD, 0, DOG_1d}; // Set correct screen
+act7 alab1_1d = {INIT_HF_COORD, 0, PROF_1d}; // Set correct screen
-act8 aopen78_1d = {NEW_SCREEN, 1 * NORMAL_TPS + 12, 8}; // Goto to Basement
-act8 atheend2_1d = {NEW_SCREEN, 5 * NORMAL_TPS, 14};
+act8 aopen78_1d = {NEW_SCREEN, 1 * NORMAL_TPS_v1d + 12, 8}; // Goto to Basement
+act8 atheend2_1d = {NEW_SCREEN, 5 * NORMAL_TPS_v1d, 14};
act8 ascr01_1d = {NEW_SCREEN, 0, 1};
act8 ascr10_1d = {NEW_SCREEN, 0, 0};
act8 ascr1011_1d = {NEW_SCREEN, 0, 11};
@@ -8985,11 +9004,11 @@ act8 ascr109_1d = {NEW_SCREEN, 0, 9};
act8 ascr1110_1d = {NEW_SCREEN, 0, 10};
act8 ascr1112_1d = {NEW_SCREEN, 0, 12};
act8 ascr115_1d = {NEW_SCREEN, 1, 15};// Note delay for COND_CARRY
-act8 ascr12_1d = {NEW_SCREEN, 1 * NORMAL_TPS + 12, 2}; // Goto to Bed1
+act8 ascr12_1d = {NEW_SCREEN, 1 * NORMAL_TPS_v1d + 12, 2}; // Goto to Bed1
act8 ascr1211_1d = {NEW_SCREEN, 0, 11};
act8 ascr1213_1d = {NEW_SCREEN, 0, 13};
act8 ascr13_1d = {NEW_SCREEN, 0, 3};
-act8 ascr14_1d = {NEW_SCREEN, 1 * NORMAL_TPS + 12, 4}; // Goto to Bathroom
+act8 ascr14_1d = {NEW_SCREEN, 1 * NORMAL_TPS_v1d + 12, 4}; // Goto to Bathroom
act8 ascr15_1d = {NEW_SCREEN, 0, 5};
act8 ascr151_1d = {NEW_SCREEN, 0, 1};
act8 ascr21_1d = {NEW_SCREEN, 0, 1};
@@ -9007,53 +9026,53 @@ act8 ascr89_1d = {NEW_SCREEN, 0, 9};
act8 ascr910_1d = {NEW_SCREEN, 0, 10};
act8 ascr98_1d = {NEW_SCREEN, 0, 8};
-act9 aigor14_1d = {INIT_OBJSTATE, 0, GDOOR_1d, 2}; // Box now in state 2
-act9 aigor23_1d = {INIT_OBJSTATE, 0, GDOOR_1d, 3}; // Box now in state 3
-act9 aigor33_1d = {INIT_OBJSTATE, 0, GDOOR_1d, 4}; // Box now in state 4
-act9 a115g_1d = {INIT_OBJSTATE, 0, MASK_1d, 0}; // Say mask not worn!
-act9 abox12_1d = {INIT_OBJSTATE, 0, GDOOR_1d, 1}; // Box now in state 1
-act9 abut10_1d = {INIT_OBJSTATE, 10 * NORMAL_TPS, BUTLER_1d, 0}; // Ask again if we meet a bit later
-act9 abut4a_1d = {INIT_OBJSTATE, 0, BUTLER_1d, 1}; // Butler doesn't want to give chop
-act9 abut7a_1d = {INIT_OBJSTATE, 0, BUTLER_1d, 1}; // No more chops to give
-act9 ahin1_1d = {INIT_OBJSTATE, 0, HERO, 1};
-act9 ahout_1d = {INIT_OBJSTATE, 0, HERO, 0};
-act9 ast78_1d = {INIT_OBJSTATE, 1 * NORMAL_TPS + 12, TRAP_1d, 0}; // Close door after
-act9 aboatfar_1d = {INIT_OBJSTATE, 107, BOAT_1d, 1}; // Say boat on other side
-act9 aboatmov_1d = {INIT_OBJSTATE, 0, BOAT_1d, 2}; // Say boat moving
-act9 aboatnear_1d = {INIT_OBJSTATE, 13, BOAT_1d, 0}; // Say boat on near side
-act9 aompass_1d = {INIT_OBJSTATE, 0, OLDMAN_1d, 1}; // Oldman allows passage
-act9 ashedoil_1d = {INIT_OBJSTATE, 0, SHED_1d, 1};
-act9 ast01_1d = {INIT_OBJSTATE, 0, DOOR1_1d, 1}; // Close door after hero!
-act9 ast12_1d = {INIT_OBJSTATE, 1 * NORMAL_TPS + 12, DOOR2_1d, 0}; // Close door after
-act9 ast14_1d = {INIT_OBJSTATE, 1 * NORMAL_TPS + 12, DOOR3_1d, 0}; // Close door after
-act9 astatedoor4_1d = {INIT_OBJSTATE, 0, DOOR4_1d, 1}; // Change state to open
-
-act10 abata1a_1d = {INIT_PATH, 0, BAT2_1d, CHASE, DX * 2, DY * 2};
-act10 abata1b_1d = {INIT_PATH, 7, BAT2_1d, WANDER, DX, DY};
-act10 abata2a_1d = {INIT_PATH, 0, BAT3_1d, CHASE, DX * 2, DY * 2};
-act10 abata2b_1d = {INIT_PATH, 6, BAT3_1d, WANDER, DX, DY};
-act10 abata3a_1d = {INIT_PATH, 0, BAT4_1d, CHASE, DX * 2, DY * 2};
-act10 abata3b_1d = {INIT_PATH, 5, BAT4_1d, WANDER, DX, DY};
-act10 abata4a_1d = {INIT_PATH, 0, BAT5_1d, CHASE, DX * 2, DY * 2};
-act10 abata4b_1d = {INIT_PATH, 4, BAT5_1d, WANDER, DX, DY};
-act10 abin3_1d = {INIT_PATH, 0, HERO, AUTO, 0, 0};
-act10 about3_1d = {INIT_PATH, 0, HERO, USER, 0, 0};
-act10 abut2_1d = {INIT_PATH, 8 * NORMAL_TPS, BUTLER_1d, CHASE, DX - 2, DY - 2};
-act10 abut3_1d = {INIT_PATH, 0, HERO, AUTO, 0, 0}; // Stop HERO and prompt
-act10 abut8_1d = {INIT_PATH, 0, BUTLER_1d, WANDER, DX - 2, DY - 2};
-act10 abut9_1d = {INIT_PATH, 0, HERO, USER, 0, 0};
-act10 acyc1_1d = {INIT_PATH, 0, HERO, AUTO, 0, 0};
-act10 acyc2_1d = {INIT_PATH, 57, HERO, USER, 0, 0};
-act10 adef2_1d = {INIT_PATH, 1 * NORMAL_TPS, BAT2_1d, WANDER, DX, DY};
-act10 adef3_1d = {INIT_PATH, 1 * NORMAL_TPS, BAT3_1d, WANDER, DX, DY};
-act10 adef4_1d = {INIT_PATH, 1 * NORMAL_TPS, BAT4_1d, WANDER, DX, DY};
-act10 adef5_1d = {INIT_PATH, 1 * NORMAL_TPS, BAT5_1d, WANDER, DX, DY};
-act10 adog2_1d = {INIT_PATH, 0, DOG_1d, CHASE, DX * 2, DY * 2};
-act10 ahchase3_1d = {INIT_PATH, 5 * NORMAL_TPS, DOG_1d, CHASE, DX * 2, DY * 2};
-act10 ajail1_1d = {INIT_PATH, 0, HERO, AUTO, 0, 0}; // Stop user control
-act10 akchase3_1d = {INIT_PATH, 5 * NORMAL_TPS, DOG_1d, CHASE, DX * 2, DY * 2};
-act10 alab14_1d = {INIT_PATH, 40, IGOR_1d, WANDER, DX, 0};
-act10 amum2_1d = {INIT_PATH, 3 * NORMAL_TPS, MUMMY_1d, CHASE, DX * 2, DY * 2};
+act9 aigor14_1d = {INIT_OBJSTATE, 0, GDOOR_1d, 2}; // Box now in state 2
+act9 aigor23_1d = {INIT_OBJSTATE, 0, GDOOR_1d, 3}; // Box now in state 3
+act9 aigor33_1d = {INIT_OBJSTATE, 0, GDOOR_1d, 4}; // Box now in state 4
+act9 a115g_1d = {INIT_OBJSTATE, 0, MASK_1d, 0}; // Say mask not worn!
+act9 abox12_1d = {INIT_OBJSTATE, 0, GDOOR_1d, 1}; // Box now in state 1
+act9 abut10_1d = {INIT_OBJSTATE, 10 * NORMAL_TPS_v1d, BUTLER_1d, 0}; // Ask again if we meet a bit later
+act9 abut4a_1d = {INIT_OBJSTATE, 0, BUTLER_1d, 1}; // Butler doesn't want to give chop
+act9 abut7a_1d = {INIT_OBJSTATE, 0, BUTLER_1d, 1}; // No more chops to give
+act9 ahin1_1d = {INIT_OBJSTATE, 0, HERO, 1};
+act9 ahout_1d = {INIT_OBJSTATE, 0, HERO, 0};
+act9 ast78_1d = {INIT_OBJSTATE, 1 * NORMAL_TPS_v1d + 12, TRAP_1d, 0}; // Close door after
+act9 aboatfar_1d = {INIT_OBJSTATE, 107, BOAT_1d, 1}; // Say boat on other side
+act9 aboatmov_1d = {INIT_OBJSTATE, 0, BOAT_1d, 2}; // Say boat moving
+act9 aboatnear_1d = {INIT_OBJSTATE, 13, BOAT_1d, 0}; // Say boat on near side
+act9 aompass_1d = {INIT_OBJSTATE, 0, OLDMAN_1d, 1}; // Oldman allows passage
+act9 ashedoil_1d = {INIT_OBJSTATE, 0, SHED_1d, 1};
+act9 ast01_1d = {INIT_OBJSTATE, 0, DOOR1_1d, 1}; // Close door after hero!
+act9 ast12_1d = {INIT_OBJSTATE, 1 * NORMAL_TPS_v1d + 12, DOOR2_1d, 0}; // Close door after
+act9 ast14_1d = {INIT_OBJSTATE, 1 * NORMAL_TPS_v1d + 12, DOOR3_1d, 0}; // Close door after
+act9 astatedoor4_1d = {INIT_OBJSTATE, 0, DOOR4_1d, 1}; // Change state to open
+
+act10 abata1a_1d = {INIT_PATH, 0, BAT2_1d, CHASE, DX * 2, DY * 2};
+act10 abata1b_1d = {INIT_PATH, 7, BAT2_1d, WANDER, DX, DY};
+act10 abata2a_1d = {INIT_PATH, 0, BAT3_1d, CHASE, DX * 2, DY * 2};
+act10 abata2b_1d = {INIT_PATH, 6, BAT3_1d, WANDER, DX, DY};
+act10 abata3a_1d = {INIT_PATH, 0, BAT4_1d, CHASE, DX * 2, DY * 2};
+act10 abata3b_1d = {INIT_PATH, 5, BAT4_1d, WANDER, DX, DY};
+act10 abata4a_1d = {INIT_PATH, 0, BAT5_1d, CHASE, DX * 2, DY * 2};
+act10 abata4b_1d = {INIT_PATH, 4, BAT5_1d, WANDER, DX, DY};
+act10 abin3_1d = {INIT_PATH, 0, HERO, AUTO, 0, 0};
+act10 about3_1d = {INIT_PATH, 0, HERO, USER, 0, 0};
+act10 abut2_1d = {INIT_PATH, 8 * NORMAL_TPS_v1d, BUTLER_1d, CHASE, DX - 2, DY - 2};
+act10 abut3_1d = {INIT_PATH, 0, HERO, AUTO, 0, 0}; // Stop HERO and prompt
+act10 abut8_1d = {INIT_PATH, 0, BUTLER_1d, WANDER, DX - 2, DY - 2};
+act10 abut9_1d = {INIT_PATH, 0, HERO, USER, 0, 0};
+act10 acyc1_1d = {INIT_PATH, 0, HERO, AUTO, 0, 0};
+act10 acyc2_1d = {INIT_PATH, 57, HERO, USER, 0, 0};
+act10 adef2_1d = {INIT_PATH, 1 * NORMAL_TPS_v1d, BAT2_1d, WANDER, DX, DY};
+act10 adef3_1d = {INIT_PATH, 1 * NORMAL_TPS_v1d, BAT3_1d, WANDER, DX, DY};
+act10 adef4_1d = {INIT_PATH, 1 * NORMAL_TPS_v1d, BAT4_1d, WANDER, DX, DY};
+act10 adef5_1d = {INIT_PATH, 1 * NORMAL_TPS_v1d, BAT5_1d, WANDER, DX, DY};
+act10 adog2_1d = {INIT_PATH, 0, DOG_1d, CHASE, DX * 2, DY * 2};
+act10 ahchase3_1d = {INIT_PATH, 5 * NORMAL_TPS_v1d, DOG_1d, CHASE, DX * 2, DY * 2};
+act10 ajail1_1d = {INIT_PATH, 0, HERO, AUTO, 0, 0}; // Stop user control
+act10 akchase3_1d = {INIT_PATH, 5 * NORMAL_TPS_v1d, DOG_1d, CHASE, DX * 2, DY * 2};
+act10 alab14_1d = {INIT_PATH, 40, IGOR_1d, WANDER, DX, 0};
+act10 amum2_1d = {INIT_PATH, 3 * NORMAL_TPS_v1d, MUMMY_1d, CHASE, DX * 2, DY * 2};
act11 achkd0_1d = {COND_R, 0, GDOOR_1d, 0, kALok151_1d, kALchkd1_1d};
act11 achkd1_1d = {COND_R, 0, GDOOR_1d, 1, kALdmsg1_1d, kALchkd2_1d};
@@ -9083,77 +9102,77 @@ act11 atcup1_1d = {COND_R, 0, CUPBOARD_1d, 1, kALcuptxt1_1d, kALlookcupb2
act11 atcup2_1d = {COND_R, 0, CUPBOARD_1d, 2, kALcuptxt2_1d, kALcuptxt3_1d};
act11 atrap_1d = {COND_R, 0, BOLT_1d, 2, kALopenpass_1d, kALopenfail_1d};
-act12 achopfail_1d = {TEXT, 0, kSTsthrown_1d};
-act12 achopthrown_1d = {TEXT, 5 * NORMAL_TPS, kSTsachopthrown_1d};
-act12 admsg1_1d = {TEXT, 0, kSTsadmsg1_1d};
-act12 admsg2_1d = {TEXT, 0, kSTsadmsg2_1d};
-act12 admsg3_1d = {TEXT, 0, kSTsadmsg3_1d};
-act12 aeatchop_1d = {TEXT, 0, kSTsaeatchop_1d};
-act12 agobox_1d = {TEXT, 0, kSTsagobox_1d};
-act12 aigor0_1d = {TEXT, 0, kSTsaigor0_1d};
-act12 aigor13_1d = {TEXT, 0, kSTsaigor13_1d};
-act12 aigor22_1d = {TEXT, 0, kSTsaigor22_1d};
-act12 aigor32_1d = {TEXT, 0, kSTsaigor32_1d};
-act12 ainorm_1d = {TEXT, 0, kSTsainorm_1d};
-act12 a115e_1d = {TEXT, 0, kSTsa115e_1d};
-act12 abat5a_1d = {TEXT, 0, kSTsabat5a_1d};
-act12 abat5b_1d = {TEXT, 0, kSTsabat5b_1d};
-act12 abin0_1d = {TEXT, 0, kSTokgen_1d};
-act12 ablowt_1d = {TEXT, 3 * NORMAL_TPS, kSTsablowt_1d};
-act12 abox2_1d = {TEXT, 16, kSTsabox2_1d};
-act12 abox3_1d = {TEXT, 16, kSTsabox3_1d};
-act12 abox5_1d = {TEXT, 38, kSTsabox5_1d};
-act12 abox6_1d = {TEXT, 44, kSTsabox6_1d};
-act12 abung1_1d = {TEXT, 0, kSTsabung1_1d};
-act12 abut11_1d = {TEXT, NORMAL_TPS / 3, kSTsabut11_1d};
-act12 abut6a_1d = {TEXT, 0, kSTsabut6a_1d};
-act12 abut6b_1d = {TEXT, 3, kSTsabut6b_1d};
-act12 abut6c_1d = {TEXT, 6, kSTsabut6c_1d};
-act12 abut9a_1d = {TEXT, NORMAL_TPS / 3, kSTsabut9a_1d};
-act12 abut9b_1d = {TEXT, NORMAL_TPS / 3 + 1, kSTsabut9b_1d};
-act12 acuptxt0_1d = {TEXT, 0, kSTsseepkdw_1d};
-act12 acuptxt1_1d = {TEXT, 0, kSTsseedw_1d};
-act12 acuptxt2_1d = {TEXT, 0, kSTsseepk_1d};
-act12 acuptxt3_1d = {TEXT, 0, kSTsnosee_1d};
-act12 adef6_1d = {TEXT, 1 * NORMAL_TPS, kSTsdefbat1_1d};
-act12 adef7_1d = {TEXT, 3 * NORMAL_TPS, kSTsdefbat2_1d};
-act12 adoggy4_1d = {TEXT, 0, kSTsadoggy4_1d};
-act12 adwwhy_1d = {TEXT, 0, kSTsadwwhy_1d};
-act12 agive1_1d = {TEXT, 0, kSTsagive1_1d};
-act12 agive2_1d = {TEXT, 0, kSTsagive2_1d};
-act12 ahelps1_1d = {TEXT, 0, kSTsahelps1_1d};
-act12 ahelps2_1d = {TEXT, 0, kSTsahelps2_1d};
-act12 ahout1_1d = {TEXT, 0, kSTokgen_1d};
-act12 ajails1_1d = {TEXT, 0, kSTsajails1_1d};
-act12 ajails2_1d = {TEXT, 0, kSTsajails2_1d};
-act12 ajails3_1d = {TEXT, 0, kSTsajails3_1d};
-act12 ajails4_1d = {TEXT, 0, kSTsajails4_1d};
-act12 alab12_1d = {TEXT, 24, kSTsalab12_1d};
-act12 alab13_1d = {TEXT, 24, kSTsalab13_1d};
-act12 amans1_1d = {TEXT, 0, kSTsamans1_1d};
-act12 amans3_1d = {TEXT, 0, kSTsamans3_1d};
-act12 amans4_1d = {TEXT, 0, kSTsamans4_1d};
-act12 amans5_1d = {TEXT, 0, kSTsamans5_1d};
-act12 amans6_1d = {TEXT, 0, kSTsamans6_1d};
-act12 amans7_1d = {TEXT, 0, kSTsamans7_1d};
-act12 amoving_1d = {TEXT, 0, kSTsamoving_1d};
-act12 amum3_1d = {TEXT, 0, kSTsabat5a_1d};
-act12 amum4_1d = {TEXT, 0, kSTsamum4_1d};
-act12 anodeboat_1d = {TEXT, 0, kSTsanodeboat_1d};
-act12 anogive_1d = {TEXT, 0, kSTsanogive_1d};
-act12 anohelp_1d = {TEXT, 0, kSTsanohelp_1d};
-act12 anoopen_1d = {TEXT, 0, kSTsanoopen_1d};
-act12 anotcut_1d = {TEXT, 0, kSTsanotcut_1d};
-act12 anought_1d = {TEXT, 1 * NORMAL_TPS, kSTsanought_1d};
-act12 aopen4_1d = {TEXT, 0, kSTsaopen4_1d};
-act12 aopenfail_1d = {TEXT, 0, kSTsaopenfail_1d};
-act12 apbreak_1d = {TEXT, 0, kSTspbreak_1d};
-act12 arepno5_1d = {TEXT, 0, kSTsarepno5_1d};
-act12 arepnop_1d = {TEXT, 0, kSTsarepnop_1d};
-act12 arepyep_1d = {TEXT, 0, kSTsarepyep_1d};
-act12 arepyep2_1d = {TEXT, 0, kSTsarepyep2_1d};
-act12 at78a_1d = {TEXT, 0, kSTsat78a_1d};
-act12 bye1_1d = {TEXT, 2 * NORMAL_TPS, kSTsabye1_1d};
+act12 achopfail_1d = {TEXT, 0, kSTsthrown_1d};
+act12 achopthrown_1d = {TEXT, 5 * NORMAL_TPS_v1d, kSTsachopthrown_1d};
+act12 admsg1_1d = {TEXT, 0, kSTsadmsg1_1d};
+act12 admsg2_1d = {TEXT, 0, kSTsadmsg2_1d};
+act12 admsg3_1d = {TEXT, 0, kSTsadmsg3_1d};
+act12 aeatchop_1d = {TEXT, 0, kSTsaeatchop_1d};
+act12 agobox_1d = {TEXT, 0, kSTsagobox_1d};
+act12 aigor0_1d = {TEXT, 0, kSTsaigor0_1d};
+act12 aigor13_1d = {TEXT, 0, kSTsaigor13_1d};
+act12 aigor22_1d = {TEXT, 0, kSTsaigor22_1d};
+act12 aigor32_1d = {TEXT, 0, kSTsaigor32_1d};
+act12 ainorm_1d = {TEXT, 0, kSTsainorm_1d};
+act12 a115e_1d = {TEXT, 0, kSTsa115e_1d};
+act12 abat5a_1d = {TEXT, 0, kSTsabat5a_1d};
+act12 abat5b_1d = {TEXT, 0, kSTsabat5b_1d};
+act12 abin0_1d = {TEXT, 0, kSTokgen_1d};
+act12 ablowt_1d = {TEXT, 3 * NORMAL_TPS_v1d, kSTsablowt_1d};
+act12 abox2_1d = {TEXT, 16, kSTsabox2_1d};
+act12 abox3_1d = {TEXT, 16, kSTsabox3_1d};
+act12 abox5_1d = {TEXT, 38, kSTsabox5_1d};
+act12 abox6_1d = {TEXT, 44, kSTsabox6_1d};
+act12 abung1_1d = {TEXT, 0, kSTsabung1_1d};
+act12 abut11_1d = {TEXT, NORMAL_TPS_v1d / 3, kSTsabut11_1d};
+act12 abut6a_1d = {TEXT, 0, kSTsabut6a_1d};
+act12 abut6b_1d = {TEXT, 3, kSTsabut6b_1d};
+act12 abut6c_1d = {TEXT, 6, kSTsabut6c_1d};
+act12 abut9a_1d = {TEXT, NORMAL_TPS_v1d / 3, kSTsabut9a_1d};
+act12 abut9b_1d = {TEXT, NORMAL_TPS_v1d / 3 + 1, kSTsabut9b_1d};
+act12 acuptxt0_1d = {TEXT, 0, kSTsseepkdw_1d};
+act12 acuptxt1_1d = {TEXT, 0, kSTsseedw_1d};
+act12 acuptxt2_1d = {TEXT, 0, kSTsseepk_1d};
+act12 acuptxt3_1d = {TEXT, 0, kSTsnosee_1d};
+act12 adef6_1d = {TEXT, 1 * NORMAL_TPS_v1d, kSTsdefbat1_1d};
+act12 adef7_1d = {TEXT, 3 * NORMAL_TPS_v1d, kSTsdefbat2_1d};
+act12 adoggy4_1d = {TEXT, 0, kSTsadoggy4_1d};
+act12 adwwhy_1d = {TEXT, 0, kSTsadwwhy_1d};
+act12 agive1_1d = {TEXT, 0, kSTsagive1_1d};
+act12 agive2_1d = {TEXT, 0, kSTsagive2_1d};
+act12 ahelps1_1d = {TEXT, 0, kSTsahelps1_1d};
+act12 ahelps2_1d = {TEXT, 0, kSTsahelps2_1d};
+act12 ahout1_1d = {TEXT, 0, kSTokgen_1d};
+act12 ajails1_1d = {TEXT, 0, kSTsajails1_1d};
+act12 ajails2_1d = {TEXT, 0, kSTsajails2_1d};
+act12 ajails3_1d = {TEXT, 0, kSTsajails3_1d};
+act12 ajails4_1d = {TEXT, 0, kSTsajails4_1d};
+act12 alab12_1d = {TEXT, 24, kSTsalab12_1d};
+act12 alab13_1d = {TEXT, 24, kSTsalab13_1d};
+act12 amans1_1d = {TEXT, 0, kSTsamans1_1d};
+act12 amans3_1d = {TEXT, 0, kSTsamans3_1d};
+act12 amans4_1d = {TEXT, 0, kSTsamans4_1d};
+act12 amans5_1d = {TEXT, 0, kSTsamans5_1d};
+act12 amans6_1d = {TEXT, 0, kSTsamans6_1d};
+act12 amans7_1d = {TEXT, 0, kSTsamans7_1d};
+act12 amoving_1d = {TEXT, 0, kSTsamoving_1d};
+act12 amum3_1d = {TEXT, 0, kSTsabat5a_1d};
+act12 amum4_1d = {TEXT, 0, kSTsamum4_1d};
+act12 anodeboat_1d = {TEXT, 0, kSTsanodeboat_1d};
+act12 anogive_1d = {TEXT, 0, kSTsanogive_1d};
+act12 anohelp_1d = {TEXT, 0, kSTsanohelp_1d};
+act12 anoopen_1d = {TEXT, 0, kSTsanoopen_1d};
+act12 anotcut_1d = {TEXT, 0, kSTsanotcut_1d};
+act12 anought_1d = {TEXT, 1 * NORMAL_TPS_v1d, kSTsanought_1d};
+act12 aopen4_1d = {TEXT, 0, kSTsaopen4_1d};
+act12 aopenfail_1d = {TEXT, 0, kSTsaopenfail_1d};
+act12 apbreak_1d = {TEXT, 0, kSTspbreak_1d};
+act12 arepno5_1d = {TEXT, 0, kSTsarepno5_1d};
+act12 arepnop_1d = {TEXT, 0, kSTsarepnop_1d};
+act12 arepyep_1d = {TEXT, 0, kSTsarepyep_1d};
+act12 arepyep2_1d = {TEXT, 0, kSTsarepyep2_1d};
+act12 at78a_1d = {TEXT, 0, kSTsat78a_1d};
+act12 bye1_1d = {TEXT, 2 * NORMAL_TPS_v1d, kSTsabye1_1d};
act13 aigor10_1d = {SWAP_IMAGES, 30, HERO, WHERO_1d};
act13 aigor11_1d = {SWAP_IMAGES, 30, HERO, SPACHERO_1d};
@@ -9173,32 +9192,32 @@ act14 acond9_1d = {COND_SCR, 0, HERO, 9, kALdefbats_1d, kALnought_1d};
act15 adogchop_1d = {AUTOPILOT, 0, DOG_1d, CHOP_1d, DX + 2, DY * 2};
-act16 abin1_1d = {INIT_OBJ_SEQ, 0, BOAT_1d, 1}; // Hero gets in boat
-act16 about1_1d = {INIT_OBJ_SEQ, 0, BOAT_1d, 0}; // Hero gets out of boat
-act16 aclosedoor2_1d = {INIT_OBJ_SEQ, 1 * NORMAL_TPS + 12, DOOR2_1d, 0};
-act16 aclosedoor3_1d = {INIT_OBJ_SEQ, 1 * NORMAL_TPS + 12, DOOR3_1d, 0};
-act16 acutrope_1d = {INIT_OBJ_SEQ, 0, ROPE_1d, 1};
-act16 adog5_1d = {INIT_OBJ_SEQ, 0, DOG_1d, 0}; // Go right
-act16 adogseq_1d = {INIT_OBJ_SEQ, 0, DOG_1d, 1}; // Go left
-act16 adogseq2_1d = {INIT_OBJ_SEQ, 4 * NORMAL_TPS, DOG_1d, 2}; // Sit up
-act16 aguardgo2_1d = {INIT_OBJ_SEQ, 0, GUARD_1d, 1};
-act16 ajail3_1d = {INIT_OBJ_SEQ, 0, HERO, 0}; // Hero dances for joy!
-act16 ajail4_1d = {INIT_OBJ_SEQ, 2, HERO, 1};
-act16 alab10_1d = {INIT_OBJ_SEQ, 14, PROF_1d, 1}; // Look to left
-act16 alab11_1d = {INIT_OBJ_SEQ, 18, IGOR_1d, 1}; // Look to left
-act16 alab4_1d = {INIT_OBJ_SEQ, 0, PROF_1d, 0}; // Walk to right
-act16 at78c_1d = {INIT_OBJ_SEQ, 1 * NORMAL_TPS + 12, TRAP_1d, 0};// Close trap
-act16 aturnguard_1d = {INIT_OBJ_SEQ, 2 * NORMAL_TPS, GUARD_1d, 0};
+act16 abin1_1d = {INIT_OBJ_SEQ, 0, BOAT_1d, 1}; // Hero gets in boat
+act16 about1_1d = {INIT_OBJ_SEQ, 0, BOAT_1d, 0}; // Hero gets out of boat
+act16 aclosedoor2_1d = {INIT_OBJ_SEQ, 1 * NORMAL_TPS_v1d + 12, DOOR2_1d, 0};
+act16 aclosedoor3_1d = {INIT_OBJ_SEQ, 1 * NORMAL_TPS_v1d + 12, DOOR3_1d, 0};
+act16 acutrope_1d = {INIT_OBJ_SEQ, 0, ROPE_1d, 1};
+act16 adog5_1d = {INIT_OBJ_SEQ, 0, DOG_1d, 0}; // Go right
+act16 adogseq_1d = {INIT_OBJ_SEQ, 0, DOG_1d, 1}; // Go left
+act16 adogseq2_1d = {INIT_OBJ_SEQ, 4 * NORMAL_TPS_v1d, DOG_1d, 2}; // Sit up
+act16 aguardgo2_1d = {INIT_OBJ_SEQ, 0, GUARD_1d, 1};
+act16 ajail3_1d = {INIT_OBJ_SEQ, 0, HERO, 0}; // Hero dances for joy!
+act16 ajail4_1d = {INIT_OBJ_SEQ, 2, HERO, 1};
+act16 alab10_1d = {INIT_OBJ_SEQ, 14, PROF_1d, 1}; // Look to left
+act16 alab11_1d = {INIT_OBJ_SEQ, 18, IGOR_1d, 1}; // Look to left
+act16 alab4_1d = {INIT_OBJ_SEQ, 0, PROF_1d, 0}; // Walk to right
+act16 at78c_1d = {INIT_OBJ_SEQ, 1 * NORMAL_TPS_v1d + 12, TRAP_1d, 0}; // Close trap
+act16 aturnguard_1d = {INIT_OBJ_SEQ, 2 * NORMAL_TPS_v1d, GUARD_1d, 0};
act17 acupbdw_1d = {SET_STATE_BITS, 0, CUPBOARD_1d, 2};
act17 acupbpk_1d = {SET_STATE_BITS, 0, CUPBOARD_1d, 1};
-act20 adef1_1d = {DEL_EVENTS, 1 * NORMAL_TPS, ASCHEDULE}; // Stop bats looping
+act20 adef1_1d = {DEL_EVENTS, 1 * NORMAL_TPS_v1d, ASCHEDULE}; // Stop bats looping
act21 abut6g_1d = {GAMEOVER, 7};
act21 adoggy6_1d = {GAMEOVER, 0};
-act23 bye2_1d = {EXIT, 2 * NORMAL_TPS};
+act23 bye2_1d = {EXIT, 2 * NORMAL_TPS_v1d};
act24 abonus0_1d = {BONUS, 0, 0};
act24 abonus1_1d = {BONUS, 0, 1};
@@ -9221,10 +9240,10 @@ act29 achkmask_1d = {COND_CARRY, 0, MASK_1d, kALputmask_1d, 0};
act29 achkmask2_1d = {COND_CARRY, 0, MASK_1d, kALridmask_1d, 0};
//Strangerke - act26 are stored in new act49, as songs were not handled the same way in DOS version (in harcoded strings)
-act49 ahchase4_1d = {OLD_SONG, 4 * NORMAL_TPS, kDTsong3_1d};
-act49 asong1_1d = {OLD_SONG, 0, kDTsong1_1d};
-act49 asong2_1d = {OLD_SONG, 1 * NORMAL_TPS, kDTsong2_1d};
-act49 asong3_1d = {OLD_SONG, 0, kDTsong3_1d};
+act49 ahchase4_1d = {OLD_SONG, 4 * NORMAL_TPS_v1d, kDTsong3_1d};
+act49 asong1_1d = {OLD_SONG, 0, kDTsong1_1d};
+act49 asong2_1d = {OLD_SONG, 1 * NORMAL_TPS_v1d, kDTsong2_1d};
+act49 asong3_1d = {OLD_SONG, 0, kDTsong3_1d};
actListPtr ALbat_1d[] = {&abatxy_1d, &abatvxy1_1d, &abatvxy2_1d, &abatvxy3_1d, &abatvxy4_1d, &abatvxy5_1d, &arepbat_1d, 0};
actListPtr ALbatattack_1d[] = {&abata1a_1d, &abata1b_1d, &abata1c_1d, &abata2a_1d, &abata2b_1d, &abata2c_1d, &abata3a_1d, &abata3b_1d, &abata3c_1d, &abata4a_1d, &abata4b_1d, &abata4c_1d, &arepbata_1d, 0};
@@ -9422,14 +9441,14 @@ int dialrsp_2d[] = {kSTSdial2_2d, -1};
int hestrsp_2d[] = {kSTYes_2d, -1};
int whorsp_2d[] = {kSTNobody_2d, kSTNo_one1_2d, kSTNo_one2_2d, kSTSharry_2d, -1};
-act0 aclimax_2d = {ASCHEDULE, 20, kALclimax_2d};
-act0 aclue09_2d = {ASCHEDULE, 300 * NORMAL_TPS, kALchkc09_2d};
-act0 ahdrink10_2d = {ASCHEDULE, 52, kALhfaint_2d};
-act0 aschedbut_2d = {ASCHEDULE, 30, kALschedbut_2d};
-act0 arepbuga_2d = {ASCHEDULE, 3 * NORMAL_TPS, kALbugrep1_2d};
-act0 arepbugf_2d = {ASCHEDULE, 2 * NORMAL_TPS, kALbugrep2_2d};
-act0 arepblah_2d = {ASCHEDULE, 12 * NORMAL_TPS, kALblah_2d};
-act0 arepmsg1_2d = {ASCHEDULE, 120 * NORMAL_TPS, kALrepmsg1_2d};
+act0 aclimax_2d = {ASCHEDULE, 20, kALclimax_2d};
+act0 aclue09_2d = {ASCHEDULE, 300 * NORMAL_TPS_v2d, kALchkc09_2d};
+act0 ahdrink10_2d = {ASCHEDULE, 52, kALhfaint_2d};
+act0 aschedbut_2d = {ASCHEDULE, 30, kALschedbut_2d};
+act0 arepbuga_2d = {ASCHEDULE, 3 * NORMAL_TPS_v2d, kALbugrep1_2d};
+act0 arepbugf_2d = {ASCHEDULE, 2 * NORMAL_TPS_v2d, kALbugrep2_2d};
+act0 arepblah_2d = {ASCHEDULE, 12 * NORMAL_TPS_v2d, kALblah_2d};
+act0 arepmsg1_2d = {ASCHEDULE, 120 * NORMAL_TPS_v2d, kALrepmsg1_2d};
act1 aback1_2d = {START_OBJ, 0, CAT_2d, 0, ALMOST_INVISIBLE};
act1 aback2_2d = {START_OBJ, 2, CAT_2d, 0, NOT_CYCLING};
@@ -9915,189 +9934,189 @@ act11 achkmaid_2d = {COND_R, 0, MAID_2d, 0, kALmaidx_2d, kALblah_2d}
act11 achkstate0_2d = {COND_R, 0, BOOK_2d, 0, kALhugone_2d, kALchkstate1_2d};
act11 achkstate1_2d = {COND_R, 0, BOOK_2d, 1, kALhole_2d, kALpengone_2d};
-act12 aball4_2d = {TEXT, 2, kSTBalloon1_2d};
-act12 aball5_2d = {TEXT, 2, kSTBalloon2_2d};
-act12 aball6_2d = {TEXT, 2, kSTBalloon3_2d};
-act12 abanana1_2d = {TEXT, 0, kSTBanana1_2d};
-act12 abanana3_2d = {TEXT, 0, kSTBanana2_2d};
-act12 abell_2d = {TEXT, 0, kSTBell1_2d};
-act12 abell1_2d = {TEXT, 8, kSTMaid7_2d};
-act12 abite2_2d = {TEXT, 0, kSTSnake5_2d};
-act12 ablah_2d = {TEXT, 8, kSTBlah_2d};
-act12 aboom_2d = {TEXT, 0, kSTDyn4_2d};
-act12 acallp2_2d = {TEXT, 0, kSTCall1_2d};
-act12 acallp3_2d = {TEXT, 0, kSTCall2_2d};
-act12 acallp4_2d = {TEXT, 0, kSTCall3_2d};
-act12 acallp5_2d = {TEXT, 0, kSTCall4_2d};
-act12 acallp6_2d = {TEXT, 0, kSTCall5_2d};
-act12 acallp7_2d = {TEXT, 0, kSTCall6_2d};
-act12 acantpush_2d = {TEXT, 0, kSTPush1_2d};
-act12 acat1_2d = {TEXT, 0, kSTCat3_2d};
-act12 acat4_2d = {TEXT, 0, kSTMaid8_2d};
-act12 achasm1_2d = {TEXT, 12, kSTChasm1_2d};
-act12 acheat1_2d = {TEXT, 0, kSTScheat1_2d};
-act12 acheat2_2d = {TEXT, 0, kSTScheat2_2d};
-act12 aclimax1_2d = {TEXT, 0, kSTSclimax1_2d};
-act12 aclimax2_2d = {TEXT, 8, kSTSclimax2_2d};
-act12 aclimax3_2d = {TEXT, 80, kSTSclimax3_2d};
-act12 aclimax4_2d = {TEXT, 80, kSTSclimax4_2d};
-act12 aclimax5_2d = {TEXT, 80, kSTSclimax5_2d};
-act12 aclimax6_2d = {TEXT, 80, kSTSclimax6_2d};
-act12 aclue09a_2d = {TEXT, 0, kSTSclue09a_2d};
-act12 aclue09b_2d = {TEXT, 0, kSTSclue09b_2d};
-act12 aclue09c_2d = {TEXT, 0, kSTSclue09c_2d};
-act12 acomb1_2d = {TEXT, 0, kSTScomb1_2d};
-act12 acomb2_2d = {TEXT, 0, kSTScomb2_2d};
-act12 acook1_2d = {TEXT, 8, kSTCook1_2d};
-act12 acook2_2d = {TEXT, 8, kSTCook2_2d};
-act12 acook3_2d = {TEXT, 8, kSTCook3_2d};
-act12 acook4_2d = {TEXT, 24, kSTCook4_2d};
-act12 acook5_2d = {TEXT, 24, kSTCook5_2d};
-act12 adalek1_2d = {TEXT, 0, kSTFire3_2d};
-act12 adidnt1_2d = {TEXT, 0, kSTSdidnt1_2d};
-act12 adidnt2_2d = {TEXT, 0, kSTSdidnt2_2d};
-act12 adog1_2d = {TEXT, 0, kSTDyn2_2d};
-act12 adone1_2d = {TEXT, 10, kSTSdone1_2d};
-act12 adone13_2d = {TEXT, 50, kSTSdone5_2d};
-act12 adone14_2d = {TEXT, 50, kSTSdone6_2d};
-act12 adone2_2d = {TEXT, 10, kSTSdone2_2d};
-act12 adone3_2d = {TEXT, 10, kSTSdone3_2d};
-act12 adone4_2d = {TEXT, 10, kSTSdone4_2d};
-act12 adraught_2d = {TEXT, 5 * 60 * NORMAL_TPS, kSTDraught_2d};
-act12 adropdyn2_2d = {TEXT, 0, kSTDyn3_2d};
-act12 adumb12_2d = {TEXT, 0, kSTDumb2_2d};
-act12 adumb2_2d = {TEXT, 0, kSTDumb1_2d};
-act12 adyn1_2d = {TEXT, 0, kSTDyn1_2d};
-act12 aeatban_2d = {TEXT, 0, kSTSeatbanana_2d};
-act12 aeatgarl1_2d = {TEXT, 0, kSTSgarl1_2d};
-act12 aeatgarl2_2d = {TEXT, 0, kSTSgarl2_2d};
-act12 aexplainb_2d = {TEXT, 0, kSTSexplainb_2d};
-act12 aext1_2d = {TEXT, 0, kSTSdalek1_2d};
-act12 aext2_2d = {TEXT, 0, kSTSdalek2_2d};
-act12 aext3_2d = {TEXT, 0, kSTSdalek3_2d};
-act12 agard10_2d = {TEXT, 300, kSTSgard6_2d};
-act12 agard5_2d = {TEXT, 20, kSTSgard1_2d};
-act12 agard6_2d = {TEXT, 30, kSTSgard2_2d};
-act12 agard7_2d = {TEXT, 40, kSTSgard3_2d};
-act12 agard8_2d = {TEXT, 90, kSTSgard4_2d};
-act12 agard9_2d = {TEXT, 100, kSTSgard5_2d};
-act12 agenie1_2d = {TEXT, 0, kSTRub2_2d};
-act12 agiveb3_2d = {TEXT, 0, kSTCat2_2d};
-act12 ahdrink11_2d = {TEXT, 62, kSTHest4_2d};
-act12 ahdrink12_2d = {TEXT, 64, kSTSay1_2d};
-act12 ahdrink13_2d = {TEXT, 64, kSTSay2_2d};
-act12 ahdrink2_2d = {TEXT, 0, kSTHest1_2d};
-act12 ahdrink8_2d = {TEXT, 52, kSTHest2_2d};
-act12 ahdrink9_2d = {TEXT, 52, kSTHest3_2d};
-act12 ahest12_2d = {TEXT, 8, kSTHest6_2d};
-act12 ahest13_2d = {TEXT, 12, kSTHest7_2d};
-act12 ahest14_2d = {TEXT, 16, kSTHest8_2d};
-act12 ahest15_2d = {TEXT, 50, kSTHest9_2d};
-act12 ahestd2_2d = {TEXT, 0, kSTHest5_2d};
-act12 ahnod1_2d = {TEXT, 0, kSTNod1_2d};
-act12 ahnod2_2d = {TEXT, 0, kSTSay1_2d};
-act12 ahnod3_2d = {TEXT, 0, kSTSay2_2d};
-act12 akaboom1_2d = {TEXT, 0, kSTDyn5_2d};
-act12 alookm1_2d = {TEXT, 0, kSTMatch1_2d};
-act12 alookm2_2d = {TEXT, 0, kSTMatch2_2d};
-act12 amat5_2d = {TEXT, 0, kSTMatch4_2d};
-act12 amissed2_2d = {TEXT, 0, kSTFire1_2d};
-act12 amissed3_2d = {TEXT, 0, kSTFire2_2d};
-act12 amurd4_2d = {TEXT, 10, kSTArgue1_2d};
-act12 anobang_2d = {TEXT, 0, kSTDyn7_2d};
-act12 anobang2_2d = {TEXT, 0, kSTDyn6_2d};
-act12 anobell_2d = {TEXT, 8, kSTBell2_2d};
-act12 anogenie_2d = {TEXT, 0, kSTRub1_2d};
-act12 anoreply_2d = {TEXT, 0, kSTBrrr_2d};
-act12 anotrap_2d = {TEXT, 0, kSTTrap1_2d};
-act12 aom1_2d = {TEXT, 8, kSTSom1_2d};
-act12 aom10_2d = {TEXT, 50, kSTSom4_2d};
-act12 aom11_2d = {TEXT, 50, kSTSom5_2d};
-act12 aom12_2d = {TEXT, 50, kSTSom6_2d};
-act12 aom13_2d = {TEXT, 54, kSTSom7_2d};
-act12 aom14_2d = {TEXT, 54, kSTSom8_2d};
-act12 aom5_2d = {TEXT, 16, kSTSom2_2d};
-act12 aom6_2d = {TEXT, 20, kSTSom3_2d};
-act12 aom9_2d = {TEXT, 40, kSTSom3a_2d};
-act12 apen1_2d = {TEXT, 0, kSTSpen1_2d};
-act12 apen2_2d = {TEXT, 0, kSTSpen2_2d};
-act12 apen3_2d = {TEXT, 0, kSTSpen3_2d};
-act12 aphoto4_2d = {TEXT, 0, kSTSphoto_2d};
-act12 aphoto6_2d = {TEXT, 0, kSTSphoto1_2d};
-act12 apois1_2d = {TEXT, 0, kSTSnake1_2d};
-act12 apois2_2d = {TEXT, 0, kSTSnake2_2d};
-act12 apois3_2d = {TEXT, 0, kSTSnake3_2d};
-act12 apois4_2d = {TEXT, 0, kSTSnake4_2d};
-act12 aridkey2_2d = {TEXT, 0, kSTSridkey_2d};
-act12 arok_2d = {TEXT, 0, kSTWell1_2d};
-act12 arumbling_2d = {TEXT, 0, kSTRumble_2d};
-act12 arup_2d = {TEXT, 0, kSTDyn8_2d};
-act12 asafe1_2d = {TEXT, 0, kSTSsafe1_2d};
-act12 ascr31_2d = {TEXT, 0, kSTLock1_2d};
-act12 aserum1_2d = {TEXT, 0, kSTSserum1_2d};
-act12 aserum2_2d = {TEXT, 0, kSTSserum2_2d};
-act12 asilly_2d = {TEXT, 0, kSTDyn9_2d};
-act12 asniff_2d = {TEXT, 0, kSTCat1_2d};
-act12 asonic1_2d = {TEXT, 0, kSTSsonic1_2d};
-act12 asonic2_2d = {TEXT, 0, kSTSsonic2_2d};
-act12 asonic3_2d = {TEXT, 0, kSTSsonic3_2d};
-act12 asonic4_2d = {TEXT, 0, kSTSsonic4_2d};
-act12 astick1_2d = {TEXT, 0, kSTWeee_2d};
-act12 astrike1_2d = {TEXT, 0, kSTMatch3_2d};
-act12 astung_2d = {TEXT, 0, kSTStung_2d};
-act12 awarn_2d = {TEXT, 8, kSTSwarn_2d};
-act12 awarnz_2d = {TEXT, 8, kSTSwarnz_2d};
-act12 awho1_2d = {TEXT, 0, kSTTard1_2d};
-act12 awho2_2d = {TEXT, 0, kSTTard2_2d};
-act12 awill1_2d = {TEXT, 0, kSTSwill1_2d};
-act12 awill2_2d = {TEXT, 0, kSTSwill2_2d};
-act12 awill3_2d = {TEXT, 0, kSTSwill3_2d};
-act12 awill4_2d = {TEXT, 0, kSTSwill4_2d};
-act12 abell2_2d = {TEXT, 16, kSTMaid6_2d};
-act12 abug5a_2d = {TEXT, 0, kSTStingeroo_2d};
-act12 abug5b_2d = {TEXT, 0, kSTSbug5b_2d};
-act12 aclick_2d = {TEXT, 0, kSTClick_2d};
-act12 aempty_2d = {TEXT, 0, kSTEmpty_2d};
-act12 afaint1_2d = {TEXT, 5, kSTSfaint1_2d};
-act12 afaint10_2d = {TEXT, 35, kSTSfaint4_2d};
-act12 afaint5_2d = {TEXT, 20, kSTSfaint2_2d};
-act12 afaint9_2d = {TEXT, 35, kSTSfaint3_2d};
-act12 agone10_2d = {TEXT, 115, kSTSgone6_2d};
-act12 agone11_2d = {TEXT, 115, kSTSgone7_2d};
-act12 agone5_2d = {TEXT, 0, kSTSgone1_2d};
-act12 agone6_2d = {TEXT, 34, kSTSgone2_2d};
-act12 agone7_2d = {TEXT, 70, kSTSgone3_2d};
-act12 agone8_2d = {TEXT, 90, kSTSgone4_2d};
-act12 agone9_2d = {TEXT, 115, kSTSgone5_2d};
-act12 aharry3_2d = {TEXT, 4, kSTOrgan1_2d};
-act12 aharry4_2d = {TEXT, 4, kSTOrgan2_2d};
-act12 aharry5_2d = {TEXT, 4, kSTOrgan3_2d};
-act12 aharry7_2d = {TEXT, 8, kSTOrgan4_2d};
-act12 ahole_2d = {TEXT, 0, kSTFirst2_2d};
-act12 akeyhole1_2d = {TEXT, 0, kSTHole1_2d};
-act12 alie1_2d = {TEXT, 13, kSTTired_2d};
-act12 alie2_2d = {TEXT, 18, kSTTired2_2d};
-act12 amaid10_2d = {TEXT, 90 * NORMAL_TPS, kSTSmaid1_8_2d};
-act12 amaid11_2d = {TEXT, 99 * NORMAL_TPS, kSTSmaid1_9_2d};
-act12 amaid12_2d = {TEXT, 0, kSTSmaid1_10_2d};
-act12 amaid3_2d = {TEXT, 4, kSTSmaid1_1_2d};
-act12 amaid4_2d = {TEXT, 17, kSTSmaid1_2_2d};
-act12 amaid5_2d = {TEXT, 17, kSTSmaid1_3_2d};
-act12 amaid6_2d = {TEXT, 17, kSTSmaid1_4_2d};
-act12 amaid7_2d = {TEXT, 30, kSTSmaid1_5_2d};
-act12 amaid8_2d = {TEXT, 30 * NORMAL_TPS, kSTSmaid1_6_2d};
-act12 amaid9_2d = {TEXT, 60 * NORMAL_TPS, kSTSmaid1_7_2d};
-act12 amaidp3_2d = {TEXT, 8, kSTMaid1_2d};
-act12 amaidp4_2d = {TEXT, 8, kSTMaid2_2d};
-act12 amaidp5_2d = {TEXT, 8, kSTMaid3_2d};
-act12 amaidp7_2d = {TEXT, 12, kSTMaid4_2d};
-act12 amaidp8_2d = {TEXT, 12, kSTMaid5_2d};
-act12 anocarry_2d = {TEXT, 0, kSTNocarry_2d};
-act12 anopurps_2d = {TEXT, 0, kSTNopurps_2d};
-act12 aok_2d = {TEXT, 0, kSTOkgen_2d};
-act12 ascr21_2d = {TEXT, 0, kSTSfirst_2d};
-act12 astory1_2d = {TEXT, STORYDELAY, kSTStory_2d};
-act12 astory2_2d = {TEXT, STORYDELAY, kSTStory1_2d};
+act12 aball4_2d = {TEXT, 2, kSTBalloon1_2d};
+act12 aball5_2d = {TEXT, 2, kSTBalloon2_2d};
+act12 aball6_2d = {TEXT, 2, kSTBalloon3_2d};
+act12 abanana1_2d = {TEXT, 0, kSTBanana1_2d};
+act12 abanana3_2d = {TEXT, 0, kSTBanana2_2d};
+act12 abell_2d = {TEXT, 0, kSTBell1_2d};
+act12 abell1_2d = {TEXT, 8, kSTMaid7_2d};
+act12 abite2_2d = {TEXT, 0, kSTSnake5_2d};
+act12 ablah_2d = {TEXT, 8, kSTBlah_2d};
+act12 aboom_2d = {TEXT, 0, kSTDyn4_2d};
+act12 acallp2_2d = {TEXT, 0, kSTCall1_2d};
+act12 acallp3_2d = {TEXT, 0, kSTCall2_2d};
+act12 acallp4_2d = {TEXT, 0, kSTCall3_2d};
+act12 acallp5_2d = {TEXT, 0, kSTCall4_2d};
+act12 acallp6_2d = {TEXT, 0, kSTCall5_2d};
+act12 acallp7_2d = {TEXT, 0, kSTCall6_2d};
+act12 acantpush_2d = {TEXT, 0, kSTPush1_2d};
+act12 acat1_2d = {TEXT, 0, kSTCat3_2d};
+act12 acat4_2d = {TEXT, 0, kSTMaid8_2d};
+act12 achasm1_2d = {TEXT, 12, kSTChasm1_2d};
+act12 acheat1_2d = {TEXT, 0, kSTScheat1_2d};
+act12 acheat2_2d = {TEXT, 0, kSTScheat2_2d};
+act12 aclimax1_2d = {TEXT, 0, kSTSclimax1_2d};
+act12 aclimax2_2d = {TEXT, 8, kSTSclimax2_2d};
+act12 aclimax3_2d = {TEXT, 80, kSTSclimax3_2d};
+act12 aclimax4_2d = {TEXT, 80, kSTSclimax4_2d};
+act12 aclimax5_2d = {TEXT, 80, kSTSclimax5_2d};
+act12 aclimax6_2d = {TEXT, 80, kSTSclimax6_2d};
+act12 aclue09a_2d = {TEXT, 0, kSTSclue09a_2d};
+act12 aclue09b_2d = {TEXT, 0, kSTSclue09b_2d};
+act12 aclue09c_2d = {TEXT, 0, kSTSclue09c_2d};
+act12 acomb1_2d = {TEXT, 0, kSTScomb1_2d};
+act12 acomb2_2d = {TEXT, 0, kSTScomb2_2d};
+act12 acook1_2d = {TEXT, 8, kSTCook1_2d};
+act12 acook2_2d = {TEXT, 8, kSTCook2_2d};
+act12 acook3_2d = {TEXT, 8, kSTCook3_2d};
+act12 acook4_2d = {TEXT, 24, kSTCook4_2d};
+act12 acook5_2d = {TEXT, 24, kSTCook5_2d};
+act12 adalek1_2d = {TEXT, 0, kSTFire3_2d};
+act12 adidnt1_2d = {TEXT, 0, kSTSdidnt1_2d};
+act12 adidnt2_2d = {TEXT, 0, kSTSdidnt2_2d};
+act12 adog1_2d = {TEXT, 0, kSTDyn2_2d};
+act12 adone1_2d = {TEXT, 10, kSTSdone1_2d};
+act12 adone13_2d = {TEXT, 50, kSTSdone5_2d};
+act12 adone14_2d = {TEXT, 50, kSTSdone6_2d};
+act12 adone2_2d = {TEXT, 10, kSTSdone2_2d};
+act12 adone3_2d = {TEXT, 10, kSTSdone3_2d};
+act12 adone4_2d = {TEXT, 10, kSTSdone4_2d};
+act12 adraught_2d = {TEXT, 5 * 60 * NORMAL_TPS_v2d, kSTDraught_2d};
+act12 adropdyn2_2d = {TEXT, 0, kSTDyn3_2d};
+act12 adumb12_2d = {TEXT, 0, kSTDumb2_2d};
+act12 adumb2_2d = {TEXT, 0, kSTDumb1_2d};
+act12 adyn1_2d = {TEXT, 0, kSTDyn1_2d};
+act12 aeatban_2d = {TEXT, 0, kSTSeatbanana_2d};
+act12 aeatgarl1_2d = {TEXT, 0, kSTSgarl1_2d};
+act12 aeatgarl2_2d = {TEXT, 0, kSTSgarl2_2d};
+act12 aexplainb_2d = {TEXT, 0, kSTSexplainb_2d};
+act12 aext1_2d = {TEXT, 0, kSTSdalek1_2d};
+act12 aext2_2d = {TEXT, 0, kSTSdalek2_2d};
+act12 aext3_2d = {TEXT, 0, kSTSdalek3_2d};
+act12 agard10_2d = {TEXT, 300, kSTSgard6_2d};
+act12 agard5_2d = {TEXT, 20, kSTSgard1_2d};
+act12 agard6_2d = {TEXT, 30, kSTSgard2_2d};
+act12 agard7_2d = {TEXT, 40, kSTSgard3_2d};
+act12 agard8_2d = {TEXT, 90, kSTSgard4_2d};
+act12 agard9_2d = {TEXT, 100, kSTSgard5_2d};
+act12 agenie1_2d = {TEXT, 0, kSTRub2_2d};
+act12 agiveb3_2d = {TEXT, 0, kSTCat2_2d};
+act12 ahdrink11_2d = {TEXT, 62, kSTHest4_2d};
+act12 ahdrink12_2d = {TEXT, 64, kSTSay1_2d};
+act12 ahdrink13_2d = {TEXT, 64, kSTSay2_2d};
+act12 ahdrink2_2d = {TEXT, 0, kSTHest1_2d};
+act12 ahdrink8_2d = {TEXT, 52, kSTHest2_2d};
+act12 ahdrink9_2d = {TEXT, 52, kSTHest3_2d};
+act12 ahest12_2d = {TEXT, 8, kSTHest6_2d};
+act12 ahest13_2d = {TEXT, 12, kSTHest7_2d};
+act12 ahest14_2d = {TEXT, 16, kSTHest8_2d};
+act12 ahest15_2d = {TEXT, 50, kSTHest9_2d};
+act12 ahestd2_2d = {TEXT, 0, kSTHest5_2d};
+act12 ahnod1_2d = {TEXT, 0, kSTNod1_2d};
+act12 ahnod2_2d = {TEXT, 0, kSTSay1_2d};
+act12 ahnod3_2d = {TEXT, 0, kSTSay2_2d};
+act12 akaboom1_2d = {TEXT, 0, kSTDyn5_2d};
+act12 alookm1_2d = {TEXT, 0, kSTMatch1_2d};
+act12 alookm2_2d = {TEXT, 0, kSTMatch2_2d};
+act12 amat5_2d = {TEXT, 0, kSTMatch4_2d};
+act12 amissed2_2d = {TEXT, 0, kSTFire1_2d};
+act12 amissed3_2d = {TEXT, 0, kSTFire2_2d};
+act12 amurd4_2d = {TEXT, 10, kSTArgue1_2d};
+act12 anobang_2d = {TEXT, 0, kSTDyn7_2d};
+act12 anobang2_2d = {TEXT, 0, kSTDyn6_2d};
+act12 anobell_2d = {TEXT, 8, kSTBell2_2d};
+act12 anogenie_2d = {TEXT, 0, kSTRub1_2d};
+act12 anoreply_2d = {TEXT, 0, kSTBrrr_2d};
+act12 anotrap_2d = {TEXT, 0, kSTTrap1_2d};
+act12 aom1_2d = {TEXT, 8, kSTSom1_2d};
+act12 aom10_2d = {TEXT, 50, kSTSom4_2d};
+act12 aom11_2d = {TEXT, 50, kSTSom5_2d};
+act12 aom12_2d = {TEXT, 50, kSTSom6_2d};
+act12 aom13_2d = {TEXT, 54, kSTSom7_2d};
+act12 aom14_2d = {TEXT, 54, kSTSom8_2d};
+act12 aom5_2d = {TEXT, 16, kSTSom2_2d};
+act12 aom6_2d = {TEXT, 20, kSTSom3_2d};
+act12 aom9_2d = {TEXT, 40, kSTSom3a_2d};
+act12 apen1_2d = {TEXT, 0, kSTSpen1_2d};
+act12 apen2_2d = {TEXT, 0, kSTSpen2_2d};
+act12 apen3_2d = {TEXT, 0, kSTSpen3_2d};
+act12 aphoto4_2d = {TEXT, 0, kSTSphoto_2d};
+act12 aphoto6_2d = {TEXT, 0, kSTSphoto1_2d};
+act12 apois1_2d = {TEXT, 0, kSTSnake1_2d};
+act12 apois2_2d = {TEXT, 0, kSTSnake2_2d};
+act12 apois3_2d = {TEXT, 0, kSTSnake3_2d};
+act12 apois4_2d = {TEXT, 0, kSTSnake4_2d};
+act12 aridkey2_2d = {TEXT, 0, kSTSridkey_2d};
+act12 arok_2d = {TEXT, 0, kSTWell1_2d};
+act12 arumbling_2d = {TEXT, 0, kSTRumble_2d};
+act12 arup_2d = {TEXT, 0, kSTDyn8_2d};
+act12 asafe1_2d = {TEXT, 0, kSTSsafe1_2d};
+act12 ascr31_2d = {TEXT, 0, kSTLock1_2d};
+act12 aserum1_2d = {TEXT, 0, kSTSserum1_2d};
+act12 aserum2_2d = {TEXT, 0, kSTSserum2_2d};
+act12 asilly_2d = {TEXT, 0, kSTDyn9_2d};
+act12 asniff_2d = {TEXT, 0, kSTCat1_2d};
+act12 asonic1_2d = {TEXT, 0, kSTSsonic1_2d};
+act12 asonic2_2d = {TEXT, 0, kSTSsonic2_2d};
+act12 asonic3_2d = {TEXT, 0, kSTSsonic3_2d};
+act12 asonic4_2d = {TEXT, 0, kSTSsonic4_2d};
+act12 astick1_2d = {TEXT, 0, kSTWeee_2d};
+act12 astrike1_2d = {TEXT, 0, kSTMatch3_2d};
+act12 astung_2d = {TEXT, 0, kSTStung_2d};
+act12 awarn_2d = {TEXT, 8, kSTSwarn_2d};
+act12 awarnz_2d = {TEXT, 8, kSTSwarnz_2d};
+act12 awho1_2d = {TEXT, 0, kSTTard1_2d};
+act12 awho2_2d = {TEXT, 0, kSTTard2_2d};
+act12 awill1_2d = {TEXT, 0, kSTSwill1_2d};
+act12 awill2_2d = {TEXT, 0, kSTSwill2_2d};
+act12 awill3_2d = {TEXT, 0, kSTSwill3_2d};
+act12 awill4_2d = {TEXT, 0, kSTSwill4_2d};
+act12 abell2_2d = {TEXT, 16, kSTMaid6_2d};
+act12 abug5a_2d = {TEXT, 0, kSTStingeroo_2d};
+act12 abug5b_2d = {TEXT, 0, kSTSbug5b_2d};
+act12 aclick_2d = {TEXT, 0, kSTClick_2d};
+act12 aempty_2d = {TEXT, 0, kSTEmpty_2d};
+act12 afaint1_2d = {TEXT, 5, kSTSfaint1_2d};
+act12 afaint10_2d = {TEXT, 35, kSTSfaint4_2d};
+act12 afaint5_2d = {TEXT, 20, kSTSfaint2_2d};
+act12 afaint9_2d = {TEXT, 35, kSTSfaint3_2d};
+act12 agone10_2d = {TEXT, 115, kSTSgone6_2d};
+act12 agone11_2d = {TEXT, 115, kSTSgone7_2d};
+act12 agone5_2d = {TEXT, 0, kSTSgone1_2d};
+act12 agone6_2d = {TEXT, 34, kSTSgone2_2d};
+act12 agone7_2d = {TEXT, 70, kSTSgone3_2d};
+act12 agone8_2d = {TEXT, 90, kSTSgone4_2d};
+act12 agone9_2d = {TEXT, 115, kSTSgone5_2d};
+act12 aharry3_2d = {TEXT, 4, kSTOrgan1_2d};
+act12 aharry4_2d = {TEXT, 4, kSTOrgan2_2d};
+act12 aharry5_2d = {TEXT, 4, kSTOrgan3_2d};
+act12 aharry7_2d = {TEXT, 8, kSTOrgan4_2d};
+act12 ahole_2d = {TEXT, 0, kSTFirst2_2d};
+act12 akeyhole1_2d = {TEXT, 0, kSTHole1_2d};
+act12 alie1_2d = {TEXT, 13, kSTTired_2d};
+act12 alie2_2d = {TEXT, 18, kSTTired2_2d};
+act12 amaid10_2d = {TEXT, 90 * NORMAL_TPS_v2d, kSTSmaid1_8_2d};
+act12 amaid11_2d = {TEXT, 99 * NORMAL_TPS_v2d, kSTSmaid1_9_2d};
+act12 amaid12_2d = {TEXT, 0, kSTSmaid1_10_2d};
+act12 amaid3_2d = {TEXT, 4, kSTSmaid1_1_2d};
+act12 amaid4_2d = {TEXT, 17, kSTSmaid1_2_2d};
+act12 amaid5_2d = {TEXT, 17, kSTSmaid1_3_2d};
+act12 amaid6_2d = {TEXT, 17, kSTSmaid1_4_2d};
+act12 amaid7_2d = {TEXT, 30, kSTSmaid1_5_2d};
+act12 amaid8_2d = {TEXT, 30 * NORMAL_TPS_v2d, kSTSmaid1_6_2d};
+act12 amaid9_2d = {TEXT, 60 * NORMAL_TPS_v2d, kSTSmaid1_7_2d};
+act12 amaidp3_2d = {TEXT, 8, kSTMaid1_2d};
+act12 amaidp4_2d = {TEXT, 8, kSTMaid2_2d};
+act12 amaidp5_2d = {TEXT, 8, kSTMaid3_2d};
+act12 amaidp7_2d = {TEXT, 12, kSTMaid4_2d};
+act12 amaidp8_2d = {TEXT, 12, kSTMaid5_2d};
+act12 anocarry_2d = {TEXT, 0, kSTNocarry_2d};
+act12 anopurps_2d = {TEXT, 0, kSTNopurps_2d};
+act12 aok_2d = {TEXT, 0, kSTOkgen_2d};
+act12 ascr21_2d = {TEXT, 0, kSTSfirst_2d};
+act12 astory1_2d = {TEXT, STORYDELAY, kSTStory_2d};
+act12 astory2_2d = {TEXT, STORYDELAY, kSTStory1_2d};
act13 ascr33b_2d = {SWAP_IMAGES, 4, HERO, PENNY_2d};
act13 aswaphero_2d = {SWAP_IMAGES, 23, HERO, PENNY_2d};
@@ -10292,14 +10311,14 @@ act33 amaidc11_2d = {INIT_SCREEN, 30, MAID_2d, 31};
act33 amaidc2_2d = {INIT_SCREEN, 8, MAID_2d, 32};
act33 amaidp1_2d = {INIT_SCREEN, 0, MAID_2d, 31};
-act34 abang1_2d = {AGSCHEDULE, 5 * NORMAL_TPS, kALbang2_2d};
-act34 abite3_2d = {AGSCHEDULE, 60 * NORMAL_TPS, kALpois1_2d};
-act34 abite4_2d = {AGSCHEDULE, 200 * NORMAL_TPS, kALpois2_2d};
-act34 abite5_2d = {AGSCHEDULE, 290 * NORMAL_TPS, kALpois3_2d};
-act34 abite6_2d = {AGSCHEDULE, 300 * NORMAL_TPS, kALpois4_2d};
-act34 acat3_2d = {AGSCHEDULE, 8 * NORMAL_TPS, kALchkcarry_2d};
-act34 akaboom2_2d = {AGSCHEDULE, 1, kALkaboom3_2d};
-act34 amaidb6_2d = {AGSCHEDULE, 8 * NORMAL_TPS, kALmaidbk_2d};
+act34 abang1_2d = {AGSCHEDULE, 5 * NORMAL_TPS_v2d, kALbang2_2d};
+act34 abite3_2d = {AGSCHEDULE, 60 * NORMAL_TPS_v2d, kALpois1_2d};
+act34 abite4_2d = {AGSCHEDULE, 200 * NORMAL_TPS_v2d, kALpois2_2d};
+act34 abite5_2d = {AGSCHEDULE, 290 * NORMAL_TPS_v2d, kALpois3_2d};
+act34 abite6_2d = {AGSCHEDULE, 300 * NORMAL_TPS_v2d, kALpois4_2d};
+act34 acat3_2d = {AGSCHEDULE, 8 * NORMAL_TPS_v2d, kALchkcarry_2d};
+act34 akaboom2_2d = {AGSCHEDULE, 1, kALkaboom3_2d};
+act34 amaidb6_2d = {AGSCHEDULE, 8 * NORMAL_TPS_v2d, kALmaidbk_2d};
act35 amap0_2d = {REMAPPAL, 0, _TLIGHTMAGENTA, _LIGHTMAGENTA};
act35 amap1_2d = {REMAPPAL, 0, _TLIGHTMAGENTA, _BLACK};
@@ -10919,47 +10938,47 @@ act8 ascr_wfall_clf_3d = {NEW_SCREEN, 0, CLIFF_3d};
act8 ascr_wfallb_wbase_3d = {NEW_SCREEN, 0, WBASE_3d};
act8 aweb23_3d = {NEW_SCREEN, 117, CRASH_3d};
-act9 abrg_msg2_3d = {INIT_OBJSTATE, 0, VINE_3d, 1};
-act9 acamp0a_3d = {INIT_OBJSTATE, 4, NAT2_3d, 0};
-act9 acom0b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 1};
-act9 acom1b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 2};
-act9 acom2b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 3};
-act9 acom3b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 4};
-act9 acom4b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 5};
-act9 acom5b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 6};
-act9 acom6b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 7};
-act9 acom7b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 8};
-act9 acom8b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 9};
-act9 adart1_3d = {INIT_OBJSTATE, 0, BLOWPIPE_3d, 1};
-act9 adn2_3d = {INIT_OBJSTATE, 0, HERO, 0};
-act9 adrink_3d = {INIT_OBJSTATE, 0, FLASK_3d, 0};
-act9 adropcheese3_3d = {INIT_OBJSTATE, 0, CHEESE_3d, 1};
-act9 aelewoken_3d = {INIT_OBJSTATE, 0, ELEPHANT_3d, 0};
-act9 aemptyflask_3d = {INIT_OBJSTATE, 0, FLASK_3d, 0};
-act9 aendaction_3d = {INIT_OBJSTATE, DARTTIME + 30, E_EYES_3d, 0};
-act9 aenter1_3d = {INIT_OBJSTATE, 0, MOUSE_3d, 2};
-act9 aex7_3d = {INIT_OBJSTATE, 0, GHOST_3d, 1};
-act9 afillmagic3_3d = {INIT_OBJSTATE, 0, FLASK_3d, 2};
-act9 afillord2_3d = {INIT_OBJSTATE, 0, FLASK_3d, 1};
-act9 afindb1_3d = {INIT_OBJSTATE, 0, BOOK_3d, 1};
-act9 agive3_3d = {INIT_OBJSTATE, 0, NAT1_3d, 10};
-act9 agot1_3d = {INIT_OBJSTATE, 0, DOCTOR_3d, 1};
-act9 ahelp2_3d = {INIT_OBJSTATE, 0, HERO, 1};
-act9 ahole5a_3d = {INIT_OBJSTATE, 0, MOUSE_3d, 1};
-act9 ahole5b_3d = {INIT_OBJSTATE, 0, MOUSE_3d, 0};
-act9 amakeclay2_3d = {INIT_OBJSTATE, 0, CLAY_3d, 1};
-act9 amission1_3d = {INIT_OBJSTATE, 0, PENNY_3d, 2};
-act9 amousefree_3d = {INIT_OBJSTATE, 0, MOUSE_3d, 3};
-act9 aoldstate_3d = {INIT_OBJSTATE, 0, MOUTH_3d, 1};
-act9 aopen2_3d = {INIT_OBJSTATE, 0, CDOOR_3d, 1};
-act9 apause0_3d = {INIT_OBJSTATE, 3 * NORMAL_TPS, NAT2_3d, 0};
-act9 apause1_3d = {INIT_OBJSTATE, 0, NAT2_3d, 1};
-act9 astartaction_3d = {INIT_OBJSTATE, 0, E_EYES_3d, 1};
-act9 astick3_3d = {INIT_OBJSTATE, 0, DOCTOR_3d, 2};
-act9 atakecheese1_3d = {INIT_OBJSTATE, 0, CHEESE_3d, 0};
-act9 aup2_3d = {INIT_OBJSTATE, 0, HERO, 1};
-act9 avine6_3d = {INIT_OBJSTATE, 0, BLOCK1_3d, 1};
-act9 aweb1_3d = {INIT_OBJSTATE, 0, PENNY_3d, 1};
+act9 abrg_msg2_3d = {INIT_OBJSTATE, 0, VINE_3d, 1};
+act9 acamp0a_3d = {INIT_OBJSTATE, 4, NAT2_3d, 0};
+act9 acom0b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 1};
+act9 acom1b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 2};
+act9 acom2b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 3};
+act9 acom3b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 4};
+act9 acom4b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 5};
+act9 acom5b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 6};
+act9 acom6b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 7};
+act9 acom7b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 8};
+act9 acom8b_3d = {INIT_OBJSTATE, 0, NAT1_3d, 9};
+act9 adart1_3d = {INIT_OBJSTATE, 0, BLOWPIPE_3d, 1};
+act9 adn2_3d = {INIT_OBJSTATE, 0, HERO, 0};
+act9 adrink_3d = {INIT_OBJSTATE, 0, FLASK_3d, 0};
+act9 adropcheese3_3d = {INIT_OBJSTATE, 0, CHEESE_3d, 1};
+act9 aelewoken_3d = {INIT_OBJSTATE, 0, ELEPHANT_3d, 0};
+act9 aemptyflask_3d = {INIT_OBJSTATE, 0, FLASK_3d, 0};
+act9 aendaction_3d = {INIT_OBJSTATE, DARTTIME + 30, E_EYES_3d, 0};
+act9 aenter1_3d = {INIT_OBJSTATE, 0, MOUSE_3d, 2};
+act9 aex7_3d = {INIT_OBJSTATE, 0, GHOST_3d, 1};
+act9 afillmagic3_3d = {INIT_OBJSTATE, 0, FLASK_3d, 2};
+act9 afillord2_3d = {INIT_OBJSTATE, 0, FLASK_3d, 1};
+act9 afindb1_3d = {INIT_OBJSTATE, 0, BOOK_3d, 1};
+act9 agive3_3d = {INIT_OBJSTATE, 0, NAT1_3d, 10};
+act9 agot1_3d = {INIT_OBJSTATE, 0, DOCTOR_3d, 1};
+act9 ahelp2_3d = {INIT_OBJSTATE, 0, HERO, 1};
+act9 ahole5a_3d = {INIT_OBJSTATE, 0, MOUSE_3d, 1};
+act9 ahole5b_3d = {INIT_OBJSTATE, 0, MOUSE_3d, 0};
+act9 amakeclay2_3d = {INIT_OBJSTATE, 0, CLAY_3d, 1};
+act9 amission1_3d = {INIT_OBJSTATE, 0, PENNY_3d, 2};
+act9 amousefree_3d = {INIT_OBJSTATE, 0, MOUSE_3d, 3};
+act9 aoldstate_3d = {INIT_OBJSTATE, 0, MOUTH_3d, 1};
+act9 aopen2_3d = {INIT_OBJSTATE, 0, CDOOR_3d, 1};
+act9 apause0_3d = {INIT_OBJSTATE, 3 * NORMAL_TPS_v2d, NAT2_3d, 0};
+act9 apause1_3d = {INIT_OBJSTATE, 0, NAT2_3d, 1};
+act9 astartaction_3d = {INIT_OBJSTATE, 0, E_EYES_3d, 1};
+act9 astick3_3d = {INIT_OBJSTATE, 0, DOCTOR_3d, 2};
+act9 atakecheese1_3d = {INIT_OBJSTATE, 0, CHEESE_3d, 0};
+act9 aup2_3d = {INIT_OBJSTATE, 0, HERO, 1};
+act9 avine6_3d = {INIT_OBJSTATE, 0, BLOCK1_3d, 1};
+act9 aweb1_3d = {INIT_OBJSTATE, 0, PENNY_3d, 1};
act10 acamp1a_3d = {INIT_PATH, 0, NAT2_3d, AUTO, 0, 0};
act10 acamp1b_3d = {INIT_PATH, 0, NATG_3d, AUTO, 0, 0};
@@ -10983,58 +11002,58 @@ act10 aenable_3d = {INIT_PATH, 0, HERO, USER, 0, 0};
act10 ahoriz6_3d = {INIT_PATH, 1, HERO, USER, 0, 0};
act10 aquiet_3d = {INIT_PATH, 0, HERO, QUIET, 0, 0};
-act11 aactiontest1_3d = {COND_R, 0, E_EYES_3d, 1, 0, kALoktoleave1_3d};
-act11 aactiontest2_3d = {COND_R, 0, E_EYES_3d, 1, 0, kALoktoleave2_3d};
-act11 ablktest_3d = {COND_R, 0, BLOCK1_3d, 0, kALblk1_3d, 0};
-act11 abrgmsgtest_3d = {COND_R, 0, VINE_3d, 0, kALbrg_clftop_msg_3d, kALbrg_clftop1_3d};
-act11 abrgtest_3d = {COND_R, 0, VINE_3d, 0, kALbrg_ok_3d, kALbrg_down_3d};
-act11 acagetest_3d = {COND_R, 0, MOUSE_3d, 2, 0, kALpostest_3d};
-act11 acagetest1_3d = {COND_R, 0, MOUSE_3d, 2, kALcagetest2_3d, kALok_3d};
-act11 acamptest_3d = {COND_R, 0, NAT1_3d, 0, kALcampers_3d, kALchase_3d};
-act11 acavetest_3d = {COND_R, 0, GHOST_3d, 0, kALspirit_3d, kALcave_man_3d};
-act11 acrashtest1_3d = {COND_R, 0, PENNY_3d, 0, kALcrashed_3d, kALcrashtest2_3d};
-act11 acrashtest2_3d = {COND_R, 0, PENNY_3d, 1, kALcryhelp_3d, 0};
-act11 adartedtest_3d = {COND_R, 0, BLOWPIPE_3d, 0, kALdodart_3d, kALdarted_3d};
-act11 adoctest_3d = {COND_R, 0, DOCTOR_3d, 0, kALdoc_3d, 0};
-act11 adrinktest_3d = {COND_R, 0, FLASK_3d, 0, kALdrinkno_3d, kALdrinkyes_3d};
-act11 aeletest1_3d = {COND_R, 0, ELEPHANT_3d, 1, kALele_sleep_3d, kALeletest2_3d};
-act11 aeletest2_3d = {COND_R, 0, ELEPHANT_3d, 0, kALeleblink_3d, 0};
-act11 aemptytest1_3d = {COND_R, 0, FLASK_3d, 2, kALemptymagic_3d, kALemptytest2_3d};
-act11 aemptytest2_3d = {COND_R, 0, FLASK_3d, 1, kALemptyord_3d, kALdrinkno_3d};
-act11 aentertest1_3d = {COND_R, 0, CHEESE_3d, 1, kALentertest2_3d, 0};
-act11 aentertest2_3d = {COND_R, 0, MOUSE_3d, 0, kALentertest3_3d, 0};
-act11 aexotest1_3d = {COND_R, 0, GHOST_3d, 0, kALexotest2_3d, kALexordone_3d};
-act11 afindbtest_3d = {COND_R, 0, BOOK_3d, 0, kALfindit_3d, 0};
-act11 aflasktest2_3d = {COND_R, 0, FLASK_3d, 2, kALremedy_3d, kALflasktest3_3d};
-act11 aflasktest3_3d = {COND_R, 0, FLASK_3d, 1, kALnoremedy_3d, kALrefuseflask_3d};
-act11 agettest2_3d = {COND_R, 0, DOCTOR_3d, 0, kALgot_3d, 0};
-act11 agivetest_3d = {COND_R, 0, NAT1_3d, 10, kALrefuse_3d, kALgive_3d};
-act11 anat0_3d = {COND_R, 0, NAT1_3d, 0, kALcom0_3d, kALnat1_3d};
-act11 anat1_3d = {COND_R, 0, NAT1_3d, 1, kALcom1_3d, kALnat2_3d};
-act11 anat2_3d = {COND_R, 0, NAT1_3d, 2, kALcom2_3d, kALnat3_3d};
-act11 anat3_3d = {COND_R, 0, NAT1_3d, 3, kALcom3_3d, kALnat4_3d};
-act11 anat4_3d = {COND_R, 0, NAT1_3d, 4, kALcom4_3d, kALnat5_3d};
-act11 anat5_3d = {COND_R, 0, NAT1_3d, 5, kALcom5_3d, kALnat6_3d};
-act11 anat6_3d = {COND_R, 0, NAT1_3d, 6, kALcom6_3d, kALnat7_3d};
-act11 anat7_3d = {COND_R, 0, NAT1_3d, 7, kALcom7_3d, kALnat8_3d};
-act11 anat8_3d = {COND_R, 0, NAT1_3d, 8, kALcom8_3d, 0};
-act11 aold5_3d = {COND_R, 0, FLASK_3d, 2, kALold6_3d, kALwrong_3d};
-act11 aoldmantest_3d = {COND_R, 0, MOUTH_3d, 0, kALoldfirst_3d, kALoldsubseq_3d};
-act11 aopentest_3d = {COND_R, 0, DOCTOR_3d, 1, kALprod_3d, kALopencdoor_3d};
-act11 apausetest_3d = {COND_R, 0, NAT2_3d, 1, 0, kALcomment_3d};
-act11 apostest_3d = {COND_R, 0, MOUSE_3d, 0, kALmousel_3d, kALmouser_3d};
-act11 aspirittest_3d = {COND_R, 0, GHOST_3d, 0, kALwarn_3d, 0};
-act11 asticktest1_3d = {COND_R, 0, DOCTOR_3d, 2, kALstuckpin_3d, kALsticktest2_3d};
-act11 asticktest2_3d = {COND_R, 0, CLAY_3d, 1, kALstickpin_3d, kALnostickpin_3d};
-act11 ataketest1_3d = {COND_R, 0, MOUSE_3d, 2, kALtakeit_3d, kALcanttake_3d};
-act11 ataketest2_3d = {COND_R, 0, MOUSE_3d, 3, kALmousegone_3d, kALtaketest1_3d};
-act11 atalktest1_3d = {COND_R, 0, NAT1_3d, 9, kALnat9_3d, kALnative_3d};
-act11 atiptest_3d = {COND_R, 60 * NORMAL_TPS, BLOCK1_3d, 0, kALbtipprompt_3d, 0};
-act11 auntietest_3d = {COND_R, 0, BLOCK1_3d, 0, kALnottied_3d, kALuntie_3d};
-act11 avinetest_3d = {COND_R, 0, BLOCK1_3d, 0, kALtievine_3d, kALtied_3d};
-act11 awebtest1_3d = {COND_R, 0, PENNY_3d, 0, kALspider_3d, kALwebtest2_3d};
-act11 awebtest2_3d = {COND_R, 0, PENNY_3d, 1, kALmission_3d, kALreturn_3d};
-act11 ahoriz5_3d = {COND_R, 1, HERO, 0, kALup_3d, kALdn_3d};
+act11 aactiontest1_3d = {COND_R, 0, E_EYES_3d, 1, 0, kALoktoleave1_3d};
+act11 aactiontest2_3d = {COND_R, 0, E_EYES_3d, 1, 0, kALoktoleave2_3d};
+act11 ablktest_3d = {COND_R, 0, BLOCK1_3d, 0, kALblk1_3d, 0};
+act11 abrgmsgtest_3d = {COND_R, 0, VINE_3d, 0, kALbrg_clftop_msg_3d, kALbrg_clftop1_3d};
+act11 abrgtest_3d = {COND_R, 0, VINE_3d, 0, kALbrg_ok_3d, kALbrg_down_3d};
+act11 acagetest_3d = {COND_R, 0, MOUSE_3d, 2, 0, kALpostest_3d};
+act11 acagetest1_3d = {COND_R, 0, MOUSE_3d, 2, kALcagetest2_3d, kALok_3d};
+act11 acamptest_3d = {COND_R, 0, NAT1_3d, 0, kALcampers_3d, kALchase_3d};
+act11 acavetest_3d = {COND_R, 0, GHOST_3d, 0, kALspirit_3d, kALcave_man_3d};
+act11 acrashtest1_3d = {COND_R, 0, PENNY_3d, 0, kALcrashed_3d, kALcrashtest2_3d};
+act11 acrashtest2_3d = {COND_R, 0, PENNY_3d, 1, kALcryhelp_3d, 0};
+act11 adartedtest_3d = {COND_R, 0, BLOWPIPE_3d, 0, kALdodart_3d, kALdarted_3d};
+act11 adoctest_3d = {COND_R, 0, DOCTOR_3d, 0, kALdoc_3d, 0};
+act11 adrinktest_3d = {COND_R, 0, FLASK_3d, 0, kALdrinkno_3d, kALdrinkyes_3d};
+act11 aeletest1_3d = {COND_R, 0, ELEPHANT_3d, 1, kALele_sleep_3d, kALeletest2_3d};
+act11 aeletest2_3d = {COND_R, 0, ELEPHANT_3d, 0, kALeleblink_3d, 0};
+act11 aemptytest1_3d = {COND_R, 0, FLASK_3d, 2, kALemptymagic_3d, kALemptytest2_3d};
+act11 aemptytest2_3d = {COND_R, 0, FLASK_3d, 1, kALemptyord_3d, kALdrinkno_3d};
+act11 aentertest1_3d = {COND_R, 0, CHEESE_3d, 1, kALentertest2_3d, 0};
+act11 aentertest2_3d = {COND_R, 0, MOUSE_3d, 0, kALentertest3_3d, 0};
+act11 aexotest1_3d = {COND_R, 0, GHOST_3d, 0, kALexotest2_3d, kALexordone_3d};
+act11 afindbtest_3d = {COND_R, 0, BOOK_3d, 0, kALfindit_3d, 0};
+act11 aflasktest2_3d = {COND_R, 0, FLASK_3d, 2, kALremedy_3d, kALflasktest3_3d};
+act11 aflasktest3_3d = {COND_R, 0, FLASK_3d, 1, kALnoremedy_3d, kALrefuseflask_3d};
+act11 agettest2_3d = {COND_R, 0, DOCTOR_3d, 0, kALgot_3d, 0};
+act11 agivetest_3d = {COND_R, 0, NAT1_3d, 10, kALrefuse_3d, kALgive_3d};
+act11 anat0_3d = {COND_R, 0, NAT1_3d, 0, kALcom0_3d, kALnat1_3d};
+act11 anat1_3d = {COND_R, 0, NAT1_3d, 1, kALcom1_3d, kALnat2_3d};
+act11 anat2_3d = {COND_R, 0, NAT1_3d, 2, kALcom2_3d, kALnat3_3d};
+act11 anat3_3d = {COND_R, 0, NAT1_3d, 3, kALcom3_3d, kALnat4_3d};
+act11 anat4_3d = {COND_R, 0, NAT1_3d, 4, kALcom4_3d, kALnat5_3d};
+act11 anat5_3d = {COND_R, 0, NAT1_3d, 5, kALcom5_3d, kALnat6_3d};
+act11 anat6_3d = {COND_R, 0, NAT1_3d, 6, kALcom6_3d, kALnat7_3d};
+act11 anat7_3d = {COND_R, 0, NAT1_3d, 7, kALcom7_3d, kALnat8_3d};
+act11 anat8_3d = {COND_R, 0, NAT1_3d, 8, kALcom8_3d, 0};
+act11 aold5_3d = {COND_R, 0, FLASK_3d, 2, kALold6_3d, kALwrong_3d};
+act11 aoldmantest_3d = {COND_R, 0, MOUTH_3d, 0, kALoldfirst_3d, kALoldsubseq_3d};
+act11 aopentest_3d = {COND_R, 0, DOCTOR_3d, 1, kALprod_3d, kALopencdoor_3d};
+act11 apausetest_3d = {COND_R, 0, NAT2_3d, 1, 0, kALcomment_3d};
+act11 apostest_3d = {COND_R, 0, MOUSE_3d, 0, kALmousel_3d, kALmouser_3d};
+act11 aspirittest_3d = {COND_R, 0, GHOST_3d, 0, kALwarn_3d, 0};
+act11 asticktest1_3d = {COND_R, 0, DOCTOR_3d, 2, kALstuckpin_3d, kALsticktest2_3d};
+act11 asticktest2_3d = {COND_R, 0, CLAY_3d, 1, kALstickpin_3d, kALnostickpin_3d};
+act11 ataketest1_3d = {COND_R, 0, MOUSE_3d, 2, kALtakeit_3d, kALcanttake_3d};
+act11 ataketest2_3d = {COND_R, 0, MOUSE_3d, 3, kALmousegone_3d, kALtaketest1_3d};
+act11 atalktest1_3d = {COND_R, 0, NAT1_3d, 9, kALnat9_3d, kALnative_3d};
+act11 atiptest_3d = {COND_R, 60 * NORMAL_TPS_v2d, BLOCK1_3d, 0, kALbtipprompt_3d, 0};
+act11 auntietest_3d = {COND_R, 0, BLOCK1_3d, 0, kALnottied_3d, kALuntie_3d};
+act11 avinetest_3d = {COND_R, 0, BLOCK1_3d, 0, kALtievine_3d, kALtied_3d};
+act11 awebtest1_3d = {COND_R, 0, PENNY_3d, 0, kALspider_3d, kALwebtest2_3d};
+act11 awebtest2_3d = {COND_R, 0, PENNY_3d, 1, kALmission_3d, kALreturn_3d};
+act11 ahoriz5_3d = {COND_R, 1, HERO, 0, kALup_3d, kALdn_3d};
act12 ablk1_3d = {TEXT, 0, kSTBlk1_3d};
act12 abook1_3d = {TEXT, 0, kSTBook1_3d};
diff --git a/tools/create_hugo/staticdisplay.h b/tools/create_hugo/staticdisplay.h
index 2dfc939371..a9f38ba7a0 100644
--- a/tools/create_hugo/staticdisplay.h
+++ b/tools/create_hugo/staticdisplay.h
@@ -35,6 +35,7 @@
#define SIZE_PAL_ARRAY 64
+#if 1
// Color table of standard 16 VGA colors
// Values from "Programmers guide to EGA/VGA cards" Ferraro, p303
#define V1 168 // Low intensity value
@@ -44,22 +45,49 @@
byte _palette[SIZE_PAL_ARRAY] = {
- 0, 0, 0, 0, // BLACK
- 0, 0, V1, 0, // BLUE
- 0, V1, 0, 0, // GREEN
- 0, V1, V1, 0, // CYAN
- V1, 0, 0, 0, // RED
- V1, 0, V1, 0, // MAGENTA
- V1, V3, 0, 0, // BROWN
- V1, V1, V1, 0, // WHITE (LIGHT GRAY)
- V3, V3, V3, 0, // GRAY (DARK GRAY)
- V4, V4, V2, 0, // LIGHTBLUE
- V4, V2, V4, 0, // LIGHTGREEN
- V4, V2, V2, 0, // LIGHTCYAN
- V2, V4, V4, 0, // LIGHTRED
- V2, V4, V2, 0, // LIGHTMAGENTA
- V2, V2, V4, 0, // YELLOW
- V2, V2, V2, 0 // BRIGHTWHITE
+ 0, 0, 0, 0, // BLACK
+ 0, 0, V1, 0, // BLUE
+ 0, V1, 0, 0, // GREEN
+ 0, V1, V1, 0, // CYAN
+ V1, 0, 0, 0, // RED
+ V1, 0, V1, 0, // MAGENTA
+ V1, V3, 0, 0, // BROWN
+ V1, V1, V1, 0, // WHITE (LIGHT GRAY)
+ V3, V3, V3, 0, // GRAY (DARK GRAY)
+ V4, V4, V2, 0, // LIGHTBLUE
+ V4, V2, V4, 0, // LIGHTGREEN
+ V4, V2, V2, 0, // LIGHTCYAN
+ V2, V4, V4, 0, // LIGHTRED
+ V2, V4, V2, 0, // LIGHTMAGENTA
+ V2, V2, V4, 0, // YELLOW
+ V2, V2, V2, 0 // BRIGHTWHITE
};
+#else
+// Original paletter found in original exe.
+// Currently disabled, because the result is quite ugly!
+// Color table of nearest standard 16 colors in system static palette
+#define C1 191 // Low intensity value
+#define C2 255 // High intensity value
+#define C3 127 // Special for Brown/Gray
+byte _palette[SIZE_PAL_ARRAY] = {
+ 0, 0, 0, 0, // BLACK
+ 0, 0, C1, 0, // BLUE
+ 0, C1, 0, 0, // GREEN
+ 0, C1, C1, 0, // CYAN
+ C1, 0, 0, 0, // RED
+ C1, 0, C1, 0, // MAGENTA
+ C3, C3, 0, 0, // BROWN
+ C1, C1, C1, 0, // WHITE (LIGHT GRAY)
+ C3, C3, C3, 0, // GRAY (DARK GRAY)
+ 0, 0, C2, 0, // LIGHTBLUE
+ 0, C2, 0, 0, // LIGHTGREEN
+ 0, C2, C2, 0, // LIGHTCYAN
+ C2, 0, 0, 0, // LIGHTRED
+ C2, 0, C2, 0, // LIGHTMAGENTA
+ C2, C2, 0, 0, // YELLOW
+ C2, C2, C2, 0 // BRIGHTWHITE
+};
+#endif
+
#endif
diff --git a/tools/create_kyradat/create_kyradat.cpp b/tools/create_kyradat/create_kyradat.cpp
index 85038a0820..7a4b8d73a1 100644
--- a/tools/create_kyradat/create_kyradat.cpp
+++ b/tools/create_kyradat/create_kyradat.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
// HACK to allow building with the SDL backend on MinGW
// see bug #1800764 "TOOLS: MinGW tools building broken"
#ifdef main
@@ -45,7 +48,7 @@
#include <map>
enum {
- kKyraDatVersion = 72
+ kKyraDatVersion = 73
};
const ExtractFilename extractFilenames[] = {
@@ -53,7 +56,7 @@ const ExtractFilename extractFilenames[] = {
{ kIdMap, -1, true },
// INTRO / OUTRO sequences
- { k1ForestSeq, kTypeRawData, false },
+ { k1ForestSeq, kTypeForestSeqData, false },
{ k1KallakWritingSeq, kTypeRawData, false },
{ k1KyrandiaLogoSeq, kTypeRawData, false },
{ k1KallakMalcolmSeq, kTypeRawData, false },
diff --git a/tools/create_kyradat/extract.cpp b/tools/create_kyradat/extract.cpp
index 8286d1ca63..87254b03cf 100644
--- a/tools/create_kyradat/extract.cpp
+++ b/tools/create_kyradat/extract.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "extract.h"
#include <algorithm>
@@ -36,6 +39,7 @@ bool extractStrings(PAKFile &out, const ExtractInformation *info, const byte *da
bool extractStrings10(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id);
bool extractRooms(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id);
bool extractShapes(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id);
+bool extractKyraForestSeqData(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id);
bool extractAmigaSfx(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id);
bool extractWdSfx(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id);
@@ -58,6 +62,7 @@ const ExtractType extractTypeTable[] = {
{ kTypeRoomList, extractRooms },
{ kTypeShapeList, extractShapes },
{ kTypeRawData, extractRaw },
+ { kTypeForestSeqData, extractKyraForestSeqData },
{ kTypeAmigaSfxTable, extractAmigaSfx },
{ kTypeTownsWDSfxTable, extractWdSfx },
@@ -90,6 +95,7 @@ const TypeTable typeTable[] = {
{ kTypeRawData, 1 },
{ kTypeRoomList, 2 },
{ kTypeShapeList, 3 },
+ { kTypeForestSeqData, 1 },
{ kTypeAmigaSfxTable, 4 },
{ kTypeTownsWDSfxTable, 1 },
{ k2TypeSeqData, 5 },
@@ -376,6 +382,55 @@ bool extractShapes(PAKFile &out, const ExtractInformation *info, const byte *dat
return out.addFile(filename, buffer, size + 1 * 4);
}
+bool extractKyraForestSeqData(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) {
+ if (info->platform != kPlatformPC98)
+ return extractRaw(out, info, data, size, filename, id);
+
+ struct PatchEntry {
+ uint16 pos;
+ uint8 val;
+ };
+
+ // This data has been taken from the FM-Towns version
+ static const PatchEntry patchData[] = {
+ { 0x0019, 0x06 }, { 0x001A, 0x09 }, { 0x001B, 0x00 }, { 0x002E, 0x06 }, { 0x002F, 0x09 }, { 0x0030, 0x00 },
+ { 0x003D, 0x06 }, { 0x003E, 0x09 }, { 0x003F, 0x00 }, { 0x004C, 0x06 }, { 0x004D, 0x09 }, { 0x004E, 0x00 },
+ { 0x005B, 0x06 }, { 0x005C, 0x09 }, { 0x005D, 0x00 }, { 0x0064, 0x06 }, { 0x0065, 0x09 }, { 0x0066, 0x00 },
+ { 0x0079, 0x06 }, { 0x007A, 0x09 }, { 0x007B, 0x00 }, { 0x0088, 0x06 }, { 0x0089, 0x09 }, { 0x008A, 0x00 },
+ { 0x0097, 0x06 }, { 0x0098, 0x09 }, { 0x0099, 0x00 }, { 0x00A6, 0x06 }, { 0x00A7, 0x09 }, { 0x00A8, 0x00 },
+ { 0x00AD, 0x06 }, { 0x00AE, 0x09 }, { 0x00AF, 0x00 }, { 0x00B4, 0x06 }, { 0x00B5, 0x09 }, { 0x00B6, 0x00 },
+ { 0x00C3, 0x06 }, { 0x00C4, 0x09 }, { 0x00C5, 0x00 }, { 0x00CA, 0x06 }, { 0x00CB, 0x09 }, { 0x00CC, 0x00 },
+ { 0x00D1, 0x06 }, { 0x00D2, 0x09 }, { 0x00D3, 0x00 }, { 0x00E0, 0x06 }, { 0x00E1, 0x09 }, { 0x00E2, 0x00 },
+ { 0x00E7, 0x06 }, { 0x00E8, 0x09 }, { 0x00E9, 0x00 }, { 0x00EE, 0x06 }, { 0x00EF, 0x09 }, { 0x00F0, 0x00 },
+ { 0x00FD, 0x06 }, { 0x00FE, 0x09 }, { 0x00FF, 0x00 }, { 0x010A, 0x06 }, { 0x010B, 0x09 }, { 0x010C, 0x00 },
+ { 0x011D, 0x06 }, { 0x011E, 0x09 }, { 0x011F, 0x00 }, { 0x012C, 0x06 }, { 0x012D, 0x09 }, { 0x012E, 0x00 },
+ { 0x013D, 0x06 }, { 0x013E, 0x09 }, { 0x013F, 0x00 }, { 0x0148, 0x06 }, { 0x0149, 0x09 }, { 0x014A, 0x00 },
+ { 0x0153, 0x06 }, { 0x0154, 0x09 }, { 0x0155, 0x00 }, { 0x015E, 0x06 }, { 0x015F, 0x09 }, { 0x0160, 0x00 },
+ { 0x0169, 0x06 }, { 0x016A, 0x09 }, { 0x016B, 0x00 }, { 0x016C, 0x06 }, { 0x016D, 0x12 }, { 0x016E, 0x00 },
+ { 0x017B, 0x06 }, { 0x017C, 0x09 }, { 0x017D, 0x00 }, { 0x0188, 0x06 }, { 0x0189, 0x09 }, { 0x018A, 0x00 },
+ { 0x0190, 0x13 }, { 0x0000, 0x00 }
+ };
+
+ uint32 outsize = size + (ARRAYSIZE(patchData) - 1);
+ uint8 *buffer = new uint8[outsize];
+ assert(buffer);
+
+ const uint8 *src = data;
+ uint8 *dst = buffer;
+ const PatchEntry *patchPos = patchData;
+
+ while (dst < (buffer + outsize)) {
+ if ((dst - buffer) == patchPos->pos) {
+ *dst++ = patchPos->val;
+ patchPos++;
+ } else {
+ *dst++ = *src++;
+ }
+ }
+
+ return out.addFile(filename, buffer, outsize);
+}
+
bool extractAmigaSfx(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) {
const uint32 entries = size / 8;
byte *buffer = new byte[entries * 6 + 1 * 4];
diff --git a/tools/create_kyradat/extract.h b/tools/create_kyradat/extract.h
index 5aee089466..0903852dd2 100644
--- a/tools/create_kyradat/extract.h
+++ b/tools/create_kyradat/extract.h
@@ -35,6 +35,7 @@ enum kExtractType {
kTypeRoomList,
kTypeShapeList,
kTypeRawData,
+ kTypeForestSeqData,
kTypeAmigaSfxTable,
kTypeTownsWDSfxTable,
diff --git a/tools/create_kyradat/games.cpp b/tools/create_kyradat/games.cpp
index 008120868f..75a956cab0 100644
--- a/tools/create_kyradat/games.cpp
+++ b/tools/create_kyradat/games.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "create_kyradat.h"
// Game tables
diff --git a/tools/create_kyradat/md5.cpp b/tools/create_kyradat/md5.cpp
index 58e6e73add..214b5ef7ed 100644
--- a/tools/create_kyradat/md5.cpp
+++ b/tools/create_kyradat/md5.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "md5.h"
#define GET_UINT32(n, b, i) (n) = READ_LE_UINT32(b + i)
diff --git a/tools/create_kyradat/pak.cpp b/tools/create_kyradat/pak.cpp
index f0564ebfbf..4179f42df0 100644
--- a/tools/create_kyradat/pak.cpp
+++ b/tools/create_kyradat/pak.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "pak.h"
bool PAKFile::loadFile(const char *file, const bool isAmiga) {
diff --git a/tools/create_kyradat/search.cpp b/tools/create_kyradat/search.cpp
index 7ca41e2d92..28631fa652 100644
--- a/tools/create_kyradat/search.cpp
+++ b/tools/create_kyradat/search.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "search.h"
#include "md5.h"
diff --git a/tools/create_kyradat/tables.cpp b/tools/create_kyradat/tables.cpp
index 9cf145d9d3..777f237650 100644
--- a/tools/create_kyradat/tables.cpp
+++ b/tools/create_kyradat/tables.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "tables.h"
#include "create_kyradat.h"
diff --git a/tools/create_kyradat/util.cpp b/tools/create_kyradat/util.cpp
index a9ac5517bf..702a36bc0e 100644
--- a/tools/create_kyradat/util.cpp
+++ b/tools/create_kyradat/util.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "util.h"
#include <stdarg.h>
diff --git a/tools/create_lure/create_lure_dat.cpp b/tools/create_lure/create_lure_dat.cpp
index faa32541bc..ad883b808f 100644
--- a/tools/create_lure/create_lure_dat.cpp
+++ b/tools/create_lure/create_lure_dat.cpp
@@ -27,6 +27,9 @@
* to work properly
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
// HACK to allow building with the SDL backend on MinGW
// see bug #1800764 "TOOLS: MinGW tools building broken"
#ifdef main
diff --git a/tools/create_lure/process_actions.cpp b/tools/create_lure/process_actions.cpp
index 9779315ddd..30e7eed9e4 100644
--- a/tools/create_lure/process_actions.cpp
+++ b/tools/create_lure/process_actions.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "common/scummsys.h"
#include "common/util.h"
#include "create_lure_dat.h"
diff --git a/tools/create_msvc/create_msvc.cpp b/tools/create_msvc/create_msvc.cpp
index a2bc71841c..07943a7b82 100644
--- a/tools/create_msvc/create_msvc.cpp
+++ b/tools/create_msvc/create_msvc.cpp
@@ -486,12 +486,6 @@ int main(int argc, char *argv[]) {
StringList featureDefines = getFeatureDefines(setup.features);
setup.defines.splice(setup.defines.begin(), featureDefines);
- // Add WIN32 define
- setup.defines.push_back("WIN32");
-
- // Add SDL_BACKEND define
- setup.defines.push_back("SDL_BACKEND");
-
setup.libraries = getFeatureLibraries(setup.features);
setup.libraries.push_back("winmm.lib");
@@ -839,8 +833,9 @@ const Feature s_features[] = {
{ "mad", "USE_MAD", "libmad.lib", true, "libmad (MP3) support" },
{ "vorbis", "USE_VORBIS", "libvorbisfile_static.lib libvorbis_static.lib libogg_static.lib", true, "Ogg Vorbis support" },
{ "flac", "USE_FLAC", "libFLAC_static.lib", true, "FLAC support" },
+ { "theoradec", "USE_THEORADEC", "libtheora_static.lib", true, "Theora decoder support" },
+ { "png", "USE_PNG", "libpng.lib", true, "PNG support" },
{ "mpeg2", "USE_MPEG2", "libmpeg2.lib", false, "mpeg2 codec for cutscenes" },
- { "opengl", "USE_OPENGL", "opengl32.lib", true, "OpenGL for rendering engine" },
// ScummVM feature flags
{ "scalers", "USE_SCALERS", "", true, "Scalers" },
@@ -1608,6 +1603,17 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std:
"\t\t<Configuration Name=\"Release|x64\" ConfigurationType=\"4\" InheritedPropertySheets=\".\\ScummVM_Release64.vsprops\">\n"
"\t\t\t<Tool Name=\"VCCLCompilerTool\" DisableSpecificWarnings=\"" << warnings->second << "\" />\n"
"\t\t</Configuration>\n";
+ } else if (name == "sword25") {
+ // Win32
+ project << "\t\t<Configuration Name=\"Debug|Win32\" ConfigurationType=\"4\" InheritedPropertySheets=\".\\ScummVM_Debug.vsprops\">\n"
+ "\t\t\t<Tool Name=\"VCCLCompilerTool\" DisableLanguageExtensions=\"false\" />\n"
+ "\t\t</Configuration>\n"
+ "\t\t<Configuration Name=\"Release|Win32\" ConfigurationType=\"4\" InheritedPropertySheets=\".\\ScummVM_Release.vsprops\" />\n";
+ // x64
+ project << "\t\t<Configuration Name=\"Debug|x64\" ConfigurationType=\"4\" InheritedPropertySheets=\".\\ScummVM_Debug64.vsprops\">\n"
+ "\t\t\t<Tool Name=\"VCCLCompilerTool\" DisableLanguageExtensions=\"false\" />\n"
+ "\t\t</Configuration>\n"
+ "\t\t<Configuration Name=\"Release|x64\" ConfigurationType=\"4\" InheritedPropertySheets=\".\\ScummVM_Release64.vsprops\" />\n";
} else if (name == "tinsel") {
// Win32
project << "\t\t<Configuration Name=\"Debug|Win32\" ConfigurationType=\"4\" InheritedPropertySheets=\".\\ScummVM_Debug.vsprops\">\n"
@@ -2017,7 +2023,7 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s
std::map<std::string, std::string>::iterator warnings = _projectWarnings.find(name);
// Nothing to add here, move along!
- if (name != "scummvm" && name != "tinsel" && warnings == _projectWarnings.end())
+ if (name != "scummvm" && name != "sword25" && name != "tinsel" && warnings == _projectWarnings.end())
return;
project << "\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='" << (isRelease ? "Release" : "Debug") << "|" << (isWin32 ? "Win32" : "x64") << "'\">\n"
@@ -2027,6 +2033,9 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s
if (name == "scummvm") {
project << "\t\t\t<DisableLanguageExtensions>false</DisableLanguageExtensions>\n";
} else {
+ if (name == "sword25")
+ project << "\t\t\t<DisableLanguageExtensions>false</DisableLanguageExtensions>\n";
+
if (name == "tinsel" && !isRelease)
project << "\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n";
diff --git a/tools/create_teenagent/create_teenagent.cpp b/tools/create_teenagent/create_teenagent.cpp
index 930f40581f..ae88cc5d65 100644
--- a/tools/create_teenagent/create_teenagent.cpp
+++ b/tools/create_teenagent/create_teenagent.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
diff --git a/tools/create_teenagent/md5.cpp b/tools/create_teenagent/md5.cpp
index 58e6e73add..214b5ef7ed 100644
--- a/tools/create_teenagent/md5.cpp
+++ b/tools/create_teenagent/md5.cpp
@@ -23,6 +23,9 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
#include "md5.h"
#define GET_UINT32(n, b, i) (n) = READ_LE_UINT32(b + i)
diff --git a/tools/create_toon/create_toon.cpp b/tools/create_toon/create_toon.cpp
index e6253ae21f..3cf252cbcd 100644
--- a/tools/create_toon/create_toon.cpp
+++ b/tools/create_toon/create_toon.cpp
@@ -25,6 +25,9 @@
* data file, used by the game engine
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
// HACK to allow building with the SDL backend on MinGW
// see bug #1800764 "TOOLS: MinGW tools building broken"
#ifdef main
diff --git a/tools/credits.pl b/tools/credits.pl
index 1421f907db..75f9678cbc 100755
--- a/tools/credits.pl
+++ b/tools/credits.pl
@@ -542,6 +542,14 @@ begin_credits("Credits");
add_person("Jonathan Gray", "khalek", "(retired)");
end_section();
+ begin_section("Broken Sword 2.5");
+ add_person("Eugene Sandulenko", "sev", "");
+ add_person("Filippos Karapetis", "[md5]", "");
+ add_person("Max Horn", "Fingolfin", "");
+ add_person("Paul Gilbert", "dreammaster", "");
+ add_person("Torbj&ouml;rn Andersson", "eriktorbjorn", "");
+ end_section();
+
begin_section("Cinematique evo 1");
add_person("Vincent Hamm", "yaz0r", "(retired)");
add_person("Pawe&#322; Ko&#322;odziejski", "aquadran", "");
@@ -584,6 +592,12 @@ begin_credits("Credits");
add_person("Jordi Vilalta Prat", "jvprat", "");
end_section();
+ begin_section("Hugo");
+ add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
+ add_person("Oystein Eftevaag", "vinterstum", "");
+ add_person("Eugene Sandulenko", "sev", "");
+ end_section();
+
begin_section("Kyra");
add_person("Torbj&ouml;rn Andersson", "eriktorbjorn", "VQA Player");
add_person("Oystein Eftevaag", "vinterstum", "");
@@ -592,6 +606,12 @@ begin_credits("Credits");
add_person("Johannes Schickel", "LordHoto", "");
end_section();
+ begin_section("Last Express");
+ add_person("Matthew Hoops", "clone2727", "");
+ add_person("Jordi Vilalta Prat", "jvprat", "");
+ add_person("Julien Templier", "littleboy", "");
+ end_section();
+
begin_section("Lure");
add_person("Paul Gilbert", "dreammaster", "");
end_section();
@@ -654,6 +674,10 @@ begin_credits("Credits");
add_person("Joost Peters", "joostp", "");
end_section();
+ begin_section("Toon");
+ add_person("Sylvain Dupont", "SylvainTV", "");
+ end_section();
+
begin_section("Touch&eacute;");
add_person("Gregory Montoir", "cyx", "");
end_section();
@@ -674,7 +698,7 @@ begin_credits("Credits");
add_person("Marcus Comstedt", "", "");
end_section();
- begin_section("GP2X");
+ begin_section("GPH Devices (GP2X, GP2XWiz &amp; Caanoo)");
add_person("John Willis", "DJWillis", "");
end_section();
@@ -698,6 +722,10 @@ begin_credits("Credits");
add_person("Neil Millstone", "agent-q", "");
end_section();
+ begin_section("OpenPandora");
+ add_person("John Willis", "DJWillis", "");
+ end_section();
+
begin_section("PocketPC / WinCE");
add_person("Nicolas Bacca", "arisme", "(retired)");
add_person("Kostas Nakos", "Jubanka", "");
@@ -733,6 +761,7 @@ begin_credits("Credits");
begin_section("Infrastructure");
add_person("Max Horn", "Fingolfin", "Backend &amp; Engine APIs, file API, sound mixer, audiostreams, data structures, etc.");
add_person("Eugene Sandulenko", "sev", "");
+ add_person("Johannes Schickel", "LordHoto", "");
end_section();
begin_section("GUI");
@@ -764,7 +793,7 @@ begin_credits("Credits");
begin_section("Documentation");
begin_persons();
add_person("Thierry Crozat", "criezy", "Numerous contributions to documentation");
- add_person("Joachim Eberhard", "joachimeberhard", "Numerous contributions to documentation");
+ add_person("Joachim Eberhard", "joachimeberhard", "Numerous contributions to documentation (retired)");
add_person("Matthew Hoops", "clone2727", "Wiki editor");
end_persons();
end_section();
@@ -1033,6 +1062,10 @@ begin_credits("Credits");
"David P. Gray from Gray Design Associate for sharing the source code ".
"of the Hugo trilogy.");
+ add_paragraph(
+ "Broken Sword 2.5 team for providing sources of their engine and their great ".
+ "support.");
+
end_section();
end_credits();
diff --git a/tools/sci/classes.cpp b/tools/sci/classes.cpp
deleted file mode 100644
index d7699bfe4c..0000000000
--- a/tools/sci/classes.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <engine.h>
-#include <vocabulary.h>
-
-int main(int argc, char** argv) {
- int res;
- int sizes[1000];
- int altsizes[1000];
- int count, *classes;
- loadResources(SCI_VERSION_AUTODETECT, 1);
-
- for (res = 0; res < 1000; res++) {
- resource_t* r;
- int i = 0;
-
- sizes[res] = -1;
-
- if ((r = findResource(sci_script, res)) == 0) continue;
- sizes[res] = 0;
- altsizes[res] = 0;
- i += 2;
- i = getInt16(r->data + i);
-
- while (i < r->length - 2) {
- switch (getInt16(r->data + i)) {
- case 1:
- case 6:
- sizes[res]++;
- break;
- default:
- altsizes[res]++;
- }
- i += getInt16(r->data + i + 2);
- }
- fflush(stdout);
- }
-
- for (res = 0; res < 1000; res++) if (sizes[res] != -1) printf("%03d %d\n", res, sizes[res]);
- printf("\n");
-
- classes = vocabulary_get_classes(&count);
- for (res = 0; res < count; res++) {
- printf("%03d %d (%d)\n", classes[res],
- sizes[classes[res]]--, altsizes[classes[res]]);
- }
-
- freeResources();
- return 0;
-}
diff --git a/tools/sci/graphics_png.h b/tools/sci/graphics_png.h
deleted file mode 100644
index 84358478f1..0000000000
--- a/tools/sci/graphics_png.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/* Provides facilities for writing pictures and seperate views to .png files */
-
-
-#ifndef _SCI_GRAPHICS_PNG_H_
-#define _SCI_GRAPHICS_PNG_H_
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif /* HAVE_CONFIG_H */
-
-#ifdef HAVE_LIBPNG
-
-#include <resource.h>
-#include <graphics.h>
-#include <png.h>
-
-int
-write_pic_png(char *filename, guint8 *pic);
-/* Stores a picture map in a png file
-** --DEPRECATED--
-** Parameters: (filename) The name of the file to create
-** (pic) A pointer to the picture map to store
-** Returns : (int) 0 on success, != 0 otherwise
-** Please note that pic must not point to a picture_t, it must point to a
-** map.
-** E.g. to store the foreground picture, you could use
-** write_pic_png("filename.png", picture->maps[0]).
-*/
-
-
-int
-png_save_buffer(picture_t pic, char *name,
- int xoffset, int yoffset, int width, int height,
- byte *data, int force_8bpp_special);
-/* Stores any buffer in a png file
-** Parameters: (picture_t) pic: The picture_t containing the parameters of the buffer
-** (char *) name: File name to write to
-** (int x int) xoffset, yoffset: relative screen position of the buffer
-** (int x int) width, height: Buffer size
-** (byte *) data: The actual data to write
-** (int) force_8bpp_special: See below
-** Returns : (int) 0 on success, 1 otherwise
-** Each graphics buffer is stored in the way that the corresponding picture_t
-** dictates (all buffers are either identical to, or parts of a past representation
-** of the picture_t map 0, after all).
-** force_8bpp_special overrides this and forces 8bpp palette mode for writing the
-** buffer.
-** This should only be used for maps 1 through 3, which are always in this format.
-*/
-
-
-byte *
-png_load_buffer(picture_t pic, char *name,
- int *xoffset, int *yoffset, int *width, int *height,
- int *size, int force_8bpp_special);
-/* Loads a buffer from a png file
-** Parameters: (picture_t) pic: The picture_t containing the target parameters
-** (char *) name: The file name of the file to read from
-** (int* x int*) xoffset, yoffset: Offset storage pointers
-** (int* x int*) width, height: Size storage pointers
-** (int*) size: Memory size storage pointer
-** (int) force_8bpp_special: Import file as 8bpp with palette
-** Returns : (byte *): The buffer on success, NULL otherwise
-** xoffset, yoffset, width, height, and size should each point to ints the picture
-** parameters are stored in. xoffset and yoffset may be set to NULL, though, in
-** order to be omitted.
-*/
-
-
-int
-png_save_pic(picture_t pic);
-/* Stores a picture_t in the current directory
-** Parameters: (picture_t) pic: The picture_t to store
-** Returns : (int) 0 on success, 1 otherwise
-*/
-
-int
-png_load_pic(picture_t pic);
-/* Loads a picture_t from the cwd
-** Parameters: (picture_t) pic: The structure to write to
-** Returns : (int) 0 on success, 1 otherwise
-** On error, the original pic status is retained.
-*/
-
-
-#endif /* HAVE_LIBPNG */
-#endif /* !_SCI_GRAPHICS_PNG_H_ */
diff --git a/tools/sci/listwords.cpp b/tools/sci/listwords.cpp
deleted file mode 100644
index 3951a1e779..0000000000
--- a/tools/sci/listwords.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sciunpack.h"
-#include <engine.h>
-#include <kernel.h>
-
-int
-_vocab_cmp_group(const void *word1, const void *word2) {
-#define fw (* ((word_t **) word1))
-#define sw (* ((word_t **) word2))
- if (fw->group < sw->group)
- return -1;
- else if (fw->group == sw->group)
- return 0;
- else
- return 1;
-}
-
-int vocab_sort = DEFAULT_SORTING;
-
-int
-vocab_print(void) {
- int b, words_nr, counter;
- word_t **words, **tracker;
-
- tracker = words = vocab_get_words(resmgr, &words_nr);
-
- counter = words_nr;
-
- if (vocab_sort == SORT_METHOD_GROUP)
- qsort(words, words_nr, sizeof(word_t *), _vocab_cmp_group); /* Sort entries */
-
- while (counter--) {
- printf("%s (class %03x, group %03x) ", &tracker[0]->word,
- tracker[0]->w_class, tracker[0]->group);
-
- if ((tracker[0]->w_class >= 0xf00) ||
- (tracker[0]->w_class == 0))
- printf("anyword\n");
- else
- while (tracker[0]->w_class) {
- b = sci_ffs(tracker[0]->w_class) - 1;
- tracker[0]->w_class &= ~(1 << b);
- printf("%s", class_names[b]);
- if (tracker[0]->w_class)
- printf("|");
- else
- printf("\n");
- }
- tracker++;
- }
-
- vocab_free_words(words, words_nr);
-
- return 0;
-}
-
-
-
-
-
-
diff --git a/tools/sci/old_objects.cpp b/tools/sci/old_objects.cpp
deleted file mode 100644
index 048a0fd2b9..0000000000
--- a/tools/sci/old_objects.cpp
+++ /dev/null
@@ -1,679 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include <sciresource.h>
-#include <console.h>
-#include <script.h>
-#include <vocabulary.h>
-#include <old_objects.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <util.h>
-#include <vm.h>
-#include <assert.h>
-
-#ifdef SCI_CONSOLE
-#define printf sciprintf
-/* Yeah, I shouldn't be doing this ;-) [CJR] */
-#endif
-
-FLEXARRAY_NOEXTRA(object*) fobjects;
-
-static int knames_count;
-static char** knames;
-static char** snames;
-static opcode* opcodes;
-
-object **object_map, *object_root;
-int max_object;
-
-const char* globals[] = {
- /*00*/
- "ego",
- "GAMEID",
- "roomXX",
- "speed",
- /*04*/
- "quitFlag",
- "cast",
- "regions",
- "timer",
- /*08*/
- "sounds",
- "inv",
- "eventHandler",
- "roomNumberExit",
- /*0C*/
- "previousRoomNumber",
- "roomNumber",
- "enterDebugModeOnRoomExit",
- "score",
- /*10*/
- "maximumScore",
- "11",
- "speed",
- "13",
- /*14*/
- "14",
- "loadCursor",
- "normalFont",
- "restoreSaveFont", /*dialogFont*/
- /*18*/
- "18",
- "19",
- "defaultFont",
- "1B",
- /*1C*/
- "pointerToVersionNumber",
- "locales",
- "pointerToSaveGameDirectory",
- "1F"
-};
-
-static int add_object(object* obj) {
- FLEXARRAY_APPEND(object*, fobjects, obj, return 1);
- return 0;
-}
-
-static void dump(byte* data, int len) {
- int i = 0;
- while (i < len) {
- printf("%02X ", data[i++]);
- if (i % 8 == 0) printf(" ");
- if (i % 16 == 0) printf("\n");
- }
- if (i % 16) printf("\n");
-}
-
-static void printMethod(object* obj, int meth, int indent) {
- script_method* m = obj->methods[meth];
- int i, j;
-
- for (j = 0; j < indent*2 - 1; j++) printf(" ");
- printf("Method %s\n", snames[m->number]);
-
- for (i = 0; i < m->used; i++) {
- script_opcode op = m->data[i];
-
- for (j = 0; j < indent; j++) printf(" ");
- printf("%s ", opcodes[op.opcode].name);
-
- switch (op.opcode) {
- case 0x21: { /*callk*/
- if (op.arg1 > knames_count) printf("<no such kernel function %02X> ", op.arg1);
- else printf("%s ", knames[op.arg1]);
- printf("%02X", op.arg2);
- }
- break;
- case 0x28: { /*class*/
- if (op.arg1 > max_object) printf("<no such class %02X>", op.arg1);
- else {
- /* [DJ] op.arg1+1 adjusts for the <root> object */
- if (fobjects.data[op.arg1+1] == 0) printf("<null object>");
- else printf("%s", fobjects.data[op.arg1+1]->name);
- }
- }
- break;
- case 0x44: {
- if (op.arg1 > 0x20) printf("<no such global %02X> ", op.arg1);
- else printf("%s ", globals[op.arg1]);
- }
- break;
- default: {
- int args[3];
- args[0] = op.arg1;
- args[1] = op.arg2;
- args[2] = op.arg3;
- for (j = 0; j < 3; j++) {
- switch (formats[op.opcode][j]) {
- case Script_Invalid: {
- printf("<invalid> ");
- }
- break;
- case Script_None: {
- j = 3;
- }
- break;
- case Script_SByte:
- case Script_Byte: {
- printf("%02X ", args[j]);
- }
- break;
- case Script_Word:
- case Script_SVariable:
- case Script_Variable:
- case Script_SRelative:
- case Script_Property:
- case Script_Global:
- case Script_Local:
- case Script_Temp:
- case Script_Param: {
- printf("%04X ", args[j]);
- }
- break;
- case Script_SWord: {
- if (args[j] < 0) printf("-%04X", -args[j]);
- else printf("%04X", args[j]);
- }
- break;
- case Script_End: {
- printf("\n");
- return;
- }
- break;
- default: {
- printf("<unknown arg type %d> ", formats[op.opcode][j]);
- }
- }
- }
- }
- break;
- }
- printf("\n");
- }
-}
-
-static void printObject_r(object* obj, int flags, int level) {
- int i;
- for (i = 0; i < level; i++) printf(" ");
- if (obj == 0) printf("(null)\n");
- else {
- printf("%s\n", obj->name);
- if (flags&SCRIPT_PRINT_METHODS) {
- for (i = 0; i < obj->method_count; i++) {
- printMethod(obj, i, level + 1);
- }
- }
- if (flags&SCRIPT_PRINT_CHILDREN) {
- for (i = 0; i < obj->children.used; i++) {
- printObject_r(obj->children.data[i], flags, level + 1);
- }
- }
- }
-}
-
-void printObject(object* obj, int flags) {
- printf("pO(%p, %d)\n", obj, flags);
- printObject_r(obj, flags, 0);
-}
-
-static object* object_new() {
- object* obj = (object*)sci_malloc(sizeof(object));
- if (obj == 0) return 0;
-
- obj->parent = 0;
- FLEXARRAY_INIT(object*, obj->children);
- obj->name = 0;
- obj->selector_count = 0;
- obj->selector_numbers = 0;
- obj->methods = 0;
- obj->method_count = 0;
-
- return obj;
-}
-
-static int add_child(object* parent, object* child) {
- FLEXARRAY_APPEND(object*, parent->children, child, return 1);
- return 0;
-}
-
-static object* fake_object(const char* reason) {
- object* obj = object_new();
- if (obj == 0) {
-#ifdef SCRIPT_DEBUG
- printf("object_new failed during fake for %s\n", reason);
-#endif
- free(obj);
- return 0;
- }
- if (add_child(object_root, obj)) {
-#ifdef SCRIPT_DEBUG
- printf("add_child failed during fake for %s\n", reason);
-#endif
- free(obj);
- return 0;
- }
- obj->name = reason;
- if (add_object(obj)) {
-#ifdef SCRIPT_DEBUG
- printf("add_object failed during fake for %s\n", reason);
-#endif
- /*FIXME: clean up parent*/
- return 0;
- }
- return obj;
-}
-
-static script_method* decode_method(byte* data) {
- script_method* m;
- int done = 0;
- int pos = 0;
- static int count = 0;
-
- count++;
-
- if ((m = (script_method*)sci_malloc(sizeof(script_method))) == 0) return 0;
- FLEXARRAY_INIT(script_opcode, *m);
-
- while (!done) {
- int op = data[pos] >> 1;
- int size = 2 - (data[pos] & 1);
- int* args[3];
- int arg;
- int old_pos;
-
- FLEXARRAY_ADD_SPACE(script_opcode, *m, 1, return 0);
- old_pos = pos;
- m->data[m->used-1].pos = pos;
- m->data[m->used-1].opcode = op;
-
- /*Copy the adresses of the args to an array for convenience*/
- args[0] = &m->data[m->used-1].arg1;
- args[1] = &m->data[m->used-1].arg2;
- args[2] = &m->data[m->used-1].arg3;
-
- /*Skip past the opcode*/
- pos++;
-
- for (arg = 0; arg < 4; arg++) {
- switch (formats[op][arg]) {
- case Script_Invalid: { /*Can't happen(tm)*/
- int i;
- printf("Invalid opcode %02X at %04X in method %d\n", op, pos, count);
- for (i = m->used - 9; i < m->used - 1; i++) {
- printf("%s[%02X] ", opcodes[m->data[i].opcode].name, m->data[i].opcode);
- dump(data + m->data[i].pos, m->data[i].size);
- }
- printf("Dump from %04X-%04X\n", pos - 16, pos + 16);
- dump(data + pos - 16, 32);
- }
- break;
- case Script_None: { /*No more args*/
- arg = 4;
- }
- break;
- case Script_Byte: /*Just a one byte arg*/
- case Script_SByte: {
- *args[arg] = data[pos++];
- }
- break;
- case Script_Word: { /*A two byte arg*/
- *args[arg] = getInt16(data + pos);
- pos += 2;
- }
- break;
- case Script_SWord: { /*A signed two-byte arg*/
- int t = getInt16(data + pos);
- if (t&0x8000) *args[arg] = -(t & 0x7FFF);
- else *args[arg] = t;
- pos += 2;
- }
- break;
- case Script_Variable: /*Size of arg depends on LSB in opcode*/
- case Script_SVariable:
- case Script_SRelative:
- case Script_Property:
- case Script_Global:
- case Script_Local:
- case Script_Temp:
- case Script_Param: {
- if (size == 1) *args[arg] = data[pos++];
- else {
- *args[arg] = getInt16(data + pos);
- pos += 2;
- }
- }
- break;
- case Script_End: { /*Special tag for ret*/
- done = 1;
- arg = 4;
- }
- break;
- default: { /*Can't happen(tm)*/
- printf("Unknown argument format %d for op %02X\n", formats[op][arg], op);
- }
- break;
- }
- }
- fflush(stdout);
- if (m->used) m->data[m->used-1].size = pos - old_pos;
- }
-
- return m;
-}
-
-#ifdef SCRIPT_DEBUG
-void list_code_blocks(resource_t* r) {
- int pos = getInt16(r->data + 2);
- while (pos < r->size - 2) {
- int type = getInt16(r->data + pos);
- int len = getInt16(r->data + pos + 2);
- if (type == 2) printf("%X-%X\n", pos, pos + len);
- pos += len;
- }
-}
-#endif
-
-
-/*These expect the frame, the whole frame, and, well, other stuff too,
- *I guess, as long as it looks like a frame*/
-static int get_type(unsigned char* obj) {
- return getInt16(obj);
-}
-
-static int get_length(unsigned char* obj) {
- return getInt16(obj + 2);
-}
-
-static int get_selector_count(unsigned char* obj) {
- return getInt16(obj + 10);
-}
-
-static int get_selector_value(unsigned char* obj, int sel) {
- assert(sel < get_selector_count(obj));
- return getInt16(obj + 12 + sel*2);
-}
-
-/*Bas things happen if the method offset value is wrong*/
-static unsigned char* get_method_area(unsigned char* obj) {
- return obj + getInt16(obj + 8) + 10;
-}
-
-static int get_method_count(unsigned char* obj) {
- return getInt16(get_method_area(obj));
-}
-
-static int get_method_number(unsigned char* obj, int i) {
- assert(i < get_method_count(obj));
- return getInt16(get_method_area(obj) + 2 + 2*i);
-}
-
-static int get_method_location(unsigned char* obj, int i) {
- assert(i < get_method_count(obj));
- return getInt16(get_method_area(obj) + 4 + 2*get_method_count(obj) + 2*i);
-}
-
-
-/*Returns the position of the first frame of type 'type' in resource 'r',
- *starting from the frame starting at 'start', or -1 on failure.
- */
-static int find_frame(resource_t* r, int type, unsigned int start) {
- int t = -1;
- unsigned int pos = start;
- unsigned char* frame;
-
- assert(start <= r->size - 4);
-
-#ifdef SCRIPT_DEBUG
- printf("Searching for frame of type %d in script %03d, starting at %#x\n", type, r->number, start);
- dump(r->data + start, 32);
-#endif
-
- /*Some times there's an extra byte at the beginning. Christoph?*/
-#if 1
- if (pos == 0 && r->size >= 6 && \
- !((0 < getInt16(r->data)) && (10 > getInt16(r->data)))) pos = 2;
-#else
- if (pos == 0)
- pos = 2;
-#endif
- frame = r->data + pos;
- while (1) {
-#ifdef SCRIPT_DEBUG
- printf("offset = %#x\n", pos);
- dump(frame, 32);
-#endif
- t = get_type(frame);
- if (t == type)
- break;
-
- if (t == 0)
- return -1;
-
- pos += get_length(frame);
- if (pos > (r->size - 2))
- return -1;
- frame += get_length(frame);
- }
-
- return pos;
-}
-
-
-
-/*FIXME: lots of things are identical to read_object and read_class. Some of
- *these would benefit from being put in separate functions.*/
-
-static object* read_object(resource_mgr_t *resmgr, int script, int positions[1000]) {
- resource_t* r = scir_find_resource(resmgr, sci_script, script, 0);
- unsigned char* raw;
- int pos;
- object* obj;
-
- printf("Searching for object in script %03d\n", script);
-
- if (r == 0) return 0;
-
- /*Skip to the next object*/
-#ifdef SCRIPT_DEBUG
- printf("pre skip: pos=%#x\n", positions[script]);
-#endif
- pos = find_frame(r, 1, positions[script]);
-#ifdef SCRIPT_DEBUG
- printf("post skip: pos=%#x\n", pos);
-#endif
- if (pos == -1) return 0;
- else positions[script] = pos + get_length(r->data + pos);
-#ifdef SCRIPT_DEBUG
- printf("post post: pos=%#x (len=%#x)\n", positions[script], get_length(r->data + pos));
-#endif
-
- /*Construct the object*/
- obj = object_new();
- raw = r->data + pos;
-
- /*Fill in the name*/
- if (get_selector_count(raw) < 4) obj->name = "<anonymous>";
- else {
- if (get_selector_value(raw, 3))
- obj->name = (char *) r->data + get_selector_value(raw, 3);
- else obj->name = "<null>";
- }
-
- /*Fill in the class*/
- if (get_selector_count(raw) == 0) obj->parent = object_root;
- else {
- int parent_id = get_selector_value(raw, 1);
- if (parent_id >= fobjects.used) {
- free(obj);
- return 0;
- }
- if (parent_id < 1) obj->parent = object_root;
- else obj->parent = fobjects.data[parent_id];
- }
-
- /*Add the object to the class*/
- if (!obj->parent) {
- free(obj);
- return 0;
- }
- if (add_child(obj->parent, obj)) {
- free(obj);
- return 0;
- }
- if (add_object(obj)) {
- free(obj);
- return 0;
- }
-
- /*FIXME: decode selectors here*/
-
- obj->method_count = get_method_count(raw);
- obj->methods = (script_method**)sci_malloc(obj->method_count * sizeof(script_method));
- if (obj->methods == 0) {
- free(obj);
- return 0;
- } else {
- int i;
- for (i = 0; i < obj->method_count; i++) {
- int number = get_method_number(raw, i);
- int position = get_method_location(raw, i);
-
- if ((obj->methods[i] = decode_method(r->data + position)) == 0) {
- obj->method_count = i - 1;
- break;
- }
- obj->methods[i]->number = number;
- }
- }
-
- return obj;
-}
-
-static object* read_class(resource_mgr_t *resmgr, int script, int positions[1000]) {
- resource_t* r = scir_find_resource(resmgr, sci_script, script, 0);
- unsigned char* raw;
- int pos;
- object* obj;
-
- printf("Searching for class in script %03d\n", script);
-
- if (r == 0) return fake_object("<resource not found>");
-
- /*Skip to the next class*/
-#ifdef SCRIPT_DEBUG
- printf("pre skip: pos=%#x\n", positions[script]);
-#endif
- pos = find_frame(r, 6, positions[script]);
-#ifdef SCRIPT_DEBUG
- printf("post skip: pos=%#x\n", pos);
-#endif
- if (pos == -1) return fake_object("<no more classes in script>");
- else positions[script] = pos + get_length(r->data + pos);
-#ifdef SCRIPT_DEBUG
- printf("post post: pos=%#x (len=%#x)\n", positions[script], get_length(r->data + pos));
-#endif
-
- /*Construct the object*/
- obj = object_new();
- raw = r->data + pos;
-
- /*Fill in the name*/
- if (get_selector_count(raw) < 4) obj->name = "<anonymous>";
- else {
- if (get_selector_value(raw, 3))
- obj->name = (char *) r->data + get_selector_value(raw, 3);
- else obj->name = "<null>";
- }
-
- /*Fill in the parent*/
- if (get_selector_count(raw) == 0) obj->parent = object_root;
- else {
- int superclass_id = get_selector_value(raw, 1);
- printf("superclass==%d\n", superclass_id);
- if (superclass_id >= fobjects.used) {
- free(obj);
- return fake_object("<no such superclass>");
- }
- if (superclass_id < 1) obj->parent = object_root;
- else obj->parent = fobjects.data[superclass_id];
- }
-
- /*Add the class to the hierarchy*/
- if (!obj->parent) {
- free(obj);
- return fake_object("<null parent>");
- }
- if (add_child(obj->parent, obj)) {
- free(obj);
- return fake_object("<add_child failed>");
- }
- if (add_object(obj)) {
- free(obj);
- return fake_object("<add_object failed>");
- }
-
- /*FIXME: decode selectors and methods here*/
-
- return obj;
-}
-
-void freeObject(object* obj) {
- int i;
- for (i = 0; i < obj->children.used; i++) freeObject(obj->children.data[i]);
- free(obj);
-}
-
-static int objects_init(resource_mgr_t *resmgr) {
- FLEXARRAY_INIT(object*, fobjects);
- max_object = 0;
-
- if ((object_root = object_new()) == 0) return 1;
- object_root->name = "<root>";
- add_object(object_root);
-
- opcodes = vocabulary_get_opcodes(resmgr);
- knames = vocabulary_get_knames(resmgr, &knames_count);
- snames = vocabulary_get_snames(resmgr, NULL, 0);
-
- return 0;
-}
-
-int loadObjects(resource_mgr_t *resmgr) {
- int i;
- int *classes, class_count;
- int positions[1000];
-
- if (objects_init(resmgr)) {
-#ifdef SCRIPT_DEBUG
- perror("objects_init");
-#endif
- return 1;
- }
- classes = vocabulary_get_classes(resmgr, &class_count);
-
- for (i = 0; i < 1000; i++) positions[i] = 0;
- for (i = 0; i < class_count; i++) {
-#ifdef SCRIPT_DEBUG
- printf("\n\nReading class 0x%02X\n", i);
-#endif
- if (read_class(resmgr, classes[i], positions) == 0) {
-#ifdef SCRIPT_DEBUG
- fprintf(stderr, "Failed to load class %d, which is a parent.\n", i);
-#endif
- return 1;
- }
- }
-
- for (i = 0; i < 1000; i++) positions[i] = 0;
- for (i = 0; i < 1000; i++) while (read_object(resmgr, i, positions));
-
- object_map = fobjects.data;
- max_object = fobjects.used;
-
- return 0;
-}
-
-
diff --git a/tools/sci/old_objects.h b/tools/sci/old_objects.h
deleted file mode 100644
index fe653a7d3c..0000000000
--- a/tools/sci/old_objects.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef OLD_OBJECTS_H
-#define OLD_OBJECTS_H
-
-#include "common/scummsys.h"
-#include "engine/sci/include/sciresource.h"
-#include "engine/sci/include/util.h"
-
-typedef FLEXARRAY(script_opcode, int number;) script_method;
-
-typedef struct object_ {
- /*These are based on cached selector values, and set to the values
- *the selectors had at load time. If the selectors are changed in
- *instances, inconsistency will follow*/
- struct object_* parent;
- const char* name;
-
- FLEXARRAY_NOEXTRA(struct object_*) children;
-
- /*No flexarray, size the size is known from the start*/
- script_method** methods;
- int method_count;
-
- int selector_count;
- int* selector_numbers;
-} object;
-
-typedef struct {
- int id;
- object* classID;
- byte* heap;
- int offset;
-} instance;
-
-extern object **object_map, *object_root;
-extern int max_object;
-
-#define SCRIPT_PRINT_METHODS 1
-#define SCRIPT_PRINT_CHILDREN 2
-#define SCRIPT_PRINT_SELECTORS 3
-void printObject(object* obj, int flags);
-
-int loadObjects(resource_mgr_t *resmgr);
-void freeObject(object*);
-
-extern const char* globals[];
-
-#endif
diff --git a/tools/sci/sciunpack.cpp b/tools/sci/sciunpack.cpp
deleted file mode 100644
index c9c50dc38b..0000000000
--- a/tools/sci/sciunpack.cpp
+++ /dev/null
@@ -1,473 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif /* HAVE_CONFIG_H */
-
-#include "sciunpack.h"
-
-#include <sciresource.h>
-#include <engine.h>
-#include <console.h>
-
-/* #define DRAW_GRAPHICS */
-
-#undef HAVE_OBSTACK_H
-
-#ifdef _MSC_VER
-# include <direct.h>
-# define extern __declspec(dllimport) extern
-#endif
-
-#ifdef HAVE_GETOPT_H
-# ifndef WIN32
-# include <getopt.h>
-# else
-# include <win32/getopt.h>
-# endif
-#endif /* HAVE_GETOPT_H */
-
-#ifdef DRAW_GRAPHICS
-# ifdef HAVE_LIBPNG
-# include "graphics_png.h"
-# endif /* HAVE_LIBPNG */
-#endif /* DRAW_GRAPHICS */
-
-#if defined (_MSC_VER) || defined (__BEOS__) || defined(__amigaos4__)
-/* [DJ] fchmod is not in Visual C++ RTL - and probably not needed,anyway */
-/* [RS] (see comment above, but read MS-DOS instead of Visual C++ RTL) */
-# define fchmod(file,mode)
-# define CREAT_OPTIONS O_BINARY
-#endif
-
-#ifndef CREAT_OPTIONS
-# define CREAT_OPTIONS 0x640
-#endif
-
-
-#define ACT_UNPACK 0
-#define ACT_WORDS 1
-#define ACT_LIST 2
-#define ACT_SCRIPTDUMP 3
-#define ACT_VOCABDUMP 4
-
-#define ACT_DEFAULT ACT_UNPACK
-
-static int conversion = 0;
-static int list = 0;
-static int verbose = 0;
-static int with_header = 1;
-static int color_mode = 0;
-static int action = ACT_DEFAULT;
-static guint8 midimask = 0x01; /* MT-32 */
-
-resource_mgr_t *resmgr;
-
-#ifdef WIN32
-#define fchmod(arg1, arg2)
-#endif
-
-void
-print_resource_filename(FILE* file, int type, int number) {
- if (resmgr->sci_version < SCI_VERSION_1)
- fprintf(file, "%s.%03d", sci_resource_types[type], number);
- else
- fprintf(file, "%d.%s", number, sci_resource_type_suffixes[type]);
-}
-
-void
-sprint_resource_filename(char* buf, int type, int number) {
- if (resmgr->sci_version < SCI_VERSION_1)
- sprintf(buf, "%s.%03d", sci_resource_types[type], number);
- else
- sprintf(buf, "%d.%s", number, sci_resource_type_suffixes[type]);
-}
-
-#ifdef HAVE_GETOPT_LONG
-static struct option options[] = {
- {"conversion", no_argument, &conversion, 1},
- {"version", no_argument, 0, 256},
- {"verbose", no_argument, &verbose, 1},
- {"help", no_argument, 0, 'h'},
- {"output-file", required_argument, 0, 'o'},
- {"unpack", no_argument, &action, ACT_UNPACK},
- {"list", no_argument, &action, ACT_LIST},
- {"words", no_argument, &action, ACT_WORDS},
- {"vocab", no_argument, &action, ACT_VOCABDUMP},
- {"objects", no_argument, &action, ACT_SCRIPTDUMP},
- {"with-header", no_argument, &with_header, 1},
- {"without-header", no_argument, &with_header, 0},
- {"sort-alpha", no_argument, &vocab_sort, SORT_METHOD_ALPHA},
- {"sort-group", no_argument, &vocab_sort, SORT_METHOD_GROUP},
-#ifdef DRAW_GRAPHICS
- {"palette-dither", no_argument, &color_mode, SCI_COLOR_DITHER},
- {"palette-interpolate", no_argument, &color_mode, SCI_COLOR_INTERPOLATE},
- {"palette-dither256", no_argument, &color_mode, SCI_COLOR_DITHER256},
-#endif /* DRAW_GRAPHICS */
- {"gamedir", required_argument, 0, 'd'},
- {"midimask", required_argument, 0, 'M'},
- {0, 0, 0, 0}
-};
-
-#endif /* HAVE_GETOPT_LONG */
-
-
-void unpack_resource(int stype, int snr, char *outfilename);
-
-
-int main(int argc, char** argv) {
- int retval = 0;
- int i;
- int stype = -1;
- int snr;
- char *resourcenumber_string = 0;
- char *outfilename = 0;
- int optindex = 0;
- int c;
- char *gamedir = sci_getcwd();
- int res_version = SCI_VERSION_AUTODETECT;
-
-#ifdef HAVE_GETOPT_LONG
- while ((c = getopt_long(argc, argv, "WOVUvhLcr:o:d:M:", options, &optindex)) > -1) {
-#else /* !HAVE_GETOPT_LONG */
- while ((c = getopt(argc, argv, "WOVUvhLcr:o:d:M:")) > -1) {
-#endif /* !HAVE_GETOPT_LONG */
-
- switch (c) {
- case 256:
- printf("sciunpack ("PACKAGE") "VERSION"\n");
- printf("This program is copyright (C) 1999, 2000, 2001 Christoph Reichenbach,\n"
- " Lars Skovlund, Magnus Reftel\n"
- "It comes WITHOUT WARRANTY of any kind.\n"
- "This is free software, released under the GNU General Public License.\n");
- exit(0);
-
- case 'h': {
- char *gcc_3_0_can_kiss_my_ass =
- "Usage: sciunpack [options] [-U] <resource.number>\n"
- " sciunpack [options] [-U] <resource> <number>\n"
- "Unpacks resource data\n"
- "If * is specified instead of <number>, \n"
- "all resources of given type will be unpacked.\n\n"
- " sciunpack [options] -W\n"
- "Lists vocabulary words\n\n"
- " sciunpack [options] -O\n"
- "Dumps the complete object hierarchy\n\n"
- " sciunpack [options] -V\n"
- "Prints selector names, opcodes, kernel names, and classes\n\n"
- "\nAvalable operations:\n"
- " --unpack -U Decompress resource\n"
- " --list -L List all resources\n"
- " --words -W List all vocabulary words\n"
- " --objects -O Print all objects\n"
- " --vocab -V Lists the complete vocabulary\n"
- "\nAvailable options:\n"
- "General:\n"
- " --version Prints the version number\n"
- " --verbose -v Enables additional output\n"
- " --help -h Displays this help message\n"
- " --midimask -M What 'play mask' to use. Defaults to MT-32 (0x01)\n"
-
- "Listing words:\n"
- " --sort-alpha sort in alphabetical order\n"
- " --sort-group sort in group order\n"
- "Unpacking:\n"
- " --convert -c Converts selected resources\n"
- " --output-file -o Selects output file\n"
- " --gamedir -d Read game resources from dir\n"
- " --with-header Forces the SCI header to be written (default)\n"
- " --without-header Prevents the two SCI header bytes from being written\n"
-#ifdef DRAW_GRAPHICS
- " --palette-dither Forces colors in 16 color games to be dithered\n"
- " --palette-interpolate Does color interpolation when drawing picture resources\n"
- " --palette-dither256 Does dithering in 256 colors\n"
-#endif /* DRAW_GRAPHICS */
- "\nAs a default, 'resource.number' is the output filename.\n"
- "If conversion is enabled, the following resources will be treated specially:\n"
- " sound resources: Will be converted to MIDI, stored in <number>.midi\n"
- " script resources: Will be dissected and stored in <number>.script\n"
-#ifdef DRAW_GRAPHICS
- " picture resources: Will be converted to PNG, stored in <number>.png\n"
-
-#endif /* DRAW_GRAPHICS */
- ;
-
- printf(gcc_3_0_can_kiss_my_ass);
- exit(0);
- }
-
- case 'v':
- verbose = 1;
- break;
-
- case 'L':
- action = ACT_LIST;
- break;
-
- case 'W':
- action = ACT_WORDS;
- break;
-
- case 'V':
- action = ACT_VOCABDUMP;
- break;
-
- case 'O':
- action = ACT_SCRIPTDUMP;
- break;
-
- case 'o':
- outfilename = optarg;
- break;
-
- case 'd':
- if (gamedir) sci_free(gamedir);
- gamedir = sci_strdup(optarg);
- break;
-
- case 'r':
- res_version = atoi(optarg);
- break;
-
- case 'c':
- conversion = 1;
- break;
-
- case 'M':
- midimask = (guint8) strtol(optarg, NULL, 0);
- break;
-
- case 0: /* getopt_long already did this for us */
- case '?':
- /* getopt_long already printed an error message. */
- break;
-
- default:
- return -1;
- }
- }
-
- if (action == ACT_UNPACK) {
- char *resstring = argv[optind];
-
- if (optind == argc) {
- fprintf(stderr, "Resource identifier required\n");
- return 1;
- }
-
- if ((resourcenumber_string = (char *) strchr(resstring, '.'))) {
- *resourcenumber_string++ = 0;
- } else if (optind + 1 == argc) {
- fprintf(stderr, "Resource number required\n");
- return 1;
- } else resourcenumber_string = argv[optind+1];
-
- for (i = 0; i < 18; i++)
- if ((strcmp(sci_resource_types[i], resstring) == 0)) stype = i;
- if (stype == -1) {
- printf("Could not find the resource type '%s'.\n", resstring);
- return 1;
- }
- } /* ACT_UNPACK */
-
- if (gamedir)
- if (chdir(gamedir)) {
- printf("Error changing to game directory '%s'\n", gamedir);
- exit(1);
- }
-
- if (!(resmgr = scir_new_resource_manager(gamedir, res_version,
- 0, 1024 * 128))) {
- fprintf(stderr, "Could not find any resources; quitting.\n");
- exit(1);
- }
-
- if (verbose) printf("Autodetect determined: %s\n",
- sci_version_types[resmgr->sci_version]);
-
-
- switch (action) {
-
- case ACT_LIST: {
- int i;
-
- if (verbose) {
- for (i = 0; i < resmgr->resources_nr; i++) {
- printf("%i: ", i);
- print_resource_filename(stdout,
- resmgr->resources[i].type,
- resmgr->resources[i].number);
- printf(" has size %i\n", resmgr->resources[i].size);
- }
-
- fprintf(stderr, " Reading complete. Actual resource count is %i\n",
- resmgr->resources_nr);
- } else {
- for (i = 0; i < resmgr->resources_nr; i++) {
- print_resource_filename(stdout,
- resmgr->resources[i].type,
- resmgr->resources[i].number);
- printf("\n");
- }
- }
- break;
- }
-
- case ACT_UNPACK: {
-
- if (!strcmp(resourcenumber_string, "*")) {
- int i;
- for (i = 0; i < resmgr->resources_nr; i++)
- if (resmgr->resources[i].type == stype)
- unpack_resource(stype, resmgr->resources[i].number, NULL);
- } else {
- snr = atoi(resourcenumber_string);
- unpack_resource(stype, snr, outfilename);
- }
- break;
- }
-
- case ACT_WORDS:
- retval = vocab_print();
- break;
-
- case ACT_SCRIPTDUMP:
- retval = script_dump();
- break;
-
- case ACT_VOCABDUMP:
- retval = vocab_dump();
- break;
-
- default:
- fprintf(stderr, "Invalid action %d- internal error!\n", action);
- return 1;
- }
-
-
- scir_free_resource_manager(resmgr);
- return retval;
-}
-
-
-void unpack_resource(int stype, int snr, char *outfilename) {
- char fnamebuffer[12]; /* stores default file name */
- resource_t *found;
-
- if ((stype == sci_sound) && conversion && (resmgr->sci_version > SCI_VERSION_0)) {
- fprintf(stderr, "MIDI conversion is only supported for SCI version 0\n");
- conversion = 0;
- }
-
- if (!outfilename) {
- outfilename = fnamebuffer;
- if ((stype == sci_sound) && conversion) {
-#ifdef HAVE_OBSTACK_H
- map_MIDI_instruments(resmgr);
-#endif
- sprintf(outfilename, "%03d.midi", snr);
- }
-#ifdef DRAW_GRAPHICS
- else if ((stype == sci_pic) && conversion)
- sprintf(outfilename, "%03d.png", snr);
-#endif /* DRAW_GRAPHICS */
- else
- sprint_resource_filename(outfilename, stype, snr);
- }
-
- if (verbose) {
- printf("seeking ");
- print_resource_filename(stdout, stype, snr);
- printf("...\n");
- }
-
- if ((found = scir_find_resource(resmgr, stype, snr, 0))) {
-
-#ifdef DRAW_GRAPHICS
- if ((stype == sci_pic) && conversion) {
- int i;
- picture_t pic = alloc_empty_picture(SCI_RESOLUTION_320X200, SCI_COLORDEPTH_8BPP);
- draw_pic0(pic, 1, 0, found->data);
- if ((i = write_pic_png(outfilename, pic->maps[0]))) {
- fprintf(stderr, "Writing the png failed (%d)\n", i);
- } else if (verbose) printf("Done.\n");
- free_picture(pic);
- } else
-#endif /* DRAW_GRAPHICS */
- if ((stype == sci_script) && conversion) {
- sprintf(outfilename, "%03d.script", snr);
- open_console_file(outfilename);
- script_dissect(resmgr, snr, NULL, 0);
- close_console_file();
- } else {
-
- /* Visual C++ doesn't allow to specify O_BINARY with creat() */
-#ifdef _MSC_VER
- int outf = open(outfilename, _O_CREAT | _O_BINARY | _O_RDWR);
-#else
- int outf = creat(outfilename, CREAT_OPTIONS);
-#endif
-
-#ifdef HAVE_OBSTACK_H
- if ((stype == sci_sound) && conversion) {
- int midilength;
- guint8 *outdata = makeMIDI0(found->data, &midilength, midimask);
- if (!outdata) {
- fprintf(stderr, "MIDI conversion failed. Aborting...\n");
- return;
- }
- if (verbose) printf("MIDI conversion from %d bytes of sound resource"
- " to a %d bytes MIDI file.\n",
- found->size, midilength);
- write(outf, outdata, midilength);
- free(outdata);
- } else {
-#endif /* HAVE_OBSTACK_H */
- guint8 header = 0x80 | found->type;
-
- if (with_header) {
- write(outf, &header, 1);
- header = 0x00;
- write(outf, &header, 1);
- }
-
- write(outf, found->data, found->size);
-#ifdef HAVE_OBSTACK_H
- }
-#endif /* HAVE_OBSTACK_H */
-
- fchmod(outf, 0644);
- close(outf);
- fchmod(outf, 0644);
-
- if (verbose) printf("Done.\n");
- }
-
- } else printf("Resource not found.\n");
-}
-
-
-
diff --git a/tools/sci/sciunpack.h b/tools/sci/sciunpack.h
deleted file mode 100644
index df605ed19b..0000000000
--- a/tools/sci/sciunpack.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef SCI_UNPACK_H_
-#define SCI_UNPACK_H_
-
-#include <sciresource.h>
-
-#define SORT_METHOD_ALPHA 0
-#define SORT_METHOD_GROUP 1
-
-#define DEFAULT_SORTING SORT_METHOD_ALPHA
-
-extern int vocab_sort; /* Sorting strategy for vocab */
-extern resource_mgr_t *resmgr;
-
-int
-vocab_print(void);
-/* Prints vocab data
-** Parameters: (void)
-** Returns : (int) 0 on success, 1 on failure
-** Controlled by vocab_sort
-*/
-
-int
-script_dump(void);
-/* Prints all object information
-** Parameters: (void)
-** Returns : (int) 0 on success, 1 on failure
-*/
-
-int
-vocab_dump(void);
-/* Prints full vocabulary information
-** Parameters: (void)
-** Returns : (int) 0 on success, 1 on failure
-*/
-
-int
-print_classes(void);
-/* Prints full class information
-** Parameters: (void)
-** Returns : (int) 0 on success, 1 otherwise
-*/
-
-#endif
diff --git a/tools/sci/scriptdump.cpp b/tools/sci/scriptdump.cpp
deleted file mode 100644
index 9a5ef00035..0000000000
--- a/tools/sci/scriptdump.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include <console.h>
-#include <script.h>
-#include <vocabulary.h>
-#include <old_objects.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <engine.h>
-#include "sciunpack.h"
-
-int script_dump() {
- con_passthrough = 1;
-
- if (loadObjects(resmgr)) {
- fprintf(stderr, "Unable to load object hierarchy\n");
- return 1;
- }
-
- printObject(object_root, SCRIPT_PRINT_METHODS | SCRIPT_PRINT_CHILDREN);
- return 0;
-}
diff --git a/tools/sci/vocabdump.cpp b/tools/sci/vocabdump.cpp
deleted file mode 100644
index 26bac4dcf0..0000000000
--- a/tools/sci/vocabdump.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include <engine.h>
-#include "sciunpack.h"
-
-int
-vocab_dump() {
- char **names;
- opcode *opcodes;
- int i = 0, count;
- int *classes;
-
- printf("Selectors:\n");
- names = vocabulary_get_snames(resmgr, NULL, 0);
- while (names[i]) {
- printf("0x%02X: %s\n", i, names[i]);
- i++;
- }
- vocabulary_free_snames(names);
-
- i = 0;
- printf("\nOpcodes:\n");
- opcodes = vocabulary_get_opcodes(resmgr);
- while ((i < 256) && (opcodes[i].name)) {
- printf("%s: Type %i, Number %i\n", opcodes[i].name,
- opcodes[i].type, opcodes[i].number);
- i++;
- }
-
- names = vocabulary_get_knames(resmgr, &count);
- printf("\nKernel names:\n");
- if (names == 0) printf("Error loading kernel names\n");
- else {
- for (i = 0; i < count; i++) printf("0x%02X: %s\n", i, names[i]);
- vocabulary_free_knames(names);
- }
-
- classes = vocabulary_get_classes(resmgr, &count);
- printf("\nClasses:\n");
- if (classes == 0) printf("Error loading classes\n");
- else {
- for (i = 0; i < count; i++) printf("0x%02X: script %i\n", i, classes [i]);
- free(classes);
- }
-
- return 0;
-}
diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt
index fe5813fc5c..60fc615057 100644
--- a/tools/scumm-md5.txt
+++ b/tools/scumm-md5.txt
@@ -392,7 +392,7 @@ football Backyard Football
football2002 Backyard Football 2002
a095616d2d23ccf43b8e257711202cba -1 en All - - - clone2727
d0549508a06bbb9f99ed19c9e97891f3 -1 en All - - - Kirben
- 2e85f7aa054930c692a5b1bed1dfc295 -1 en All - Demo - khalek
+ 2e85f7aa054930c692a5b1bed1dfc295 -1 en All - Patched - khalek
soccer Backyard Soccer
701246819d1a70573f41bf33fc19214f -1 en All - - - sev
@@ -745,7 +745,7 @@ puttputt Putt-Putt Joins the Parade
6a30a07f353a75cdc602db27d73e1b42 -1 en Windows HE 70 - - khalek
31aa57f460a3d12429f0552a46a90b39 6150 en DOS Demo Demo -
- f40a7f495f59188ca57a9d1d50301bb6 -1 en Mac Demo Demo - khalek
+ f40a7f495f59188ca57a9d1d50301bb6 -1 en Mac HE 60 Demo - khalek
37ff1b308999c4cca7319edfcc1280a0 8269 en Windows HE 70 Demo - khalek
puttzoo Putt-Putt Saves the Zoo
diff --git a/tools/update-version.pl b/tools/update-version.pl
index 81aa5c27f9..f8a46b9a7e 100755
--- a/tools/update-version.pl
+++ b/tools/update-version.pl
@@ -49,7 +49,8 @@ my %subs = (
VER_MINOR => $VER_MINOR,
VER_PATCH => $VER_PATCH,
VER_EXTRA => $VER_EXTRA,
- VERSION => $VERSION
+ VERSION => $VERSION,
+ SVN_REVISION=> "",
);
foreach my $file (@subs_files) {