aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorMatthew Hoops2012-08-26 15:49:45 -0400
committerMatthew Hoops2012-08-26 16:12:25 -0400
commitbb1e60e8b2f3bba06ae3b089097f94ea82a70c8a (patch)
treea434233367725fbb6dc7072776c312f52254d57f /engines
parent7a49b3669a0e18210a2f5409cb35da735f549b11 (diff)
parent857b92f8ffececa9c1f990d21a6a8d1630199a62 (diff)
downloadscummvm-rg350-bb1e60e8b2f3bba06ae3b089097f94ea82a70c8a.tar.gz
scummvm-rg350-bb1e60e8b2f3bba06ae3b089097f94ea82a70c8a.tar.bz2
scummvm-rg350-bb1e60e8b2f3bba06ae3b089097f94ea82a70c8a.zip
Merge remote branch 'upstream/master' into pegasus
Conflicts: AUTHORS devtools/credits.pl gui/credits.h
Diffstat (limited to 'engines')
-rw-r--r--engines/advancedDetector.cpp101
-rw-r--r--engines/advancedDetector.h29
-rw-r--r--engines/agi/detection.cpp15
-rw-r--r--engines/agos/animation.cpp105
-rw-r--r--engines/agos/animation.h7
-rw-r--r--engines/agos/event.cpp6
-rw-r--r--engines/agos/saveload.cpp44
-rw-r--r--engines/cge/bitmap.cpp3
-rw-r--r--engines/cge/cge.cpp16
-rw-r--r--engines/cge/cge.h5
-rw-r--r--engines/cge/cge_main.cpp33
-rw-r--r--engines/cge/cge_main.h6
-rw-r--r--engines/cge/detection.cpp4
-rw-r--r--engines/cge/events.cpp31
-rw-r--r--engines/cge/events.h1
-rw-r--r--engines/cge/fileio.cpp25
-rw-r--r--engines/cge/sound.cpp6
-rw-r--r--engines/cge/vga13h.cpp9
-rw-r--r--engines/cge/vga13h.h3
-rw-r--r--engines/cge/vmenu.cpp6
-rw-r--r--engines/cge/vmenu.h2
-rw-r--r--engines/cine/anim.cpp19
-rw-r--r--engines/cine/anim.h2
-rw-r--r--engines/cine/bg_list.cpp12
-rw-r--r--engines/cine/cine.cpp2
-rw-r--r--engines/cine/detection_tables.h36
-rw-r--r--engines/cine/gfx.cpp135
-rw-r--r--engines/cine/gfx.h10
-rw-r--r--engines/cine/main_loop.cpp17
-rw-r--r--engines/cine/saveload.cpp16
-rw-r--r--engines/cine/script_fw.cpp19
-rw-r--r--engines/cine/sound.cpp3
-rw-r--r--engines/cine/various.cpp21
-rw-r--r--engines/cine/various.h2
-rw-r--r--engines/composer/composer.cpp8
-rw-r--r--engines/cruise/detection.cpp2
-rw-r--r--engines/draci/detection.cpp2
-rw-r--r--engines/dreamweb/detection.cpp2
-rw-r--r--engines/dreamweb/detection_tables.h24
-rw-r--r--engines/dreamweb/dreamweb.h4
-rw-r--r--engines/dreamweb/stubs.cpp4
-rw-r--r--engines/gob/anifile.cpp39
-rw-r--r--engines/gob/anifile.h3
-rw-r--r--engines/gob/aniobject.cpp105
-rw-r--r--engines/gob/aniobject.h19
-rw-r--r--engines/gob/backbuffer.cpp100
-rw-r--r--engines/gob/backbuffer.h59
-rw-r--r--engines/gob/cmpfile.cpp14
-rw-r--r--engines/gob/cmpfile.h2
-rw-r--r--engines/gob/decfile.cpp42
-rw-r--r--engines/gob/detection/detection.cpp151
-rw-r--r--engines/gob/detection/tables.h4
-rw-r--r--engines/gob/detection/tables_ajworld.h1
-rw-r--r--engines/gob/detection/tables_fallback.h135
-rw-r--r--engines/gob/detection/tables_geisha.h60
-rw-r--r--engines/gob/detection/tables_onceupon.h518
-rw-r--r--engines/gob/draw.cpp25
-rw-r--r--engines/gob/draw.h2
-rw-r--r--engines/gob/draw_fascin.cpp4
-rw-r--r--engines/gob/draw_playtoons.cpp4
-rw-r--r--engines/gob/draw_v2.cpp9
-rw-r--r--engines/gob/game.cpp2
-rw-r--r--engines/gob/gob.cpp75
-rw-r--r--engines/gob/gob.h21
-rw-r--r--engines/gob/init.cpp14
-rw-r--r--engines/gob/inter_bargon.cpp4
-rw-r--r--engines/gob/inter_geisha.cpp8
-rw-r--r--engines/gob/inter_v5.cpp10
-rw-r--r--engines/gob/minigames/geisha/penetration.cpp47
-rw-r--r--engines/gob/module.mk12
-rw-r--r--engines/gob/pregob/gctfile.cpp306
-rw-r--r--engines/gob/pregob/gctfile.h149
-rw-r--r--engines/gob/pregob/onceupon/abracadabra.cpp137
-rw-r--r--engines/gob/pregob/onceupon/abracadabra.h61
-rw-r--r--engines/gob/pregob/onceupon/babayaga.cpp137
-rw-r--r--engines/gob/pregob/onceupon/babayaga.h61
-rw-r--r--engines/gob/pregob/onceupon/brokenstrings.h60
-rw-r--r--engines/gob/pregob/onceupon/chargenchild.cpp117
-rw-r--r--engines/gob/pregob/onceupon/chargenchild.h60
-rw-r--r--engines/gob/pregob/onceupon/onceupon.cpp1904
-rw-r--r--engines/gob/pregob/onceupon/onceupon.h344
-rw-r--r--engines/gob/pregob/onceupon/palettes.h411
-rw-r--r--engines/gob/pregob/onceupon/parents.cpp217
-rw-r--r--engines/gob/pregob/onceupon/parents.h94
-rw-r--r--engines/gob/pregob/onceupon/stork.cpp234
-rw-r--r--engines/gob/pregob/onceupon/stork.h103
-rw-r--r--engines/gob/pregob/onceupon/title.cpp117
-rw-r--r--engines/gob/pregob/onceupon/title.h55
-rw-r--r--engines/gob/pregob/pregob.cpp351
-rw-r--r--engines/gob/pregob/pregob.h194
-rw-r--r--engines/gob/pregob/seqfile.cpp384
-rw-r--r--engines/gob/pregob/seqfile.h193
-rw-r--r--engines/gob/pregob/txtfile.cpp232
-rw-r--r--engines/gob/pregob/txtfile.h91
-rw-r--r--engines/gob/rxyfile.cpp19
-rw-r--r--engines/gob/rxyfile.h4
-rw-r--r--engines/gob/sound/sound.cpp13
-rw-r--r--engines/gob/sound/sound.h4
-rw-r--r--engines/gob/sound/soundblaster.cpp2
-rw-r--r--engines/gob/sound/soundblaster.h2
-rw-r--r--engines/gob/surface.cpp6
-rw-r--r--engines/gob/surface.h2
-rw-r--r--engines/gob/util.cpp115
-rw-r--r--engines/gob/util.h8
-rw-r--r--engines/gob/video.cpp27
-rw-r--r--engines/gob/video.h5
-rw-r--r--engines/groovie/saveload.cpp2
-rw-r--r--engines/hugo/detection.cpp3
-rw-r--r--engines/kyra/detection_tables.h33
-rw-r--r--engines/kyra/eobcommon.cpp4
-rw-r--r--engines/kyra/eobcommon.h6
-rw-r--r--engines/kyra/screen.cpp6
-rw-r--r--engines/kyra/screen.h3
-rw-r--r--engines/kyra/screen_eob.cpp2
-rw-r--r--engines/kyra/screen_lol.cpp2
-rw-r--r--engines/kyra/screen_lol.h2
-rw-r--r--engines/kyra/sound_intern.h1
-rw-r--r--engines/kyra/sound_midi.cpp4
-rw-r--r--engines/kyra/sound_towns.cpp2
-rw-r--r--engines/kyra/staticres.cpp2
-rw-r--r--engines/lastexpress/data/animation.cpp6
-rw-r--r--engines/lastexpress/data/cursor.cpp2
-rw-r--r--engines/lastexpress/data/font.cpp6
-rw-r--r--engines/lastexpress/data/scene.cpp13
-rw-r--r--engines/lastexpress/data/sequence.cpp3
-rw-r--r--engines/lastexpress/data/sequence.h6
-rw-r--r--engines/lastexpress/data/snd.cpp14
-rw-r--r--engines/lastexpress/data/subtitle.cpp3
-rw-r--r--engines/lastexpress/debug.cpp7
-rw-r--r--engines/lastexpress/detection.cpp3
-rw-r--r--engines/lastexpress/entities/abbot.cpp46
-rw-r--r--engines/lastexpress/entities/abbot.h1
-rw-r--r--engines/lastexpress/entities/alexei.cpp48
-rw-r--r--engines/lastexpress/entities/alexei.h1
-rw-r--r--engines/lastexpress/entities/alouan.cpp50
-rw-r--r--engines/lastexpress/entities/alouan.h1
-rw-r--r--engines/lastexpress/entities/anna.cpp119
-rw-r--r--engines/lastexpress/entities/anna.h1
-rw-r--r--engines/lastexpress/entities/august.cpp113
-rw-r--r--engines/lastexpress/entities/august.h1
-rw-r--r--engines/lastexpress/entities/boutarel.cpp55
-rw-r--r--engines/lastexpress/entities/boutarel.h1
-rw-r--r--engines/lastexpress/entities/chapters.cpp197
-rw-r--r--engines/lastexpress/entities/chapters.h4
-rw-r--r--engines/lastexpress/entities/cooks.cpp29
-rw-r--r--engines/lastexpress/entities/cooks.h1
-rw-r--r--engines/lastexpress/entities/coudert.cpp227
-rw-r--r--engines/lastexpress/entities/coudert.h2
-rw-r--r--engines/lastexpress/entities/entity.cpp558
-rw-r--r--engines/lastexpress/entities/entity.h349
-rw-r--r--engines/lastexpress/entities/entity39.cpp1
-rw-r--r--engines/lastexpress/entities/entity39.h3
-rw-r--r--engines/lastexpress/entities/entity_intern.h496
-rw-r--r--engines/lastexpress/entities/francois.cpp120
-rw-r--r--engines/lastexpress/entities/francois.h5
-rw-r--r--engines/lastexpress/entities/gendarmes.cpp25
-rw-r--r--engines/lastexpress/entities/gendarmes.h1
-rw-r--r--engines/lastexpress/entities/hadija.cpp68
-rw-r--r--engines/lastexpress/entities/hadija.h1
-rw-r--r--engines/lastexpress/entities/ivo.cpp15
-rw-r--r--engines/lastexpress/entities/ivo.h1
-rw-r--r--engines/lastexpress/entities/kahina.cpp77
-rw-r--r--engines/lastexpress/entities/kahina.h1
-rw-r--r--engines/lastexpress/entities/kronos.cpp19
-rw-r--r--engines/lastexpress/entities/kronos.h1
-rw-r--r--engines/lastexpress/entities/mahmud.cpp26
-rw-r--r--engines/lastexpress/entities/mahmud.h1
-rw-r--r--engines/lastexpress/entities/max.cpp23
-rw-r--r--engines/lastexpress/entities/max.h1
-rw-r--r--engines/lastexpress/entities/mertens.cpp282
-rw-r--r--engines/lastexpress/entities/mertens.h4
-rw-r--r--engines/lastexpress/entities/milos.cpp70
-rw-r--r--engines/lastexpress/entities/milos.h1
-rw-r--r--engines/lastexpress/entities/mmeboutarel.cpp41
-rw-r--r--engines/lastexpress/entities/mmeboutarel.h1
-rw-r--r--engines/lastexpress/entities/pascale.cpp51
-rw-r--r--engines/lastexpress/entities/pascale.h1
-rw-r--r--engines/lastexpress/entities/rebecca.cpp63
-rw-r--r--engines/lastexpress/entities/rebecca.h1
-rw-r--r--engines/lastexpress/entities/salko.cpp14
-rw-r--r--engines/lastexpress/entities/salko.h1
-rw-r--r--engines/lastexpress/entities/servers0.cpp37
-rw-r--r--engines/lastexpress/entities/servers0.h1
-rw-r--r--engines/lastexpress/entities/servers1.cpp19
-rw-r--r--engines/lastexpress/entities/servers1.h1
-rw-r--r--engines/lastexpress/entities/sophie.cpp75
-rw-r--r--engines/lastexpress/entities/sophie.h5
-rw-r--r--engines/lastexpress/entities/tables.cpp2
-rw-r--r--engines/lastexpress/entities/tables.h1
-rw-r--r--engines/lastexpress/entities/tatiana.cpp65
-rw-r--r--engines/lastexpress/entities/tatiana.h1
-rw-r--r--engines/lastexpress/entities/train.cpp20
-rw-r--r--engines/lastexpress/entities/train.h1
-rw-r--r--engines/lastexpress/entities/vassili.cpp16
-rw-r--r--engines/lastexpress/entities/vassili.h1
-rw-r--r--engines/lastexpress/entities/verges.cpp114
-rw-r--r--engines/lastexpress/entities/verges.h1
-rw-r--r--engines/lastexpress/entities/vesna.cpp26
-rw-r--r--engines/lastexpress/entities/vesna.h1
-rw-r--r--engines/lastexpress/entities/yasmin.cpp76
-rw-r--r--engines/lastexpress/entities/yasmin.h1
-rw-r--r--engines/lastexpress/fight/fight.cpp7
-rw-r--r--engines/lastexpress/fight/fighter.cpp27
-rw-r--r--engines/lastexpress/fight/fighter.h3
-rw-r--r--engines/lastexpress/game/action.cpp31
-rw-r--r--engines/lastexpress/game/beetle.cpp33
-rw-r--r--engines/lastexpress/game/beetle.h1
-rw-r--r--engines/lastexpress/game/entities.cpp77
-rw-r--r--engines/lastexpress/game/entities.h1
-rw-r--r--engines/lastexpress/game/inventory.cpp90
-rw-r--r--engines/lastexpress/game/inventory.h24
-rw-r--r--engines/lastexpress/game/logic.cpp39
-rw-r--r--engines/lastexpress/game/logic.h3
-rw-r--r--engines/lastexpress/game/object.cpp2
-rw-r--r--engines/lastexpress/game/savegame.cpp417
-rw-r--r--engines/lastexpress/game/savegame.h92
-rw-r--r--engines/lastexpress/game/savepoint.cpp23
-rw-r--r--engines/lastexpress/game/savepoint.h10
-rw-r--r--engines/lastexpress/game/scenes.cpp37
-rw-r--r--engines/lastexpress/game/scenes.h1
-rw-r--r--engines/lastexpress/game/state.cpp12
-rw-r--r--engines/lastexpress/game/state.h2
-rw-r--r--engines/lastexpress/helpers.h2
-rw-r--r--engines/lastexpress/lastexpress.cpp13
-rw-r--r--engines/lastexpress/menu/menu.cpp7
-rw-r--r--engines/lastexpress/resource.cpp6
-rw-r--r--engines/lastexpress/resource.h2
-rw-r--r--engines/lastexpress/shared.h59
-rw-r--r--engines/lastexpress/sound/entry.cpp23
-rw-r--r--engines/lastexpress/sound/queue.cpp24
-rw-r--r--engines/lastexpress/sound/queue.h2
-rw-r--r--engines/lastexpress/sound/sound.cpp25
-rw-r--r--engines/lure/surface.cpp4
-rw-r--r--engines/mohawk/detection.cpp2
-rw-r--r--engines/mohawk/detection_tables.h18
-rw-r--r--engines/mohawk/livingbooks.cpp15
-rw-r--r--engines/mohawk/livingbooks.h3
-rw-r--r--engines/mohawk/myst.cpp44
-rw-r--r--engines/mohawk/myst_graphics.cpp136
-rw-r--r--engines/mohawk/myst_graphics.h15
-rw-r--r--engines/mohawk/myst_stacks/dni.cpp2
-rw-r--r--engines/mohawk/myst_stacks/intro.cpp25
-rw-r--r--engines/mohawk/riven.cpp2
-rw-r--r--engines/mohawk/video.cpp22
-rw-r--r--engines/mohawk/video.h6
-rw-r--r--engines/parallaction/disk_br.cpp2
-rw-r--r--engines/parallaction/disk_ns.cpp2
-rw-r--r--engines/parallaction/graphics.cpp2
-rw-r--r--engines/parallaction/graphics.h2
-rw-r--r--engines/parallaction/sound_ns.cpp2
-rw-r--r--engines/pegasus/movie.cpp16
-rw-r--r--engines/pegasus/movie.h6
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria.cpp4
-rw-r--r--engines/pegasus/neighborhood/mars/mars.cpp4
-rw-r--r--engines/pegasus/pegasus.cpp19
-rw-r--r--engines/pegasus/pegasus.h4
-rw-r--r--engines/pegasus/surface.cpp8
-rw-r--r--engines/pegasus/surface.h8
-rw-r--r--engines/queen/queen.cpp4
-rw-r--r--engines/saga/detection.cpp3
-rw-r--r--engines/saga/introproc_saga2.cpp7
-rw-r--r--engines/saga/shorten.cpp3
-rw-r--r--engines/savestate.h2
-rw-r--r--engines/sci/console.cpp17
-rw-r--r--engines/sci/detection.cpp7
-rw-r--r--engines/sci/detection_tables.h118
-rw-r--r--engines/sci/engine/file.cpp17
-rw-r--r--engines/sci/engine/kernel.cpp125
-rw-r--r--engines/sci/engine/kernel.h21
-rw-r--r--engines/sci/engine/kernel_tables.h94
-rw-r--r--engines/sci/engine/kfile.cpp20
-rw-r--r--engines/sci/engine/kgraphics.cpp93
-rw-r--r--engines/sci/engine/kgraphics32.cpp219
-rw-r--r--engines/sci/engine/klists.cpp5
-rw-r--r--engines/sci/engine/kmath.cpp11
-rw-r--r--engines/sci/engine/kmisc.cpp12
-rw-r--r--engines/sci/engine/ksound.cpp11
-rw-r--r--engines/sci/engine/kvideo.cpp28
-rw-r--r--engines/sci/engine/message.cpp20
-rw-r--r--engines/sci/engine/script.cpp17
-rw-r--r--engines/sci/engine/script.h4
-rw-r--r--engines/sci/engine/script_patches.cpp23
-rw-r--r--engines/sci/engine/seg_manager.cpp34
-rw-r--r--engines/sci/engine/seg_manager.h8
-rw-r--r--engines/sci/engine/state.cpp3
-rw-r--r--engines/sci/engine/state.h2
-rw-r--r--engines/sci/engine/vm.cpp1
-rw-r--r--engines/sci/engine/vm.h4
-rw-r--r--engines/sci/engine/workarounds.cpp9
-rw-r--r--engines/sci/graphics/font.cpp2
-rw-r--r--engines/sci/graphics/frameout.cpp98
-rw-r--r--engines/sci/graphics/frameout.h4
-rw-r--r--engines/sci/graphics/palette.cpp92
-rw-r--r--engines/sci/graphics/palette.h21
-rw-r--r--engines/sci/graphics/screen.cpp48
-rw-r--r--engines/sci/graphics/screen.h1
-rw-r--r--engines/sci/graphics/view.cpp17
-rw-r--r--engines/sci/sci.cpp2
-rw-r--r--engines/sci/sound/audio.cpp3
-rw-r--r--engines/sci/sound/soundcmd.cpp43
-rw-r--r--engines/sci/video/robot_decoder.cpp377
-rw-r--r--engines/sci/video/robot_decoder.h129
-rw-r--r--engines/sci/video/seq_decoder.cpp61
-rw-r--r--engines/sci/video/seq_decoder.h67
-rw-r--r--engines/scumm/detection.cpp18
-rw-r--r--engines/scumm/he/animation_he.cpp7
-rw-r--r--engines/scumm/scumm-md5.h3
-rw-r--r--engines/sword1/animation.cpp72
-rw-r--r--engines/sword1/animation.h32
-rw-r--r--engines/sword1/detection.cpp3
-rw-r--r--engines/sword1/logic.cpp2
-rw-r--r--engines/sword1/objectman.cpp253
-rw-r--r--engines/sword1/objectman.h19
-rw-r--r--engines/sword1/sound.cpp2
-rw-r--r--engines/sword2/animation.cpp62
-rw-r--r--engines/sword2/animation.h30
-rw-r--r--engines/sword2/function.cpp2
-rw-r--r--engines/sword25/fmv/movieplayer.cpp1
-rw-r--r--engines/sword25/fmv/movieplayer.h4
-rw-r--r--engines/sword25/fmv/theora_decoder.cpp565
-rw-r--r--engines/sword25/fmv/theora_decoder.h144
-rw-r--r--engines/sword25/module.mk5
-rw-r--r--engines/sword25/sfx/soundengine.cpp18
-rw-r--r--engines/sword25/util/pluto/pluto.cpp4
-rw-r--r--engines/teenagent/callbacks.cpp6
-rw-r--r--engines/teenagent/detection.cpp10
-rw-r--r--engines/teenagent/resources.cpp46
-rw-r--r--engines/teenagent/teenagent.cpp3
-rw-r--r--engines/testbed/graphics.cpp4
-rw-r--r--engines/testbed/testsuite.cpp2
-rw-r--r--engines/tinsel/detection.cpp8
-rw-r--r--engines/tinsel/detection_tables.h142
-rw-r--r--engines/tinsel/dialogs.cpp49
-rw-r--r--engines/tinsel/dialogs.h2
-rw-r--r--engines/tinsel/drives.cpp2
-rw-r--r--engines/tinsel/handle.cpp12
-rw-r--r--engines/tinsel/music.cpp141
-rw-r--r--engines/tinsel/pcode.cpp43
-rw-r--r--engines/tinsel/saveload.cpp50
-rw-r--r--engines/tinsel/scene.h6
-rw-r--r--engines/tinsel/sound.cpp6
-rw-r--r--engines/tinsel/tinlib.cpp25
-rw-r--r--engines/tinsel/tinsel.h26
-rw-r--r--engines/toltecs/detection.cpp2
-rw-r--r--engines/toon/anim.cpp112
-rw-r--r--engines/toon/anim.h58
-rw-r--r--engines/toon/audio.cpp2
-rw-r--r--engines/toon/character.cpp38
-rw-r--r--engines/toon/detection.cpp5
-rw-r--r--engines/toon/font.cpp46
-rw-r--r--engines/toon/font.h6
-rw-r--r--engines/toon/hotspot.cpp4
-rw-r--r--engines/toon/hotspot.h4
-rw-r--r--engines/toon/movie.cpp58
-rw-r--r--engines/toon/movie.h14
-rw-r--r--engines/toon/picture.cpp60
-rw-r--r--engines/toon/picture.h24
-rw-r--r--engines/toon/script_func.cpp4
-rw-r--r--engines/toon/toon.cpp24
-rw-r--r--engines/toon/toon.h5
-rw-r--r--engines/touche/detection.cpp18
-rw-r--r--engines/tsage/blue_force/blueforce_dialogs.cpp4
-rw-r--r--engines/tsage/blue_force/blueforce_scenes9.cpp73
-rw-r--r--engines/tsage/converse.cpp2
-rw-r--r--engines/tsage/detection.cpp2
-rw-r--r--engines/tsage/detection_tables.h8
-rw-r--r--engines/tsage/dialogs.cpp2
-rw-r--r--engines/tsage/globals.cpp4
-rw-r--r--engines/tsage/globals.h2
-rw-r--r--engines/tsage/graphics.cpp6
-rw-r--r--engines/tsage/graphics.h2
-rw-r--r--engines/tsage/ringworld/ringworld_dialogs.cpp4
-rw-r--r--engines/tsage/ringworld/ringworld_logic.cpp2
-rw-r--r--engines/tsage/ringworld/ringworld_scenes5.cpp2
-rw-r--r--engines/tsage/ringworld2/ringworld2_dialogs.cpp2
-rw-r--r--engines/tsage/ringworld2/ringworld2_speakers.h14
-rw-r--r--engines/tsage/user_interface.cpp2
-rw-r--r--engines/tucker/sequences.cpp4
378 files changed, 13213 insertions, 4933 deletions
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp
index ac06e74e0a..9beba6ce4a 100644
--- a/engines/advancedDetector.cpp
+++ b/engines/advancedDetector.cpp
@@ -22,7 +22,6 @@
#include "common/debug.h"
#include "common/util.h"
-#include "common/hash-str.h"
#include "common/file.h"
#include "common/macresman.h"
#include "common/md5.h"
@@ -308,14 +307,7 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
return Common::kNoError;
}
-struct SizeMD5 {
- int size;
- Common::String md5;
-};
-
-typedef Common::HashMap<Common::String, SizeMD5, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SizeMD5Map;
-
-static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSizeMD5) {
+void AdvancedMetaEngine::reportUnknown(const Common::FSNode &path, const ADFilePropertiesMap &filesProps) const {
// TODO: This message should be cleaned up / made more specific.
// For example, we should specify at least which engine triggered this.
//
@@ -327,7 +319,7 @@ static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSiz
report += _("of the game you tried to add and its version/language/etc.:");
report += "\n";
- for (SizeMD5Map::const_iterator file = filesSizeMD5.begin(); file != filesSizeMD5.end(); ++file)
+ for (ADFilePropertiesMap::const_iterator file = filesProps.begin(); file != filesProps.end(); ++file)
report += Common::String::format(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5.c_str(), file->_value.size);
report += "\n";
@@ -375,8 +367,36 @@ void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSL
}
}
+bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const {
+ // FIXME/TODO: We don't handle the case that a file is listed as a regular
+ // file and as one with resource fork.
+
+ if (game.flags & ADGF_MACRESFORK) {
+ Common::MacResManager macResMan;
+
+ if (!macResMan.open(parent, fname))
+ return false;
+
+ fileProps.md5 = macResMan.computeResForkMD5AsString(_md5Bytes);
+ fileProps.size = macResMan.getResForkDataSize();
+ return true;
+ }
+
+ if (!allFiles.contains(fname))
+ return false;
+
+ Common::File testFile;
+
+ if (!testFile.open(allFiles[fname]))
+ return false;
+
+ fileProps.size = (int32)testFile.size();
+ fileProps.md5 = Common::computeStreamMD5AsString(testFile, _md5Bytes);
+ return true;
+}
+
ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
- SizeMD5Map filesSizeMD5;
+ ADFilePropertiesMap filesProps;
const ADGameFileDescription *fileDesc;
const ADGameDescription *g;
@@ -391,39 +411,14 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
Common::String fname = fileDesc->fileName;
- SizeMD5 tmp;
+ ADFileProperties tmp;
- if (filesSizeMD5.contains(fname))
+ if (filesProps.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;
-
- if (macResMan.open(parent, fname)) {
- tmp.md5 = macResMan.computeResForkMD5AsString(_md5Bytes);
- tmp.size = macResMan.getResForkDataSize();
- debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str());
- filesSizeMD5[fname] = tmp;
- }
- } else {
- if (allFiles.contains(fname)) {
- debug(3, "+ %s", fname.c_str());
-
- Common::File testFile;
-
- if (testFile.open(allFiles[fname])) {
- tmp.size = (int32)testFile.size();
- tmp.md5 = Common::computeStreamMD5AsString(testFile, _md5Bytes);
- } else {
- tmp.size = -1;
- }
-
- debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str());
- filesSizeMD5[fname] = tmp;
- }
+ if (getFileProperties(parent, allFiles, *g, fname, tmp)) {
+ debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str());
+ filesProps[fname] = tmp;
}
}
}
@@ -456,19 +451,19 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
Common::String tstr = fileDesc->fileName;
- if (!filesSizeMD5.contains(tstr)) {
+ if (!filesProps.contains(tstr)) {
fileMissing = true;
allFilesPresent = false;
break;
}
- if (fileDesc->md5 != NULL && fileDesc->md5 != filesSizeMD5[tstr].md5) {
- debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesSizeMD5[tstr].md5.c_str());
+ if (fileDesc->md5 != NULL && fileDesc->md5 != filesProps[tstr].md5) {
+ debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesProps[tstr].md5.c_str());
fileMissing = true;
break;
}
- if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesSizeMD5[tstr].size) {
+ if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesProps[tstr].size) {
debug(3, "Size Mismatch. Skipping");
fileMissing = true;
break;
@@ -514,8 +509,8 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
// We didn't find a match
if (matched.empty()) {
- if (!filesSizeMD5.empty() && gotAnyMatchesWithAllFiles) {
- reportUnknown(parent, filesSizeMD5);
+ if (!filesProps.empty() && gotAnyMatchesWithAllFiles) {
+ reportUnknown(parent, filesProps);
}
// Filename based fallback
@@ -524,7 +519,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
return matched;
}
-const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const {
+const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback, ADFilePropertiesMap *filesProps) const {
const ADFileBasedFallback *ptr;
const char* const* filenames;
@@ -554,6 +549,16 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &
maxNumMatchedFiles = numMatchedFiles;
debug(4, "and overridden");
+
+ if (filesProps) {
+ for (filenames = ptr->filenames; *filenames; ++filenames) {
+ ADFileProperties tmp;
+
+ if (getFileProperties(fslist.begin()->getParent(), allFiles, *agdesc, *filenames, tmp))
+ (*filesProps)[*filenames] = tmp;
+ }
+ }
+
}
}
}
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h
index 45a9f183e8..8c19d03691 100644
--- a/engines/advancedDetector.h
+++ b/engines/advancedDetector.h
@@ -26,6 +26,8 @@
#include "engines/metaengine.h"
#include "engines/engine.h"
+#include "common/hash-str.h"
+
#include "common/gui_options.h" // FIXME: Temporary hack?
namespace Common {
@@ -46,6 +48,20 @@ struct ADGameFileDescription {
};
/**
+ * A record describing the properties of a file. Used on the existing
+ * files while detecting a game.
+ */
+struct ADFileProperties {
+ int32 size;
+ Common::String md5;
+};
+
+/**
+ * A map of all relevant existing files in a game directory while detecting.
+ */
+typedef Common::HashMap<Common::String, ADFileProperties, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ADFilePropertiesMap;
+
+/**
* A shortcut to produce an empty ADGameFileDescription record. Used to mark
* the end of a list of these.
*/
@@ -286,9 +302,17 @@ protected:
* In case of a tie, the entry coming first in the list is chosen.
*
* @param allFiles a map describing all present files
+ * @param fslist a list of nodes for all present files
* @param fileBasedFallback a list of ADFileBasedFallback records, zero-terminated
+ * @param filesProps if not 0, return a map of properties for all detected files here
+ */
+ const ADGameDescription *detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback, ADFilePropertiesMap *filesProps = 0) const;
+
+ /**
+ * Log and print a report that we found an unknown game variant, together with the file
+ * names, sizes and MD5 sums.
*/
- const ADGameDescription *detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const;
+ void reportUnknown(const Common::FSNode &path, const ADFilePropertiesMap &filesProps) const;
// TODO
void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const;
@@ -298,6 +322,9 @@ protected:
* Includes nifty stuff like removing trailing dots and ignoring case.
*/
void composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth) const;
+
+ /** Get the properties (size and MD5) of this file. */
+ bool getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const;
};
#endif
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 805fe7d366..5f7780bfe3 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -20,9 +20,6 @@
*
*/
-// FIXME: Avoid using printf
-#define FORBIDDEN_SYMBOL_EXCEPTION_printf
-
#include "base/plugins.h"
#include "engines/advancedDetector.h"
@@ -491,10 +488,14 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
g_fallbackDesc.desc.gameid = _gameid.c_str();
g_fallbackDesc.desc.extra = _extra.c_str();
- printf("Your game version has been detected using fallback matching as a\n");
- printf("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra);
- printf("If this is an original and unmodified version or new made Fanmade game,\n");
- printf("please report any, information previously printed by ScummVM to the team.\n");
+ Common::String fallbackWarning;
+
+ fallbackWarning = "Your game version has been detected using fallback matching as a\n";
+ fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra);
+ fallbackWarning += "If this is an original and unmodified version or new made Fanmade game,\n";
+ fallbackWarning += "please report any, information previously printed by ScummVM to the team.\n";
+
+ g_system->logMessage(LogMessageType::kWarning, fallbackWarning.c_str());
return (const ADGameDescription *)&g_fallbackDesc;
}
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index 10c01741ae..9176412e0e 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -260,9 +260,6 @@ bool MoviePlayerDXA::load() {
debug(0, "Playing video %s", videoName.c_str());
CursorMan.showMouse(false);
-
- _firstFrameOffset = _fileStream->pos();
-
return true;
}
@@ -271,6 +268,10 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
uint w = getWidth();
const Graphics::Surface *surface = decodeNextFrame();
+
+ if (!surface)
+ return;
+
byte *src = (byte *)surface->pixels;
dst += y * pitch + x;
@@ -281,7 +282,7 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
} while (--h);
if (hasDirtyPalette())
- setSystemPalette();
+ g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
}
void MoviePlayerDXA::playVideo() {
@@ -302,34 +303,7 @@ void MoviePlayerDXA::stopVideo() {
}
void MoviePlayerDXA::startSound() {
- uint32 offset, size;
-
- if (getSoundTag() == MKTAG('W','A','V','E')) {
- size = _fileStream->readUint32BE();
-
- if (_sequenceNum) {
- Common::File in;
-
- _fileStream->seek(size, SEEK_CUR);
-
- in.open("audio.wav");
- if (!in.isOpen()) {
- error("Can't read offset file 'audio.wav'");
- }
-
- in.seek(_sequenceNum * 8, SEEK_SET);
- offset = in.readUint32LE();
- size = in.readUint32LE();
-
- in.seek(offset, SEEK_SET);
- _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES);
- in.close();
- } else {
- _bgSoundStream = Audio::makeWAVStream(_fileStream->readStream(size), DisposeAfterUse::YES);
- }
- } else {
- _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName);
- }
+ start();
if (_bgSoundStream != NULL) {
_vm->_mixer->stopHandle(_bgSound);
@@ -344,8 +318,7 @@ void MoviePlayerDXA::nextFrame() {
}
if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) {
- _fileStream->seek(_firstFrameOffset);
- _curFrame = -1;
+ rewind();
startSound();
}
@@ -374,13 +347,15 @@ bool MoviePlayerDXA::processFrame() {
copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch);
_vm->_system->unlockScreen();
- Common::Rational soundTime(_mixer->getSoundElapsedTime(_bgSound), 1000);
- if ((_bgSoundStream == NULL) || ((soundTime * getFrameRate()).toInt() / 1000 < getCurFrame() + 1)) {
+ uint32 soundTime = _mixer->getSoundElapsedTime(_bgSound);
+ uint32 nextFrameStartTime = ((Video::VideoDecoder::VideoTrack *)getTrack(0))->getNextFrameStartTime();
+
+ if ((_bgSoundStream == NULL) || soundTime < nextFrameStartTime) {
if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) {
- while (_mixer->isSoundHandleActive(_bgSound) && (soundTime * getFrameRate()).toInt() < getCurFrame()) {
+ while (_mixer->isSoundHandleActive(_bgSound) && soundTime < nextFrameStartTime) {
_vm->_system->delayMillis(10);
- soundTime = Common::Rational(_mixer->getSoundElapsedTime(_bgSound), 1000);
+ soundTime = _mixer->getSoundElapsedTime(_bgSound);
}
// In case the background sound ends prematurely, update
// _ticks so that we can still fall back on the no-sound
@@ -399,14 +374,35 @@ bool MoviePlayerDXA::processFrame() {
return false;
}
-void MoviePlayerDXA::updateVolume() {
- if (g_system->getMixer()->isSoundHandleActive(_bgSound))
- g_system->getMixer()->setChannelVolume(_bgSound, getVolume());
-}
+void MoviePlayerDXA::readSoundData(Common::SeekableReadStream *stream) {
+ uint32 tag = stream->readUint32BE();
+
+ if (tag == MKTAG('W','A','V','E')) {
+ uint32 size = stream->readUint32BE();
+
+ if (_sequenceNum) {
+ Common::File in;
+
+ stream->skip(size);
+
+ in.open("audio.wav");
+ if (!in.isOpen()) {
+ error("Can't read offset file 'audio.wav'");
+ }
+
+ in.seek(_sequenceNum * 8, SEEK_SET);
+ uint32 offset = in.readUint32LE();
+ size = in.readUint32LE();
-void MoviePlayerDXA::updateBalance() {
- if (g_system->getMixer()->isSoundHandleActive(_bgSound))
- g_system->getMixer()->setChannelBalance(_bgSound, getBalance());
+ in.seek(offset, SEEK_SET);
+ _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES);
+ in.close();
+ } else {
+ _bgSoundStream = Audio::makeWAVStream(stream->readStream(size), DisposeAfterUse::YES);
+ }
+ } else {
+ _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName);
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -415,7 +411,7 @@ void MoviePlayerDXA::updateBalance() {
MoviePlayerSMK::MoviePlayerSMK(AGOSEngine_Feeble *vm, const char *name)
- : MoviePlayer(vm), SmackerDecoder(vm->_mixer) {
+ : MoviePlayer(vm), SmackerDecoder() {
debug(0, "Creating SMK cutscene player");
memset(baseName, 0, sizeof(baseName));
@@ -435,8 +431,6 @@ bool MoviePlayerSMK::load() {
CursorMan.showMouse(false);
- _firstFrameOffset = _fileStream->pos();
-
return true;
}
@@ -445,6 +439,10 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
uint w = getWidth();
const Graphics::Surface *surface = decodeNextFrame();
+
+ if (!surface)
+ return;
+
byte *src = (byte *)surface->pixels;
dst += y * pitch + x;
@@ -455,7 +453,7 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
} while (--h);
if (hasDirtyPalette())
- setSystemPalette();
+ g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
}
void MoviePlayerSMK::playVideo() {
@@ -468,6 +466,7 @@ void MoviePlayerSMK::stopVideo() {
}
void MoviePlayerSMK::startSound() {
+ start();
}
void MoviePlayerSMK::handleNextFrame() {
@@ -477,10 +476,8 @@ void MoviePlayerSMK::handleNextFrame() {
}
void MoviePlayerSMK::nextFrame() {
- if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) {
- _fileStream->seek(_firstFrameOffset);
- _curFrame = -1;
- }
+ if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo())
+ rewind();
if (!endOfVideo()) {
decodeNextFrame();
@@ -503,7 +500,7 @@ bool MoviePlayerSMK::processFrame() {
uint32 waitTime = getTimeToNextFrame();
- if (!waitTime) {
+ if (!waitTime && !endOfVideoTracks()) {
warning("dropped frame %i", getCurFrame());
return false;
}
diff --git a/engines/agos/animation.h b/engines/agos/animation.h
index d1ff074b03..9e31fced6d 100644
--- a/engines/agos/animation.h
+++ b/engines/agos/animation.h
@@ -67,9 +67,6 @@ protected:
virtual void handleNextFrame();
virtual bool processFrame() = 0;
virtual void startSound() {}
-
-protected:
- uint32 _firstFrameOffset;
};
class MoviePlayerDXA : public MoviePlayer, Video::DXADecoder {
@@ -84,9 +81,7 @@ public:
virtual void stopVideo();
protected:
- // VideoDecoder API
- void updateVolume();
- void updateBalance();
+ void readSoundData(Common::SeekableReadStream *stream);
private:
void handleNextFrame();
diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp
index ed26b96381..cc1c40c207 100644
--- a/engines/agos/event.cpp
+++ b/engines/agos/event.cpp
@@ -467,11 +467,7 @@ void AGOSEngine::delay(uint amount) {
memset(_saveLoadName, 0, sizeof(_saveLoadName));
sprintf(_saveLoadName, "Quick %d", _saveLoadSlot);
_saveLoadType = (event.kbd.hasFlags(Common::KBD_ALT)) ? 1 : 2;
-
- // We should only allow a load or save when it was possible in original
- // This stops load/save during copy protection, conversations and cut scenes
- if (!_mouseHideCount && !_showPreposition)
- quickLoadOrSave();
+ quickLoadOrSave();
} else if (event.kbd.hasFlags(Common::KBD_CTRL)) {
if (event.kbd.keycode == Common::KEYCODE_a) {
GUI::Dialog *_aboutDialog;
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp
index b3ec916b47..c6bca1a6e6 100644
--- a/engines/agos/saveload.cpp
+++ b/engines/agos/saveload.cpp
@@ -142,23 +142,41 @@ void AGOSEngine_Feeble::quickLoadOrSave() {
}
#endif
+// The function uses segments of code from the original game scripts
+// to allow quick loading and saving, but isn't perfect.
+//
+// Unfortuntely this allows loading and saving in locations,
+// which aren't supported, and will not restore correctly:
+// Various locations in Elvira 1/2 and Waxworks where saving
+// was disabled
void AGOSEngine::quickLoadOrSave() {
- // The function uses segments of code from the original game scripts
- // to allow quick loading and saving, but isn't perfect.
- //
- // Unfortuntely this allows loading and saving in locations,
- // which aren't supported, and will not restore correctly:
- // Any overhead maps in Simon the Sorcerer 2
- // Various locations in Elvira 1/2 and Waxworks where saving
- // was disabled
-
- // The floppy disk demo of Simon the Sorcerer 1 doesn't work.
- if (getFeatures() & GF_DEMO)
- return;
-
bool success;
Common::String buf;
+ // Disable loading and saving when it was not possible in the original:
+ // In overhead maps areas in Simon the Sorcerer 2
+ // In the floppy disk demo of Simon the Sorcerer 1
+ // In copy protection, conversations and cut scenes
+ if ((getGameType() == GType_SIMON2 && _boxStarHeight == 200) ||
+ (getGameType() == GType_SIMON1 && (getFeatures() & GF_DEMO)) ||
+ _mouseHideCount || _showPreposition) {
+ buf = Common::String::format("Quick load or save game isn't supported in this location");
+ GUI::MessageDialog dialog(buf, "OK");
+ dialog.runModal();
+ return;
+ }
+
+ // Check if Simon is walking, and stop when required
+ if (getGameType() == GType_SIMON1 && getBitFlag(11)) {
+ vcStopAnimation(11, 1122);
+ animate(4, 11, 1122, 0, 0, 2);
+ waitForSync(1122);
+ } else if (getGameType() == GType_SIMON2 && getBitFlag(11)) {
+ vcStopAnimation(11, 232);
+ animate(4, 11, 232, 0, 0, 2);
+ waitForSync(1122);
+ }
+
char *filename = genSaveName(_saveLoadSlot);
if (_saveLoadType == 2) {
Subroutine *sub;
diff --git a/engines/cge/bitmap.cpp b/engines/cge/bitmap.cpp
index 309b89bdda..4f85957b3d 100644
--- a/engines/cge/bitmap.cpp
+++ b/engines/cge/bitmap.cpp
@@ -123,12 +123,15 @@ Bitmap::~Bitmap() {
Bitmap &Bitmap::operator=(const Bitmap &bmp) {
debugC(1, kCGEDebugBitmap, "&Bitmap::operator =");
+ if (this == &bmp)
+ return *this;
uint8 *v0 = bmp._v;
_w = bmp._w;
_h = bmp._h;
_m = NULL;
_map = 0;
+ _vm = bmp._vm;
delete[] _v;
if (v0 == NULL) {
diff --git a/engines/cge/cge.cpp b/engines/cge/cge.cpp
index 875ac34cd0..6cc0c45963 100644
--- a/engines/cge/cge.cpp
+++ b/engines/cge/cge.cpp
@@ -30,6 +30,8 @@
#include "common/fs.h"
#include "engines/advancedDetector.h"
#include "engines/util.h"
+#include "gui/message.h"
+
#include "cge/cge.h"
#include "cge/vga13h.h"
#include "cge/cge_main.h"
@@ -50,7 +52,6 @@ CGEEngine::CGEEngine(OSystem *syst, const ADGameDescription *gameDescription)
DebugMan.addDebugChannel(kCGEDebugEngine, "engine", "CGE Engine debug channel");
_startupMode = 1;
- _demoText = kDemo;
_oldLev = 0;
_pocPtr = 0;
_bitmapPalette = NULL;
@@ -122,7 +123,7 @@ void CGEEngine::init() {
_maxScene = 0;
_dark = false;
_game = false;
- _finis = false;
+ _endGame = false;
_now = 1;
_lev = -1;
_recentStep = -2;
@@ -134,7 +135,6 @@ void CGEEngine::init() {
_soundOk = 1;
_sprTv = NULL;
_gameCase2Cpt = 0;
- _offUseCount = 0;
_startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
}
@@ -196,6 +196,16 @@ Common::Error CGEEngine::run() {
// Run the game
cge_main();
+ // If game is finished, display ending message
+ if (_flag[3]) {
+ Common::String msg = Common::String(_text->getText(kSayTheEnd));
+ if (msg.size() != 0) {
+ g_system->delayMillis(10);
+ GUI::MessageDialog dialog(msg, "OK");
+ dialog.runModal();
+ }
+ }
+
// Remove game objects
deinit();
diff --git a/engines/cge/cge.h b/engines/cge/cge.h
index 4ebc836ee0..0e8c5a05bb 100644
--- a/engines/cge/cge.h
+++ b/engines/cge/cge.h
@@ -78,6 +78,8 @@ class Talk;
#define kMapZCnt 20
#define kMapTop 80
+#define kSayTheEnd 41
+
// our engine debug channels
enum {
kCGEDebugBitmap = 1 << 0,
@@ -147,7 +149,6 @@ public:
const ADGameDescription *_gameDescription;
int _startupMode;
- int _demoText;
int _oldLev;
int _pocPtr;
bool _music;
@@ -157,7 +158,7 @@ public:
bool _flag[4];
bool _dark;
bool _game;
- bool _finis;
+ bool _endGame;
int _now;
int _lev;
int _mode;
diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp
index 2620147c4d..3ba5f7fed9 100644
--- a/engines/cge/cge_main.cpp
+++ b/engines/cge/cge_main.cpp
@@ -150,11 +150,11 @@ void CGEEngine::sndSetVolume() {
void CGEEngine::syncHeader(Common::Serializer &s) {
debugC(1, kCGEDebugEngine, "CGEEngine::syncHeader(s)");
- int i;
+ int i = kDemo;
s.syncAsUint16LE(_now);
s.syncAsUint16LE(_oldLev);
- s.syncAsUint16LE(_demoText);
+ s.syncAsUint16LE(i); // unused Demo string id
for (i = 0; i < 5; i++)
s.syncAsUint16LE(_game);
s.syncAsSint16LE(i); // unused VGA::Mono variable
@@ -305,12 +305,21 @@ Common::Error CGEEngine::saveGameState(int slot, const Common::String &desc) {
_hero->park();
_oldLev = _lev;
+ int x = _hero->_x;
+ int y = _hero->_y;
+ int z = _hero->_z;
+
// Write out the user's progress
saveGame(slot, desc);
+ _commandHandler->addCommand(kCmdLevel, -1, _oldLev, &_sceneLight);
// Reload the scene
sceneUp();
+ _hero->_x = x;
+ _hero->_y = y;
+ _hero->_z = z;
+
return Common::kNoError;
}
@@ -518,8 +527,8 @@ Square::Square(CGEEngine *vm) : Sprite(vm, NULL), _vm(vm) {
setShapeList(MB);
}
-void Square::touch(uint16 mask, int x, int y) {
- Sprite::touch(mask, x, y);
+void Square::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) {
+ Sprite::touch(mask, x, y, keyCode);
if (mask & kMouseLeftUp) {
_vm->XZ(_x + x, _y + y).cell() = 0;
_vm->_commandHandlerTurbo->addCommand(kCmdKill, -1, 0, this);
@@ -706,7 +715,7 @@ void CGEEngine::qGame() {
saveGame(0, Common::String("Automatic Savegame"));
_vga->sunset();
- _finis = true;
+ _endGame = true;
}
void CGEEngine::switchScene(int newScene) {
@@ -758,11 +767,11 @@ void System::funTouch() {
_funDel = n;
}
-void System::touch(uint16 mask, int x, int y) {
+void System::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) {
funTouch();
if (mask & kEventKeyb) {
- if (x == Common::KEYCODE_ESCAPE) {
+ if (keyCode == Common::KEYCODE_ESCAPE) {
// The original was calling keyClick()
// The sound is uselessly annoying and noisy, so it has been removed
_vm->killText();
@@ -926,7 +935,7 @@ void CGEEngine::optionTouch(int opt, uint16 mask) {
}
#pragma argsused
-void Sprite::touch(uint16 mask, int x, int y) {
+void Sprite::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) {
_vm->_sys->funTouch();
if ((mask & kEventAttn) != 0)
@@ -1312,7 +1321,7 @@ void CGEEngine::runGame() {
_sceneLight->_flags._tran = true;
_vga->_showQ->append(_sceneLight);
- _sceneLight->_flags._hide = true;
+ _sceneLight->_flags._hide = false;
const Seq pocSeq[] = {
{ 0, 0, 0, 0, 20 },
@@ -1403,14 +1412,14 @@ void CGEEngine::runGame() {
_keyboard->setClient(_sys);
// main loop
- while (!_finis && !_quitFlag) {
- if (_flag[3])
+ while (!_endGame && !_quitFlag) {
+ if (_flag[3]) // Flag FINIS
_commandHandler->addCallback(kCmdExec, -1, 0, kQGame);
mainLoop();
}
// If finishing game due to closing ScummVM window, explicitly save the game
- if (!_finis && canSaveGameStateCurrently())
+ if (!_endGame && canSaveGameStateCurrently())
qGame();
_keyboard->setClient(NULL);
diff --git a/engines/cge/cge_main.h b/engines/cge/cge_main.h
index 87199ee524..bde8306f36 100644
--- a/engines/cge/cge_main.h
+++ b/engines/cge/cge_main.h
@@ -78,7 +78,7 @@ namespace CGE {
#define kScrHeight 200
#define kWorldHeight (kScrHeight - kPanHeight)
#define kStackSize 2048
-#define kSavegameCheckSum (1956 + _now + _oldLev + _game + _music + _demoText)
+#define kSavegameCheckSum (1956 + _now + _oldLev + _game + _music + kDemo)
#define kSavegame0Name ("{{INIT}}" kSvgExt)
#define kSavegameStrSize 11
#define kGameFrameDelay (1000 / 50)
@@ -92,7 +92,7 @@ public:
void setPal();
void funTouch();
- virtual void touch(uint16 mask, int x, int y);
+ virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode);
void tick();
private:
CGEEngine *_vm;
@@ -101,7 +101,7 @@ private:
class Square : public Sprite {
public:
Square(CGEEngine *vm);
- virtual void touch(uint16 mask, int x, int y);
+ virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode);
private:
CGEEngine *_vm;
};
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index f723ec8fbd..2e04b82026 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -108,7 +108,7 @@ public:
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- return detectGameFilebased(allFiles, CGE::fileBasedFallback);
+ return detectGameFilebased(allFiles, fslist, CGE::fileBasedFallback);
}
virtual const char *getName() const {
@@ -217,8 +217,6 @@ SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int sl
} else {
// Create the return descriptor
SaveStateDescriptor desc(slot, header.saveName);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
desc.setThumbnail(header.thumbnail);
desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
desc.setSaveTime(header.saveHour, header.saveMinutes);
diff --git a/engines/cge/events.cpp b/engines/cge/events.cpp
index 095aac2412..1530c870ef 100644
--- a/engines/cge/events.cpp
+++ b/engines/cge/events.cpp
@@ -55,7 +55,7 @@ Sprite *Keyboard::setClient(Sprite *spr) {
bool Keyboard::getKey(Common::Event &event) {
Common::KeyCode keycode = event.kbd.keycode;
- if ((keycode == Common::KEYCODE_LALT) || (keycode == Common::KEYCODE_RALT))
+ if (((keycode == Common::KEYCODE_LALT) || (keycode == Common::KEYCODE_RALT)) && event.type == Common::EVENT_KEYDOWN)
_keyAlt = true;
else
_keyAlt = false;
@@ -109,9 +109,19 @@ bool Keyboard::getKey(Common::Event &event) {
case Common::KEYCODE_3:
case Common::KEYCODE_4:
if (event.kbd.flags & Common::KBD_ALT) {
- _vm->_commandHandler->addCommand(kCmdLevel, -1, keycode - '0', NULL);
+ _vm->_commandHandler->addCommand(kCmdLevel, -1, keycode - Common::KEYCODE_0, NULL);
return false;
}
+ // Fallthrough intended
+ case Common::KEYCODE_5:
+ case Common::KEYCODE_6:
+ case Common::KEYCODE_7:
+ case Common::KEYCODE_8:
+ if (event.type == Common::EVENT_KEYDOWN && !(event.kbd.flags & Common::KBD_ALT) && keycode != Common::KEYCODE_0) {
+ _vm->selectPocket(keycode - Common::KEYCODE_1);
+ return false;
+ }
+ break;
default:
break;
}
@@ -125,9 +135,11 @@ void Keyboard::newKeyboard(Common::Event &event) {
if ((event.type == Common::EVENT_KEYDOWN) && (_client)) {
CGEEvent &evt = _vm->_eventManager->getNextEvent();
- evt._x = event.kbd.keycode; // Keycode
- evt._mask = kEventKeyb; // Event mask
- evt._spritePtr = _client; // Sprite pointer
+ evt._x = 0;
+ evt._y = 0;
+ evt._keyCode = event.kbd.keycode; // Keycode
+ evt._mask = kEventKeyb; // Event mask
+ evt._spritePtr = _client; // Sprite pointer
}
}
@@ -194,6 +206,7 @@ void Mouse::newMouse(Common::Event &event) {
CGEEvent &evt = _vm->_eventManager->getNextEvent();
evt._x = event.mouse.x;
evt._y = event.mouse.y;
+ evt._keyCode = Common::KEYCODE_INVALID;
evt._spritePtr = _vm->spriteAt(evt._x, evt._y);
switch (event.type) {
@@ -259,7 +272,7 @@ void EventManager::handleEvents() {
CGEEvent e = _eventQueue[_eventQueueTail];
if (e._mask) {
if (_vm->_mouse->_hold && e._spritePtr != _vm->_mouse->_hold)
- _vm->_mouse->_hold->touch(e._mask | kEventAttn, e._x - _vm->_mouse->_hold->_x, e._y - _vm->_mouse->_hold->_y);
+ _vm->_mouse->_hold->touch(e._mask | kEventAttn, e._x - _vm->_mouse->_hold->_x, e._y - _vm->_mouse->_hold->_y, e._keyCode);
// update mouse cursor position
if (e._mask & kMouseRoll)
@@ -268,11 +281,11 @@ void EventManager::handleEvents() {
// activate current touched SPRITE
if (e._spritePtr) {
if (e._mask & kEventKeyb)
- e._spritePtr->touch(e._mask, e._x, e._y);
+ e._spritePtr->touch(e._mask, e._x, e._y, e._keyCode);
else
- e._spritePtr->touch(e._mask, e._x - e._spritePtr->_x, e._y - e._spritePtr->_y);
+ e._spritePtr->touch(e._mask, e._x - e._spritePtr->_x, e._y - e._spritePtr->_y, e._keyCode);
} else if (_vm->_sys)
- _vm->_sys->touch(e._mask, e._x, e._y);
+ _vm->_sys->touch(e._mask, e._x, e._y, e._keyCode);
if (e._mask & kMouseLeftDown) {
_vm->_mouse->_hold = e._spritePtr;
diff --git a/engines/cge/events.h b/engines/cge/events.h
index 6bbd52e4a5..522aa67905 100644
--- a/engines/cge/events.h
+++ b/engines/cge/events.h
@@ -70,6 +70,7 @@ struct CGEEvent {
uint16 _mask;
uint16 _x;
uint16 _y;
+ Common::KeyCode _keyCode;
Sprite *_spritePtr;
};
diff --git a/engines/cge/fileio.cpp b/engines/cge/fileio.cpp
index c50db4e929..f23105d823 100644
--- a/engines/cge/fileio.cpp
+++ b/engines/cge/fileio.cpp
@@ -201,9 +201,28 @@ EncryptedStream::EncryptedStream(CGEEngine *vm, const char *name) : _vm(vm) {
_error = true;
_vm->_resman->seek(kp->_pos);
- byte *dataBuffer = (byte *)malloc(kp->_size);
- _vm->_resman->read(dataBuffer, kp->_size);
- _readStream = new Common::MemoryReadStream(dataBuffer, kp->_size, DisposeAfterUse::YES);
+ byte *dataBuffer;
+ int bufSize;
+
+ if ((strlen(name) > 4) && (scumm_stricmp(name + strlen(name) - 4, ".SPR") == 0)) {
+ // SPR files have some inconsistencies. Some have extra 0x1A at the end, some others
+ // do not have a carriage return at the end of the last line
+ // Therefore, we remove this ending 0x1A and add extra new lines.
+ // This fixes bug #3537527
+ dataBuffer = (byte *)malloc(kp->_size + 2);
+ _vm->_resman->read(dataBuffer, kp->_size);
+ if (dataBuffer[kp->_size - 1] == 0x1A)
+ dataBuffer[kp->_size - 1] = '\n';
+ dataBuffer[kp->_size] = '\n';
+ dataBuffer[kp->_size + 1] = '\n';
+ bufSize = kp->_size + 2;
+ } else {
+ dataBuffer = (byte *)malloc(kp->_size);
+ _vm->_resman->read(dataBuffer, kp->_size);
+ bufSize = kp->_size;
+ }
+
+ _readStream = new Common::MemoryReadStream(dataBuffer, bufSize, DisposeAfterUse::YES);
}
uint32 EncryptedStream::read(void *dataPtr, uint32 dataSize) {
diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp
index 7f74794474..b378898955 100644
--- a/engines/cge/sound.cpp
+++ b/engines/cge/sound.cpp
@@ -91,6 +91,12 @@ void Sound::sndDigiStart(SmpInfo *PSmpInfo) {
// Start the new sound
_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle,
Audio::makeLoopingAudioStream(_audioStream, (uint)PSmpInfo->_counter));
+
+ // CGE pan:
+ // 8 = Center
+ // Less = Left
+ // More = Right
+ _vm->_mixer->setChannelBalance(_soundHandle, (int8)CLIP(((PSmpInfo->_span - 8) * 16), -127, 127));
}
void Sound::stop() {
diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp
index 3800b6643a..e178795b7c 100644
--- a/engines/cge/vga13h.cpp
+++ b/engines/cge/vga13h.cpp
@@ -637,15 +637,6 @@ Vga::Vga(CGEEngine *vm) : _frmCnt(0), _msg(NULL), _name(NULL), _setPal(false), _
_page[idx]->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
}
-#if 0
- // This part was used to display credits at the beginning of the game
- for (int i = 10; i < 20; i++) {
- char *text = _text->getText(i);
- if (text) {
- debugN(1, "%s\n", text);
- }
- }
-#endif
_oldColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
_newColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
getColors(_oldColors);
diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h
index beca19f667..a816f7756f 100644
--- a/engines/cge/vga13h.h
+++ b/engines/cge/vga13h.h
@@ -29,6 +29,7 @@
#define CGE_VGA13H_H
#include "common/serializer.h"
+#include "common/events.h"
#include "graphics/surface.h"
#include "cge/general.h"
#include "cge/bitmap.h"
@@ -146,7 +147,7 @@ public:
void step(int nr = -1);
Seq *setSeq(Seq *seq);
CommandHandler::Command *snList(SnList type);
- virtual void touch(uint16 mask, int x, int y);
+ virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode);
virtual void tick();
void sync(Common::Serializer &s);
private:
diff --git a/engines/cge/vmenu.cpp b/engines/cge/vmenu.cpp
index a317a765d4..910e54d267 100644
--- a/engines/cge/vmenu.cpp
+++ b/engines/cge/vmenu.cpp
@@ -63,7 +63,7 @@ Vmenu *Vmenu::_addr = NULL;
int Vmenu::_recent = -1;
Vmenu::Vmenu(CGEEngine *vm, Choice *list, int x, int y)
- : Talk(vm, VMGather(list), kTBRect), _menu(list), _bar(NULL), _vm(vm) {
+ : Talk(vm, VMGather(list), kTBRect), _menu(list), _bar(NULL), _vmgt(NULL), _vm(vm) {
Choice *cp;
_addr = this;
@@ -89,11 +89,11 @@ Vmenu::~Vmenu() {
#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
-void Vmenu::touch(uint16 mask, int x, int y) {
+void Vmenu::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) {
if (!_items)
return;
- Sprite::touch(mask, x, y);
+ Sprite::touch(mask, x, y, keyCode);
y -= kTextVMargin - 1;
int n = 0;
diff --git a/engines/cge/vmenu.h b/engines/cge/vmenu.h
index 89ef7a9484..928b48f11c 100644
--- a/engines/cge/vmenu.h
+++ b/engines/cge/vmenu.h
@@ -58,7 +58,7 @@ public:
MenuBar *_bar;
Vmenu(CGEEngine *vm, Choice *list, int x, int y);
~Vmenu();
- virtual void touch(uint16 mask, int x, int y);
+ virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode);
private:
char *_vmgt;
CGEEngine *_vm;
diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp
index 410fcca1f3..60168831a1 100644
--- a/engines/cine/anim.cpp
+++ b/engines/cine/anim.cpp
@@ -682,9 +682,10 @@ void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) {
* Load image set
* @param resourceName Image set filename
* @param idx Target index in animDataTable (-1 if any empty space will do)
+ * @param frameIndex frame of animation to load (-1 for all frames)
* @return The number of the animDataTable entry after the loaded image set (-1 if error)
*/
-int loadSet(const char *resourceName, int16 idx) {
+int loadSet(const char *resourceName, int16 idx, int16 frameIndex =-1 ) {
AnimHeader2Struct header2;
uint16 numSpriteInAnim;
int16 foundFileIdx = findFileInBundle(resourceName);
@@ -708,7 +709,17 @@ int loadSet(const char *resourceName, int16 idx) {
entry = idx < 0 ? emptyAnimSpace() : idx;
assert(entry >= 0);
- for (int16 i = 0; i < numSpriteInAnim; i++, entry++) {
+ int16 startFrame = 0;
+ int16 endFrame = numSpriteInAnim;
+
+ if(frameIndex>=0)
+ {
+ startFrame = frameIndex;
+ endFrame = frameIndex+1;
+ ptr += 0x10 * frameIndex;
+ }
+
+ for (int16 i = startFrame; i < endFrame; i++, entry++) {
Common::MemoryReadStream readS(ptr, 0x10);
header2.field_0 = readS.readUint32BE();
@@ -767,7 +778,7 @@ int loadSeq(const char *resourceName, int16 idx) {
* @return The number of the animDataTable entry after the loaded resource (-1 if error)
* @todo Implement loading of all resource types
*/
-int loadResource(const char *resourceName, int16 idx) {
+int loadResource(const char *resourceName, int16 idx, int16 frameIndex) {
int result = -1; // Return an error by default
if (strstr(resourceName, ".SPL")) {
result = loadSpl(resourceName, idx);
@@ -778,7 +789,7 @@ int loadResource(const char *resourceName, int16 idx) {
} else if (strstr(resourceName, ".ANM")) {
result = loadAni(resourceName, idx);
} else if (strstr(resourceName, ".SET")) {
- result = loadSet(resourceName, idx);
+ result = loadSet(resourceName, idx, frameIndex);
} else if (strstr(resourceName, ".SEQ")) {
result = loadSeq(resourceName, idx);
} else if (strstr(resourceName, ".H32")) {
diff --git a/engines/cine/anim.h b/engines/cine/anim.h
index 9c06c260ce..c5130aab82 100644
--- a/engines/cine/anim.h
+++ b/engines/cine/anim.h
@@ -98,7 +98,7 @@ public:
void freeAnimDataTable();
void freeAnimDataRange(byte startIdx, byte numIdx);
-int loadResource(const char *resourceName, int16 idx = -1);
+int loadResource(const char *resourceName, int16 idx = -1, int16 frameIndex = -1);
void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat);
void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency);
diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp
index 693fea3294..36ecf53dea 100644
--- a/engines/cine/bg_list.cpp
+++ b/engines/cine/bg_list.cpp
@@ -39,9 +39,9 @@ uint32 var8;
* @param objIdx Sprite description
*/
void addToBGList(int16 objIdx) {
- renderer->incrustSprite(g_cine->_objectTable[objIdx]);
-
createBgIncrustListElement(objIdx, 0);
+
+ renderer->incrustSprite(g_cine->_bgIncrustList.back());
}
/**
@@ -49,9 +49,9 @@ void addToBGList(int16 objIdx) {
* @param objIdx Sprite description
*/
void addSpriteFilledToBGList(int16 objIdx) {
- renderer->incrustMask(g_cine->_objectTable[objIdx]);
-
createBgIncrustListElement(objIdx, 1);
+
+ renderer->incrustMask(g_cine->_bgIncrustList.back());
}
/**
@@ -103,9 +103,9 @@ void loadBgIncrustFromSave(Common::SeekableReadStream &fHandle) {
g_cine->_bgIncrustList.push_back(tmp);
if (tmp.param == 0) {
- renderer->incrustSprite(g_cine->_objectTable[tmp.objIdx]);
+ renderer->incrustSprite(tmp);
} else {
- renderer->incrustMask(g_cine->_objectTable[tmp.objIdx]);
+ renderer->incrustMask(tmp);
}
}
}
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp
index 6b94c33c31..bbe2cd4896 100644
--- a/engines/cine/cine.cpp
+++ b/engines/cine/cine.cpp
@@ -189,6 +189,8 @@ void CineEngine::initialize() {
g_cine->_messageTable.clear();
resetObjectTable();
+ disableSystemMenu = 1;
+
var8 = 0;
var2 = var3 = var4 = var5 = 0;
diff --git a/engines/cine/detection_tables.h b/engines/cine/detection_tables.h
index 0ec2768bae..bf02f0519c 100644
--- a/engines/cine/detection_tables.h
+++ b/engines/cine/detection_tables.h
@@ -251,7 +251,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs00", "d6752e7d25924cb866b61eb7cb0c8b56"),
Common::EN_GRB,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -267,7 +267,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs1", "9629129b86979fa592c1787385bf3695"),
Common::EN_GRB,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -281,7 +281,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs1", "d8c3a9d05a63e4cfa801826a7063a126"),
Common::EN_USA,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -295,7 +295,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs00", "862a75d76fb7fffec30e52be9ad1c474"),
Common::EN_USA,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -309,7 +309,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs1", "39b91ae35d1297ce0a76a1a803ca1593"),
Common::DE_DEU,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -323,7 +323,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs1", "74c2dabd9d212525fca8875a5f6d8994"),
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -341,7 +341,7 @@ static const CINEGameDescription gameDescriptions[] = {
},
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -355,7 +355,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs00", "f143567f08cfd1a9b1c9a41c89eadfef"),
Common::FR_FRA,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -369,7 +369,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs1", "da066e6b8dd93f2502c2a3755f08dc12"),
Common::IT_ITA,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO0()
},
GType_OS,
@@ -383,7 +383,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs0", "a9da5531ead0ebf9ad387fa588c0cbb0"),
Common::EN_GRB,
Common::kPlatformAmiga,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
@@ -397,7 +397,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs0", "8a429ced2f4acff8a15ae125174042e8"),
Common::EN_GRB,
Common::kPlatformAmiga,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
@@ -411,7 +411,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs0", "d5f27e33fc29c879f36f15b86ccfa58c"),
Common::EN_USA,
Common::kPlatformAmiga,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
@@ -425,7 +425,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs0", "8b7dce249821d3a62b314399c4334347"),
Common::DE_DEU,
Common::kPlatformAmiga,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
@@ -439,7 +439,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs0", "35fc295ddd0af9da932d256ba799a4b0"),
Common::ES_ESP,
Common::kPlatformAmiga,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
@@ -453,7 +453,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs0", "d4ea4a97e01fa67ea066f9e785050ed2"),
Common::FR_FRA,
Common::kPlatformAmiga,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
@@ -467,7 +467,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("demo", "8d3a750d1c840b1b1071e42f9e6f6aa2"),
Common::EN_GRB,
Common::kPlatformAmiga,
- ADGF_DEMO,
+ ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
@@ -481,7 +481,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs0", "1501d5ae364b2814a33ed19347c3fcae"),
Common::EN_GRB,
Common::kPlatformAtariST,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
@@ -495,7 +495,7 @@ static const CINEGameDescription gameDescriptions[] = {
AD_ENTRY1("procs0", "2148d25de3219dd4a36580ca735d0afa"),
Common::FR_FRA,
Common::kPlatformAtariST,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
},
GType_OS,
diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp
index 918d522606..7a988227f6 100644
--- a/engines/cine/gfx.cpp
+++ b/engines/cine/gfx.cpp
@@ -174,7 +174,8 @@ void FWRenderer::fillSprite(const ObjectStruct &obj, uint8 color) {
* @param obj Object info
* @param fillColor Sprite color
*/
-void FWRenderer::incrustMask(const ObjectStruct &obj, uint8 color) {
+void FWRenderer::incrustMask(const BGIncrust &incrust, uint8 color) {
+ const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx];
const byte *data = g_cine->_animDataTable[obj.frame].data();
int x, y, width, height;
@@ -218,7 +219,9 @@ void FWRenderer::drawSprite(const ObjectStruct &obj) {
* Draw color sprite on background
* @param obj Object info
*/
-void FWRenderer::incrustSprite(const ObjectStruct &obj) {
+void FWRenderer::incrustSprite(const BGIncrust &incrust) {
+ const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx];
+
const byte *data = g_cine->_animDataTable[obj.frame].data();
const byte *mask = g_cine->_animDataTable[obj.frame].mask();
int x, y, width, height;
@@ -246,14 +249,16 @@ void FWRenderer::drawCommand() {
unsigned int i;
int x = 10, y = _cmdY;
- drawPlainBox(x, y, 301, 11, 0);
- drawBorder(x - 1, y - 1, 302, 12, 2);
+ if(disableSystemMenu == 0) {
+ drawPlainBox(x, y, 301, 11, 0);
+ drawBorder(x - 1, y - 1, 302, 12, 2);
- x += 2;
- y += 2;
+ x += 2;
+ y += 2;
- for (i = 0; i < _cmd.size(); i++) {
- x = drawChar(_cmd[i], x, y);
+ for (i = 0; i < _cmd.size(); i++) {
+ x = drawChar(_cmd[i], x, y);
+ }
}
}
@@ -298,7 +303,8 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, int color
for (i = 0; str[i]; i++, line--) {
// Fit line of text into textbox
if (!line) {
- while (str[i] == ' ') i++;
+ while (str[i] == ' ')
+ i++;
line = fitLine(str + i, tw, words, cw);
if ( str[i + line] != '\0' && str[i + line] != 0x7C && words) {
@@ -839,7 +845,7 @@ void OSRenderer::restorePalette(Common::SeekableReadStream &fHandle, int version
fHandle.read(buf, kHighPalNumBytes);
- if (colorCount == kHighPalNumBytes) {
+ if (colorCount == kHighPalNumColors) {
// Load the active 256 color palette from file
_activePal.load(buf, sizeof(buf), kHighPalFormat, kHighPalNumColors, CINE_LITTLE_ENDIAN);
} else {
@@ -1119,7 +1125,8 @@ void OSRenderer::clear() {
* @param obj Object info
* @param fillColor Sprite color
*/
-void OSRenderer::incrustMask(const ObjectStruct &obj, uint8 color) {
+void OSRenderer::incrustMask(const BGIncrust &incrust, uint8 color) {
+ const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx];
const byte *data = g_cine->_animDataTable[obj.frame].data();
int x, y, width, height;
@@ -1154,15 +1161,16 @@ void OSRenderer::drawSprite(const ObjectStruct &obj) {
* Draw color sprite
* @param obj Object info
*/
-void OSRenderer::incrustSprite(const ObjectStruct &obj) {
- const byte *data = g_cine->_animDataTable[obj.frame].data();
+void OSRenderer::incrustSprite(const BGIncrust &incrust) {
+ const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx];
+ const byte *data = g_cine->_animDataTable[incrust.frame].data();
int x, y, width, height, transColor;
- x = obj.x;
- y = obj.y;
+ x = incrust.x;
+ y = incrust.y;
transColor = obj.part;
- width = g_cine->_animDataTable[obj.frame]._realWidth;
- height = g_cine->_animDataTable[obj.frame]._height;
+ width = g_cine->_animDataTable[incrust.frame]._realWidth;
+ height = g_cine->_animDataTable[incrust.frame]._height;
if (_bgTable[_currentBg].bg) {
drawSpriteRaw2(data, transColor, width, height, _bgTable[_currentBg].bg, x, y);
@@ -1225,7 +1233,6 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
int len, idx, width, height;
ObjectStruct *obj;
AnimData *sprite;
- byte *mask;
byte color;
switch (it->type) {
@@ -1235,14 +1242,8 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
break;
}
sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame];
- len = sprite->_realWidth * sprite->_height;
- mask = new byte[len];
- generateMask(sprite->data(), mask, len, g_cine->_objectTable[it->objIdx].part);
- remaskSprite(mask, it);
- drawMaskedSprite(g_cine->_objectTable[it->objIdx], mask);
- delete[] mask;
+ drawSprite(&(*it), sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, g_cine->_objectTable[it->objIdx].x, g_cine->_objectTable[it->objIdx].y, g_cine->_objectTable[it->objIdx].part, sprite->_bpp);
break;
-
// game message
case 2:
if (it->objIdx >= g_cine->_messageTable.size()) {
@@ -1290,14 +1291,6 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y);
break;
- // FIXME: Implement correct drawing of type 21 overlays.
- // Type 21 overlays aren't just filled rectangles, I found their drawing routine
- // from Operation Stealth's drawSprite routine. So they're likely some kind of sprites
- // and it's just a coincidence that the oxygen meter during the first arcade sequence
- // works even somehow currently. I tried the original under DOSBox and the oxygen gauge
- // is a long red bar that gets shorter as the air runs out.
- case 21:
- // A filled rectangle:
case 22:
// TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing).
assert(it->objIdx < NUM_MAX_OBJECT);
@@ -1752,6 +1745,82 @@ void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int1
}
}
+void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 width, int16 height, byte *page, int16 x, int16 y, byte transparentColor, byte bpp) {
+ byte *pMask = NULL;
+
+ // draw the mask based on next objects in the list
+ Common::List<overlay>::iterator it;
+ for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) {
+ if(&(*it) == overlayPtr) {
+ break;
+ }
+ }
+
+ while(it != g_cine->_overlayList.end()) {
+ overlay *pCurrentOverlay = &(*it);
+ if ((pCurrentOverlay->type == 5) || ((pCurrentOverlay->type == 21) && (pCurrentOverlay->x == overlayPtr->objIdx))) {
+ AnimData *sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame];
+
+ if (pMask == NULL) {
+ pMask = new byte[width*height];
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ byte spriteColor= spritePtr[width * i + j];
+ pMask[width * i + j] = spriteColor;
+ }
+ }
+ }
+
+ for (int i = 0; i < sprite->_realWidth; i++) {
+ for (int j = 0; j < sprite->_height; j++) {
+ int inMaskX = (g_cine->_objectTable[it->objIdx].x + i) - x;
+ int inMaskY = (g_cine->_objectTable[it->objIdx].y + j) - y;
+
+ if (inMaskX >=0 && inMaskX < width) {
+ if (inMaskY >= 0 && inMaskY < height) {
+ if (sprite->_bpp == 1) {
+ if (!sprite->getColor(i, j)) {
+ pMask[inMaskY * width + inMaskX] = page[x + y * 320 + inMaskX + inMaskY * 320];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ it++;
+ }
+
+ // now, draw with the mask we created
+ if(pMask) {
+ spritePtr = pMask;
+ }
+
+ // ignore transparent color in 1bpp
+ if (bpp == 1) {
+ transparentColor = 1;
+ }
+
+ {
+ for (int i = 0; i < height; i++) {
+ byte *destPtr = page + x + y * 320;
+ destPtr += i * 320;
+
+ for (int j = 0; j < width; j++) {
+ byte color= *(spritePtr++);
+ if ((transparentColor != color) && x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200) {
+ *(destPtr++) = color;
+ } else {
+ destPtr++;
+ }
+ }
+ }
+ }
+
+ delete[] pMask;
+}
+
void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 height, byte *page, int16 x, int16 y) {
int16 i, j;
diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h
index 737c49cc36..3434cf9fc2 100644
--- a/engines/cine/gfx.h
+++ b/engines/cine/gfx.h
@@ -27,6 +27,7 @@
#include "common/rect.h"
#include "common/stack.h"
#include "cine/object.h"
+#include "cine/bg_list.h"
namespace Cine {
@@ -177,8 +178,8 @@ public:
void drawFrame();
void setCommand(Common::String cmd);
- virtual void incrustMask(const ObjectStruct &obj, uint8 color = 0);
- virtual void incrustSprite(const ObjectStruct &obj);
+ virtual void incrustMask(const BGIncrust &incrust, uint8 color = 0);
+ virtual void incrustSprite(const BGIncrust &incrust);
virtual void loadBg16(const byte *bg, const char *name, unsigned int idx = 0);
virtual void loadCt16(const byte *ct, const char *name);
@@ -223,6 +224,7 @@ private:
protected:
void drawSprite(const ObjectStruct &obj);
+ void drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 width, int16 height, byte *page, int16 x, int16 y, byte transparentColor, byte bpp);
int drawChar(char character, int x, int y);
void drawBackground();
void renderOverlay(const Common::List<overlay>::iterator &it);
@@ -238,8 +240,8 @@ public:
void clear();
- void incrustMask(const ObjectStruct &obj, uint8 color = 0);
- void incrustSprite(const ObjectStruct &obj);
+ void incrustMask(const BGIncrust &incrust, uint8 color = 0);
+ void incrustSprite(const BGIncrust &incrust);
void loadBg16(const byte *bg, const char *name, unsigned int idx = 0);
void loadCt16(const byte *ct, const char *name);
diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp
index 971830ce8f..f13f38a45e 100644
--- a/engines/cine/main_loop.cpp
+++ b/engines/cine/main_loop.cpp
@@ -56,6 +56,12 @@ static void processEvent(Common::Event &event) {
case Common::EVENT_RBUTTONDOWN:
mouseRight = 1;
break;
+ case Common::EVENT_LBUTTONUP:
+ mouseLeft = 0;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ mouseRight = 0;
+ break;
case Common::EVENT_MOUSEMOVE:
break;
case Common::EVENT_KEYDOWN:
@@ -115,7 +121,7 @@ static void processEvent(Common::Event &event) {
}
break;
case Common::KEYCODE_F10:
- if (!disableSystemMenu && !inMenu) {
+ if (!inMenu) {
g_cine->makeSystemMenu();
}
break;
@@ -214,8 +220,6 @@ void manageEvents() {
g_sound->update();
mouseData.left = mouseLeft;
mouseData.right = mouseRight;
- mouseLeft = 0;
- mouseRight = 0;
}
void getMouseData(uint16 param, uint16 *pButton, uint16 *pX, uint16 *pY) {
@@ -311,6 +315,7 @@ void CineEngine::mainLoop(int bootScriptIdx) {
// HACK: Force amount of oxygen left to maximum during Operation Stealth's first arcade sequence.
// This makes it possible to pass the arcade sequence for now.
// FIXME: Remove the hack and make the first arcade sequence normally playable.
+ /*
if (g_cine->getGameType() == Cine::GType_OS) {
Common::String bgName(renderer->getBgName());
// Check if the background is one of the three backgrounds
@@ -320,7 +325,7 @@ void CineEngine::mainLoop(int bootScriptIdx) {
// Force the amount of oxygen left to the maximum.
g_cine->_objectTable[oxygenObjNum].x = maxOxygen;
}
- }
+ }*/
// HACK: In Operation Stealth after the first arcade sequence jump player's position to avoid getting stuck.
// After the first arcade sequence the player comes up stairs from
@@ -379,8 +384,8 @@ void CineEngine::mainLoop(int bootScriptIdx) {
playerAction = false;
_messageLen <<= 3;
- if (_messageLen < 0x800)
- _messageLen = 0x800;
+ if (_messageLen < 800)
+ _messageLen = 800;
do {
manageEvents();
diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp
index 223099a587..20952eea52 100644
--- a/engines/cine/saveload.cpp
+++ b/engines/cine/saveload.cpp
@@ -991,7 +991,7 @@ void CineEngine::makeSave(char *saveFileName) {
* at a time.
*/
void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) {
- int16 currentAnim, foundFileIdx;
+ int16 foundFileIdx;
char *animName, part[256], name[10];
strcpy(part, currentPartName);
@@ -1001,10 +1001,10 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam
const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30);
const int fileStartPos = fHandle.pos();
- currentAnim = 0;
- while (currentAnim < NUM_MAX_ANIMDATA) {
+
+ for(int resourceIndex=0; resourceIndex<NUM_MAX_ANIMDATA; resourceIndex++) {
// Seek to the start of the current animation's entry
- fHandle.seek(fileStartPos + currentAnim * entrySize);
+ fHandle.seek(fileStartPos + resourceIndex * entrySize);
// Read in the current animation entry
fHandle.readUint16BE(); // width
fHandle.readUint16BE();
@@ -1019,7 +1019,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam
}
foundFileIdx = fHandle.readSint16BE();
- fHandle.readSint16BE(); // frame
+ int16 frameIndex = fHandle.readSint16BE(); // frame
fHandle.read(name, 10);
// Handle variables only present in animation entries of size 23
@@ -1029,7 +1029,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam
// Don't try to load invalid entries.
if (foundFileIdx < 0 || !validPtr) {
- currentAnim++; // Jump over the invalid entry
+ //resourceIndex++; // Jump over the invalid entry
continue;
}
@@ -1041,9 +1041,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam
animName = g_cine->_partBuffer[foundFileIdx].partName;
loadRelatedPalette(animName); // Is this for Future Wars only?
- const int16 prevAnim = currentAnim;
- currentAnim = loadResource(animName, currentAnim);
- assert(currentAnim > prevAnim); // Make sure we advance forward
+ loadResource(animName, resourceIndex, frameIndex);
}
loadPart(part);
diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp
index 66150cc5b2..9cbe3c3fab 100644
--- a/engines/cine/script_fw.cpp
+++ b/engines/cine/script_fw.cpp
@@ -533,7 +533,6 @@ void RawScript::setData(const FWScriptInfo &info, const byte *data) {
* @return Precalculated script labels
*/
const ScriptVars &RawScript::labels() const {
- assert(_data);
return _labels;
}
@@ -687,7 +686,7 @@ const char *FWScript::getNextString() {
* @param pos Restored script position
*/
void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) {
- assert(pos < _script._size);
+ assert(pos <= _script._size);
_labels = labels;
_localVars = local;
_compare = compare;
@@ -705,13 +704,15 @@ void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 co
int FWScript::execute() {
int ret = 0;
- while (!ret) {
- _line = _pos;
- byte opcode = getNextByte();
- OpFunc handler = _info->opcodeHandler(opcode);
+ if(_script._size) {
+ while (!ret) {
+ _line = _pos;
+ byte opcode = getNextByte();
+ OpFunc handler = _info->opcodeHandler(opcode);
- if (handler) {
- ret = (this->*handler)();
+ if (handler) {
+ ret = (this->*handler)();
+ }
}
}
@@ -1861,7 +1862,7 @@ int FWScript::o1_disableSystemMenu() {
byte param = getNextByte();
debugC(5, kCineDebugScript, "Line: %d: disableSystemMenu(%d)", _line, param);
- disableSystemMenu = (param != 0);
+ disableSystemMenu = param;
return 0;
}
diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp
index b2e992e8f6..52e1cdac7e 100644
--- a/engines/cine/sound.cpp
+++ b/engines/cine/sound.cpp
@@ -785,7 +785,6 @@ PCSoundFxPlayer::~PCSoundFxPlayer() {
bool PCSoundFxPlayer::load(const char *song) {
debug(9, "PCSoundFxPlayer::load('%s')", song);
- Common::StackLock lock(_mutex);
/* stop (w/ fade out) the previous song */
while (_fadeOutCounter != 0 && _fadeOutCounter < 100) {
@@ -793,6 +792,8 @@ bool PCSoundFxPlayer::load(const char *song) {
}
_fadeOutCounter = 0;
+ Common::StackLock lock(_mutex);
+
stop();
_sfxData = readBundleSoundFile(song);
diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp
index 9b73ae1101..eccd71cf05 100644
--- a/engines/cine/various.cpp
+++ b/engines/cine/various.cpp
@@ -36,7 +36,7 @@
namespace Cine {
-bool disableSystemMenu = false;
+int16 disableSystemMenu = 0;
bool inMenu;
int16 commandVar3[4];
@@ -341,7 +341,7 @@ void CineEngine::makeSystemMenu() {
int16 mouseX, mouseY, mouseButton;
int16 selectedSave;
- if (!disableSystemMenu) {
+ if (disableSystemMenu != 1) {
inMenu = true;
do {
@@ -544,14 +544,16 @@ int16 buildObjectListCommand(int16 param) {
int16 selectSubObject(int16 x, int16 y, int16 param) {
int16 listSize = buildObjectListCommand(param);
- int16 selectedObject;
+ int16 selectedObject = -1;
bool osExtras = g_cine->getGameType() == Cine::GType_OS;
if (!listSize) {
return -2;
}
- selectedObject = makeMenuChoice(objectListCommand, listSize, x, y, 140, osExtras);
+ if (disableSystemMenu == 0) {
+ selectedObject = makeMenuChoice(objectListCommand, listSize, x, y, 140, osExtras);
+ }
if (selectedObject == -1)
return -1;
@@ -691,9 +693,6 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X,
int16 var_4;
SelectionMenu *menu;
- if (disableSystemMenu)
- return -1;
-
paramY = (height * 9) + 10;
if (X + width > 319) {
@@ -810,14 +809,18 @@ void makeActionMenu() {
getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY);
if (g_cine->getGameType() == Cine::GType_OS) {
- playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true);
+ if(disableSystemMenu == 0) {
+ playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true);
+ }
if (playerCommand >= 8000) {
playerCommand -= 8000;
canUseOnObject = canUseOnItemTable[playerCommand];
}
} else {
- playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70);
+ if(disableSystemMenu == 0) {
+ playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70);
+ }
}
inMenu = false;
diff --git a/engines/cine/various.h b/engines/cine/various.h
index 0c1883c323..813619816d 100644
--- a/engines/cine/various.h
+++ b/engines/cine/various.h
@@ -41,7 +41,7 @@ void makeActionMenu();
void waitPlayerInput();
void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4);
-extern bool disableSystemMenu;
+extern int16 disableSystemMenu;
extern bool inMenu;
extern CommandeType currentSaveName[10];
diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp
index 556dad7e94..23a9d2ff85 100644
--- a/engines/composer/composer.cpp
+++ b/engines/composer/composer.cpp
@@ -381,11 +381,17 @@ void ComposerEngine::loadLibrary(uint id) {
filename = getStringFromConfig(_bookGroup, Common::String::format("%d", id));
filename = mangleFilename(filename);
+ // bookGroup is the basename of the path.
+ // TODO: tidy this up.
_bookGroup.clear();
for (uint i = 0; i < filename.size(); i++) {
- if (filename[i] == '\\' || filename[i] == ':')
+ if (filename[i] == '~' || filename[i] == '/' || filename[i] == ':')
continue;
for (uint j = 0; j < filename.size(); j++) {
+ if (filename[j] == '/') {
+ _bookGroup.clear();
+ continue;
+ }
if (filename[j] == '.')
break;
_bookGroup += filename[j];
diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp
index b2e267ca49..cbe17ea4d3 100644
--- a/engines/cruise/detection.cpp
+++ b/engines/cruise/detection.cpp
@@ -303,8 +303,6 @@ SaveStateDescriptor CruiseMetaEngine::querySaveMetaInfos(const char *target, int
// Create the return descriptor
SaveStateDescriptor desc(slot, header.saveName);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
desc.setThumbnail(header.thumbnail);
return desc;
diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp
index de76eb83e0..61705a1e59 100644
--- a/engines/draci/detection.cpp
+++ b/engines/draci/detection.cpp
@@ -161,8 +161,6 @@ SaveStateDescriptor DraciMetaEngine::querySaveMetaInfos(const char *target, int
// Create the return descriptor
SaveStateDescriptor desc(slot, header.saveName);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
desc.setThumbnail(header.thumbnail);
int day = (header.date >> 24) & 0xFF;
diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp
index 6468281ac2..f2e2f42216 100644
--- a/engines/dreamweb/detection.cpp
+++ b/engines/dreamweb/detection.cpp
@@ -172,8 +172,6 @@ SaveStateDescriptor DreamWebMetaEngine::querySaveMetaInfos(const char *target, i
saveName += (char)in->readByte();
SaveStateDescriptor desc(slot, saveName);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
// Check if there is a ScummVM data block
if (header.len(6) == SCUMMVM_BLOCK_MAGIC_SIZE) {
diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h
index 063aabbd89..8a2f94f99b 100644
--- a/engines/dreamweb/detection_tables.h
+++ b/engines/dreamweb/detection_tables.h
@@ -46,7 +46,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_TESTING,
+ 0,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -63,7 +63,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -84,7 +84,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::EN_GRB,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -101,7 +101,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::EN_USA,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -118,7 +118,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::FR_FRA,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -136,7 +136,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::FR_FRA,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -153,7 +153,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::DE_DEU,
Common::kPlatformPC,
- ADGF_TESTING,
+ 0,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -170,7 +170,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::DE_DEU,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -187,7 +187,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_TESTING,
+ 0,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -204,7 +204,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -222,7 +222,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -239,7 +239,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::IT_ITA,
Common::kPlatformPC,
- ADGF_TESTING,
+ 0,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
diff --git a/engines/dreamweb/dreamweb.h b/engines/dreamweb/dreamweb.h
index 48d44c0380..1f6deb8566 100644
--- a/engines/dreamweb/dreamweb.h
+++ b/engines/dreamweb/dreamweb.h
@@ -152,8 +152,8 @@ public:
uint8 modifyChar(uint8 c) const;
Common::String modifyFileName(const char *);
- const Common::String& getDatafilePrefix() { return _datafilePrefix; };
- const Common::String& getSpeechDirName() { return _speechDirName; };
+ const Common::String& getDatafilePrefix() { return _datafilePrefix; }
+ const Common::String& getSpeechDirName() { return _speechDirName; }
private:
void keyPressed(uint16 ascii);
diff --git a/engines/dreamweb/stubs.cpp b/engines/dreamweb/stubs.cpp
index 4515939ebc..f235f7c2fd 100644
--- a/engines/dreamweb/stubs.cpp
+++ b/engines/dreamweb/stubs.cpp
@@ -2920,9 +2920,7 @@ void DreamWebEngine::setupInitialVars() {
_vars._progressPoints = 0;
_vars._watchOn = 0;
_vars._shadesOn = 0;
- _vars._secondCount = 0;
- _vars._minuteCount = 30;
- _vars._hourCount = 19;
+ getTime();
_vars._zoomOn = 1;
_vars._location = 0;
_vars._exPos = 0;
diff --git a/engines/gob/anifile.cpp b/engines/gob/anifile.cpp
index 2671fe0405..085ac800cd 100644
--- a/engines/gob/anifile.cpp
+++ b/engines/gob/anifile.cpp
@@ -37,30 +37,38 @@ ANIFile::ANIFile(GobEngine *vm, const Common::String &fileName,
uint16 width, uint8 bpp) : _vm(vm),
_width(width), _bpp(bpp), _hasPadding(false) {
- Common::SeekableReadStream *ani = _vm->_dataIO->getFile(fileName);
- if (ani) {
- Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), false, DisposeAfterUse::YES);
+ bool bigEndian = false;
+ Common::String endianFileName = fileName;
- load(sub, fileName);
- return;
- }
+ if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) &&
+ !_vm->_dataIO->hasFile(fileName)) {
+ // If the game has alternate big-endian files, look if one exist
- // File doesn't exist, try to open the big-endian'd alternate file
- Common::String alternateFileName = fileName;
- alternateFileName.setChar('_', 0);
+ Common::String alternateFileName = fileName;
+ alternateFileName.setChar('_', 0);
- ani = _vm->_dataIO->getFile(alternateFileName);
+ if (_vm->_dataIO->hasFile(alternateFileName)) {
+ bigEndian = true;
+ endianFileName = alternateFileName;
+ }
+ } else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
+ ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
+ (_vm->getEndianness() == kEndiannessBE)))
+ // Game always little endian or it follows the system and it is big endian
+ bigEndian = true;
+
+ Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName);
if (ani) {
- Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), true, DisposeAfterUse::YES);
+ Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES);
// The big endian version pads a few fields to even size
- _hasPadding = true;
+ _hasPadding = bigEndian;
load(sub, fileName);
return;
}
- warning("ANIFile::ANIFile(): No such file \"%s\"", fileName.c_str());
+ warning("ANIFile::ANIFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str());
}
ANIFile::~ANIFile() {
@@ -281,4 +289,9 @@ void ANIFile::drawLayer(Surface &dest, uint16 layer, uint16 part,
_layers[layer]->draw(dest, part, x, y, transp);
}
+void ANIFile::recolor(uint8 from, uint8 to) {
+ for (LayerArray::iterator l = _layers.begin(); l != _layers.end(); ++l)
+ (*l)->recolor(from, to);
+}
+
} // End of namespace Gob
diff --git a/engines/gob/anifile.h b/engines/gob/anifile.h
index b6d9c735b5..c930aafc6b 100644
--- a/engines/gob/anifile.h
+++ b/engines/gob/anifile.h
@@ -92,6 +92,9 @@ public:
/** Draw an animation frame. */
void draw(Surface &dest, uint16 animation, uint16 frame, int16 x, int16 y) const;
+ /** Recolor the animation sprites. */
+ void recolor(uint8 from, uint8 to);
+
private:
typedef Common::Array<CMPFile *> LayerArray;
typedef Common::Array<Animation> AnimationArray;
diff --git a/engines/gob/aniobject.cpp b/engines/gob/aniobject.cpp
index 8d739fb3a4..7e3668a0ce 100644
--- a/engines/gob/aniobject.cpp
+++ b/engines/gob/aniobject.cpp
@@ -28,23 +28,20 @@
namespace Gob {
ANIObject::ANIObject(const ANIFile &ani) : _ani(&ani), _cmp(0),
- _visible(false), _paused(false), _mode(kModeContinuous),
- _x(0), _y(0), _background(0), _drawn(false) {
+ _visible(false), _paused(false), _mode(kModeContinuous), _x(0), _y(0) {
setAnimation(0);
setPosition();
}
ANIObject::ANIObject(const CMPFile &cmp) : _ani(0), _cmp(&cmp),
- _visible(false), _paused(false), _mode(kModeContinuous),
- _x(0), _y(0), _background(0), _drawn(false) {
+ _visible(false), _paused(false), _mode(kModeContinuous), _x(0), _y(0) {
setAnimation(0);
setPosition();
}
ANIObject::~ANIObject() {
- delete _background;
}
void ANIObject::setVisible(bool visible) {
@@ -104,7 +101,7 @@ void ANIObject::getPosition(int16 &x, int16 &y) const {
y = _y;
}
-void ANIObject::getFramePosition(int16 &x, int16 &y) const {
+void ANIObject::getFramePosition(int16 &x, int16 &y, uint16 n) const {
// CMP "animations" have no specific frame positions
if (_cmp) {
getPosition(x, y);
@@ -118,11 +115,24 @@ void ANIObject::getFramePosition(int16 &x, int16 &y) const {
if (_frame >= animation.frameCount)
return;
- x = _x + animation.frameAreas[_frame].left;
- y = _y + animation.frameAreas[_frame].top;
+ // If we're paused, we don't advance any frames
+ if (_paused)
+ n = 0;
+
+ // Number of cycles run through after n frames
+ uint16 cycles = (_frame + n) / animation.frameCount;
+ // Frame position after n frames
+ uint16 frame = (_frame + n) % animation.frameCount;
+
+ // Only doing one cycle?
+ if (_mode == kModeOnce)
+ cycles = MAX<uint16>(cycles, 1);
+
+ x = _x + animation.frameAreas[frame].left + cycles * animation.deltaX;
+ y = _y + animation.frameAreas[frame].top + cycles * animation.deltaY;
}
-void ANIObject::getFrameSize(int16 &width, int16 &height) const {
+void ANIObject::getFrameSize(int16 &width, int16 &height, uint16 n) const {
if (_cmp) {
width = _cmp->getWidth (_animation);
height = _cmp->getHeight(_animation);
@@ -137,8 +147,15 @@ void ANIObject::getFrameSize(int16 &width, int16 &height) const {
if (_frame >= animation.frameCount)
return;
- width = animation.frameAreas[_frame].right - animation.frameAreas[_frame].left + 1;
- height = animation.frameAreas[_frame].bottom - animation.frameAreas[_frame].top + 1;
+ // If we're paused, we don't advance any frames
+ if (_paused)
+ n = 0;
+
+ // Frame position after n frames
+ uint16 frame = (_frame + n) % animation.frameCount;
+
+ width = animation.frameAreas[frame].right - animation.frameAreas[frame].left + 1;
+ height = animation.frameAreas[frame].bottom - animation.frameAreas[frame].top + 1;
}
bool ANIObject::isIn(int16 x, int16 y) const {
@@ -188,46 +205,36 @@ bool ANIObject::draw(Surface &dest, int16 &left, int16 &top,
bool ANIObject::drawCMP(Surface &dest, int16 &left, int16 &top,
int16 &right, int16 &bottom) {
- if (!_background) {
+ if (!hasBuffer()) {
uint16 width, height;
_cmp->getMaxSize(width, height);
- _background = new Surface(width, height, dest.getBPP());
+ resizeBuffer(width, height);
}
- const uint16 cR = _cmp->getWidth (_animation) - 1;
- const uint16 cB = _cmp->getHeight(_animation) - 1;
-
- _backgroundLeft = CLIP<int16>( + _x, 0, dest.getWidth () - 1);
- _backgroundTop = CLIP<int16>( + _y, 0, dest.getHeight() - 1);
- _backgroundRight = CLIP<int16>(cR + _x, 0, dest.getWidth () - 1);
- _backgroundBottom = CLIP<int16>(cB + _y, 0, dest.getHeight() - 1);
+ left = _x;
+ top = _y;
+ right = _x + _cmp->getWidth (_animation) - 1;
+ bottom = _y + _cmp->getHeight(_animation) - 1;
- _background->blit(dest, _backgroundLeft , _backgroundTop,
- _backgroundRight, _backgroundBottom, 0, 0);
+ if (!saveScreen(dest, left, top, right, bottom))
+ return false;
_cmp->draw(dest, _animation, _x, _y, 0);
- _drawn = true;
-
- left = _backgroundLeft;
- top = _backgroundTop;
- right = _backgroundRight;
- bottom = _backgroundBottom;
-
return true;
}
bool ANIObject::drawANI(Surface &dest, int16 &left, int16 &top,
int16 &right, int16 &bottom) {
- if (!_background) {
+ if (!hasBuffer()) {
uint16 width, height;
_ani->getMaxSize(width, height);
- _background = new Surface(width, height, dest.getBPP());
+ resizeBuffer(width, height);
}
const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation);
@@ -236,45 +243,23 @@ bool ANIObject::drawANI(Surface &dest, int16 &left, int16 &top,
const ANIFile::FrameArea &area = animation.frameAreas[_frame];
- _backgroundLeft = CLIP<int16>(area.left + _x, 0, dest.getWidth () - 1);
- _backgroundTop = CLIP<int16>(area.top + _y, 0, dest.getHeight() - 1);
- _backgroundRight = CLIP<int16>(area.right + _x, 0, dest.getWidth () - 1);
- _backgroundBottom = CLIP<int16>(area.bottom + _y, 0, dest.getHeight() - 1);
+ left = _x + area.left;
+ top = _y + area.top;
+ right = _x + area.right;
+ bottom = _y + area.bottom;
- _background->blit(dest, _backgroundLeft , _backgroundTop,
- _backgroundRight, _backgroundBottom, 0, 0);
+ if (!saveScreen(dest, left, top, right, bottom))
+ return false;
_ani->draw(dest, _animation, _frame, _x, _y);
- _drawn = true;
-
- left = _backgroundLeft;
- top = _backgroundTop;
- right = _backgroundRight;
- bottom = _backgroundBottom;
-
return true;
}
bool ANIObject::clear(Surface &dest, int16 &left, int16 &top,
int16 &right, int16 &bottom) {
- if (!_drawn)
- return false;
-
- const int16 bgRight = _backgroundRight - _backgroundLeft;
- const int16 bgBottom = _backgroundBottom - _backgroundTop;
-
- dest.blit(*_background, 0, 0, bgRight, bgBottom, _backgroundLeft, _backgroundTop);
-
- _drawn = false;
-
- left = _backgroundLeft;
- top = _backgroundTop;
- right = _backgroundRight;
- bottom = _backgroundBottom;
-
- return true;
+ return restoreScreen(dest, left, top, right, bottom);
}
void ANIObject::advance() {
diff --git a/engines/gob/aniobject.h b/engines/gob/aniobject.h
index 00f42b43ce..d8c8edc2b8 100644
--- a/engines/gob/aniobject.h
+++ b/engines/gob/aniobject.h
@@ -25,6 +25,8 @@
#include "common/system.h"
+#include "gob/backbuffer.h"
+
namespace Gob {
class ANIFile;
@@ -32,7 +34,7 @@ class CMPFile;
class Surface;
/** An ANI object, controlling an animation within an ANI file. */
-class ANIObject {
+class ANIObject : public BackBuffer {
public:
enum Mode {
kModeContinuous, ///< Play the animation continuously.
@@ -68,10 +70,10 @@ public:
/** Return the current position. */
void getPosition(int16 &x, int16 &y) const;
- /** Return the current frame position. */
- void getFramePosition(int16 &x, int16 &y) const;
- /** Return the current frame size. */
- void getFrameSize(int16 &width, int16 &height) const;
+ /** Return the frame position after another n frames. */
+ void getFramePosition(int16 &x, int16 &y, uint16 n = 0) const;
+ /** Return the current frame size after another n frames. */
+ void getFrameSize(int16 &width, int16 &height, uint16 n = 0) const;
/** Are there coordinates within the animation sprite? */
bool isIn(int16 x, int16 y) const;
@@ -118,13 +120,6 @@ private:
int16 _x; ///< The current X position.
int16 _y; ///< The current Y position.
- Surface *_background; ///< The saved background.
- bool _drawn; ///< Was the animation drawn?
-
- int16 _backgroundLeft; ///< The left position of the saved background.
- int16 _backgroundTop; ///< The top of the saved background.
- int16 _backgroundRight; ///< The right position of the saved background.
- int16 _backgroundBottom; ///< The bottom position of the saved background.
bool drawCMP(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
bool drawANI(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
diff --git a/engines/gob/backbuffer.cpp b/engines/gob/backbuffer.cpp
new file mode 100644
index 0000000000..752042d46e
--- /dev/null
+++ b/engines/gob/backbuffer.cpp
@@ -0,0 +1,100 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/util.h"
+
+#include "gob/backbuffer.h"
+#include "gob/surface.h"
+
+namespace Gob {
+
+BackBuffer::BackBuffer() : _background(0), _saved(false) {
+}
+
+BackBuffer::~BackBuffer() {
+ delete _background;
+}
+
+bool BackBuffer::hasBuffer() const {
+ return _background != 0;
+}
+
+bool BackBuffer::hasSavedBackground() const {
+ return _saved;
+}
+
+void BackBuffer::trashBuffer() {
+ _saved = false;
+}
+
+void BackBuffer::resizeBuffer(uint16 width, uint16 height) {
+ trashBuffer();
+
+ if (_background && (_background->getWidth() == width) && (_background->getHeight() == height))
+ return;
+
+ delete _background;
+
+ _background = new Surface(width, height, 1);
+}
+
+bool BackBuffer::saveScreen(const Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ if (!_background)
+ return false;
+
+ const int16 width = MIN<int16>(right - left + 1, _background->getWidth ());
+ const int16 height = MIN<int16>(bottom - top + 1, _background->getHeight());
+ if ((width <= 0) || (height <= 0))
+ return false;
+
+ right = left + width - 1;
+ bottom = top + height - 1;
+
+ _saveLeft = left;
+ _saveTop = top;
+ _saveRight = right;
+ _saveBottom = bottom;
+
+ _background->blit(dest, _saveLeft, _saveTop, _saveRight, _saveBottom, 0, 0);
+
+ _saved = true;
+
+ return true;
+}
+
+bool BackBuffer::restoreScreen(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ if (!_saved)
+ return false;
+
+ left = _saveLeft;
+ top = _saveTop;
+ right = _saveRight;
+ bottom = _saveBottom;
+
+ dest.blit(*_background, 0, 0, right - left, bottom - top, left, top);
+
+ _saved = false;
+
+ return true;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/backbuffer.h b/engines/gob/backbuffer.h
new file mode 100644
index 0000000000..c978689e9f
--- /dev/null
+++ b/engines/gob/backbuffer.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_BACKBUFFER_H
+#define GOB_BACKBUFFER_H
+
+#include "common/system.h"
+
+namespace Gob {
+
+class Surface;
+
+class BackBuffer {
+public:
+ BackBuffer();
+ ~BackBuffer();
+
+protected:
+ void trashBuffer();
+ void resizeBuffer(uint16 width, uint16 height);
+
+ bool saveScreen (const Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+ bool restoreScreen( Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ bool hasBuffer() const;
+ bool hasSavedBackground() const;
+
+private:
+ Surface *_background; ///< The saved background.
+ bool _saved; ///< Was the background saved?
+
+ int16 _saveLeft; ///< The left position of the saved background.
+ int16 _saveTop; ///< The top of the saved background.
+ int16 _saveRight; ///< The right position of the saved background.
+ int16 _saveBottom; ///< The bottom position of the saved background.
+};
+
+} // End of namespace Gob
+
+#endif // GOB_BACKBUFFER_H
diff --git a/engines/gob/cmpfile.cpp b/engines/gob/cmpfile.cpp
index 7b21c4c835..d304958f76 100644
--- a/engines/gob/cmpfile.cpp
+++ b/engines/gob/cmpfile.cpp
@@ -21,6 +21,7 @@
*/
#include "common/stream.h"
+#include "common/substream.h"
#include "common/str.h"
#include "gob/gob.h"
@@ -143,7 +144,13 @@ void CMPFile::loadCMP(Common::SeekableReadStream &cmp) {
}
void CMPFile::loadRXY(Common::SeekableReadStream &rxy) {
- _coordinates = new RXYFile(rxy);
+ bool bigEndian = (_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
+ ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
+ (_vm->getEndianness() == kEndiannessBE));
+
+ Common::SeekableSubReadStreamEndian sub(&rxy, 0, rxy.size(), bigEndian, DisposeAfterUse::NO);
+
+ _coordinates = new RXYFile(sub);
for (uint i = 0; i < _coordinates->size(); i++) {
const RXYFile::Coordinates &c = (*_coordinates)[i];
@@ -243,4 +250,9 @@ uint16 CMPFile::addSprite(uint16 left, uint16 top, uint16 right, uint16 bottom)
return _coordinates->add(left, top, right, bottom);
}
+void CMPFile::recolor(uint8 from, uint8 to) {
+ if (_surface)
+ _surface->recolor(from, to);
+}
+
} // End of namespace Gob
diff --git a/engines/gob/cmpfile.h b/engines/gob/cmpfile.h
index 2b669e4d38..9c858238af 100644
--- a/engines/gob/cmpfile.h
+++ b/engines/gob/cmpfile.h
@@ -70,6 +70,8 @@ public:
uint16 addSprite(uint16 left, uint16 top, uint16 right, uint16 bottom);
+ void recolor(uint8 from, uint8 to);
+
private:
GobEngine *_vm;
diff --git a/engines/gob/decfile.cpp b/engines/gob/decfile.cpp
index fb67c52627..85b4c09ca3 100644
--- a/engines/gob/decfile.cpp
+++ b/engines/gob/decfile.cpp
@@ -38,30 +38,38 @@ DECFile::DECFile(GobEngine *vm, const Common::String &fileName,
uint16 width, uint16 height, uint8 bpp) : _vm(vm),
_width(width), _height(height), _bpp(bpp), _hasPadding(false), _backdrop(0) {
- Common::SeekableReadStream *dec = _vm->_dataIO->getFile(fileName);
- if (dec) {
- Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), false, DisposeAfterUse::YES);
-
- load(sub, fileName);
- return;
- }
-
- // File doesn't exist, try to open the big-endian'd alternate file
- Common::String alternateFileName = fileName;
- alternateFileName.setChar('_', 0);
-
- dec = _vm->_dataIO->getFile(alternateFileName);
- if (dec) {
- Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), true, DisposeAfterUse::YES);
+ bool bigEndian = false;
+ Common::String endianFileName = fileName;
+
+ if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) &&
+ !_vm->_dataIO->hasFile(fileName)) {
+ // If the game has alternate big-endian files, look if one exist
+
+ Common::String alternateFileName = fileName;
+ alternateFileName.setChar('_', 0);
+
+ if (_vm->_dataIO->hasFile(alternateFileName)) {
+ bigEndian = true;
+ endianFileName = alternateFileName;
+ }
+ } else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) ||
+ ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) &&
+ (_vm->getEndianness() == kEndiannessBE)))
+ // Game always little endian or it follows the system and it is big endian
+ bigEndian = true;
+
+ Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName);
+ if (ani) {
+ Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES);
// The big endian version pads a few fields to even size
- _hasPadding = true;
+ _hasPadding = bigEndian;
load(sub, fileName);
return;
}
- warning("DECFile::DECFile(): No such file \"%s\"", fileName.c_str());
+ warning("DECFile::DECFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str());
}
DECFile::~DECFile() {
diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp
index bcfd5dacfa..8fb0052a5b 100644
--- a/engines/gob/detection/detection.cpp
+++ b/engines/gob/detection/detection.cpp
@@ -25,40 +25,146 @@
#include "engines/obsolete.h"
#include "gob/gob.h"
+#include "gob/dataio.h"
#include "gob/detection/tables.h"
class GobMetaEngine : public AdvancedMetaEngine {
public:
- GobMetaEngine() : AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) {
- _singleid = "gob";
- _guioptions = GUIO1(GUIO_NOLAUNCHLOAD);
- }
+ GobMetaEngine();
- virtual GameDescriptor findGame(const char *gameid) const {
- return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
- }
+ virtual GameDescriptor findGame(const char *gameid) const;
+
+ virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+
+ virtual const char *getName() const;
+ virtual const char *getOriginalCopyright() const;
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+
+ virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+
+private:
+ /**
+ * Inspect the game archives to detect which Once Upon A Time game this is.
+ */
+ static const Gob::GOBGameDescription *detectOnceUponATime(const Common::FSList &fslist);
+};
+
+GobMetaEngine::GobMetaEngine() :
+ AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) {
+
+ _singleid = "gob";
+ _guioptions = GUIO1(GUIO_NOLAUNCHLOAD);
+}
+
+GameDescriptor GobMetaEngine::findGame(const char *gameid) const {
+ return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
+}
+
+const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADFilePropertiesMap filesProps;
+
+ const Gob::GOBGameDescription *game;
+ game = (const Gob::GOBGameDescription *)detectGameFilebased(allFiles, fslist, Gob::fileBased, &filesProps);
+ if (!game)
+ return 0;
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- return detectGameFilebased(allFiles, Gob::fileBased);
+ if (game->gameType == Gob::kGameTypeOnceUponATime) {
+ game = detectOnceUponATime(fslist);
+ if (!game)
+ return 0;
}
- virtual const char *getName() const {
- return "Gob";
+ reportUnknown(fslist.begin()->getParent(), filesProps);
+ return (const ADGameDescription *)game;
+}
+
+const Gob::GOBGameDescription *GobMetaEngine::detectOnceUponATime(const Common::FSList &fslist) {
+ // Add the game path to the search manager
+ SearchMan.clear();
+ SearchMan.addDirectory(fslist.begin()->getParent().getPath(), fslist.begin()->getParent());
+
+ // Open the archives
+ Gob::DataIO dataIO;
+ if (!dataIO.openArchive("stk1.stk", true) ||
+ !dataIO.openArchive("stk2.stk", true) ||
+ !dataIO.openArchive("stk3.stk", true)) {
+
+ SearchMan.clear();
+ return 0;
}
- virtual const char *getOriginalCopyright() const {
- return "Goblins Games (C) Coktel Vision";
+ Gob::OnceUponATime gameType = Gob::kOnceUponATimeInvalid;
+ Gob::OnceUponATimePlatform platform = Gob::kOnceUponATimePlatformInvalid;
+
+ // If these animal files are present, it's Abracadabra
+ if (dataIO.hasFile("arai.anm") &&
+ dataIO.hasFile("crab.anm") &&
+ dataIO.hasFile("crap.anm") &&
+ dataIO.hasFile("drag.anm") &&
+ dataIO.hasFile("guep.anm") &&
+ dataIO.hasFile("loup.anm") &&
+ dataIO.hasFile("mous.anm") &&
+ dataIO.hasFile("rhin.anm") &&
+ dataIO.hasFile("saut.anm") &&
+ dataIO.hasFile("scor.anm"))
+ gameType = Gob::kOnceUponATimeAbracadabra;
+
+ // If these animal files are present, it's Baba Yaga
+ if (dataIO.hasFile("abei.anm") &&
+ dataIO.hasFile("arai.anm") &&
+ dataIO.hasFile("drag.anm") &&
+ dataIO.hasFile("fauc.anm") &&
+ dataIO.hasFile("gren.anm") &&
+ dataIO.hasFile("rena.anm") &&
+ dataIO.hasFile("sang.anm") &&
+ dataIO.hasFile("serp.anm") &&
+ dataIO.hasFile("tort.anm") &&
+ dataIO.hasFile("vaut.anm"))
+ gameType = Gob::kOnceUponATimeBabaYaga;
+
+ // Detect the platform by endianness and existence of a MOD file
+ Common::SeekableReadStream *villeDEC = dataIO.getFile("ville.dec");
+ if (villeDEC && (villeDEC->size() > 6)) {
+ byte data[6];
+
+ if (villeDEC->read(data, 6) == 6) {
+ if (!memcmp(data, "\000\000\000\001\000\007", 6)) {
+ // Big endian -> Amiga or Atari ST
+
+ if (dataIO.hasFile("mod.babayaga"))
+ platform = Gob::kOnceUponATimePlatformAmiga;
+ else
+ platform = Gob::kOnceUponATimePlatformAtariST;
+
+ } else if (!memcmp(data, "\000\000\001\000\007\000", 6))
+ // Little endian -> DOS
+ platform = Gob::kOnceUponATimePlatformDOS;
+ }
+
+ delete villeDEC;
}
- virtual bool hasFeature(MetaEngineFeature f) const;
+ SearchMan.clear();
- virtual Common::Error createInstance(OSystem *syst, Engine **engine) const {
- Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable);
- return AdvancedMetaEngine::createInstance(syst, engine);
+ if ((gameType == Gob::kOnceUponATimeInvalid) || (platform == Gob::kOnceUponATimePlatformInvalid)) {
+ warning("GobMetaEngine::detectOnceUponATime(): Detection failed (%d, %d)",
+ (int) gameType, (int) platform);
+ return 0;
}
- virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
-};
+
+ return &Gob::fallbackOnceUpon[gameType][platform];
+}
+
+const char *GobMetaEngine::getName() const {
+ return "Gob";
+}
+
+const char *GobMetaEngine::getOriginalCopyright() const {
+ return "Goblins Games (C) Coktel Vision";
+}
bool GobMetaEngine::hasFeature(MetaEngineFeature f) const {
return false;
@@ -68,6 +174,12 @@ bool Gob::GobEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsRTL);
}
+
+Common::Error GobMetaEngine::createInstance(OSystem *syst, Engine **engine) const {
+ Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable);
+ return AdvancedMetaEngine::createInstance(syst, engine);
+}
+
bool GobMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
const Gob::GOBGameDescription *gd = (const Gob::GOBGameDescription *)desc;
if (gd) {
@@ -77,6 +189,7 @@ bool GobMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD
return gd != 0;
}
+
#if PLUGIN_ENABLED_DYNAMIC(GOB)
REGISTER_PLUGIN_DYNAMIC(GOB, PLUGIN_TYPE_ENGINE, GobMetaEngine);
#else
diff --git a/engines/gob/detection/tables.h b/engines/gob/detection/tables.h
index 5d211ac7d8..271f75af79 100644
--- a/engines/gob/detection/tables.h
+++ b/engines/gob/detection/tables.h
@@ -48,7 +48,10 @@ static const PlainGameDescriptor gobGames[] = {
{"gob2cd", "Gobliins 2 CD"},
{"ween", "Ween: The Prophecy"},
{"bargon", "Bargon Attack"},
+ {"babayaga", "Once Upon A Time: Baba Yaga"},
+ {"abracadabra", "Once Upon A Time: Abracadabra"},
{"littlered", "Once Upon A Time: Little Red Riding Hood"},
+ {"onceupon", "Once Upon A Time"},
{"ajworld", "A.J.'s World of Discovery"},
{"gob3", "Goblins Quest 3"},
{"gob3cd", "Goblins Quest 3 CD"},
@@ -94,6 +97,7 @@ static const GOBGameDescription gameDescriptions[] = {
#include "gob/detection/tables_ween.h" // Ween: The Prophecy
#include "gob/detection/tables_bargon.h" // Bargon Attack
#include "gob/detection/tables_littlered.h" // Once Upon A Time: Little Red Riding Hood
+ #include "gob/detection/tables_onceupon.h" // Once Upon A Time: Baba Yaga and Abracadabra
#include "gob/detection/tables_lit.h" // Lost in Time
#include "gob/detection/tables_fascin.h" // Fascination
#include "gob/detection/tables_geisha.h" // Geisha
diff --git a/engines/gob/detection/tables_ajworld.h b/engines/gob/detection/tables_ajworld.h
index c78d11a6ad..d86bdb16be 100644
--- a/engines/gob/detection/tables_ajworld.h
+++ b/engines/gob/detection/tables_ajworld.h
@@ -1,4 +1,3 @@
-
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
diff --git a/engines/gob/detection/tables_fallback.h b/engines/gob/detection/tables_fallback.h
index 2853ee7b4f..05f579c08c 100644
--- a/engines/gob/detection/tables_fallback.h
+++ b/engines/gob/detection/tables_fallback.h
@@ -23,6 +23,8 @@
#ifndef GOB_DETECTION_TABLES_FALLBACK_H
#define GOB_DETECTION_TABLES_FALLBACK_H
+// -- Tables for the filename-based fallback --
+
static const GOBGameDescription fallbackDescs[] = {
{ //0
{
@@ -362,6 +364,20 @@ static const GOBGameDescription fallbackDescs[] = {
},
{ //24
{
+ "onceupon",
+ "unknown",
+ AD_ENTRY1(0, 0),
+ UNK_LANG,
+ kPlatformUnknown,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeOnceUponATime,
+ kFeaturesEGA,
+ 0, 0, 0
+ },
+ { //25
+ {
"adi2",
"",
AD_ENTRY1(0, 0),
@@ -374,7 +390,7 @@ static const GOBGameDescription fallbackDescs[] = {
kFeatures640x480,
"adi2.stk", 0, 0
},
- { //25
+ { //26
{
"adi4",
"",
@@ -388,7 +404,7 @@ static const GOBGameDescription fallbackDescs[] = {
kFeatures640x480,
"adif41.stk", 0, 0
},
- { //26
+ { //27
{
"coktelplayer",
"unknown",
@@ -430,10 +446,119 @@ static const ADFileBasedFallback fileBased[] = {
{ &fallbackDescs[21].desc, { "disk1.stk", "disk2.stk", "disk3.stk", 0 } },
{ &fallbackDescs[22].desc, { "intro.stk", "stk2.stk", "stk3.stk", 0 } },
{ &fallbackDescs[23].desc, { "intro.stk", "stk2.stk", "stk3.stk", "mod.babayaga", 0 } },
- { &fallbackDescs[24].desc, { "adi2.stk", 0 } },
- { &fallbackDescs[25].desc, { "adif41.stk", "adim41.stk", 0 } },
- { &fallbackDescs[26].desc, { "coktelplayer.scn", 0 } },
+ { &fallbackDescs[24].desc, { "stk1.stk", "stk2.stk", "stk3.stk", 0 } },
+ { &fallbackDescs[25].desc, { "adi2.stk", 0 } },
+ { &fallbackDescs[26].desc, { "adif41.stk", "adim41.stk", 0 } },
+ { &fallbackDescs[27].desc, { "coktelplayer.scn", 0 } },
{ 0, { 0 } }
};
+// -- Tables for detecting the specific Once Upon A Time game --
+
+enum OnceUponATime {
+ kOnceUponATimeInvalid = -1,
+ kOnceUponATimeAbracadabra = 0,
+ kOnceUponATimeBabaYaga = 1,
+ kOnceUponATimeMAX
+};
+
+enum OnceUponATimePlatform {
+ kOnceUponATimePlatformInvalid = -1,
+ kOnceUponATimePlatformDOS = 0,
+ kOnceUponATimePlatformAmiga = 1,
+ kOnceUponATimePlatformAtariST = 2,
+ kOnceUponATimePlatformMAX
+};
+
+static const GOBGameDescription fallbackOnceUpon[kOnceUponATimeMAX][kOnceUponATimePlatformMAX] = {
+ { // kOnceUponATimeAbracadabra
+ { // kOnceUponATimePlatformDOS
+ {
+ "abracadabra",
+ "",
+ AD_ENTRY1(0, 0),
+ UNK_LANG,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesAdLib | kFeaturesEGA,
+ 0, 0, 0
+ },
+ { // kOnceUponATimePlatformAmiga
+ {
+ "abracadabra",
+ "",
+ AD_ENTRY1(0, 0),
+ UNK_LANG,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+ },
+ { // kOnceUponATimePlatformAtariST
+ {
+ "abracadabra",
+ "",
+ AD_ENTRY1(0, 0),
+ UNK_LANG,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+ }
+ },
+ { // kOnceUponATimeBabaYaga
+ { // kOnceUponATimePlatformDOS
+ {
+ "babayaga",
+ "",
+ AD_ENTRY1(0, 0),
+ UNK_LANG,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesAdLib | kFeaturesEGA,
+ 0, 0, 0
+ },
+ { // kOnceUponATimePlatformAmiga
+ {
+ "babayaga",
+ "",
+ AD_ENTRY1(0, 0),
+ UNK_LANG,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+ },
+ { // kOnceUponATimePlatformAtariST
+ {
+ "babayaga",
+ "",
+ AD_ENTRY1(0, 0),
+ UNK_LANG,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+ }
+ }
+};
+
#endif // GOB_DETECTION_TABLES_FALLBACK_H
diff --git a/engines/gob/detection/tables_geisha.h b/engines/gob/detection/tables_geisha.h
index 331e17e31d..a32d1ebf81 100644
--- a/engines/gob/detection/tables_geisha.h
+++ b/engines/gob/detection/tables_geisha.h
@@ -32,7 +32,63 @@
"geisha",
"",
AD_ENTRY1s("disk1.stk", "6eebbb98ad90cd3c44549fc2ab30f632", 212153),
- UNK_LANG,
+ EN_ANY,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeGeisha,
+ kFeaturesEGA | kFeaturesAdLib,
+ "disk1.stk", "intro.tot", 0
+},
+{
+ {
+ "geisha",
+ "",
+ AD_ENTRY1s("disk1.stk", "6eebbb98ad90cd3c44549fc2ab30f632", 212153),
+ DE_DEU,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeGeisha,
+ kFeaturesEGA | kFeaturesAdLib,
+ "disk1.stk", "intro.tot", 0
+},
+{ // Supplied by misterhands in bug report #3539797
+ {
+ "geisha",
+ "",
+ AD_ENTRY1s("disk1.stk", "0c4c16090921664f50baefdfd24d7f5d", 211889),
+ FR_FRA,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeGeisha,
+ kFeaturesEGA | kFeaturesAdLib,
+ "disk1.stk", "intro.tot", 0
+},
+{ // Supplied by einstein95 in bug report #3544449
+ {
+ "geisha",
+ "",
+ AD_ENTRY1s("disk1.stk", "49107ac897e7c00af6c4ecd78a74a710", 212169),
+ ES_ESP,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeGeisha,
+ kFeaturesEGA | kFeaturesAdLib,
+ "disk1.stk", "intro.tot", 0
+},
+{ // Supplied by einstein95 in bug report #3544449
+ {
+ "geisha",
+ "",
+ AD_ENTRY1s("disk1.stk", "49107ac897e7c00af6c4ecd78a74a710", 212169),
+ IT_ITA,
kPlatformPC,
ADGF_NO_FLAGS,
GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
@@ -63,7 +119,7 @@
"geisha",
"",
AD_ENTRY1s("disk1.stk", "e5892f00917c62423e93f5fd9920cf47", 208120),
- UNK_LANG,
+ EN_ANY,
kPlatformAmiga,
ADGF_NO_FLAGS,
GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
diff --git a/engines/gob/detection/tables_onceupon.h b/engines/gob/detection/tables_onceupon.h
new file mode 100644
index 0000000000..366024d43c
--- /dev/null
+++ b/engines/gob/detection/tables_onceupon.h
@@ -0,0 +1,518 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/* Detection tables for Once Upon A Time: Baba Yaga and Abracadabra. */
+
+#ifndef GOB_DETECTION_TABLES_ONCEUPON_H
+#define GOB_DETECTION_TABLES_ONCEUPON_H
+
+// -- Once Upon A Time: Abracadabra, Amiga --
+
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+ {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+ {0, 0, 0, 0}
+ },
+ FR_FRA,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+ {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+ {0, 0, 0, 0}
+ },
+ DE_DEU,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+ {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+ {0, 0, 0, 0}
+ },
+ EN_ANY,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+ {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+ {0, 0, 0, 0}
+ },
+ IT_ITA,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106},
+ {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482},
+ {0, 0, 0, 0}
+ },
+ ES_ESP,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+
+// -- Once Upon A Time: Abracadabra, Atari ST --
+
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+ {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+ {0, 0, 0, 0}
+ },
+ FR_FRA,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+ {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+ {0, 0, 0, 0}
+ },
+ DE_DEU,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+ {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+ {0, 0, 0, 0}
+ },
+ EN_ANY,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+ {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+ {0, 0, 0, 0}
+ },
+ IT_ITA,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "abracadabra",
+ "",
+ {
+ {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806},
+ {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123},
+ {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257},
+ {0, 0, 0, 0}
+ },
+ ES_ESP,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeAbracadabra,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+
+// -- Once Upon A Time: Baba Yaga, DOS EGA Floppy --
+
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+ {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+ {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+ {0, 0, 0, 0}
+ },
+ FR_FRA,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesAdLib | kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+ {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+ {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+ {0, 0, 0, 0}
+ },
+ DE_DEU,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesAdLib | kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+ {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+ {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+ {0, 0, 0, 0}
+ },
+ EN_ANY,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesAdLib | kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+ {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+ {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+ {0, 0, 0, 0}
+ },
+ IT_ITA,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesAdLib | kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813},
+ {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582},
+ {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925},
+ {0, 0, 0, 0}
+ },
+ ES_ESP,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesAdLib | kFeaturesEGA,
+ 0, 0, 0
+},
+
+// -- Once Upon A Time: Baba Yaga, Amiga --
+
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+ {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ FR_FRA,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+ {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ DE_DEU,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+ {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ EN_ANY,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+ {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ IT_ITA,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090},
+ {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ ES_ESP,
+ kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+
+// -- Once Upon A Time: Baba Yaga, Atari ST --
+
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+ {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ FR_FRA,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+ {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ DE_DEU,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+ {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ EN_ANY,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+ {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ IT_ITA,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+{
+ {
+ "babayaga",
+ "",
+ {
+ {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095},
+ {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128},
+ {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922},
+ {0, 0, 0, 0}
+ },
+ ES_ESP,
+ kPlatformAtariST,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeBabaYaga,
+ kFeaturesEGA,
+ 0, 0, 0
+},
+
+#endif // GOB_DETECTION_TABLES_ONCEUPON_H
diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp
index fe59b11f76..8c6919416d 100644
--- a/engines/gob/draw.cpp
+++ b/engines/gob/draw.cpp
@@ -256,7 +256,7 @@ void Draw::blitInvalidated() {
if (_cursorIndex == 4)
blitCursor();
- if (_vm->_inter->_terminate)
+ if (_vm->_inter && _vm->_inter->_terminate)
return;
if (_noInvalidated && !_applyPal)
@@ -271,7 +271,9 @@ void Draw::blitInvalidated() {
return;
}
- _showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1);
+ if (_cursorSprites)
+ _showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1);
+
if (_applyPal) {
clearPalette();
forceBlit();
@@ -425,28 +427,13 @@ int Draw::stringLength(const char *str, uint16 fontIndex) {
return len;
}
-void Draw::drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2,
- int16 transp, Surface &dest, const Font &font) {
-
- while (*str != '\0') {
- const int16 charRight = x + font.getCharWidth(*str);
- const int16 charBottom = y + font.getCharHeight();
-
- if ((charRight <= dest.getWidth()) && (charBottom <= dest.getHeight()))
- font.drawLetter(dest, *str, x, y, color1, color2, transp);
-
- x += font.getCharWidth(*str);
- str++;
- }
-}
-
void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right,
int16 bottom, const char *str, int16 fontIndex, int16 color) {
adjustCoords(1, &left, &top);
adjustCoords(1, &right, &bottom);
- uint16 centerOffset = _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter);
+ uint16 centerOffset = _vm->_game->_script ? _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter) : 0;
if (centerOffset != 0) {
_vm->_game->_script->call(centerOffset);
@@ -505,7 +492,7 @@ void Draw::oPlaytoons_sub_F_1B(uint16 id, int16 left, int16 top, int16 right, in
adjustCoords(1, &left, &top);
adjustCoords(1, &right, &bottom);
- uint16 centerOffset = _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter);
+ uint16 centerOffset = _vm->_game->_script ? _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter) : 0;
if (centerOffset != 0) {
_vm->_game->_script->call(centerOffset);
diff --git a/engines/gob/draw.h b/engines/gob/draw.h
index e7af1f9af3..b51c6466e0 100644
--- a/engines/gob/draw.h
+++ b/engines/gob/draw.h
@@ -194,8 +194,6 @@ public:
adjustCoords(adjust, (int16 *)coord1, (int16 *)coord2);
}
int stringLength(const char *str, uint16 fontIndex);
- void drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2,
- int16 transp, Surface &dest, const Font &font);
void printTextCentered(int16 id, int16 left, int16 top, int16 right,
int16 bottom, const char *str, int16 fontIndex, int16 color);
void oPlaytoons_sub_F_1B( uint16 id, int16 left, int16 top, int16 right, int16 bottom, char *paramStr, int16 var3, int16 var4, int16 shortId);
diff --git a/engines/gob/draw_fascin.cpp b/engines/gob/draw_fascin.cpp
index 54cd52b660..12009d7ee5 100644
--- a/engines/gob/draw_fascin.cpp
+++ b/engines/gob/draw_fascin.cpp
@@ -222,8 +222,8 @@ void Draw_Fascination::spriteOperation(int16 operation) {
_destSpriteX, _destSpriteY, _frontColor, _backColor, _transparency);
}
} else {
- drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor,
- _backColor, _transparency, *_spritesArray[_destSurface], *font);
+ font->drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor,
+ _backColor, _transparency, *_spritesArray[_destSurface]);
_destSpriteX += len * font->getCharWidth();
}
} else {
diff --git a/engines/gob/draw_playtoons.cpp b/engines/gob/draw_playtoons.cpp
index a443f81ccf..76e2ae591c 100644
--- a/engines/gob/draw_playtoons.cpp
+++ b/engines/gob/draw_playtoons.cpp
@@ -283,8 +283,8 @@ void Draw_Playtoons::spriteOperation(int16 operation) {
_destSpriteX, _destSpriteY, _frontColor, _backColor, _transparency);
}
} else {
- drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor,
- _backColor, _transparency, *_spritesArray[_destSurface], *font);
+ font->drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor,
+ _backColor, _transparency, *_spritesArray[_destSurface]);
_destSpriteX += len * font->getCharWidth();
}
} else {
diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp
index b637ecbd2b..f5475278c4 100644
--- a/engines/gob/draw_v2.cpp
+++ b/engines/gob/draw_v2.cpp
@@ -74,13 +74,16 @@ void Draw_v2::closeScreen() {
}
void Draw_v2::blitCursor() {
- if (_cursorIndex == -1)
+ if (!_cursorSprites || (_cursorIndex == -1))
return;
_showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1);
}
void Draw_v2::animateCursor(int16 cursor) {
+ if (!_cursorSprites)
+ return;
+
int16 cursorIndex = cursor;
int16 newX = 0, newY = 0;
uint16 hotspotX, hotspotY;
@@ -831,8 +834,8 @@ void Draw_v2::spriteOperation(int16 operation) {
getColor(_backColor), _transparency);
}
} else {
- drawString(_textToPrint, _destSpriteX, _destSpriteY, getColor(_frontColor),
- getColor(_backColor), _transparency, *_spritesArray[_destSurface], *font);
+ font->drawString(_textToPrint, _destSpriteX, _destSpriteY, getColor(_frontColor),
+ getColor(_backColor), _transparency, *_spritesArray[_destSurface]);
_destSpriteX += len * font->getCharWidth();
}
} else {
diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp
index 0d1953322f..de0c3f2d5c 100644
--- a/engines/gob/game.cpp
+++ b/engines/gob/game.cpp
@@ -64,7 +64,7 @@ void Environments::clear() {
// Deleting unique variables, script and resources
for (uint i = 0; i < kEnvironmentCount; i++) {
- if (_environments[i].variables == _vm->_inter->_variables)
+ if (_vm->_inter && (_environments[i].variables == _vm->_inter->_variables))
continue;
if (!has(_environments[i].variables, i + 1))
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 3d8a18ed38..fcf98f0355 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -48,6 +48,10 @@
#include "gob/videoplayer.h"
#include "gob/save/saveload.h"
+#include "gob/pregob/pregob.h"
+#include "gob/pregob/onceupon/abracadabra.h"
+#include "gob/pregob/onceupon/babayaga.h"
+
namespace Gob {
#define MAX_TIME_DELTA 100
@@ -115,7 +119,7 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst), _rnd("gob") {
_vidPlayer = 0; _init = 0; _inter = 0;
_map = 0; _palAnim = 0; _scenery = 0;
_draw = 0; _util = 0; _video = 0;
- _saveLoad = 0;
+ _saveLoad = 0; _preGob = 0;
_pauseStart = 0;
@@ -180,6 +184,10 @@ void GobEngine::validateVideoMode(int16 videoMode) {
error("Video mode 0x%X is not supported", videoMode);
}
+EndiannessMethod GobEngine::getEndiannessMethod() const {
+ return _endiannessMethod;
+}
+
Endianness GobEngine::getEndianness() const {
if ((getPlatform() == Common::kPlatformAmiga) ||
(getPlatform() == Common::kPlatformMacintosh) ||
@@ -274,15 +282,15 @@ void GobEngine::setTrueColor(bool trueColor) {
}
Common::Error GobEngine::run() {
- if (!initGameParts()) {
- GUIErrorMessage("GobEngine::init(): Unknown version of game engine");
- return Common::kUnknownError;
- }
+ Common::Error err;
- if (!initGraphics()) {
- GUIErrorMessage("GobEngine::init(): Failed to set up graphics");
- return Common::kUnknownError;
- }
+ err = initGameParts();
+ if (err.getCode() != Common::kNoError)
+ return err;
+
+ err = initGraphics();
+ if (err.getCode() != Common::kNoError)
+ return err;
// On some systems it's not safe to run CD audio games from the CD.
if (isCD())
@@ -368,11 +376,12 @@ void GobEngine::pauseEngineIntern(bool pause) {
_game->_startTimeKey += duration;
_draw->_cursorTimeKey += duration;
- if (_inter->_soundEndTimeKey != 0)
+ if (_inter && (_inter->_soundEndTimeKey != 0))
_inter->_soundEndTimeKey += duration;
}
- _vidPlayer->pauseAll(pause);
+ if (_vidPlayer)
+ _vidPlayer->pauseAll(pause);
_mixer->pauseAll(pause);
}
@@ -392,12 +401,13 @@ void GobEngine::pauseGame() {
pauseEngineIntern(false);
}
-bool GobEngine::initGameParts() {
+Common::Error GobEngine::initGameParts() {
_resourceSizeWorkaround = false;
// just detect some devices some of which will be always there if the music is not disabled
_noMusic = MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB)) == MT_NULL ? true : false;
- _saveLoad = 0;
+
+ _endiannessMethod = kEndiannessMethodSystem;
_global = new Global(this);
_util = new Util(this);
@@ -429,6 +439,8 @@ bool GobEngine::initGameParts() {
_goblin = new Goblin_v1(this);
_scenery = new Scenery_v1(this);
_saveLoad = new SaveLoad_Geisha(this, _targetName.c_str());
+
+ _endiannessMethod = kEndiannessMethodAltFile;
break;
case kGameTypeFascination:
@@ -605,20 +617,45 @@ bool GobEngine::initGameParts() {
_scenery = new Scenery_v2(this);
_saveLoad = new SaveLoad_v2(this, _targetName.c_str());
break;
+
+ case kGameTypeAbracadabra:
+ _init = new Init_v2(this);
+ _video = new Video_v2(this);
+ _mult = new Mult_v2(this);
+ _draw = new Draw_v2(this);
+ _map = new Map_v2(this);
+ _goblin = new Goblin_v2(this);
+ _scenery = new Scenery_v2(this);
+ _preGob = new OnceUpon::Abracadabra(this);
+ break;
+
+ case kGameTypeBabaYaga:
+ _init = new Init_v2(this);
+ _video = new Video_v2(this);
+ _mult = new Mult_v2(this);
+ _draw = new Draw_v2(this);
+ _map = new Map_v2(this);
+ _goblin = new Goblin_v2(this);
+ _scenery = new Scenery_v2(this);
+ _preGob = new OnceUpon::BabaYaga(this);
+ break;
+
default:
deinitGameParts();
- return false;
+ return Common::kUnsupportedGameidError;
}
// Setup mixer
syncSoundSettings();
- _inter->setupOpcodes();
+ if (_inter)
+ _inter->setupOpcodes();
- return true;
+ return Common::kNoError;
}
void GobEngine::deinitGameParts() {
+ delete _preGob; _preGob = 0;
delete _saveLoad; _saveLoad = 0;
delete _mult; _mult = 0;
delete _vidPlayer; _vidPlayer = 0;
@@ -637,10 +674,10 @@ void GobEngine::deinitGameParts() {
delete _dataIO; _dataIO = 0;
}
-bool GobEngine::initGraphics() {
+Common::Error GobEngine::initGraphics() {
if (is800x600()) {
warning("GobEngine::initGraphics(): 800x600 games currently unsupported");
- return false;
+ return Common::kUnsupportedGameidError;
} else if (is640x480()) {
_width = 640;
_height = 480;
@@ -664,7 +701,7 @@ bool GobEngine::initGraphics() {
_global->_primarySurfDesc = SurfacePtr(new Surface(_width, _height, _pixelFormat.bytesPerPixel));
- return true;
+ return Common::kNoError;
}
} // End of namespace Gob
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
index 52f3ba8f2d..df73404596 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -75,6 +75,7 @@ class Scenery;
class Util;
class SaveLoad;
class GobConsole;
+class PreGob;
#define WRITE_VAR_UINT32(var, val) _vm->_inter->_variables->writeVar32(var, val)
#define WRITE_VAR_UINT16(var, val) _vm->_inter->_variables->writeVar16(var, val)
@@ -129,7 +130,10 @@ enum GameType {
kGameTypeAdi4,
kGameTypeAdibou2,
kGameTypeAdibou1,
+ kGameTypeAbracadabra,
+ kGameTypeBabaYaga,
kGameTypeLittleRed,
+ kGameTypeOnceUponATime, // Need more inspection to see if Baba Yaga or Abracadabra
kGameTypeAJWorld
};
@@ -145,6 +149,13 @@ enum Features {
kFeaturesTrueColor = 1 << 7
};
+enum EndiannessMethod {
+ kEndiannessMethodLE, ///< Always little endian.
+ kEndiannessMethodBE, ///< Always big endian.
+ kEndiannessMethodSystem, ///< Follows system endianness.
+ kEndiannessMethodAltFile ///< Different endianness in alternate file.
+};
+
enum {
kDebugFuncOp = 1 << 0,
kDebugDrawOp = 1 << 1,
@@ -168,6 +179,8 @@ private:
int32 _features;
Common::Platform _platform;
+ EndiannessMethod _endiannessMethod;
+
uint32 _pauseStart;
// Engine APIs
@@ -176,10 +189,10 @@ private:
virtual void pauseEngineIntern(bool pause);
virtual void syncSoundSettings();
- bool initGameParts();
- void deinitGameParts();
+ Common::Error initGameParts();
+ Common::Error initGraphics();
- bool initGraphics();
+ void deinitGameParts();
public:
static const Common::Language _gobToScummVMLang[];
@@ -220,6 +233,7 @@ public:
Inter *_inter;
SaveLoad *_saveLoad;
VideoPlayer *_vidPlayer;
+ PreGob *_preGob;
const char *getLangDesc(int16 language) const;
void validateLanguage();
@@ -227,6 +241,7 @@ public:
void pauseGame();
+ EndiannessMethod getEndiannessMethod() const;
Endianness getEndianness() const;
Common::Platform getPlatform() const;
GameType getGameType() const;
diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp
index a61261f355..814d4d1821 100644
--- a/engines/gob/init.cpp
+++ b/engines/gob/init.cpp
@@ -34,9 +34,13 @@
#include "gob/inter.h"
#include "gob/video.h"
#include "gob/videoplayer.h"
+
+#include "gob/sound/sound.h"
+
#include "gob/demos/scnplayer.h"
#include "gob/demos/batplayer.h"
-#include "gob/sound/sound.h"
+
+#include "gob/pregob/pregob.h"
namespace Gob {
@@ -118,6 +122,14 @@ void Init::initGame() {
return;
}
+ if (_vm->_preGob) {
+ _vm->_preGob->run();
+ delete _palDesc;
+ _vm->_video->initPrimary(-1);
+ cleanup();
+ return;
+ }
+
Common::SeekableReadStream *infFile = _vm->_dataIO->getFile("intro.inf");
if (!infFile) {
diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp
index 134203fa9d..029f7c697b 100644
--- a/engines/gob/inter_bargon.cpp
+++ b/engines/gob/inter_bargon.cpp
@@ -119,7 +119,7 @@ void Inter_Bargon::oBargon_intro2(OpGobParams &params) {
MouseButtons buttons;
SurfacePtr surface;
SoundDesc samples[4];
- int16 comp[5] = { 0, 1, 2, 3, -1 };
+ static const int16 comp[5] = { 0, 1, 2, 3, -1 };
static const char *const sndFiles[] = {"1INTROII.snd", "2INTROII.snd", "1INTRO3.snd", "2INTRO3.snd"};
surface = _vm->_video->initSurfDesc(320, 200);
@@ -167,8 +167,8 @@ void Inter_Bargon::oBargon_intro3(OpGobParams &params) {
MouseButtons buttons;
Video::Color *palBak;
SoundDesc samples[2];
- int16 comp[3] = { 0, 1, -1 };
byte *palettes[4];
+ static const int16 comp[3] = { 0, 1, -1 };
static const char *const sndFiles[] = {"1INTROIV.snd", "2INTROIV.snd"};
static const char *const palFiles[] = {"2ou2.clt", "2ou3.clt", "2ou4.clt", "2ou5.clt"};
diff --git a/engines/gob/inter_geisha.cpp b/engines/gob/inter_geisha.cpp
index 8a4d4246b6..8d05cefa66 100644
--- a/engines/gob/inter_geisha.cpp
+++ b/engines/gob/inter_geisha.cpp
@@ -200,8 +200,12 @@ void Inter_Geisha::oGeisha_checkData(OpFuncParams &params) {
if (mode == SaveLoad::kSaveModeNone) {
exists = _vm->_dataIO->hasFile(file);
- if (!exists)
- warning("File \"%s\" not found", file.c_str());
+ if (!exists) {
+ // NOTE: Geisha looks if fin.tot exists to check if it needs to open disk3.stk.
+ // This is completely normal, so don't print a warning.
+ if (file != "fin.tot")
+ warning("File \"%s\" not found", file.c_str());
+ }
} else if (mode == SaveLoad::kSaveModeSave)
exists = _vm->_saveLoad->getSize(file.c_str()) >= 0;
diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp
index c0e8978afd..24905b08d1 100644
--- a/engines/gob/inter_v5.cpp
+++ b/engines/gob/inter_v5.cpp
@@ -281,7 +281,7 @@ void Inter_v5::o5_getSystemCDSpeed(OpGobParams &params) {
Font *font;
if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
- _vm->_draw->drawString("100 %", 402, 89, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+ font->drawString("100 %", 402, 89, 112, 144, 0, *_vm->_draw->_backSurface);
_vm->_draw->forceBlit();
delete font;
@@ -293,7 +293,7 @@ void Inter_v5::o5_getSystemRAM(OpGobParams &params) {
Font *font;
if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
- _vm->_draw->drawString("100 %", 402, 168, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+ font->drawString("100 %", 402, 168, 112, 144, 0, *_vm->_draw->_backSurface);
_vm->_draw->forceBlit();
delete font;
@@ -305,7 +305,7 @@ void Inter_v5::o5_getSystemCPUSpeed(OpGobParams &params) {
Font *font;
if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
- _vm->_draw->drawString("100 %", 402, 248, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+ font->drawString("100 %", 402, 248, 112, 144, 0, *_vm->_draw->_backSurface);
_vm->_draw->forceBlit();
delete font;
@@ -317,7 +317,7 @@ void Inter_v5::o5_getSystemDrawSpeed(OpGobParams &params) {
Font *font;
if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
- _vm->_draw->drawString("100 %", 402, 326, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+ font->drawString("100 %", 402, 326, 112, 144, 0, *_vm->_draw->_backSurface);
_vm->_draw->forceBlit();
delete font;
@@ -329,7 +329,7 @@ void Inter_v5::o5_totalSystemSpecs(OpGobParams &params) {
Font *font;
if ((font = _vm->_draw->loadFont("SPEED.LET"))) {
- _vm->_draw->drawString("100 %", 402, 405, 112, 144, 0, *_vm->_draw->_backSurface, *font);
+ font->drawString("100 %", 402, 405, 112, 144, 0, *_vm->_draw->_backSurface);
_vm->_draw->forceBlit();
delete font;
diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp
index 3be9f1f651..c8c4f2bba7 100644
--- a/engines/gob/minigames/geisha/penetration.cpp
+++ b/engines/gob/minigames/geisha/penetration.cpp
@@ -505,7 +505,7 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) {
// Draw, fade in if necessary and wait for the end of the frame
_vm->_draw->blitInvalidated();
fadeIn();
- _vm->_util->waitEndFrame();
+ _vm->_util->waitEndFrame(false);
// Handle the input
checkInput();
@@ -778,29 +778,24 @@ void Penetration::drawFloorText() {
else if (_floor == 2)
floorString = strings[kString1stBasement];
+ Surface &surface = *_vm->_draw->_backSurface;
+
if (floorString)
- _vm->_draw->drawString(floorString, 10, 15, kColorFloorText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
+ font->drawString(floorString, 10, 15, kColorFloorText, kColorBlack, 1, surface);
if (_exits.size() > 0) {
int exitCount = kString2Exits;
if (_exits.size() == 1)
exitCount = kString1Exit;
- _vm->_draw->drawString(strings[kStringYouHave] , 10, 38, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
- _vm->_draw->drawString(strings[exitCount] , 10, 53, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
- _vm->_draw->drawString(strings[kStringToReach] , 10, 68, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
- _vm->_draw->drawString(strings[kStringUpperLevel1], 10, 84, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
- _vm->_draw->drawString(strings[kStringUpperLevel2], 10, 98, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
+ font->drawString(strings[kStringYouHave] , 10, 38, kColorExitText, kColorBlack, 1, surface);
+ font->drawString(strings[exitCount] , 10, 53, kColorExitText, kColorBlack, 1, surface);
+ font->drawString(strings[kStringToReach] , 10, 68, kColorExitText, kColorBlack, 1, surface);
+ font->drawString(strings[kStringUpperLevel1], 10, 84, kColorExitText, kColorBlack, 1, surface);
+ font->drawString(strings[kStringUpperLevel2], 10, 98, kColorExitText, kColorBlack, 1, surface);
} else
- _vm->_draw->drawString(strings[kStringNoExit], 10, 53, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
+ font->drawString(strings[kStringNoExit], 10, 53, kColorExitText, kColorBlack, 1, surface);
}
void Penetration::drawEndText() {
@@ -814,21 +809,17 @@ void Penetration::drawEndText() {
if (!font)
return;
+ Surface &surface = *_vm->_draw->_backSurface;
+
const char **strings = kStrings[getLanguage()];
- _vm->_draw->drawString(strings[kStringLevel0] , 11, 21, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
- _vm->_draw->drawString(strings[kStringPenetration], 11, 42, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
- _vm->_draw->drawString(strings[kStringSuccessful] , 11, 58, kColorExitText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
-
- _vm->_draw->drawString(strings[kStringDanger] , 11, 82, kColorFloorText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
- _vm->_draw->drawString(strings[kStringGynoides] , 11, 98, kColorFloorText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
- _vm->_draw->drawString(strings[kStringActivated], 11, 113, kColorFloorText, kColorBlack, 1,
- *_vm->_draw->_backSurface, *font);
+ font->drawString(strings[kStringLevel0] , 11, 21, kColorExitText, kColorBlack, 1, surface);
+ font->drawString(strings[kStringPenetration], 11, 42, kColorExitText, kColorBlack, 1, surface);
+ font->drawString(strings[kStringSuccessful] , 11, 58, kColorExitText, kColorBlack, 1, surface);
+
+ font->drawString(strings[kStringDanger] , 11, 82, kColorFloorText, kColorBlack, 1, surface);
+ font->drawString(strings[kStringGynoides] , 11, 98, kColorFloorText, kColorBlack, 1, surface);
+ font->drawString(strings[kStringActivated], 11, 113, kColorFloorText, kColorBlack, 1, surface);
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBigBottom);
_vm->_draw->blitInvalidated();
diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 3395046b6c..d5ee6478be 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/gob
MODULE_OBJS := \
anifile.o \
aniobject.o \
+ backbuffer.o \
cheater.o \
cheater_geisha.o \
cmpfile.o \
@@ -77,6 +78,17 @@ MODULE_OBJS := \
demos/scnplayer.o \
demos/batplayer.o \
detection/detection.o \
+ pregob/pregob.o \
+ pregob/txtfile.o \
+ pregob/gctfile.o \
+ pregob/seqfile.o \
+ pregob/onceupon/onceupon.o \
+ pregob/onceupon/abracadabra.o \
+ pregob/onceupon/babayaga.o \
+ pregob/onceupon/title.o \
+ pregob/onceupon/parents.o \
+ pregob/onceupon/stork.o \
+ pregob/onceupon/chargenchild.o \
minigames/geisha/evilfish.o \
minigames/geisha/oko.o \
minigames/geisha/meter.o \
diff --git a/engines/gob/pregob/gctfile.cpp b/engines/gob/pregob/gctfile.cpp
new file mode 100644
index 0000000000..08c32cda76
--- /dev/null
+++ b/engines/gob/pregob/gctfile.cpp
@@ -0,0 +1,306 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/random.h"
+#include "common/stream.h"
+
+#include "gob/surface.h"
+#include "gob/video.h"
+
+#include "gob/pregob/gctfile.h"
+
+namespace Gob {
+
+GCTFile::Chunk::Chunk() : type(kChunkTypeNone) {
+}
+
+
+GCTFile::GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd) : _rnd(&rnd),
+ _areaLeft(0), _areaTop(0), _areaRight(0), _areaBottom(0), _currentItem(0xFFFF) {
+
+ load(gct);
+}
+
+GCTFile::~GCTFile() {
+}
+
+void GCTFile::load(Common::SeekableReadStream &gct) {
+ gct.skip(4); // Required buffer size
+ gct.skip(2); // Unknown
+
+ // Read the selector and line counts for each item
+ const uint16 itemCount = gct.readUint16LE();
+ _items.resize(itemCount);
+
+ for (Items::iterator i = _items.begin(); i != _items.end(); ++i) {
+ const uint16 selector = gct.readUint16LE();
+ const uint16 lineCount = gct.readUint16LE();
+
+ i->selector = selector;
+ i->lines.resize(lineCount);
+ }
+
+ // Read all item lines
+ for (Items::iterator i = _items.begin(); i != _items.end(); ++i) {
+ for (Lines::iterator l = i->lines.begin(); l != i->lines.end(); ++l) {
+ const uint16 lineSize = gct.readUint16LE();
+
+ readLine(gct, *l, lineSize);
+ }
+ }
+
+ if (gct.err())
+ error("GCTFile::load(): Failed reading GCT");
+}
+
+void GCTFile::readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const {
+ line.chunks.push_back(Chunk());
+
+ while (lineSize > 0) {
+ byte c = gct.readByte();
+ lineSize--;
+
+ if (c == 0) {
+ // Command byte
+
+ if (lineSize == 0)
+ break;
+
+ byte cmd = gct.readByte();
+ lineSize--;
+
+ // Line end command
+ if (cmd == 0)
+ break;
+
+ // Item reference command
+ if (cmd == 1) {
+ if (lineSize < 2) {
+ warning("GCTFile::readLine(): Item reference command is missing parameters");
+ break;
+ }
+
+ const uint32 itemRef = gct.readUint16LE();
+ lineSize -= 2;
+
+ line.chunks.push_back(Chunk());
+ line.chunks.back().type = kChunkTypeItem;
+ line.chunks.back().item = itemRef;
+
+ line.chunks.push_back(Chunk());
+ continue;
+ }
+
+ warning("GCTFile::readLine(): Invalid command 0x%02X", cmd);
+ break;
+ }
+
+ // Text
+ line.chunks.back().type = kChunkTypeString;
+ line.chunks.back().text += (char)c;
+ }
+
+ // Skip bytes we didn't read (because of errors)
+ gct.skip(lineSize);
+
+ // Remove empty chunks from the end of the list
+ while (!line.chunks.empty() && (line.chunks.back().type == kChunkTypeNone))
+ line.chunks.pop_back();
+}
+
+uint16 GCTFile::getLineCount(uint item) const {
+ if (item >= _items.size())
+ return 0;
+
+ return _items[item].lines.size();
+}
+
+void GCTFile::selectLine(uint item, uint16 line) {
+ if ((item >= _items.size()) && (item != kSelectorAll) && (item != kSelectorRandom))
+ return;
+
+ _items[item].selector = line;
+}
+
+void GCTFile::setText(uint item, uint16 line, const Common::String &text) {
+ if ((item >= _items.size()) || (line >= _items[item].lines.size()))
+ return;
+
+ _items[item].lines[line].chunks.clear();
+ _items[item].lines[line].chunks.push_back(Chunk());
+
+ _items[item].lines[line].chunks.back().type = kChunkTypeString;
+ _items[item].lines[line].chunks.back().text = text;
+}
+
+void GCTFile::setText(uint item, const Common::String &text) {
+ if (item >= _items.size())
+ return;
+
+ _items[item].selector = 0;
+
+ _items[item].lines.resize(1);
+
+ setText(item, 0, text);
+}
+
+void GCTFile::reset() {
+ _currentItem = 0xFFFF;
+ _currentText.clear();
+}
+
+Common::String GCTFile::getLineText(const Line &line) const {
+ Common::String text;
+
+ // Go over all chunks in this line
+ for (Chunks::const_iterator c = line.chunks.begin(); c != line.chunks.end(); ++c) {
+ // A chunk is either a direct string, or a reference to another item
+
+ if (c->type == kChunkTypeItem) {
+ Common::List<Common::String> lines;
+
+ getItemText(c->item, lines);
+ if (lines.empty())
+ continue;
+
+ if (lines.size() > 1)
+ warning("GCTFile::getLineText(): Referenced item has multiple lines");
+
+ text += lines.front();
+ } else if (c->type == kChunkTypeString)
+ text += c->text;
+ }
+
+ return text;
+}
+
+void GCTFile::getItemText(uint item, Common::List<Common::String> &text) const {
+ text.clear();
+
+ if ((item >= _items.size()) || _items[item].lines.empty())
+ return;
+
+ uint16 line = _items[item].selector;
+
+ // Draw all lines
+ if (line == kSelectorAll) {
+ for (Lines::const_iterator l = _items[item].lines.begin(); l != _items[item].lines.end(); ++l)
+ text.push_back(getLineText(*l));
+
+ return;
+ }
+
+ // Draw random line
+ if (line == kSelectorRandom)
+ line = _rnd->getRandomNumber(_items[item].lines.size() - 1);
+
+ if (line >= _items[item].lines.size())
+ return;
+
+ text.push_back(getLineText(_items[item].lines[line]));
+}
+
+void GCTFile::setArea(int16 left, int16 top, int16 right, int16 bottom) {
+ trashBuffer();
+
+ _hasArea = false;
+
+ const int16 width = right - left + 1;
+ const int16 height = bottom - top + 1;
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ _areaLeft = left;
+ _areaTop = top;
+ _areaRight = right;
+ _areaBottom = bottom;
+
+ _hasArea = true;
+
+ resizeBuffer(width, height);
+}
+
+bool GCTFile::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ return restoreScreen(dest, left, top, right, bottom);
+}
+
+bool GCTFile::fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ left = _areaLeft;
+ top = _areaTop;
+ right = _areaRight;
+ bottom = _areaBottom;
+
+ if (!hasSavedBackground())
+ saveScreen(dest, left, top, right, bottom);
+
+ dest.fillRect(left, top, right, bottom, color);
+
+ return true;
+}
+
+bool GCTFile::finished() const {
+ return (_currentItem != 0xFFFF) && _currentText.empty();
+}
+
+bool GCTFile::draw(Surface &dest, uint16 item, const Font &font, uint8 color,
+ int16 &left, int16 &top, int16 &right, int16 &bottom) {
+
+ if ((item >= _items.size()) || !_hasArea)
+ return false;
+
+ left = _areaLeft;
+ top = _areaTop;
+ right = _areaRight;
+ bottom = _areaBottom;
+
+ const int16 width = right - left + 1;
+ const int16 height = bottom - top + 1;
+
+ const uint lineCount = height / font.getCharHeight();
+ if (lineCount == 0)
+ return false;
+
+ if (!hasSavedBackground())
+ saveScreen(dest, left, top, right, bottom);
+
+ if (item != _currentItem) {
+ _currentItem = item;
+
+ getItemText(_currentItem, _currentText);
+ }
+
+ if (_currentText.empty())
+ return false;
+
+ int16 y = top;
+ for (uint i = 0; (i < lineCount) && !_currentText.empty(); i++, y += font.getCharHeight()) {
+ const Common::String &line = _currentText.front();
+ const int16 x = left + ((width - (line.size() * font.getCharWidth())) / 2);
+
+ font.drawString(line, x, y, color, 0, true, dest);
+ _currentText.pop_front();
+ }
+
+ return true;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/gctfile.h b/engines/gob/pregob/gctfile.h
new file mode 100644
index 0000000000..ed6351b7a8
--- /dev/null
+++ b/engines/gob/pregob/gctfile.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.
+ *
+ */
+
+#ifndef GOB_PREGOB_GCTFILE_H
+#define GOB_PREGOB_GCTFILE_H
+
+#include "common/str.h"
+#include "common/array.h"
+#include "common/list.h"
+
+#include "gob/backbuffer.h"
+
+namespace Common {
+ class RandomSource;
+ class SeekableReadStream;
+}
+
+namespace Gob {
+
+class Surface;
+class Font;
+
+class GCTFile : public BackBuffer {
+public:
+ static const uint16 kSelectorAll = 0xFFFE; ///< Print all lines.
+ static const uint16 kSelectorRandom = 0xFFFF; ///< Print a random line.
+
+
+ GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd);
+ ~GCTFile();
+
+ /** Return the number of lines in an item. */
+ uint16 getLineCount(uint item) const;
+
+ /** Set the area the text will be printed in. */
+ void setArea(int16 left, int16 top, int16 right, int16 bottom);
+
+ /** Set which line of this item should be printed. */
+ void selectLine(uint item, uint16 line);
+
+ /** Change the text of an items' line. */
+ void setText(uint item, uint16 line, const Common::String &text);
+ /** Change the item into one one line and set that line's text. */
+ void setText(uint item, const Common::String &text);
+
+ /** Reset the item drawing state. */
+ void reset();
+
+ /** Clear the drawn text, restoring the original content. */
+ bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ /** Fill the text area with a color. */
+ bool fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ /** Draw an item onto the surface, until all text has been drawn or the area is filled. */
+ bool draw(Surface &dest, uint16 item, const Font &font, uint8 color,
+ int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ /** Did we draw all text? */
+ bool finished() const;
+
+private:
+ /** The type of a chunk. */
+ enum ChunkType {
+ kChunkTypeNone = 0, ///< Do nothing.
+ kChunkTypeString , ///< A direct string.
+ kChunkTypeItem ///< A reference to an item to print instead.
+ };
+
+ /** A chunk in an item text line. */
+ struct Chunk {
+ ChunkType type; ///< The type of the chunk.
+
+ Common::String text; ///< Text to print.
+
+ int item; ///< Item to print instead.
+
+ Chunk();
+ };
+
+ typedef Common::List<Chunk> Chunks;
+
+ /** A line in an item. */
+ struct Line {
+ Chunks chunks; ///< The chunks that make up the line.
+ };
+
+ typedef Common::Array<Line> Lines;
+
+ /** A GCT item. */
+ struct Item {
+ Lines lines; ///< The text lines in the item
+ uint16 selector; ///< Which line to print.
+ };
+
+ typedef Common::Array<Item> Items;
+
+
+ Common::RandomSource *_rnd;
+
+ Items _items; ///< All GCT items.
+
+ // The area on which to print
+ bool _hasArea;
+ int16 _areaLeft;
+ int16 _areaTop;
+ int16 _areaRight;
+ int16 _areaBottom;
+
+ /** Index of the current item we're drawing. */
+ uint16 _currentItem;
+ /** Text left to draw. */
+ Common::List<Common::String> _currentText;
+
+
+ // -- Loading helpers --
+
+ void load(Common::SeekableReadStream &gct);
+ void readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const;
+
+
+ // -- Draw helpers --
+
+ Common::String getLineText(const Line &line) const;
+ void getItemText(uint item, Common::List<Common::String> &text) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_GCTFILE_H
diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
new file mode 100644
index 0000000000..2cf6855ef8
--- /dev/null
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -0,0 +1,137 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/textconsole.h"
+
+#include "gob/gob.h"
+
+#include "gob/pregob/onceupon/abracadabra.h"
+
+static const uint8 kCopyProtectionColors[7] = {
+ 14, 11, 13, 1, 7, 12, 2
+};
+
+static const uint8 kCopyProtectionShapes[7 * 20] = {
+ 3, 4, 3, 0, 1, 2, 0, 2, 2, 0, 2, 4, 0, 3, 4, 1, 1, 4, 1, 3,
+ 0, 2, 0, 4, 2, 4, 4, 2, 3, 0, 1, 1, 1, 1, 3, 0, 4, 2, 3, 4,
+ 0, 0, 1, 2, 1, 1, 2, 4, 3, 1, 4, 2, 4, 4, 2, 4, 1, 2, 3, 3,
+ 1, 0, 2, 3, 4, 2, 3, 2, 2, 0, 0, 0, 4, 2, 3, 4, 4, 0, 4, 1,
+ 4, 2, 1, 1, 1, 1, 4, 3, 4, 2, 3, 0, 0, 3, 0, 2, 3, 0, 2, 4,
+ 4, 2, 4, 3, 0, 4, 0, 2, 3, 1, 4, 1, 3, 1, 0, 0, 2, 1, 3, 2,
+ 3, 1, 0, 3, 1, 3, 4, 2, 4, 4, 3, 2, 0, 2, 0, 1, 2, 0, 1, 4
+};
+
+static const uint8 kCopyProtectionObfuscate[4] = {
+ 1, 0, 2, 3
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const OnceUpon::MenuButton Abracadabra::kAnimalsButtons = {
+ true, 131, 127, 183, 164, 193, 0, 243, 35, 132, 128, 0
+};
+
+const OnceUpon::MenuButton Abracadabra::kAnimalButtons[] = {
+ {false, 37, 89, 95, 127, 37, 89, 95, 127, 131, 25, 0},
+ {false, 114, 65, 172, 111, 114, 65, 172, 111, 131, 25, 1},
+ {false, 186, 72, 227, 96, 186, 72, 227, 96, 139, 25, 2},
+ {false, 249, 87, 282, 112, 249, 87, 282, 112, 143, 25, 3},
+ {false, 180, 102, 234, 138, 180, 102, 234, 138, 133, 25, 4},
+ {false, 197, 145, 242, 173, 197, 145, 242, 173, 137, 25, 5},
+ {false, 113, 151, 171, 176, 113, 151, 171, 176, 131, 25, 6},
+ {false, 114, 122, 151, 150, 114, 122, 151, 150, 141, 25, 7},
+ {false, 36, 136, 94, 176, 36, 136, 94, 176, 131, 25, 8},
+ {false, 243, 123, 295, 155, 243, 123, 295, 155, 136, 25, 9}
+};
+
+const char *Abracadabra::kAnimalNames[] = {
+ "loup",
+ "drag",
+ "arai",
+ "crap",
+ "crab",
+ "mous",
+ "saut",
+ "guep",
+ "rhin",
+ "scor"
+};
+
+// The houses where the stork can drop a bundle
+const OnceUpon::MenuButton Abracadabra::kStorkHouses[] = {
+ {false, 16, 80, 87, 125, 0, 0, 0, 0, 0, 0, 0}, // Castle , Lord & Lady
+ {false, 61, 123, 96, 149, 0, 0, 0, 0, 0, 0, 1}, // Cottage, Farmers
+ {false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2}, // Hut , Woodcutters
+ {false, 229, 91, 304, 188, 0, 0, 0, 0, 0, 0, 3} // Palace , King & Queen
+};
+
+// The stork bundle drop parameters
+const Stork::BundleDrop Abracadabra::kStorkBundleDrops[] = {
+ { 14, 65, 127, true },
+ { 14, 76, 152, true },
+ { 14, 204, 137, true },
+ { 11, 275, 179, false }
+};
+
+// Parameters for the stork section.
+const OnceUpon::StorkParam Abracadabra::kStorkParam = {
+ "present.cmp", ARRAYSIZE(kStorkHouses), kStorkHouses, kStorkBundleDrops
+};
+
+
+Abracadabra::Abracadabra(GobEngine *vm) : OnceUpon(vm) {
+}
+
+Abracadabra::~Abracadabra() {
+}
+
+void Abracadabra::run() {
+ init();
+
+ // Copy protection
+ bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate);
+ if (_vm->shouldQuit() || !correctCP)
+ return;
+
+ // Show the intro
+ showIntro();
+ if (_vm->shouldQuit())
+ return;
+
+ // Handle the start menu
+ doStartMenu(&kAnimalsButtons, ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
+ if (_vm->shouldQuit())
+ return;
+
+ // Play the actual game
+ playGame();
+}
+
+const OnceUpon::StorkParam &Abracadabra::getStorkParameters() const {
+ return kStorkParam;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/abracadabra.h b/engines/gob/pregob/onceupon/abracadabra.h
new file mode 100644
index 0000000000..8048213f5f
--- /dev/null
+++ b/engines/gob/pregob/onceupon/abracadabra.h
@@ -0,0 +1,61 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_ABRACADABRA_H
+#define GOB_PREGOB_ONCEUPON_ABRACADABRA_H
+
+#include "gob/pregob/onceupon/onceupon.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+class Abracadabra : public OnceUpon {
+public:
+ Abracadabra(GobEngine *vm);
+ ~Abracadabra();
+
+ void run();
+
+protected:
+ const StorkParam &getStorkParameters() const;
+
+private:
+ /** Definition of the menu button that leads to the animal names screen. */
+ static const MenuButton kAnimalsButtons;
+
+ /** Definition of the buttons that make up the animals in the animal names screen. */
+ static const MenuButton kAnimalButtons[];
+ /** File prefixes for the name of each animal. */
+ static const char *kAnimalNames[];
+
+ // Parameters for the stork section.
+ static const MenuButton kStorkHouses[];
+ static const Stork::BundleDrop kStorkBundleDrops[];
+ static const struct StorkParam kStorkParam;
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_ABRACADABRA_H
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
new file mode 100644
index 0000000000..ef56b9dd0b
--- /dev/null
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -0,0 +1,137 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/textconsole.h"
+
+#include "gob/gob.h"
+
+#include "gob/pregob/onceupon/babayaga.h"
+
+static const uint8 kCopyProtectionColors[7] = {
+ 14, 11, 13, 1, 7, 12, 2
+};
+
+static const uint8 kCopyProtectionShapes[7 * 20] = {
+ 0, 0, 1, 2, 1, 1, 2, 4, 3, 1, 4, 2, 4, 4, 2, 4, 1, 2, 3, 3,
+ 3, 1, 0, 3, 1, 3, 4, 2, 4, 4, 3, 2, 0, 2, 0, 1, 2, 0, 1, 4,
+ 1, 0, 2, 3, 4, 2, 3, 2, 2, 0, 0, 0, 4, 2, 3, 4, 4, 0, 4, 1,
+ 0, 2, 0, 4, 2, 4, 4, 2, 3, 0, 1, 1, 1, 1, 3, 0, 4, 2, 3, 4,
+ 3, 4, 3, 0, 1, 2, 0, 2, 2, 0, 2, 4, 0, 3, 4, 1, 1, 4, 1, 3,
+ 4, 2, 1, 1, 1, 1, 4, 3, 4, 2, 3, 0, 0, 3, 0, 2, 3, 0, 2, 4,
+ 4, 2, 4, 3, 0, 4, 0, 2, 3, 1, 4, 1, 3, 1, 0, 0, 2, 1, 3, 2
+};
+
+static const uint8 kCopyProtectionObfuscate[4] = {
+ 0, 1, 2, 3
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const OnceUpon::MenuButton BabaYaga::kAnimalsButtons = {
+ true, 131, 127, 183, 164, 193, 0, 245, 37, 131, 127, 0
+};
+
+const OnceUpon::MenuButton BabaYaga::kAnimalButtons[] = {
+ {false, 34, 84, 92, 127, 34, 84, 92, 127, 131, 25, 0},
+ {false, 114, 65, 172, 111, 114, 65, 172, 111, 131, 25, 1},
+ {false, 186, 72, 227, 96, 186, 72, 227, 96, 139, 25, 2},
+ {false, 249, 87, 282, 112, 249, 87, 282, 112, 143, 25, 3},
+ {false, 180, 97, 234, 138, 180, 97, 234, 138, 133, 25, 4},
+ {false, 197, 145, 242, 173, 197, 145, 242, 173, 137, 25, 5},
+ {false, 113, 156, 171, 176, 113, 156, 171, 176, 131, 25, 6},
+ {false, 114, 127, 151, 150, 114, 127, 151, 150, 141, 25, 7},
+ {false, 36, 136, 94, 176, 36, 136, 94, 176, 131, 25, 8},
+ {false, 245, 123, 293, 155, 245, 123, 293, 155, 136, 25, 9}
+};
+
+const char *BabaYaga::kAnimalNames[] = {
+ "vaut",
+ "drag",
+ "arai",
+ "gren",
+ "fauc",
+ "abei",
+ "serp",
+ "tort",
+ "sang",
+ "rena"
+};
+
+// The houses where the stork can drop a bundle
+const OnceUpon::MenuButton BabaYaga::kStorkHouses[] = {
+ {false, 16, 80, 87, 125, 0, 0, 0, 0, 0, 0, 0}, // Castle , Lord & Lady
+ {false, 61, 123, 96, 149, 0, 0, 0, 0, 0, 0, 1}, // Cottage, Farmers
+ {false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2}, // Hut , Woodcutters
+ {false, 229, 91, 304, 188, 0, 0, 0, 0, 0, 0, 3} // Palace , King & Queen
+};
+
+// The stork bundle drop parameters
+const Stork::BundleDrop BabaYaga::kStorkBundleDrops[] = {
+ { 14, 35, 129, true },
+ { 14, 70, 148, true },
+ { 14, 206, 136, true },
+ { 11, 260, 225, false }
+};
+
+// Parameters for the stork section.
+const OnceUpon::StorkParam BabaYaga::kStorkParam = {
+ "present2.cmp", ARRAYSIZE(kStorkHouses), kStorkHouses, kStorkBundleDrops
+};
+
+
+BabaYaga::BabaYaga(GobEngine *vm) : OnceUpon(vm) {
+}
+
+BabaYaga::~BabaYaga() {
+}
+
+void BabaYaga::run() {
+ init();
+
+ // Copy protection
+ bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate);
+ if (_vm->shouldQuit() || !correctCP)
+ return;
+
+ // Show the intro
+ showIntro();
+ if (_vm->shouldQuit())
+ return;
+
+ // Handle the start menu
+ doStartMenu(&kAnimalsButtons, ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
+ if (_vm->shouldQuit())
+ return;
+
+ // Play the actual game
+ playGame();
+}
+
+const OnceUpon::StorkParam &BabaYaga::getStorkParameters() const {
+ return kStorkParam;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/babayaga.h b/engines/gob/pregob/onceupon/babayaga.h
new file mode 100644
index 0000000000..0241f78f4e
--- /dev/null
+++ b/engines/gob/pregob/onceupon/babayaga.h
@@ -0,0 +1,61 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_BABAYAGA_H
+#define GOB_PREGOB_ONCEUPON_BABAYAGA_H
+
+#include "gob/pregob/onceupon/onceupon.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+class BabaYaga : public OnceUpon {
+public:
+ BabaYaga(GobEngine *vm);
+ ~BabaYaga();
+
+ void run();
+
+protected:
+ const StorkParam &getStorkParameters() const;
+
+private:
+ /** Definition of the menu button that leads to the animal names screen. */
+ static const MenuButton kAnimalsButtons;
+
+ /** Definition of the buttons that make up the animals in the animal names screen. */
+ static const MenuButton kAnimalButtons[];
+ /** File prefixes for the name of each animal. */
+ static const char *kAnimalNames[];
+
+ // Parameters for the stork section.
+ static const MenuButton kStorkHouses[];
+ static const Stork::BundleDrop kStorkBundleDrops[];
+ static const struct StorkParam kStorkParam;
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_BABAYAGA_H
diff --git a/engines/gob/pregob/onceupon/brokenstrings.h b/engines/gob/pregob/onceupon/brokenstrings.h
new file mode 100644
index 0000000000..89acb1c6bd
--- /dev/null
+++ b/engines/gob/pregob/onceupon/brokenstrings.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
+#define GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
+
+struct BrokenString {
+ const char *wrong;
+ const char *correct;
+};
+
+struct BrokenStringLanguage {
+ const BrokenString *strings;
+ uint count;
+};
+
+static const BrokenString kBrokenStringsGerman[] = {
+ { "Zeichungen von Kaki," , "Zeichnungen von Kaki," },
+ { "die es in seine Wachtr\204ume", "die es in seine Tagtr\204ume" },
+ { " Spielerfahrung" , " Spielerfahren" },
+ { " Fortgeschrittene" , " Fortgeschritten" },
+ { "die Vespe" , "die Wespe" },
+ { "das Rhinoceros" , "das Rhinozeros" },
+ { "die Heusschrecke" , "die Heuschrecke" },
+ { "Das, von Drachen gebrachte" , "Das vom Drachen gebrachte" },
+ { "Am Waldesrand es sieht" , "Am Waldesrand sieht es" },
+ { " das Kind den Palast." , "das Kind den Palast." },
+ { "Am Waldessaum sieht" , "Am Waldesrand sieht" },
+ { "tipp auf ESC!" , "dr\201cke ESC!" },
+ { "Wohin fliegt der Drachen?" , "Wohin fliegt der Drache?" }
+};
+
+static const BrokenStringLanguage kBrokenStrings[kLanguageCount] = {
+ { 0, 0 }, // French
+ { kBrokenStringsGerman, ARRAYSIZE(kBrokenStringsGerman) }, // German
+ { 0, 0 }, // English
+ { 0, 0 }, // Spanish
+ { 0, 0 }, // Italian
+};
+
+#endif // GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
diff --git a/engines/gob/pregob/onceupon/chargenchild.cpp b/engines/gob/pregob/onceupon/chargenchild.cpp
new file mode 100644
index 0000000000..ba099e4937
--- /dev/null
+++ b/engines/gob/pregob/onceupon/chargenchild.cpp
@@ -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.
+ *
+ */
+
+#include "gob/surface.h"
+#include "gob/anifile.h"
+
+#include "gob/pregob/onceupon/chargenchild.h"
+
+enum Animation {
+ kAnimWalkLeft = 0,
+ kAnimWalkRight = 1,
+ kAnimJumpLeft = 2,
+ kAnimJumpRight = 3,
+ kAnimTapFoot = 14
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+CharGenChild::CharGenChild(const ANIFile &ani) : ANIObject(ani) {
+ setPosition(265, 110);
+ setAnimation(kAnimWalkLeft);
+ setVisible(true);
+ setPause(false);
+}
+
+CharGenChild::~CharGenChild() {
+}
+
+void CharGenChild::advance() {
+ bool wasLastFrame = lastFrame();
+
+ ANIObject::advance();
+
+ int16 x, y, left, top, width, height;
+ getPosition(x, y);
+ getFramePosition(left, top);
+ getFrameSize(width, height);
+
+ const int16 right = left + width - 1;
+
+ switch (getAnimation()) {
+ case kAnimWalkLeft:
+ if (left <= 147)
+ setAnimation(kAnimWalkRight);
+ break;
+
+ case kAnimWalkRight:
+ if (right >= 290) {
+ setAnimation(kAnimJumpLeft);
+
+ setPosition(x, y - 14);
+ }
+ break;
+
+ case kAnimJumpLeft:
+ if (wasLastFrame) {
+ setAnimation(kAnimTapFoot);
+
+ setPosition(x, y - 10);
+ }
+ break;
+
+ case kAnimTapFoot:
+ if (wasLastFrame) {
+ setAnimation(kAnimJumpRight);
+
+ setPosition(x, y + 10);
+ }
+ break;
+
+ case kAnimJumpRight:
+ if (wasLastFrame) {
+ setAnimation(kAnimWalkLeft);
+
+ setPosition(x, y + 14);
+ }
+ break;
+ }
+}
+
+CharGenChild::Sound CharGenChild::shouldPlaySound() const {
+ const uint16 anim = getAnimation();
+ const uint16 frame = getFrame();
+
+ if (((anim == kAnimWalkLeft) || (anim == kAnimWalkRight)) && ((frame == 1) || (frame == 6)))
+ return kSoundWalk;
+
+ if (((anim == kAnimJumpLeft) || (anim == kAnimJumpRight)) && (frame == 0))
+ return kSoundJump;
+
+ return kSoundNone;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/chargenchild.h b/engines/gob/pregob/onceupon/chargenchild.h
new file mode 100644
index 0000000000..3b09ef112a
--- /dev/null
+++ b/engines/gob/pregob/onceupon/chargenchild.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
+#define GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
+
+#include "common/system.h"
+
+#include "gob/aniobject.h"
+
+namespace Gob {
+
+class Surface;
+class ANIFile;
+
+namespace OnceUpon {
+
+/** The child running around on the character generator screen. */
+class CharGenChild : public ANIObject {
+public:
+ enum Sound {
+ kSoundNone = 0,
+ kSoundWalk ,
+ kSoundJump
+ };
+
+ CharGenChild(const ANIFile &ani);
+ ~CharGenChild();
+
+ /** Advance the animation to the next frame. */
+ void advance();
+
+ /** Should we play a sound right now? */
+ Sound shouldPlaySound() const;
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
new file mode 100644
index 0000000000..e4c2df34c0
--- /dev/null
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -0,0 +1,1904 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/util.h"
+#include "gob/dataio.h"
+#include "gob/surface.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+#include "gob/anifile.h"
+#include "gob/aniobject.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/txtfile.h"
+#include "gob/pregob/gctfile.h"
+
+#include "gob/pregob/onceupon/onceupon.h"
+#include "gob/pregob/onceupon/palettes.h"
+#include "gob/pregob/onceupon/title.h"
+#include "gob/pregob/onceupon/parents.h"
+#include "gob/pregob/onceupon/chargenchild.h"
+
+static const uint kLanguageCount = 5;
+
+static const uint kCopyProtectionHelpStringCount = 3;
+
+static const char *kCopyProtectionHelpStrings[Gob::OnceUpon::OnceUpon::kLanguageCount][kCopyProtectionHelpStringCount] = {
+ { // French
+ "Consulte le livret des animaux, rep\212re la",
+ "page correspondant \205 la couleur de l\'\202cran",
+ "et clique le symbole associ\202 \205 l\'animal affich\202.",
+ },
+ { // German
+ "Suche im Tieralbum die Seite, die der Farbe auf",
+ "dem Bildschirm entspricht und klicke auf das",
+ "Tiersymbol.",
+ },
+ { // English
+ "Consult the book of animals, find the page",
+ "corresponding to the colour of screen and click",
+ "the symbol associated with the animal displayed.",
+ },
+ { // Spanish
+ "Consulta el libro de los animales, localiza la ",
+ "p\240gina que corresponde al color de la pantalla.",
+ "Cliquea el s\241mbolo asociado al animal que aparece.",
+ },
+ { // Italian
+ "Guarda il libretto degli animali, trova la",
+ "pagina che corrisponde al colore dello schermo,",
+ "clicca il simbolo associato all\'animale presentato",
+ }
+};
+
+static const char *kCopyProtectionWrongStrings[Gob::OnceUpon::OnceUpon::kLanguageCount] = {
+ "Tu t\'es tromp\202, dommage...", // French
+ "Schade, du hast dich geirrt." , // German
+ "You are wrong, what a pity!" , // English
+ "Te equivocas, l\240stima..." , // Spanish
+ "Sei Sbagliato, peccato..." // Italian
+};
+
+static const uint kCopyProtectionShapeCount = 5;
+
+static const int16 kCopyProtectionShapeCoords[kCopyProtectionShapeCount][6] = {
+ { 0, 51, 26, 75, 60, 154},
+ { 28, 51, 58, 81, 96, 151},
+ { 60, 51, 94, 79, 136, 152},
+ { 96, 51, 136, 71, 180, 155},
+ {140, 51, 170, 77, 228, 153}
+};
+
+enum ClownAnimation {
+ kClownAnimationClownCheer = 0,
+ kClownAnimationClownStand = 1,
+ kClownAnimationClownCry = 6
+};
+
+// 12 seconds delay for one area full of GCT text
+static const uint32 kGCTDelay = 12000;
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const OnceUpon::MenuButton OnceUpon::kMainMenuDifficultyButton[] = {
+ {false, 29, 18, 77, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyBeginner},
+ {false, 133, 18, 181, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyIntermediate},
+ {false, 241, 18, 289, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyAdvanced},
+};
+
+const OnceUpon::MenuButton OnceUpon::kSectionButtons[] = {
+ {false, 27, 121, 91, 179, 0, 0, 0, 0, 0, 0, 0},
+ { true, 95, 121, 159, 179, 4, 1, 56, 49, 100, 126, 2},
+ { true, 163, 121, 227, 179, 64, 1, 120, 49, 168, 126, 6},
+ { true, 231, 121, 295, 179, 128, 1, 184, 49, 236, 126, 10}
+};
+
+const OnceUpon::MenuButton OnceUpon::kIngameButtons[] = {
+ {true, 108, 83, 139, 116, 0, 0, 31, 34, 108, 83, 0},
+ {true, 144, 83, 175, 116, 36, 0, 67, 34, 144, 83, 1},
+ {true, 180, 83, 211, 116, 72, 0, 103, 34, 180, 83, 2}
+};
+
+const OnceUpon::MenuButton OnceUpon::kAnimalNamesBack = {
+ true, 19, 13, 50, 46, 36, 0, 67, 34, 19, 13, 1
+};
+
+const OnceUpon::MenuButton OnceUpon::kLanguageButtons[] = {
+ {true, 43, 80, 93, 115, 0, 55, 50, 90, 43, 80, 0},
+ {true, 132, 80, 182, 115, 53, 55, 103, 90, 132, 80, 1},
+ {true, 234, 80, 284, 115, 106, 55, 156, 90, 234, 80, 2},
+ {true, 43, 138, 93, 173, 159, 55, 209, 90, 43, 138, 3},
+ {true, 132, 138, 182, 173, 212, 55, 262, 90, 132, 138, 4},
+ {true, 234, 138, 284, 173, 265, 55, 315, 90, 234, 138, 2}
+};
+
+const char *OnceUpon::kSound[kSoundCount] = {
+ "diamant.snd", // kSoundClick
+ "cigogne.snd", // kSoundStork
+ "saute.snd" // kSoundJump
+};
+
+const OnceUpon::SectionFunc OnceUpon::kSectionFuncs[kSectionCount] = {
+ &OnceUpon::sectionStork,
+ &OnceUpon::sectionChapter1,
+ &OnceUpon::sectionParents,
+ &OnceUpon::sectionChapter2,
+ &OnceUpon::sectionForest0,
+ &OnceUpon::sectionChapter3,
+ &OnceUpon::sectionEvilCastle,
+ &OnceUpon::sectionChapter4,
+ &OnceUpon::sectionForest1,
+ &OnceUpon::sectionChapter5,
+ &OnceUpon::sectionBossFight,
+ &OnceUpon::sectionChapter6,
+ &OnceUpon::sectionForest2,
+ &OnceUpon::sectionChapter7,
+ &OnceUpon::sectionEnd
+};
+
+
+OnceUpon::ScreenBackup::ScreenBackup() : palette(-1), changedCursor(false), cursorVisible(false) {
+ screen = new Surface(320, 200, 1);
+}
+
+OnceUpon::ScreenBackup::~ScreenBackup() {
+ delete screen;
+}
+
+
+OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _openedArchives(false),
+ _jeudak(0), _lettre(0), _plettre(0), _glettre(0) {
+
+}
+
+OnceUpon::~OnceUpon() {
+ deinit();
+}
+
+void OnceUpon::init() {
+ deinit();
+
+ // Open data files
+
+ bool hasSTK1 = _vm->_dataIO->openArchive("stk1.stk", true);
+ bool hasSTK2 = _vm->_dataIO->openArchive("stk2.stk", true);
+ bool hasSTK3 = _vm->_dataIO->openArchive("stk3.stk", true);
+
+ if (!hasSTK1 || !hasSTK2 || !hasSTK3)
+ error("OnceUpon::OnceUpon(): Failed to open archives");
+
+ _openedArchives = true;
+
+ // Open fonts
+
+ _jeudak = _vm->_draw->loadFont("jeudak.let");
+ _lettre = _vm->_draw->loadFont("lettre.let");
+ _plettre = _vm->_draw->loadFont("plettre.let");
+ _glettre = _vm->_draw->loadFont("glettre.let");
+
+ if (!_jeudak || !_lettre || !_plettre || !_glettre)
+ error("OnceUpon::OnceUpon(): Failed to fonts (%d, %d, %d, %d)",
+ _jeudak != 0, _lettre != 0, _plettre != 0, _glettre != 0);
+
+ // Verify the language
+
+ if (_vm->_global->_language == kLanguageAmerican)
+ _vm->_global->_language = kLanguageBritish;
+
+ if ((_vm->_global->_language >= kLanguageCount))
+ error("We do not support the language \"%s\".\n"
+ "If you are certain that your game copy includes this language,\n"
+ "please contact the ScummVM team with details about this version.\n"
+ "Thanks", _vm->getLangDesc(_vm->_global->_language));
+
+ // Load all our sounds and init the screen
+
+ loadSounds(kSound, kSoundCount);
+ initScreen();
+
+ // We start with an invalid palette
+ _palette = -1;
+
+ // No quit requested at start
+ _quit = false;
+
+ // We start with no selected difficulty and at section 0
+ _difficulty = kDifficultyCount;
+ _section = 0;
+
+ // Default name
+ _name = "Nemo";
+
+ // Default character properties
+ _house = 0;
+ _head = 0;
+ _colorHair = 0;
+ _colorJacket = 0;
+ _colorTrousers = 0;
+}
+
+void OnceUpon::deinit() {
+ // Free sounds
+ freeSounds();
+
+ // Free fonts
+
+ delete _jeudak;
+ delete _lettre;
+ delete _plettre;
+ delete _glettre;
+
+ _jeudak = 0;
+ _lettre = 0;
+ _plettre = 0;
+ _glettre = 0;
+
+ // Close archives
+
+ if (_openedArchives) {
+ _vm->_dataIO->closeArchive(true);
+ _vm->_dataIO->closeArchive(true);
+ _vm->_dataIO->closeArchive(true);
+ }
+
+ _openedArchives = false;
+}
+
+void OnceUpon::setGamePalette(uint palette) {
+ if (palette >= kPaletteCount)
+ return;
+
+ _palette = palette;
+
+ setPalette(kGamePalettes[palette], kPaletteSize);
+}
+
+void OnceUpon::setGameCursor() {
+ Surface cursor(320, 16, 1);
+
+ // Set the default game cursor
+ _vm->_video->drawPackedSprite("icon.cmp", cursor);
+ setCursor(cursor, 105, 0, 120, 15, 0, 0);
+}
+
+void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
+ int16 x, int16 y) const {
+
+ // A special way of drawing something:
+ // Draw every other line "downwards", wait a bit after each line
+ // Then, draw the remaining lines "upwards" and again wait a bit after each line.
+
+ if (_vm->shouldQuit())
+ return;
+
+ const int16 width = right - left + 1;
+ const int16 height = bottom - top + 1;
+
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ // Draw the even lines downwards
+ for (int16 i = 0; i < height; i += 2) {
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
+ _vm->_draw->blitInvalidated();
+
+ _vm->_util->longDelay(1);
+ }
+
+ // Draw the odd lines upwards
+ for (int16 i = (height & 1) ? height : (height - 1); i >= 0; i -= 2) {
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
+ _vm->_draw->blitInvalidated();
+
+ _vm->_util->longDelay(1);
+ }
+}
+
+void OnceUpon::backupScreen(ScreenBackup &backup, bool setDefaultCursor) {
+ // Backup the screen and palette
+ backup.screen->blit(*_vm->_draw->_backSurface);
+ backup.palette = _palette;
+
+ // Backup the cursor
+
+ backup.cursorVisible = isCursorVisible();
+
+ backup.changedCursor = false;
+ if (setDefaultCursor) {
+ backup.changedCursor = true;
+
+ addCursor();
+ setGameCursor();
+ }
+}
+
+void OnceUpon::restoreScreen(ScreenBackup &backup) {
+ if (_vm->shouldQuit())
+ return;
+
+ // Restore the screen
+ _vm->_draw->_backSurface->blit(*backup.screen);
+ _vm->_draw->forceBlit();
+
+ // Restore the palette
+ if (backup.palette >= 0)
+ setGamePalette(backup.palette);
+
+ // Restore the cursor
+
+ if (!backup.cursorVisible)
+ hideCursor();
+
+ if (backup.changedCursor)
+ removeCursor();
+
+ backup.changedCursor = false;
+}
+
+void OnceUpon::fixTXTStrings(TXTFile &txt) const {
+ TXTFile::LineArray &lines = txt.getLines();
+ for (uint i = 0; i < lines.size(); i++)
+ lines[i].text = fixString(lines[i].text);
+}
+
+#include "gob/pregob/onceupon/brokenstrings.h"
+Common::String OnceUpon::fixString(const Common::String &str) const {
+ const BrokenStringLanguage &broken = kBrokenStrings[_vm->_global->_language];
+
+ for (uint i = 0; i < broken.count; i++) {
+ if (str == broken.strings[i].wrong)
+ return broken.strings[i].correct;
+ }
+
+ return str;
+}
+
+enum ClownAnimation {
+ kClownAnimationStand = 0,
+ kClownAnimationCheer = 1,
+ kClownAnimationCry = 2
+};
+
+const PreGob::AnimProperties OnceUpon::kClownAnimations[] = {
+ { 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 0, 0, ANIObject::kModeOnce , true, false, false, 0, 0},
+ { 6, 0, ANIObject::kModeOnce , true, false, false, 0, 0}
+};
+
+enum CopyProtectionState {
+ kCPStateSetup, // Set up the screen
+ kCPStateWaitUser, // Waiting for the user to pick a shape
+ kCPStateWaitClown, // Waiting for the clown animation to finish
+ kCPStateFinish // Finishing
+};
+
+bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]) {
+ fadeOut();
+ setPalette(kCopyProtectionPalette, kPaletteSize);
+
+ // Load the copy protection sprites
+ Surface sprites[2] = {Surface(320, 200, 1), Surface(320, 200, 1)};
+
+ _vm->_video->drawPackedSprite("grille1.cmp", sprites[0]);
+ _vm->_video->drawPackedSprite("grille2.cmp", sprites[1]);
+
+ // Load the clown animation
+ ANIFile ani (_vm, "grille.ani", 320);
+ ANIList anims;
+
+ loadAnims(anims, ani, 1, &kClownAnimations[kClownAnimationStand]);
+
+ // Set the copy protection cursor
+ setCursor(sprites[1], 5, 110, 20, 134, 3, 0);
+
+ // We start with 2 tries left, not having a correct answer and the copy protection not set up yet
+ CopyProtectionState state = kCPStateSetup;
+
+ uint8 triesLeft = 2;
+ int8 animalShape = -1;
+ bool hasCorrect = false;
+
+ while (!_vm->shouldQuit() && (state != kCPStateFinish)) {
+ clearAnim(anims);
+
+ // Set up the screen
+ if (state == kCPStateSetup) {
+ animalShape = cpSetup(colors, shapes, obfuscate, sprites);
+
+ setAnim(*anims[0], kClownAnimations[kClownAnimationStand]);
+ state = kCPStateWaitUser;
+ }
+
+ drawAnim(anims);
+
+ // If we're waiting for the clown and he finished, evaluate if we're finished
+ if (!anims[0]->isVisible() && (state == kCPStateWaitClown))
+ state = (hasCorrect || (--triesLeft == 0)) ? kCPStateFinish : kCPStateSetup;
+
+ showCursor();
+ fadeIn();
+
+ endFrame(true);
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ checkInput(mouseX, mouseY, mouseButtons);
+
+ if (state == kCPStateWaitUser) {
+ // Look if we clicked a shaped and got it right
+
+ int8 guessedShape = -1;
+ if (mouseButtons == kMouseButtonsLeft)
+ guessedShape = cpFindShape(mouseX, mouseY);
+
+ if (guessedShape >= 0) {
+ hasCorrect = guessedShape == animalShape;
+ animalShape = -1;
+
+ setAnim(*anims[0], kClownAnimations[hasCorrect ? kClownAnimationCheer : kClownAnimationCry]);
+ state = kCPStateWaitClown;
+ }
+ }
+ }
+
+ freeAnims(anims);
+
+ fadeOut();
+ hideCursor();
+ clearScreen();
+
+ // Display the "You are wrong" screen
+ if (!hasCorrect)
+ cpWrong();
+
+ return hasCorrect;
+}
+
+int8 OnceUpon::cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4],
+ const Surface sprites[2]) {
+
+ fadeOut();
+ hideCursor();
+
+ // Get a random animal and animal color
+ int8 animalColor = _vm->_util->getRandom(7);
+ while ((colors[animalColor] == 1) || (colors[animalColor] == 7) || (colors[animalColor] == 11))
+ animalColor = _vm->_util->getRandom(7);
+
+ int8 animal = _vm->_util->getRandom(20);
+
+ int8 animalShape = shapes[animalColor * 20 + animal];
+ if (animal < 4)
+ animal = obfuscate[animal];
+
+ // Get the position of the animal sprite
+ int16 animalLeft = (animal % 4) * 80;
+ int16 animalTop = (animal / 4) * 50;
+
+ uint8 sprite = 0;
+ if (animalTop >= 200) {
+ animalTop -= 200;
+ sprite = 1;
+ }
+
+ int16 animalRight = animalLeft + 80 - 1;
+ int16 animalBottom = animalTop + 50 - 1;
+
+ // Fill with the animal color
+ _vm->_draw->_backSurface->fill(colors[animalColor]);
+
+ // Print the help line strings
+ for (uint i = 0; i < kCopyProtectionHelpStringCount; i++) {
+ const char * const helpString = kCopyProtectionHelpStrings[_vm->_global->_language][i];
+
+ const int x = 160 - (strlen(helpString) * _plettre->getCharWidth()) / 2;
+ const int y = i * 10 + 5;
+
+ _plettre->drawString(helpString, x, y, 8, 0, true, *_vm->_draw->_backSurface);
+ }
+
+ // White rectangle with black border
+ _vm->_draw->_backSurface->fillRect( 93, 43, 226, 134, 15);
+ _vm->_draw->_backSurface->drawRect( 92, 42, 227, 135, 0);
+
+ // Draw the animal in the animal color
+ _vm->_draw->_backSurface->fillRect(120, 63, 199, 112, colors[animalColor]);
+ _vm->_draw->_backSurface->blit(sprites[sprite], animalLeft, animalTop, animalRight, animalBottom, 120, 63, 0);
+
+ // Draw the shapes
+ for (uint i = 0; i < kCopyProtectionShapeCount; i++) {
+ const int16 * const coords = kCopyProtectionShapeCoords[i];
+
+ _vm->_draw->_backSurface->blit(sprites[1], coords[0], coords[1], coords[2], coords[3], coords[4], coords[5], 0);
+ }
+
+ _vm->_draw->forceBlit();
+
+ return animalShape;
+}
+
+int8 OnceUpon::cpFindShape(int16 x, int16 y) const {
+ // Look through all shapes and check if the coordinates are inside one of them
+ for (uint i = 0; i < kCopyProtectionShapeCount; i++) {
+ const int16 * const coords = kCopyProtectionShapeCoords[i];
+
+ const int16 left = coords[4];
+ const int16 top = coords[5];
+ const int16 right = coords[4] + (coords[2] - coords[0] + 1) - 1;
+ const int16 bottom = coords[5] + (coords[3] - coords[1] + 1) - 1;
+
+ if ((x >= left) && (x <= right) && (y >= top) && (y <= bottom))
+ return i;
+ }
+
+ return -1;
+}
+
+void OnceUpon::cpWrong() {
+ // Display the "You are wrong" string, centered
+
+ const char * const wrongString = kCopyProtectionWrongStrings[_vm->_global->_language];
+ const int wrongX = 160 - (strlen(wrongString) * _plettre->getCharWidth()) / 2;
+
+ _vm->_draw->_backSurface->clear();
+ _plettre->drawString(wrongString, wrongX, 100, 15, 0, true, *_vm->_draw->_backSurface);
+
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+
+ waitInput();
+
+ fadeOut();
+ clearScreen();
+}
+
+void OnceUpon::showIntro() {
+ // Show all intro parts
+
+ // "Loading"
+ showWait(10);
+ if (_vm->shouldQuit())
+ return;
+
+ // Quote about fairy tales
+ showQuote();
+ if (_vm->shouldQuit())
+ return;
+
+ // Once Upon A Time title
+ showTitle();
+ if (_vm->shouldQuit())
+ return;
+
+ // Game title screen
+ showChapter(0);
+ if (_vm->shouldQuit())
+ return;
+
+ // "Loading"
+ showWait(17);
+}
+
+void OnceUpon::showWait(uint palette) {
+ // Show the loading floppy
+
+ fadeOut();
+ clearScreen();
+ setGamePalette(palette);
+
+ Surface wait(320, 43, 1);
+
+ _vm->_video->drawPackedSprite("wait.cmp", wait);
+ _vm->_draw->_backSurface->blit(wait, 0, 0, 72, 33, 122, 84);
+
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+}
+
+void OnceUpon::showQuote() {
+ // Show the quote about fairytales
+
+ fadeOut();
+ clearScreen();
+ setGamePalette(11);
+
+ static const Font *fonts[3] = { _plettre, _glettre, _plettre };
+
+ TXTFile *quote = loadTXT(getLocFile("gene.tx"), TXTFile::kFormatStringPositionColorFont);
+ quote->draw(*_vm->_draw->_backSurface, fonts, ARRAYSIZE(fonts));
+ delete quote;
+
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+
+ waitInput();
+
+ fadeOut();
+}
+
+const PreGob::AnimProperties OnceUpon::kTitleAnimation = {
+ 8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0
+};
+
+void OnceUpon::showTitle() {
+ fadeOut();
+ setGamePalette(10);
+
+ Title title(_vm);
+ title.play();
+}
+
+void OnceUpon::showChapter(int chapter) {
+ // Display the intro text to a chapter
+
+ fadeOut();
+ clearScreen();
+ setGamePalette(11);
+
+ // Parchment background
+ _vm->_video->drawPackedSprite("parch.cmp", *_vm->_draw->_backSurface);
+
+ static const Font *fonts[3] = { _plettre, _glettre, _plettre };
+
+ const Common::String chapterFile = getLocFile(Common::String::format("gene%d.tx", chapter));
+
+ TXTFile *gameTitle = loadTXT(chapterFile, TXTFile::kFormatStringPositionColorFont);
+ gameTitle->draw(*_vm->_draw->_backSurface, fonts, ARRAYSIZE(fonts));
+ delete gameTitle;
+
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+
+ waitInput();
+
+ fadeOut();
+}
+
+void OnceUpon::showByeBye() {
+ fadeOut();
+ hideCursor();
+ clearScreen();
+ setGamePalette(1);
+
+ _plettre->drawString("Bye Bye....", 140, 80, 2, 0, true, *_vm->_draw->_backSurface);
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+
+ _vm->_util->longDelay(1000);
+
+ fadeOut();
+}
+
+void OnceUpon::doStartMenu(const MenuButton *animalsButton, uint animalCount,
+ const MenuButton *animalButtons, const char * const *animalNames) {
+ clearScreen();
+
+ // Wait until we clicked on of the difficulty buttons and are ready to start playing
+ while (!_vm->shouldQuit()) {
+ MenuAction action = handleStartMenu(animalsButton);
+ if (action == kMenuActionPlay)
+ break;
+
+ // If we pressed the "listen to animal names" button, handle that screen
+ if (action == kMenuActionAnimals)
+ handleAnimalNames(animalCount, animalButtons, animalNames);
+ }
+}
+
+OnceUpon::MenuAction OnceUpon::handleStartMenu(const MenuButton *animalsButton) {
+ ScreenBackup screenBackup;
+ backupScreen(screenBackup, true);
+
+ fadeOut();
+ setGamePalette(17);
+ drawStartMenu(animalsButton);
+ showCursor();
+ fadeIn();
+
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+ endFrame(true);
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+ if (key == kKeyEscape)
+ // ESC -> Quit
+ return kMenuActionQuit;
+
+ if (mouseButtons != kMouseButtonsLeft)
+ continue;
+
+ playSound(kSoundClick);
+
+ // If we clicked on a difficulty button, show the selected difficulty and start the game
+ int diff = checkButton(kMainMenuDifficultyButton, ARRAYSIZE(kMainMenuDifficultyButton), mouseX, mouseY);
+ if (diff >= 0) {
+ _difficulty = (Difficulty)diff;
+ action = kMenuActionPlay;
+
+ drawStartMenu(animalsButton);
+ _vm->_util->longDelay(1000);
+ }
+
+ if (animalsButton && (checkButton(animalsButton, 1, mouseX, mouseY) != -1))
+ action = kMenuActionAnimals;
+
+ }
+
+ fadeOut();
+ restoreScreen(screenBackup);
+
+ return action;
+}
+
+OnceUpon::MenuAction OnceUpon::handleMainMenu() {
+ ScreenBackup screenBackup;
+ backupScreen(screenBackup, true);
+
+ fadeOut();
+ setGamePalette(17);
+ drawMainMenu();
+ showCursor();
+ fadeIn();
+
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+ endFrame(true);
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+ if (key == kKeyEscape)
+ // ESC -> Quit
+ return kMenuActionQuit;
+
+ if (mouseButtons != kMouseButtonsLeft)
+ continue;
+
+ playSound(kSoundClick);
+
+ // If we clicked on a difficulty button, change the current difficulty level
+ int diff = checkButton(kMainMenuDifficultyButton, ARRAYSIZE(kMainMenuDifficultyButton), mouseX, mouseY);
+ if ((diff >= 0) && (diff != (int)_difficulty)) {
+ _difficulty = (Difficulty)diff;
+
+ drawMainMenu();
+ }
+
+ // If we clicked on a section button, restart the game from this section
+ int section = checkButton(kSectionButtons, ARRAYSIZE(kSectionButtons), mouseX, mouseY);
+ if ((section >= 0) && (section <= _section)) {
+ _section = section;
+ action = kMenuActionRestart;
+ }
+
+ }
+
+ fadeOut();
+ restoreScreen(screenBackup);
+
+ return action;
+}
+
+OnceUpon::MenuAction OnceUpon::handleIngameMenu() {
+ ScreenBackup screenBackup;
+ backupScreen(screenBackup, true);
+
+ drawIngameMenu();
+ showCursor();
+
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+ endFrame(true);
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+ if ((key == kKeyEscape) || (mouseButtons == kMouseButtonsRight))
+ // ESC or right mouse button -> Dismiss the menu
+ action = kMenuActionPlay;
+
+ if (mouseButtons != kMouseButtonsLeft)
+ continue;
+
+ int button = checkButton(kIngameButtons, ARRAYSIZE(kIngameButtons), mouseX, mouseY);
+ if (button == 0)
+ action = kMenuActionQuit;
+ else if (button == 1)
+ action = kMenuActionMainMenu;
+ else if (button == 2)
+ action = kMenuActionPlay;
+
+ }
+
+ clearIngameMenu(*screenBackup.screen);
+ restoreScreen(screenBackup);
+
+ return action;
+}
+
+void OnceUpon::drawStartMenu(const MenuButton *animalsButton) {
+ // Draw the background
+ _vm->_video->drawPackedSprite("menu2.cmp", *_vm->_draw->_backSurface);
+
+ // Draw the "Listen to animal names" button
+ if (animalsButton) {
+ Surface elements(320, 38, 1);
+ _vm->_video->drawPackedSprite("elemenu.cmp", elements);
+ _vm->_draw->_backSurface->fillRect(animalsButton->left , animalsButton->top,
+ animalsButton->right, animalsButton->bottom, 0);
+ drawButton(*_vm->_draw->_backSurface, elements, *animalsButton);
+ }
+
+ // Highlight the current difficulty
+ drawMenuDifficulty();
+
+ _vm->_draw->forceBlit();
+}
+
+void OnceUpon::drawMainMenu() {
+ // Draw the background
+ _vm->_video->drawPackedSprite("menu.cmp", *_vm->_draw->_backSurface);
+
+ // Highlight the current difficulty
+ drawMenuDifficulty();
+
+ // Draw the section buttons
+ Surface elements(320, 200, 1);
+ _vm->_video->drawPackedSprite("elemenu.cmp", elements);
+
+ for (uint i = 0; i < ARRAYSIZE(kSectionButtons); i++) {
+ const MenuButton &button = kSectionButtons[i];
+
+ if (!button.needDraw)
+ continue;
+
+ if (_section >= (int)button.id)
+ drawButton(*_vm->_draw->_backSurface, elements, button);
+ }
+
+ _vm->_draw->forceBlit();
+}
+
+void OnceUpon::drawIngameMenu() {
+ Surface menu(320, 34, 1);
+ _vm->_video->drawPackedSprite("icon.cmp", menu);
+
+ // Draw the menu in a special way, button by button
+ for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
+ const MenuButton &button = kIngameButtons[i];
+
+ drawLineByLine(menu, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom,
+ button.dstX, button.dstY);
+ }
+
+ _vm->_draw->forceBlit();
+ _vm->_video->retrace();
+}
+
+void OnceUpon::drawMenuDifficulty() {
+ if (_difficulty == kDifficultyCount)
+ return;
+
+ TXTFile *difficulties = loadTXT(getLocFile("diffic.tx"), TXTFile::kFormatStringPositionColor);
+
+ // Draw the difficulty name
+ difficulties->draw((uint) _difficulty, *_vm->_draw->_backSurface, &_plettre, 1);
+
+ // Draw a border around the current difficulty
+ drawButtonBorder(kMainMenuDifficultyButton[_difficulty], difficulties->getLines()[_difficulty].color);
+
+ delete difficulties;
+}
+
+void OnceUpon::clearIngameMenu(const Surface &background) {
+ if (_vm->shouldQuit())
+ return;
+
+ // Find the area encompassing the whole ingame menu
+
+ int16 left = 0x7FFF;
+ int16 top = 0x7FFF;
+ int16 right = 0x0000;
+ int16 bottom = 0x0000;
+
+ for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
+ const MenuButton &button = kIngameButtons[i];
+
+ if (!button.needDraw)
+ continue;
+
+ left = MIN<int16>(left , button.dstX);
+ top = MIN<int16>(top , button.dstY);
+ right = MAX<int16>(right , button.dstX + (button.srcRight - button.srcLeft + 1) - 1);
+ bottom = MAX<int16>(bottom, button.dstY + (button.srcBottom - button.srcTop + 1) - 1);
+ }
+
+ if ((left > right) || (top > bottom))
+ return;
+
+ // Clear it line by line
+ drawLineByLine(background, left, top, right, bottom, left, top);
+}
+
+OnceUpon::MenuAction OnceUpon::doIngameMenu() {
+ // Show the ingame menu
+ MenuAction action = handleIngameMenu();
+
+ if ((action == kMenuActionQuit) || _vm->shouldQuit()) {
+
+ // User pressed the quit button, or quit ScummVM
+ _quit = true;
+ action = kMenuActionQuit;
+
+ } else if (action == kMenuActionPlay) {
+
+ // User pressed the return to game button
+ action = kMenuActionPlay;
+
+ } else if (kMenuActionMainMenu) {
+
+ // User pressed the return to main menu button
+ action = handleMainMenu();
+ }
+
+ return action;
+}
+
+OnceUpon::MenuAction OnceUpon::doIngameMenu(int16 &key, MouseButtons &mouseButtons) {
+ if ((key != kKeyEscape) && (mouseButtons != kMouseButtonsRight))
+ return kMenuActionNone;
+
+ key = 0;
+ mouseButtons = kMouseButtonsNone;
+
+ MenuAction action = doIngameMenu();
+ if (action == kMenuActionPlay)
+ action = kMenuActionNone;
+
+ return action;
+}
+
+int OnceUpon::checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue) const {
+ // Look through all buttons, and return the ID of the button we're in
+
+ for (uint i = 0; i < count; i++) {
+ const MenuButton &button = buttons[i];
+
+ if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom))
+ return (int)button.id;
+ }
+
+ // We're in none of these buttons, return the fail value
+ return failValue;
+}
+
+void OnceUpon::drawButton(Surface &dest, const Surface &src, const MenuButton &button, int transp) const {
+ dest.blit(src, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom, button.dstX, button.dstY, transp);
+}
+
+void OnceUpon::drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count, int transp) const {
+ for (uint i = 0; i < count; i++) {
+ const MenuButton &button = buttons[i];
+
+ if (!button.needDraw)
+ continue;
+
+ drawButton(dest, src, button, transp);
+ }
+}
+
+void OnceUpon::drawButtonBorder(const MenuButton &button, uint8 color) {
+ _vm->_draw->_backSurface->drawRect(button.left, button.top, button.right, button.bottom, color);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, button.left, button.top, button.right, button.bottom);
+}
+
+enum AnimalNamesState {
+ kANStateChoose, // We're in the animal chooser
+ kANStateNames, // We're in the language chooser
+ kANStateFinish // We're finished
+};
+
+void OnceUpon::handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names) {
+ fadeOut();
+ clearScreen();
+ setGamePalette(19);
+
+ bool cursorVisible = isCursorVisible();
+
+ // Set the cursor
+ addCursor();
+ setGameCursor();
+
+ anSetupChooser();
+
+ int8 _animal = -1;
+
+ AnimalNamesState state = kANStateChoose;
+ while (!_vm->shouldQuit() && (state != kANStateFinish)) {
+ showCursor();
+ fadeIn();
+
+ endFrame(true);
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ checkInput(mouseX, mouseY, mouseButtons);
+
+ // If we moused over an animal button, draw a border around it
+ int animal = checkButton(buttons, count, mouseX, mouseY);
+ if ((state == kANStateChoose) && (animal != _animal)) {
+ // Erase the old border
+ if (_animal >= 0)
+ drawButtonBorder(buttons[_animal], 15);
+
+ _animal = animal;
+
+ // Draw the new border
+ if (_animal >= 0)
+ drawButtonBorder(buttons[_animal], 10);
+ }
+
+ if (mouseButtons != kMouseButtonsLeft)
+ continue;
+
+ playSound(kSoundClick);
+
+ // We clicked on a language button, play the animal name
+ int language = checkButton(kLanguageButtons, ARRAYSIZE(kLanguageButtons), mouseX, mouseY);
+ if ((state == kANStateNames) && (language >= 0))
+ anPlayAnimalName(names[_animal], language);
+
+ // We clicked on an animal
+ if ((state == kANStateChoose) && (_animal >= 0)) {
+ anSetupNames(buttons[_animal]);
+
+ state = kANStateNames;
+ }
+
+ // If we clicked on the back button, go back
+ if (checkButton(&kAnimalNamesBack, 1, mouseX, mouseY) != -1) {
+ if (state == kANStateNames) {
+ anSetupChooser();
+
+ state = kANStateChoose;
+ } else if (state == kANStateChoose)
+ state = kANStateFinish;
+ }
+ }
+
+ fadeOut();
+
+ // Restore the cursor
+ if (!cursorVisible)
+ hideCursor();
+ removeCursor();
+}
+
+void OnceUpon::anSetupChooser() {
+ fadeOut();
+
+ _vm->_video->drawPackedSprite("dico.cmp", *_vm->_draw->_backSurface);
+
+ // Draw the back button
+ Surface menu(320, 34, 1);
+ _vm->_video->drawPackedSprite("icon.cmp", menu);
+ drawButton(*_vm->_draw->_backSurface, menu, kAnimalNamesBack);
+
+ // "Choose an animal"
+ TXTFile *choose = loadTXT(getLocFile("choisi.tx"), TXTFile::kFormatStringPosition);
+ choose->draw(*_vm->_draw->_backSurface, &_plettre, 1, 14);
+ delete choose;
+
+ _vm->_draw->forceBlit();
+}
+
+void OnceUpon::anSetupNames(const MenuButton &animal) {
+ fadeOut();
+
+ Surface background(320, 200, 1);
+
+ _vm->_video->drawPackedSprite("dico.cmp", background);
+
+ // Draw the background and clear what we don't need
+ _vm->_draw->_backSurface->blit(background);
+ _vm->_draw->_backSurface->fillRect(19, 19, 302, 186, 15);
+
+ // Draw the back button
+ Surface menu(320, 34, 1);
+ _vm->_video->drawPackedSprite("icon.cmp", menu);
+ drawButton(*_vm->_draw->_backSurface, menu, kAnimalNamesBack);
+
+ // Draw the animal
+ drawButton(*_vm->_draw->_backSurface, background, animal);
+
+ // Draw the language buttons
+ Surface elements(320, 200, 1);
+ _vm->_video->drawPackedSprite("elemenu.cmp", elements);
+ drawButtons(*_vm->_draw->_backSurface, elements, kLanguageButtons, ARRAYSIZE(kLanguageButtons));
+
+ // Draw the language names
+ _plettre->drawString("Fran\207ais", 43, 70, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("Deutsch" , 136, 70, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("English" , 238, 70, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("Italiano" , 43, 128, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("Espa\244ol" , 136, 128, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("English" , 238, 128, 10, 15, true, *_vm->_draw->_backSurface);
+
+ _vm->_draw->forceBlit();
+}
+
+void OnceUpon::anPlayAnimalName(const Common::String &animal, uint language) {
+ // Sound file to play
+ Common::String soundFile = animal + "_" + kLanguageSuffixLong[language] + ".snd";
+
+ // Get the name of the animal
+ TXTFile *names = loadTXT(animal + ".anm", TXTFile::kFormatString);
+ Common::String name = names->getLines()[language].text;
+ delete names;
+
+ // It should be centered on the screen
+ const int nameX = 160 - (name.size() * _plettre->getCharWidth()) / 2;
+
+ // Backup the screen surface
+ Surface backup(162, 23, 1);
+ backup.blit(*_vm->_draw->_backSurface, 78, 123, 239, 145, 0, 0);
+
+ // Draw the name border
+ Surface nameBorder(162, 23, 1);
+ _vm->_video->drawPackedSprite("mot.cmp", nameBorder);
+ _vm->_draw->_backSurface->blit(nameBorder, 0, 0, 161, 22, 78, 123);
+
+ // Print the animal name
+ _plettre->drawString(name, nameX, 129, 10, 0, true, *_vm->_draw->_backSurface);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145);
+
+ playSoundFile(soundFile);
+
+ // Restore the screen
+ _vm->_draw->_backSurface->blit(backup, 0, 0, 161, 22, 78, 123);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145);
+}
+
+void OnceUpon::playGame() {
+ while (!_vm->shouldQuit() && !_quit) {
+ // Play a section and advance to the next section if we finished it
+ if (playSection())
+ _section = MIN(_section + 1, kSectionCount - 1);
+ }
+
+ // If we quit through the game and not through ScummVM, show the "Bye Bye" screen
+ if (!_vm->shouldQuit())
+ showByeBye();
+}
+
+bool OnceUpon::playSection() {
+ if ((_section < 0) || (_section >= ARRAYSIZE(kSectionFuncs))) {
+ _quit = true;
+ return false;
+ }
+
+ return (this->*kSectionFuncs[_section])();
+}
+
+const PreGob::AnimProperties OnceUpon::kSectionStorkAnimations[] = {
+ { 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 2, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 3, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 4, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 5, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 7, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ {17, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ {16, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ {15, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}
+};
+
+enum StorkState {
+ kStorkStateWaitUser,
+ kStorkStateWaitBundle,
+ kStorkStateFinish
+};
+
+bool OnceUpon::sectionStork() {
+ fadeOut();
+ hideCursor();
+ setGamePalette(0);
+ setGameCursor();
+
+ const StorkParam &param = getStorkParameters();
+
+ Surface backdrop(320, 200, 1);
+
+ // Draw the frame
+ _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+
+ // Draw the backdrop
+ _vm->_video->drawPackedSprite(param.backdrop, backdrop);
+ _vm->_draw->_backSurface->blit(backdrop, 0, 0, 288, 175, 16, 12);
+
+ // "Where does the stork go?"
+ TXTFile *whereStork = loadTXT(getLocFile("ouva.tx"), TXTFile::kFormatStringPositionColor);
+ whereStork->draw(*_vm->_draw->_backSurface, &_plettre, 1);
+
+ // Where the stork actually goes
+ GCTFile *thereStork = loadGCT(getLocFile("choix.gc"));
+ thereStork->setArea(17, 18, 303, 41);
+
+ ANIFile ani(_vm, "present.ani", 320);
+ ANIList anims;
+
+ Stork *stork = new Stork(_vm, ani);
+
+ loadAnims(anims, ani, ARRAYSIZE(kSectionStorkAnimations), kSectionStorkAnimations);
+ anims.push_back(stork);
+
+ drawAnim(anims);
+
+ _vm->_draw->forceBlit();
+
+ int8 storkSoundWait = 0;
+
+ StorkState state = kStorkStateWaitUser;
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (state != kStorkStateFinish)) {
+ // Play the stork sound
+ if (--storkSoundWait == 0)
+ playSound(kSoundStork);
+ if (storkSoundWait <= 0)
+ storkSoundWait = 50 - _vm->_util->getRandom(30);
+
+ // Check if the bundle landed
+ if ((state == kStorkStateWaitBundle) && stork->hasBundleLanded())
+ state = kStorkStateFinish;
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+
+ action = doIngameMenu(key, mouseButtons);
+ if (action != kMenuActionNone) {
+ state = kStorkStateFinish;
+ break;
+ }
+
+ clearAnim(anims);
+
+ if (mouseButtons == kMouseButtonsLeft) {
+ stopSound();
+ playSound(kSoundClick);
+
+ int house = checkButton(param.houses, param.houseCount, mouseX, mouseY);
+ if ((state == kStorkStateWaitUser) && (house >= 0)) {
+
+ _house = house;
+
+ stork->dropBundle(param.drops[house]);
+ state = kStorkStateWaitBundle;
+
+ // Remove the "Where does the stork go?" text
+ int16 left, top, right, bottom;
+ if (whereStork->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+ // Print the text where the stork actually goes
+ thereStork->selectLine(3, house); // The house
+ thereStork->selectLine(4, house); // The house's inhabitants
+ if (thereStork->draw(*_vm->_draw->_backSurface, 2, *_plettre, 10, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ }
+ }
+
+ drawAnim(anims);
+ showCursor();
+ fadeIn();
+
+ endFrame(true);
+ }
+
+ freeAnims(anims);
+ delete thereStork;
+ delete whereStork;
+
+ fadeOut();
+ hideCursor();
+
+ // Didn't complete the section
+ if (action != kMenuActionNone)
+ return false;
+
+ // Move on to the character generator
+
+ CharGenAction charGenAction = kCharGenRestart;
+ while (charGenAction == kCharGenRestart)
+ charGenAction = characterGenerator();
+
+ // Did we successfully create a character?
+ return charGenAction == kCharGenDone;
+}
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHeadButtons[] = {
+ {true, 106, 146, 152, 180, 0, 0, 47, 34, 106, 146, 0},
+ {true, 155, 146, 201, 180, 49, 0, 96, 34, 155, 146, 1},
+ {true, 204, 146, 250, 180, 98, 0, 145, 34, 204, 146, 2},
+ {true, 253, 146, 299, 180, 147, 0, 194, 34, 253, 146, 3}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHeads[] = {
+ {true, 0, 0, 0, 0, 29, 4, 68, 31, 40, 51, 0},
+ {true, 0, 0, 0, 0, 83, 4, 113, 31, 45, 51, 1},
+ {true, 0, 0, 0, 0, 132, 4, 162, 31, 45, 51, 2},
+ {true, 0, 0, 0, 0, 182, 4, 211, 31, 45, 51, 3}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHairButtons[] = {
+ {true, 105, 55, 124, 70, 271, 1, 289, 15, 105, 55, 0x04},
+ {true, 105, 74, 124, 89, 271, 20, 289, 34, 105, 74, 0x07}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenJacketButtons[] = {
+ {true, 105, 90, 124, 105, 271, 39, 289, 53, 105, 90, 0x06},
+ {true, 105, 109, 124, 124, 271, 58, 289, 72, 105, 109, 0x02}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenTrousersButtons[] = {
+ {true, 105, 140, 124, 155, 271, 77, 289, 91, 105, 140, 0x01},
+ {true, 105, 159, 124, 174, 271, 96, 289, 110, 105, 159, 0x03}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenNameEntry[] = {
+ {true, 0, 0, 0, 0, 0, 38, 54, 48, 140, 145, 0},
+ {true, 0, 0, 0, 0, 106, 38, 159, 48, 195, 145, 0},
+ {true, 0, 0, 0, 0, 0, 105, 54, 121, 140, 156, 0},
+ {true, 0, 0, 0, 0, 106, 105, 159, 121, 195, 156, 0}
+};
+
+enum CharGenState {
+ kCharGenStateHead = 0, // Choose a head
+ kCharGenStateHair , // Choose hair color
+ kCharGenStateJacket , // Choose jacket color
+ kCharGenStateTrousers , // Choose trousers color
+ kCharGenStateName , // Choose name
+ kCharGenStateSure , // "Are you sure?"
+ kCharGenStateStoryName , // "We're going to tell the story of $NAME"
+ kCharGenStateFinish // Finished
+};
+
+void OnceUpon::charGenSetup(uint stage) {
+ Surface choix(320, 200, 1), elchoix(320, 200, 1), paperDoll(65, 137, 1);
+
+ _vm->_video->drawPackedSprite("choix.cmp" , choix);
+ _vm->_video->drawPackedSprite("elchoix.cmp", elchoix);
+
+ paperDoll.blit(choix, 200, 0, 264, 136, 0, 0);
+
+ GCTFile *text = loadGCT(getLocFile("choix.gc"));
+ text->setArea(17, 18, 303, 41);
+ text->setText(9, _name);
+
+ // Background
+ _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+ _vm->_draw->_backSurface->fillRect(16, 50, 303, 187, 5);
+
+ // Character sprite frame
+ _vm->_draw->_backSurface->blit(choix, 0, 38, 159, 121, 140, 54);
+
+ // Recolor the paper doll parts
+ if (_colorHair != 0xFF)
+ elchoix.recolor(0x0C, _colorHair);
+
+ if (_colorJacket != 0xFF)
+ paperDoll.recolor(0x0A, _colorJacket);
+
+ if (_colorTrousers != 0xFF)
+ paperDoll.recolor(0x09, _colorTrousers);
+
+ _vm->_draw->_backSurface->blit(paperDoll, 32, 51);
+
+ // Paper doll head
+ if (_head != 0xFF)
+ drawButton(*_vm->_draw->_backSurface, elchoix, kCharGenHeads[_head], 0);
+
+ if (stage == kCharGenStateHead) {
+ // Head buttons
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenHeadButtons, ARRAYSIZE(kCharGenHeadButtons));
+
+ // "Choose a head"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 5, *_plettre, 10, left, top, right, bottom);
+
+ } else if (stage == kCharGenStateHair) {
+ // Hair color buttons
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenHairButtons, ARRAYSIZE(kCharGenHairButtons));
+
+ // "What color is the hair?"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 6, *_plettre, 10, left, top, right, bottom);
+
+ } else if (stage == kCharGenStateJacket) {
+ // Jacket color buttons
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenJacketButtons, ARRAYSIZE(kCharGenJacketButtons));
+
+ // "What color is the jacket?"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 7, *_plettre, 10, left, top, right, bottom);
+
+ } else if (stage == kCharGenStateTrousers) {
+ // Trousers color buttons
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons));
+
+ // "What color are the trousers?"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 8, *_plettre, 10, left, top, right, bottom);
+
+ } else if (stage == kCharGenStateName) {
+ // Name entry field
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenNameEntry, ARRAYSIZE(kCharGenNameEntry));
+
+ // "Enter name"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 10, *_plettre, 10, left, top, right, bottom);
+
+ charGenDrawName();
+ } else if (stage == kCharGenStateSure) {
+ // Name entry field
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenNameEntry, ARRAYSIZE(kCharGenNameEntry));
+
+ // "Are you sure?"
+ TXTFile *sure = loadTXT(getLocFile("estu.tx"), TXTFile::kFormatStringPositionColor);
+ sure->draw(*_vm->_draw->_backSurface, &_plettre, 1);
+ delete sure;
+
+ charGenDrawName();
+ } else if (stage == kCharGenStateStoryName) {
+
+ // "We're going to tell the story of $NAME"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 11, *_plettre, 10, left, top, right, bottom);
+ }
+
+ delete text;
+}
+
+bool OnceUpon::enterString(Common::String &name, int16 key, uint maxLength, const Font &font) {
+ if (key == 0)
+ return true;
+
+ if (key == kKeyBackspace) {
+ name.deleteLastChar();
+ return true;
+ }
+
+ if (key == kKeySpace)
+ key = ' ';
+
+ if ((key >= ' ') && (key <= 0xFF)) {
+ if (name.size() >= maxLength)
+ return false;
+
+ if (!font.hasChar(key))
+ return false;
+
+ name += (char) key;
+ return true;
+ }
+
+ return false;
+}
+
+void OnceUpon::charGenDrawName() {
+ _vm->_draw->_backSurface->fillRect(147, 151, 243, 166, 1);
+
+ const int16 nameY = 151 + ((166 - 151 + 1 - _plettre->getCharHeight()) / 2);
+ const int16 nameX = 147 + ((243 - 147 + 1 - (15 * _plettre->getCharWidth ())) / 2);
+
+ _plettre->drawString(_name, nameX, nameY, 10, 0, true, *_vm->_draw->_backSurface);
+
+ const int16 cursorLeft = nameX + _name.size() * _plettre->getCharWidth();
+ const int16 cursorTop = nameY;
+ const int16 cursorRight = cursorLeft + _plettre->getCharWidth() - 1;
+ const int16 cursorBottom = cursorTop + _plettre->getCharHeight() - 1;
+
+ _vm->_draw->_backSurface->fillRect(cursorLeft, cursorTop, cursorRight, cursorBottom, 10);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 151, 243, 166);
+}
+
+OnceUpon::CharGenAction OnceUpon::characterGenerator() {
+ fadeOut();
+ hideCursor();
+ setGameCursor();
+
+ showWait(1);
+
+ _name.clear();
+
+ _head = 0xFF;
+ _colorHair = 0xFF;
+ _colorJacket = 0xFF;
+ _colorTrousers = 0xFF;
+
+ CharGenState state = kCharGenStateHead;
+ charGenSetup(state);
+
+ ANIFile ani(_vm, "ba.ani", 320);
+
+ ani.recolor(0x0F, 0x0C);
+ ani.recolor(0x0E, 0x0A);
+ ani.recolor(0x08, 0x09);
+
+ CharGenChild *child = new CharGenChild(ani);
+
+ ANIList anims;
+ anims.push_back(child);
+
+ fadeOut();
+ _vm->_draw->forceBlit();
+
+ CharGenAction action = kCharGenRestart;
+ while (!_vm->shouldQuit() && (state != kCharGenStateFinish)) {
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+
+ MenuAction menuAction = doIngameMenu(key, mouseButtons);
+ if (menuAction != kMenuActionNone) {
+ state = kCharGenStateFinish;
+ action = kCharGenAbort;
+ break;
+ }
+
+ clearAnim(anims);
+
+ if (state == kCharGenStateStoryName) {
+ if ((mouseButtons != kMouseButtonsNone) || (key != 0)) {
+ state = kCharGenStateFinish;
+ action = kCharGenDone;
+ break;
+ }
+ }
+
+ if (state == kCharGenStateSure) {
+ // Not sure => restart
+ if ((key == 'N') || (key == 'n')) { // No / Nein / Non
+ state = kCharGenStateFinish;
+ action = kCharGenRestart;
+ break;
+ }
+
+ if ((key == 'Y') || (key == 'y') || // Yes
+ (key == 'J') || (key == 'j') || // Ja
+ (key == 'S') || (key == 's') || // Si
+ (key == 'O') || (key == 'o')) { // Oui
+
+ state = kCharGenStateStoryName;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+ }
+
+ if (state == kCharGenStateName) {
+ if (enterString(_name, key, 14, *_plettre)) {
+ _vm->_draw->_backSurface->fillRect(147, 151, 243, 166, 1);
+
+ const int16 nameY = 151 + ((166 - 151 + 1 - _plettre->getCharHeight()) / 2);
+ const int16 nameX = 147 + ((243 - 147 + 1 - (15 * _plettre->getCharWidth ())) / 2);
+
+ _plettre->drawString(_name, nameX, nameY, 10, 0, true, *_vm->_draw->_backSurface);
+
+ const int16 cursorLeft = nameX + _name.size() * _plettre->getCharWidth();
+ const int16 cursorTop = nameY;
+ const int16 cursorRight = cursorLeft + _plettre->getCharWidth() - 1;
+ const int16 cursorBottom = cursorTop + _plettre->getCharHeight() - 1;
+
+ _vm->_draw->_backSurface->fillRect(cursorLeft, cursorTop, cursorRight, cursorBottom, 10);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 151, 243, 166);
+ }
+
+ if ((key == kKeyReturn) && !_name.empty()) {
+ _name.trim();
+ _name.setChar(Util::toCP850Upper(_name[0]), 0);
+
+ state = kCharGenStateSure;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+ }
+
+ if (mouseButtons == kMouseButtonsLeft) {
+ stopSound();
+ playSound(kSoundClick);
+
+ int trousers = checkButton(kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons), mouseX, mouseY);
+ if ((state == kCharGenStateTrousers) && (trousers >= 0)) {
+ _colorTrousers = trousers;
+
+ ani.recolor(0x09, _colorTrousers);
+
+ state = kCharGenStateName;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+
+ int jacket = checkButton(kCharGenJacketButtons, ARRAYSIZE(kCharGenJacketButtons), mouseX, mouseY);
+ if ((state == kCharGenStateJacket) && (jacket >= 0)) {
+ _colorJacket = jacket;
+
+ ani.recolor(0x0A, _colorJacket);
+
+ state = kCharGenStateTrousers;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+
+ int hair = checkButton(kCharGenHairButtons, ARRAYSIZE(kCharGenHairButtons), mouseX, mouseY);
+ if ((state == kCharGenStateHair) && (hair >= 0)) {
+ _colorHair = hair;
+
+ ani.recolor(0x0C, _colorHair);
+
+ state = kCharGenStateJacket;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+
+ int head = checkButton(kCharGenHeadButtons, ARRAYSIZE(kCharGenHeadButtons), mouseX, mouseY);
+ if ((state == kCharGenStateHead) && (head >= 0)) {
+ _head = head;
+
+ state = kCharGenStateHair;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+ }
+
+ drawAnim(anims);
+
+ // Play the child sounds
+ CharGenChild::Sound childSound = child->shouldPlaySound();
+ if (childSound == CharGenChild::kSoundWalk) {
+ beep(50, 10);
+ } else if (childSound == CharGenChild::kSoundJump) {
+ stopSound();
+ playSound(kSoundJump);
+ }
+
+ showCursor();
+ fadeIn();
+
+ endFrame(true);
+ }
+
+ fadeOut();
+ hideCursor();
+
+ freeAnims(anims);
+
+ if (_vm->shouldQuit())
+ return kCharGenAbort;
+
+ return action;
+}
+
+bool OnceUpon::sectionChapter1() {
+ showChapter(1);
+ return true;
+}
+
+bool OnceUpon::sectionParents() {
+ fadeOut();
+ setGamePalette(14);
+ clearScreen();
+
+ const Common::String seq = ((_house == 1) || (_house == 2)) ? "parents.seq" : "parents2.seq";
+ const Common::String gct = getLocFile("mefait.gc");
+
+ Parents parents(_vm, seq, gct, _name, _house, *_plettre, kGamePalettes[14], kGamePalettes[13], kPaletteSize);
+ parents.play();
+
+ warning("OnceUpon::sectionParents(): TODO: Item search");
+ return true;
+}
+
+bool OnceUpon::sectionChapter2() {
+ showChapter(2);
+ return true;
+}
+
+bool OnceUpon::sectionForest0() {
+ warning("OnceUpon::sectionForest0(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter3() {
+ showChapter(3);
+ return true;
+}
+
+bool OnceUpon::sectionEvilCastle() {
+ warning("OnceUpon::sectionEvilCastle(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter4() {
+ showChapter(4);
+ return true;
+}
+
+bool OnceUpon::sectionForest1() {
+ warning("OnceUpon::sectionForest1(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter5() {
+ showChapter(5);
+ return true;
+}
+
+bool OnceUpon::sectionBossFight() {
+ warning("OnceUpon::sectionBossFight(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter6() {
+ showChapter(6);
+ return true;
+}
+
+bool OnceUpon::sectionForest2() {
+ warning("OnceUpon::sectionForest2(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter7() {
+ showChapter(7);
+ return true;
+}
+
+const PreGob::AnimProperties OnceUpon::kSectionEndAnimations[] = {
+ { 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 9, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ {11, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}
+};
+
+bool OnceUpon::sectionEnd() {
+ fadeOut();
+ setGamePalette(9);
+
+ _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+
+ Surface endBackground(320, 200, 1);
+ _vm->_video->drawPackedSprite("fin.cmp", endBackground);
+
+ _vm->_draw->_backSurface->blit(endBackground, 0, 0, 288, 137, 16, 50);
+
+ GCTFile *endText = loadGCT(getLocFile("final.gc"));
+ endText->setArea(17, 18, 303, 41);
+ endText->setText(1, _name);
+
+ ANIFile ani(_vm, "fin.ani", 320);
+ ANIList anims;
+
+ loadAnims(anims, ani, ARRAYSIZE(kSectionEndAnimations), kSectionEndAnimations);
+ drawAnim(anims);
+
+ _vm->_draw->forceBlit();
+
+ uint32 textStartTime = 0;
+
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+
+ action = doIngameMenu(key, mouseButtons);
+ if (action != kMenuActionNone)
+ break;
+
+ clearAnim(anims);
+
+ // Pressed a key or mouse button => Skip to next area-full of text
+ if ((mouseButtons == kMouseButtonsLeft) || (key != 0))
+ textStartTime = 0;
+
+ // Draw the next area-full of text
+ uint32 now = _vm->_util->getTimeKey();
+ if (!endText->finished() && ((textStartTime == 0) || (now >= (textStartTime + kGCTDelay)))) {
+ textStartTime = now;
+
+ int16 left, top, right, bottom;
+ if (endText->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+ if (endText->draw(*_vm->_draw->_backSurface, 0, *_plettre, 10, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ }
+
+ drawAnim(anims);
+ fadeIn();
+
+ endFrame(true);
+ }
+
+ freeAnims(anims);
+ delete endText;
+
+ // Restart requested
+ if (action == kMenuActionRestart)
+ return false;
+
+ // Last scene. Even if we didn't explicitly request a quit, the game ends here
+ _quit = true;
+ return false;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
new file mode 100644
index 0000000000..66ef877618
--- /dev/null
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -0,0 +1,344 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_ONCEUPON_H
+#define GOB_PREGOB_ONCEUPON_ONCEUPON_H
+
+#include "common/system.h"
+#include "common/str.h"
+
+#include "gob/pregob/pregob.h"
+
+#include "gob/pregob/onceupon/stork.h"
+
+namespace Gob {
+
+class Surface;
+class Font;
+
+class ANIObject;
+
+namespace OnceUpon {
+
+class OnceUpon : public PreGob {
+public:
+ /** Number of languages we support. */
+ static const uint kLanguageCount = 5;
+
+
+ OnceUpon(GobEngine *vm);
+ ~OnceUpon();
+
+
+protected:
+ /** A description of a menu button. */
+ struct MenuButton {
+ bool needDraw; ///< Does the button need drawing?
+
+ int16 left; ///< Left coordinate of the button.
+ int16 top; ///< Top coordinate of the button.
+ int16 right; ///< Right coordinate of the button.
+ int16 bottom; ///< Bottom coordinate of the button.
+
+ int16 srcLeft; ///< Left coordinate of the button's sprite.
+ int16 srcTop; ///< Top coordinate of the button's sprite.
+ int16 srcRight; ///< Right coordinate of the button's sprite.
+ int16 srcBottom; ///< Right coordinate of the button's sprite.
+
+ int16 dstX; ///< Destination X coordinate of the button's sprite.
+ int16 dstY; ///< Destination Y coordinate of the button's sprite.
+
+ uint id; ///< The button's ID.
+ };
+
+ /** Parameters for the stork section. */
+ struct StorkParam {
+ const char *backdrop; ///< Backdrop image file.
+
+ uint houseCount; ///< Number of houses.
+ const MenuButton *houses; ///< House button definitions.
+
+ const Stork::BundleDrop *drops; ///< The bundle drop parameters.
+ };
+
+ void init();
+ void deinit();
+
+ /** Handle the copy protection.
+ *
+ * @param colors Colors the copy protection animals can be.
+ * @param shapes The shape that's the correct answer for each animal in each color.
+ * @param obfuscate Extra obfuscate table. correctShape = shapes[colors][obfuscate[animal]].
+ * @return true if the user guessed the correct shape, false otherwise.
+ */
+ bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
+
+ /** Show the intro. */
+ void showIntro();
+
+ /** Handle the start menu.
+ *
+ * @param animalsButton Definition of the menu button that leads to the animal names screen. Can be 0.
+ * @param animalCount Number of animals in the animal names screen.
+ * @param animalButtons Definition of the buttons that make up the animals in the animal names screen.
+ * @param animalNames File prefixes for the name of each animal.
+ */
+ void doStartMenu(const MenuButton *animalsButton, uint animalCount,
+ const MenuButton *animalButtons, const char * const *animalNames);
+
+ /** Play the game proper. */
+ void playGame();
+
+
+ /** Return the parameters for the stork section. */
+ virtual const StorkParam &getStorkParameters() const = 0;
+
+
+private:
+ /** All actions a user can request in a menu. */
+ enum MenuAction {
+ kMenuActionNone = 0, ///< No action.
+ kMenuActionAnimals , ///< Do the animal names.
+ kMenuActionPlay , ///< Play the game.
+ kMenuActionRestart , ///< Restart the section.
+ kMenuActionMainMenu, ///< Go to the main menu.
+ kMenuActionQuit ///< Quit the game.
+ };
+
+ /** Difficulty levels. */
+ enum Difficulty {
+ kDifficultyBeginner = 0,
+ kDifficultyIntermediate = 1,
+ kDifficultyAdvanced = 2,
+ kDifficultyCount
+ };
+
+ /** The different sounds common in the game. */
+ enum Sound {
+ kSoundClick = 0,
+ kSoundStork ,
+ kSoundJump ,
+ kSoundCount
+ };
+
+ /** Action the character generation wants us to take. */
+ enum CharGenAction {
+ kCharGenDone = 0, ///< Created a character, move on.
+ kCharGenAbort , ///< Aborted the character generation.
+ kCharGenRestart ///< Restart the character generation.
+ };
+
+ /** A complete screen backup. */
+ struct ScreenBackup {
+ Surface *screen; ///< Screen contents.
+ int palette; ///< Screen palette.
+
+ bool changedCursor; ///< Did we change the cursor?
+ bool cursorVisible; ///< Was the cursor visible?
+
+ ScreenBackup();
+ ~ScreenBackup();
+ };
+
+
+ /** The number of game sections. */
+ static const int kSectionCount = 15;
+
+ static const MenuButton kMainMenuDifficultyButton[]; ///< Difficulty buttons.
+ static const MenuButton kSectionButtons[]; ///< Section buttons.
+
+ static const MenuButton kIngameButtons[]; ///< Ingame menu buttons.
+
+ static const MenuButton kAnimalNamesBack; ///< "Back" button in the animal names screens.
+ static const MenuButton kLanguageButtons[]; ///< Language buttons in the animal names screen.
+
+ static const MenuButton kSectionStorkHouses[];
+
+ static const MenuButton kCharGenHeadButtons[];
+ static const MenuButton kCharGenHeads[];
+ static const MenuButton kCharGenHairButtons[];
+ static const MenuButton kCharGenJacketButtons[];
+ static const MenuButton kCharGenTrousersButtons[];
+ static const MenuButton kCharGenNameEntry[];
+
+ /** All general game sounds we know about. */
+ static const char *kSound[kSoundCount];
+
+
+ static const AnimProperties kClownAnimations[];
+ static const AnimProperties kTitleAnimation;
+ static const AnimProperties kSectionStorkAnimations[];
+ static const AnimProperties kSectionEndAnimations[];
+
+
+ /** Function pointer type for a section handler. */
+ typedef bool (OnceUpon::*SectionFunc)();
+ /** Section handler function. */
+ static const SectionFunc kSectionFuncs[kSectionCount];
+
+
+ /** Did we open the game archives? */
+ bool _openedArchives;
+
+ // Fonts
+ Font *_jeudak;
+ Font *_lettre;
+ Font *_plettre;
+ Font *_glettre;
+
+ /** The current palette. */
+ int _palette;
+
+ bool _quit; ///< Did the user request a normal game quit?
+
+ Difficulty _difficulty; ///< The current difficulty.
+ int _section; ///< The current game section.
+
+ Common::String _name; ///< The name of the child.
+
+ uint8 _house;
+
+ uint8 _head;
+ uint8 _colorHair;
+ uint8 _colorJacket;
+ uint8 _colorTrousers;
+
+
+ // -- General helpers --
+
+ void setGamePalette(uint palette); ///< Set a game palette.
+ void setGameCursor(); ///< Set the default game cursor.
+
+ /** Draw this sprite in a fancy, animated line-by-line way. */
+ void drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
+ int16 x, int16 y) const;
+
+ /** Backup the screen contents. */
+ void backupScreen(ScreenBackup &backup, bool setDefaultCursor = false);
+ /** Restore the screen contents with a previously made backup. */
+ void restoreScreen(ScreenBackup &backup);
+
+ Common::String fixString(const Common::String &str) const; ///< Fix a string if necessary.
+ void fixTXTStrings(TXTFile &txt) const; ///< Fix all strings in a TXT.
+
+
+ // -- Copy protection helpers --
+
+ /** Set up the copy protection. */
+ int8 cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20],
+ const uint8 obfuscate[4], const Surface sprites[2]);
+ /** Find the shape under these coordinates. */
+ int8 cpFindShape(int16 x, int16 y) const;
+ /** Display the "You are wrong" screen. */
+ void cpWrong();
+
+
+ // -- Show different game screens --
+
+ void showWait(uint palette = 0xFFFF); ///< Show the wait / loading screen.
+ void showQuote(); ///< Show the quote about fairytales.
+ void showTitle(); ///< Show the Once Upon A Time title.
+ void showChapter(int chapter); ///< Show a chapter intro text.
+ void showByeBye(); ///< Show the "bye bye" screen.
+
+ /** Handle the "listen to animal names" part. */
+ void handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names);
+
+
+ // -- Menu helpers --
+
+ MenuAction handleStartMenu(const MenuButton *animalsButton); ///< Handle the start menu.
+ MenuAction handleMainMenu(); ///< Handle the main menu.
+ MenuAction handleIngameMenu(); ///< Handle the ingame menu.
+
+ void drawStartMenu(const MenuButton *animalsButton); ///< Draw the start menu.
+ void drawMainMenu(); ///< Draw the main menu.
+ void drawIngameMenu(); ///< Draw the ingame menu.
+
+ /** Draw the difficulty label. */
+ void drawMenuDifficulty();
+
+ /** Clear the ingame menu in an animated way. */
+ void clearIngameMenu(const Surface &background);
+
+ /** Handle the whole ingame menu. */
+ MenuAction doIngameMenu();
+ /** Handle the whole ingame menu if ESC or right mouse button was pressed. */
+ MenuAction doIngameMenu(int16 &key, MouseButtons &mouseButtons);
+
+
+ // -- Menu button helpers --
+
+ /** Find the button under these coordinates. */
+ int checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue = -1) const;
+
+ /** Draw a menu button. */
+ void drawButton (Surface &dest, const Surface &src, const MenuButton &button, int transp = -1) const;
+ /** Draw multiple menu buttons. */
+ void drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count, int transp = -1) const;
+
+ /** Draw a border around a button. */
+ void drawButtonBorder(const MenuButton &button, uint8 color);
+
+
+ // -- Animal names helpers --
+
+ /** Set up the animal chooser. */
+ void anSetupChooser();
+ /** Set up the language chooser for one animal. */
+ void anSetupNames(const MenuButton &animal);
+ /** Play / Display the name of an animal in one language. */
+ void anPlayAnimalName(const Common::String &animal, uint language);
+
+
+ // -- Game sections --
+
+ bool playSection();
+
+ bool sectionStork();
+ bool sectionChapter1();
+ bool sectionParents();
+ bool sectionChapter2();
+ bool sectionForest0();
+ bool sectionChapter3();
+ bool sectionEvilCastle();
+ bool sectionChapter4();
+ bool sectionForest1();
+ bool sectionChapter5();
+ bool sectionBossFight();
+ bool sectionChapter6();
+ bool sectionForest2();
+ bool sectionChapter7();
+ bool sectionEnd();
+
+ CharGenAction characterGenerator();
+ void charGenSetup(uint stage);
+ void charGenDrawName();
+
+ static bool enterString(Common::String &name, int16 key, uint maxLength, const Font &font);
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_ONCEUPON_H
diff --git a/engines/gob/pregob/onceupon/palettes.h b/engines/gob/pregob/onceupon/palettes.h
new file mode 100644
index 0000000000..952581041c
--- /dev/null
+++ b/engines/gob/pregob/onceupon/palettes.h
@@ -0,0 +1,411 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_PALETTES_H
+#define GOB_PREGOB_ONCEUPON_PALETTES_H
+
+static const int kPaletteSize = 16;
+static const uint kPaletteCount = 20;
+
+static const byte kCopyProtectionPalette[3 * kPaletteSize] = {
+ 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x19,
+ 0x00, 0x3F, 0x00,
+ 0x00, 0x2A, 0x2A,
+ 0x2A, 0x00, 0x00,
+ 0x2A, 0x00, 0x2A,
+ 0x2A, 0x15, 0x00,
+ 0x00, 0x19, 0x12,
+ 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x3F,
+ 0x15, 0x3F, 0x15,
+ 0x00, 0x20, 0x3F,
+ 0x3F, 0x00, 0x00,
+ 0x3F, 0x00, 0x20,
+ 0x3F, 0x3F, 0x00,
+ 0x3F, 0x3F, 0x3F
+};
+
+static const byte kGamePalettes[kPaletteCount][3 * kPaletteSize] = {
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x18,
+ 0x00, 0x00, 0x3C,
+ 0x1C, 0x28, 0x00,
+ 0x10, 0x18, 0x00,
+ 0x1C, 0x1C, 0x20,
+ 0x14, 0x14, 0x14,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x14, 0x20, 0x04,
+ 0x3C, 0x2C, 0x00,
+ 0x02, 0x00, 0x18,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x38, 0x20, 0x3C,
+ 0x2C, 0x10, 0x30,
+ 0x20, 0x08, 0x28,
+ 0x14, 0x00, 0x1C,
+ 0x20, 0x20, 0x38,
+ 0x18, 0x18, 0x2C,
+ 0x10, 0x10, 0x24,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x20, 0x20,
+ 0x24, 0x14, 0x14,
+ 0x1C, 0x10, 0x10,
+ 0x14, 0x0C, 0x0C,
+ 0x1C, 0x1C, 0x1C,
+ 0x18, 0x18, 0x18,
+ 0x10, 0x10, 0x10,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x1C,
+ 0x10, 0x1C, 0x10,
+ 0x10, 0x14, 0x0C,
+ 0x1C, 0x1C, 0x3C,
+ 0x24, 0x24, 0x3C,
+ 0x18, 0x18, 0x24,
+ 0x10, 0x10, 0x18,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3F, 0x26, 0x3F,
+ 0x36, 0x1C, 0x36,
+ 0x2C, 0x12, 0x2A,
+ 0x27, 0x0C, 0x24,
+ 0x22, 0x07, 0x1E,
+ 0x1D, 0x03, 0x18,
+ 0x16, 0x00, 0x10,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3A,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3F, 0x39, 0x26,
+ 0x38, 0x34, 0x1C,
+ 0x30, 0x2F, 0x13,
+ 0x27, 0x29, 0x0C,
+ 0x1D, 0x22, 0x07,
+ 0x14, 0x1B, 0x03,
+ 0x0C, 0x14, 0x00,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3A,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x24, 0x3C, 0x3C,
+ 0x1C, 0x34, 0x38,
+ 0x14, 0x2C, 0x30,
+ 0x0C, 0x20, 0x2C,
+ 0x08, 0x18, 0x28,
+ 0x04, 0x10, 0x20,
+ 0x00, 0x08, 0x1C,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x24,
+ 0x38, 0x24, 0x1C,
+ 0x30, 0x1C, 0x14,
+ 0x28, 0x18, 0x0C,
+ 0x20, 0x10, 0x04,
+ 0x1C, 0x0C, 0x00,
+ 0x14, 0x08, 0x00,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x34, 0x24,
+ 0x38, 0x2C, 0x1C,
+ 0x30, 0x24, 0x14,
+ 0x2C, 0x1C, 0x10,
+ 0x30, 0x30, 0x3C,
+ 0x1C, 0x1C, 0x38,
+ 0x0C, 0x0C, 0x38,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0C,
+ 0x02, 0x03, 0x14,
+ 0x07, 0x07, 0x1D,
+ 0x0E, 0x0E, 0x25,
+ 0x17, 0x17, 0x2E,
+ 0x21, 0x22, 0x36,
+ 0x2F, 0x2F, 0x3F,
+ 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3B, 0x0D,
+ 0x3A, 0x31, 0x0A,
+ 0x35, 0x28, 0x07,
+ 0x30, 0x21, 0x04,
+ 0x2B, 0x19, 0x02,
+ 0x26, 0x12, 0x01,
+ 0x16, 0x0B, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00,
+ 0x21, 0x01, 0x00,
+ 0x2A, 0x02, 0x00,
+ 0x33, 0x03, 0x00,
+ 0x3D, 0x06, 0x00,
+ 0x2A, 0x19, 0x05,
+ 0x15, 0x14, 0x14,
+ 0x22, 0x1F, 0x1E,
+ 0x2F, 0x2C, 0x28,
+ 0x3F, 0x3C, 0x29,
+ 0x3F, 0x38, 0x0B,
+ 0x3B, 0x30, 0x0A,
+ 0x37, 0x29, 0x08,
+ 0x33, 0x23, 0x07,
+ 0x2F, 0x1D, 0x06
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x1C, 0x38,
+ 0x34, 0x30, 0x28,
+ 0x2C, 0x24, 0x1C,
+ 0x24, 0x18, 0x10,
+ 0x1C, 0x10, 0x08,
+ 0x14, 0x04, 0x04,
+ 0x10, 0x00, 0x00,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x1C, 0x38,
+ 0x34, 0x30, 0x28,
+ 0x2C, 0x24, 0x1C,
+ 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x1A, 0x30, 0x37,
+ 0x14, 0x28, 0x31,
+ 0x10, 0x20, 0x2C,
+ 0x0C, 0x19, 0x27,
+ 0x08, 0x12, 0x21,
+ 0x05, 0x0C, 0x1C,
+ 0x03, 0x07, 0x16,
+ 0x01, 0x03, 0x11,
+ 0x00, 0x00, 0x0C,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x34, 0x30, 0x34,
+ 0x30, 0x24, 0x30,
+ 0x28, 0x1C, 0x28,
+ 0x24, 0x14, 0x24,
+ 0x1C, 0x0C, 0x1C,
+ 0x18, 0x08, 0x18,
+ 0x14, 0x04, 0x14,
+ 0x0C, 0x04, 0x0C,
+ 0x08, 0x00, 0x08,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x2C, 0x24, 0x0C,
+ 0x34, 0x34, 0x28,
+ 0x2C, 0x2C, 0x1C,
+ 0x24, 0x24, 0x10,
+ 0x1C, 0x18, 0x08,
+ 0x14, 0x14, 0x08,
+ 0x10, 0x10, 0x04,
+ 0x0C, 0x0C, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ 0x14, 0x28, 0x31,
+ 0x10, 0x20, 0x2C,
+ 0x0C, 0x19, 0x27,
+ 0x08, 0x12, 0x21,
+ 0x05, 0x0C, 0x1C,
+ 0x03, 0x07, 0x16,
+ 0x01, 0x03, 0x11,
+ 0x00, 0x3C, 0x00,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x1C,
+ 0x10, 0x1C, 0x10,
+ 0x10, 0x14, 0x0C,
+ 0x1C, 0x1C, 0x3C,
+ 0x24, 0x24, 0x3C,
+ 0x18, 0x18, 0x24,
+ 0x10, 0x10, 0x18,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x1C,
+ 0x10, 0x1C, 0x10,
+ 0x10, 0x14, 0x0C,
+ 0x1C, 0x1C, 0x3C,
+ 0x24, 0x24, 0x3C,
+ 0x18, 0x18, 0x24,
+ 0x10, 0x10, 0x18,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ }
+};
+
+#endif // GOB_PREGOB_ONCEUPON_PALETTES_H
diff --git a/engines/gob/pregob/onceupon/parents.cpp b/engines/gob/pregob/onceupon/parents.cpp
new file mode 100644
index 0000000000..cdaee6a38d
--- /dev/null
+++ b/engines/gob/pregob/onceupon/parents.cpp
@@ -0,0 +1,217 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/dataio.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/gctfile.h"
+
+#include "gob/pregob/onceupon/palettes.h"
+#include "gob/pregob/onceupon/parents.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const char *Parents::kSound[kSoundCount] = {
+ "rire.snd", // kSoundCackle
+ "tonn.snd" // kSoundThunder
+};
+
+// So that every GCT line is displayed for 12 seconds
+const uint16 Parents::kLoop[kLoopCount][3] = {
+ { 72, 77, 33},
+ {105, 109, 38},
+ {141, 145, 38},
+ {446, 454, 23},
+ {456, 464, 23},
+ {466, 474, 23},
+ {476, 484, 23}
+};
+
+
+Parents::Parents(GobEngine *vm, const Common::String &seq, const Common::String &gct,
+ const Common::String &childName, uint8 house, const Font &font,
+ const byte *normalPalette, const byte *brightPalette, uint paletteSize) :
+ SEQFile(vm, seq),
+ _gct(0), _house(house), _font(&font),
+ _paletteSize(paletteSize), _normalPalette(normalPalette), _brightPalette(brightPalette) {
+
+ // Load sounds
+ for (int i = 0; i < kSoundCount; i++)
+ _vm->_sound->sampleLoad(&_sounds[i], SOUND_SND, kSound[i]);
+
+ // Load GCT
+ Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gct);
+ if (gctStream) {
+ _gct = new GCTFile(*gctStream, _vm->_rnd);
+
+ delete gctStream;
+ } else
+ error("Parents::Parents(): Failed to open \"%s\"", gct.c_str());
+
+ _gct->setArea(17, 18, 303, 41);
+ _gct->setText(1, childName);
+
+ _gct->selectLine(2, _house);
+ _gct->selectLine(4, _house);
+
+ for (uint i = 0; i < kLoopCount; i++)
+ _loopID[i] = addLoop(kLoop[i][0], kLoop[i][1], kLoop[i][2]);
+}
+
+Parents::~Parents() {
+ delete _gct;
+}
+
+void Parents::play() {
+ _currentLoop = 0;
+
+ SEQFile::play(true, 496, 15);
+
+ // After playback, fade out
+ if (!_vm->shouldQuit())
+ _vm->_palAnim->fade(0, 0, 0);
+}
+
+void Parents::handleFrameEvent() {
+ switch (getFrame()) {
+ case 0:
+ // On fame 0, fade in
+ _vm->_draw->forceBlit();
+ _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+ break;
+
+ case 4:
+ drawGCT(0);
+ break;
+
+ case 55:
+ drawGCT(3, 0);
+ break;
+
+ case 79:
+ drawGCT(_house + 5, 1);
+ break;
+
+ case 110:
+ drawGCT(_house + 9, 2);
+ break;
+
+ case 146:
+ drawGCT(17);
+ break;
+
+ case 198:
+ drawGCT(13);
+ break;
+
+ case 445:
+ drawGCT(14, 3);
+ break;
+
+ case 455:
+ drawGCT(18, 4);
+ break;
+
+ case 465:
+ drawGCT(19, 5);
+ break;
+
+ case 475:
+ drawGCT(20, 6);
+ break;
+
+ case 188:
+ case 228:
+ case 237:
+ case 257:
+ case 275:
+ case 426:
+ lightningEffect();
+ break;
+
+ case 203:
+ case 243:
+ case 252:
+ case 272:
+ case 290:
+ case 441:
+ playSound(kSoundThunder);
+ break;
+
+ case 340:
+ playSound(kSoundCackle);
+ break;
+ }
+}
+
+void Parents::handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons) {
+ if ((key == kKeyEscape) || (mouseButtons == kMouseButtonsRight))
+ abortPlay();
+
+ if (((key == kKeySpace) || (mouseButtons == kMouseButtonsLeft)) && (_currentLoop < kLoopCount))
+ skipLoop(_loopID[_currentLoop]);
+}
+
+void Parents::playSound(Sound sound) {
+ _vm->_sound->blasterStop(0);
+ _vm->_sound->blasterPlay(&_sounds[sound], 0, 0);
+}
+
+void Parents::lightningEffect() {
+ for (int i = 0; (i < 5) && !_vm->shouldQuit(); i++) {
+
+ setPalette(_brightPalette, _paletteSize);
+ _vm->_util->delay(5);
+
+ setPalette(_normalPalette, _paletteSize);
+ _vm->_util->delay(5);
+ }
+}
+
+void Parents::setPalette(const byte *palette, uint size) {
+ memcpy(_vm->_draw->_vgaPalette, palette, 3 * size);
+
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+ _vm->_video->retrace();
+}
+
+void Parents::drawGCT(uint item, uint loop) {
+ int16 left, top, right, bottom;
+ if (_gct->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ if (_gct->draw(*_vm->_draw->_backSurface, item, *_font, 10, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+ _currentLoop = loop;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/parents.h b/engines/gob/pregob/onceupon/parents.h
new file mode 100644
index 0000000000..f5c8307b73
--- /dev/null
+++ b/engines/gob/pregob/onceupon/parents.h
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_PARENTS_H
+#define GOB_PREGOB_ONCEUPON_PARENTS_H
+
+#include "gob/sound/sounddesc.h"
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+class Font;
+
+class GCTFile;
+
+namespace OnceUpon {
+
+/** The home / parents animation sequence. */
+class Parents : public SEQFile {
+public:
+ Parents(GobEngine *vm, const Common::String &seq, const Common::String &gct,
+ const Common::String &childName, uint8 house, const Font &font,
+ const byte *normalPalette, const byte *brightPalette, uint paletteSize);
+ ~Parents();
+
+ void play();
+
+protected:
+ void handleFrameEvent();
+ void handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons);
+
+private:
+ static const uint kLoopCount = 7;
+
+ static const uint16 kLoop[kLoopCount][3];
+
+ enum Sound {
+ kSoundCackle = 0,
+ kSoundThunder ,
+ kSoundCount
+ };
+
+ static const char *kSound[kSoundCount];
+
+
+ uint8 _house;
+
+ const Font *_font;
+
+ uint _paletteSize;
+ const byte *_normalPalette;
+ const byte *_brightPalette;
+
+ SoundDesc _sounds[kSoundCount];
+
+ GCTFile *_gct;
+
+ uint _loopID[kLoopCount];
+ uint _currentLoop;
+
+
+ void lightningEffect();
+
+ void playSound(Sound sound);
+ void setPalette(const byte *palette, uint size);
+
+ void drawGCT(uint item, uint loop = 0xFFFF);
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_PARENTS_H
diff --git a/engines/gob/pregob/onceupon/stork.cpp b/engines/gob/pregob/onceupon/stork.cpp
new file mode 100644
index 0000000000..3c38037d08
--- /dev/null
+++ b/engines/gob/pregob/onceupon/stork.cpp
@@ -0,0 +1,234 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/str.h"
+
+#include "gob/gob.h"
+#include "gob/surface.h"
+#include "gob/anifile.h"
+#include "gob/video.h"
+
+#include "gob/pregob/onceupon/stork.h"
+
+enum Animation {
+ kAnimFlyNearWithBundle = 9,
+ kAnimFlyFarWithBundle = 12,
+ kAnimFlyNearWithoutBundle = 10,
+ kAnimFlyFarWithoutBundle = 13,
+ kAnimBundleNear = 11,
+ kAnimBundleFar = 14
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+Stork::Stork(GobEngine *vm, const ANIFile &ani) : ANIObject(ani), _shouldDrop(false) {
+ _frame = new Surface(320, 200, 1);
+ vm->_video->drawPackedSprite("cadre.cmp", *_frame);
+
+ _bundle = new ANIObject(ani);
+
+ _bundle->setVisible(false);
+ _bundle->setPause(true);
+
+ setState(kStateFlyNearWithBundle, kAnimFlyNearWithBundle, -80);
+}
+
+Stork::~Stork() {
+ delete _frame;
+
+ delete _bundle;
+}
+
+bool Stork::hasBundleLanded() const {
+ if (!_shouldDrop || !_bundle->isVisible() || _bundle->isPaused())
+ return false;
+
+ int16 x, y, width, height;
+ _bundle->getFramePosition(x, y);
+ _bundle->getFrameSize(width, height);
+
+ return (y + height) >= _bundleDrop.landY;
+}
+
+void Stork::dropBundle(const BundleDrop &drop) {
+ if (_shouldDrop)
+ return;
+
+ _shouldDrop = true;
+ _bundleDrop = drop;
+}
+
+bool Stork::draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ left = 0x7FFF;
+ top = 0x7FFF;
+ right = 0x0000;
+ bottom = 0x0000;
+
+ bool drawn = ANIObject::draw(dest, left, top, right, bottom);
+ if (drawn) {
+ // Left frame edge
+ if (left <= 15)
+ dest.blit(*_frame, left, top, MIN<int16>(15, right), bottom, left, top);
+
+ // Right frame edge
+ if (right >= 304)
+ dest.blit(*_frame, MAX<int16>(304, left), top, right, bottom, MAX<int16>(304, left), top);
+ }
+
+ int16 bLeft, bTop, bRight, bBottom;
+ if (_bundle->draw(dest, bLeft, bTop, bRight, bBottom)) {
+ // Bottom frame edge
+ if (bBottom >= 188)
+ dest.blit(*_frame, bLeft, MAX<int16>(188, bTop), bRight, bBottom, bLeft, MAX<int16>(188, bTop));
+
+ left = MIN(left , bLeft );
+ top = MIN(top , bTop );
+ right = MAX(right , bRight );
+ bottom = MAX(bottom, bBottom);
+
+ drawn = true;
+ }
+
+ return drawn;
+}
+
+bool Stork::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ left = 0x7FFF;
+ top = 0x7FFF;
+ right = 0x0000;
+ bottom = 0x0000;
+
+ bool cleared = _bundle->clear(dest, left, top, right, bottom);
+
+ int16 sLeft, sTop, sRight, sBottom;
+ if (ANIObject::clear(dest, sLeft, sTop, sRight, sBottom)) {
+ left = MIN(left , sLeft );
+ top = MIN(top , sTop );
+ right = MAX(right , sRight );
+ bottom = MAX(bottom, sBottom);
+
+ cleared = true;
+ }
+
+ return cleared;
+}
+
+void Stork::advance() {
+ _bundle->advance();
+
+ ANIObject::advance();
+
+ int16 curX, curY, curWidth, curHeight;
+ getFramePosition(curX, curY, 0);
+ getFrameSize(curWidth, curHeight, 0);
+
+ const int16 curRight = curX + curWidth - 1;
+
+ int16 nextX, nextY, nextWidth, nextHeight;
+ getFramePosition(nextX, nextY, 1);
+ getFrameSize(nextWidth, nextHeight, 1);
+
+ const int16 nextRight = nextX + nextWidth - 1;
+
+ switch (_state) {
+ case kStateFlyNearWithBundle:
+ if (curX >= 330)
+ setState(kStateFlyFarWithBundle, kAnimFlyFarWithBundle, 330);
+
+ if ((curRight <= _bundleDrop.dropX) &&
+ (nextRight >= _bundleDrop.dropX) && _shouldDrop && !_bundleDrop.dropWhileFar)
+ dropBundle(kStateFlyNearWithoutBundle, kAnimFlyNearWithoutBundle);
+
+ break;
+
+ case kStateFlyFarWithBundle:
+ if (curX <= -80)
+ setState(kStateFlyNearWithBundle, kAnimFlyNearWithBundle, -80);
+
+ if ((curX >= _bundleDrop.dropX) &&
+ (nextX <= _bundleDrop.dropX) && _shouldDrop && _bundleDrop.dropWhileFar)
+ dropBundle(kStateFlyFarWithoutBundle, kAnimFlyFarWithoutBundle);
+
+ break;
+
+ case kStateFlyNearWithoutBundle:
+ if (curX >= 330)
+ setState(kStateFlyFarWithoutBundle, kAnimFlyFarWithoutBundle, 330);
+ break;
+
+ case kStateFlyFarWithoutBundle:
+ if (curX <= -80)
+ setState(kStateFlyNearWithoutBundle, kAnimFlyNearWithoutBundle, -80);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Stork::dropBundle(State state, uint16 anim) {
+ setState(state, anim);
+
+ int16 x, y, width, height;
+ getFramePosition(x, y);
+ getFrameSize(width, height);
+
+ _bundle->setAnimation(_bundleDrop.anim);
+ _bundle->setPause(false);
+ _bundle->setVisible(true);
+
+ int16 bWidth, bHeight;
+ _bundle->getFrameSize(bWidth, bHeight);
+
+ // Drop position
+ x = _bundleDrop.dropX;
+ y = y + height - bHeight;
+
+ // If the stork is flying near (from left to right), drop the bundle at the right edge
+ if (!_bundleDrop.dropWhileFar)
+ x = x - bWidth;
+
+ _bundle->setPosition(x, y);
+}
+
+void Stork::setState(State state, uint16 anim) {
+ setAnimation(anim);
+ setVisible(true);
+ setPause(false);
+
+ _state = state;
+}
+
+void Stork::setState(State state, uint16 anim, int16 x) {
+ setState(state, anim);
+ setPosition();
+
+ int16 pX, pY;
+ getPosition(pX, pY);
+ setPosition( x, pY);
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/stork.h b/engines/gob/pregob/onceupon/stork.h
new file mode 100644
index 0000000000..756f5258c7
--- /dev/null
+++ b/engines/gob/pregob/onceupon/stork.h
@@ -0,0 +1,103 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_STORK_H
+#define GOB_PREGOB_ONCEUPON_STORK_H
+
+#include "common/system.h"
+
+#include "gob/aniobject.h"
+
+namespace Common {
+ class String;
+}
+
+namespace Gob {
+
+class GobEngine;
+
+class Surface;
+class ANIFile;
+
+namespace OnceUpon {
+
+/** The stork in Baba Yaga / dragon in Abracadabra. */
+class Stork : public ANIObject {
+public:
+ /** Information on how to drop the bundle. */
+ struct BundleDrop {
+ int16 anim; ///< Animation of the bundle floating down
+
+ int16 dropX; ///< X position the stork drops the bundle
+ int16 landY; ///< Y position the bundle lands
+
+ bool dropWhileFar; ///< Does the stork drop the bundle while far instead of near?
+ };
+
+ Stork(GobEngine *vm, const ANIFile &ani);
+ ~Stork();
+
+ /** Has the bundle landed? */
+ bool hasBundleLanded() const;
+
+ /** Drop the bundle. */
+ void dropBundle(const BundleDrop &drop);
+
+ /** Draw the current frame onto the surface and return the affected rectangle. */
+ bool draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+ /** Draw the current frame from the surface and return the affected rectangle. */
+ bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ /** Advance the animation to the next frame. */
+ void advance();
+
+private:
+ enum State {
+ kStateFlyNearWithBundle = 0,
+ kStateFlyFarWithBundle ,
+ kStateFlyNearWithoutBundle ,
+ kStateFlyFarWithoutBundle
+ };
+
+
+ GobEngine *_vm;
+
+ Surface *_frame;
+ ANIObject *_bundle;
+
+ State _state;
+
+ bool _shouldDrop;
+ BundleDrop _bundleDrop;
+
+
+ void setState(State state, uint16 anim);
+ void setState(State state, uint16 anim, int16 x);
+
+ void dropBundle(State state, uint16 anim);
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_STORK_H
diff --git a/engines/gob/pregob/onceupon/title.cpp b/engines/gob/pregob/onceupon/title.cpp
new file mode 100644
index 0000000000..5163ff6822
--- /dev/null
+++ b/engines/gob/pregob/onceupon/title.cpp
@@ -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.
+ *
+ */
+
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/onceupon/title.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+Title::Title(GobEngine *vm) : SEQFile(vm, "ville.seq") {
+}
+
+Title::~Title() {
+}
+
+void Title::play() {
+ SEQFile::play(true, 0xFFFF, 15);
+
+ // After playback, fade out and stop the music
+ if (!_vm->shouldQuit())
+ _vm->_palAnim->fade(0, 0, 0);
+
+ stopMusic();
+}
+
+void Title::handleFrameEvent() {
+ // On fame 0, start the music and fade in
+ if (getFrame() == 0) {
+ playMusic();
+
+ _vm->_draw->forceBlit();
+ _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+ }
+}
+
+void Title::playMusic() {
+ // Look at what platform this is and play the appropriate music type
+
+ if (_vm->getPlatform() == Common::kPlatformPC)
+ playMusicDOS();
+ else if (_vm->getPlatform() == Common::kPlatformAmiga)
+ playMusicAmiga();
+ else if (_vm->getPlatform() == Common::kPlatformAtariST)
+ playMusicAtariST();
+}
+
+void Title::playMusicDOS() {
+ // Play an AdLib track
+
+ _vm->_sound->adlibLoadTBR("babayaga.tbr");
+ _vm->_sound->adlibLoadMDY("babayaga.mdy");
+ _vm->_sound->adlibSetRepeating(-1);
+ _vm->_sound->adlibPlay();
+}
+
+void Title::playMusicAmiga() {
+ // Play a Protracker track
+
+ _vm->_sound->protrackerPlay("mod.babayaga");
+}
+
+void Title::playMusicAtariST() {
+ // Play a Soundblaster composition
+
+ static const int16 titleMusic[21] = { 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, -1};
+ static const char * const titleFiles[ 3] = {"baba1.snd", "baba2.snd", "baba3.snd"};
+
+ for (uint i = 0; i < ARRAYSIZE(titleFiles); i++)
+ _vm->_sound->sampleLoad(_vm->_sound->sampleGetBySlot(i), SOUND_SND, titleFiles[i]);
+
+ _vm->_sound->blasterPlayComposition(titleMusic, 0);
+ _vm->_sound->blasterRepeatComposition(-1);
+}
+
+void Title::stopMusic() {
+ // Just stop everything
+
+ _vm->_sound->adlibSetRepeating(0);
+ _vm->_sound->blasterRepeatComposition(0);
+
+ _vm->_sound->adlibStop();
+ _vm->_sound->blasterStopComposition();
+ _vm->_sound->protrackerStop();
+
+ for (int i = 0; i < ::Gob::Sound::kSoundsCount; i++)
+ _vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(i));
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/title.h b/engines/gob/pregob/onceupon/title.h
new file mode 100644
index 0000000000..5e7ef76d40
--- /dev/null
+++ b/engines/gob/pregob/onceupon/title.h
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_ONCEUPON_TITLE_H
+#define GOB_PREGOB_ONCEUPON_TITLE_H
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+/** The Once Upon A Time title animation sequence. */
+class Title : public SEQFile {
+public:
+ Title(GobEngine *vm);
+ ~Title();
+
+ void play();
+
+protected:
+ void handleFrameEvent();
+
+private:
+ void playMusic(); ///< Play the title music.
+ void playMusicDOS(); ///< Play the title music of the DOS version.
+ void playMusicAmiga(); ///< Play the title music of the Amiga version.
+ void playMusicAtariST(); ///< Play the title music of the Atari ST version.
+ void stopMusic(); ///< Stop the title music.
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_TITLE_H
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
new file mode 100644
index 0000000000..54eb3c6795
--- /dev/null
+++ b/engines/gob/pregob/pregob.cpp
@@ -0,0 +1,351 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "graphics/cursorman.h"
+
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/util.h"
+#include "gob/surface.h"
+#include "gob/dataio.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+#include "gob/aniobject.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/pregob.h"
+#include "gob/pregob/gctfile.h"
+
+
+namespace Gob {
+
+const char PreGob::kLanguageSuffixShort[5] = { 't', 'g', 'a', 'e', 'i'};
+const char *PreGob::kLanguageSuffixLong [5] = {"fr", "al", "an", "it", "es"};
+
+
+PreGob::PreGob(GobEngine *vm) : _vm(vm), _fadedOut(false) {
+}
+
+PreGob::~PreGob() {
+}
+
+void PreGob::fadeOut() {
+ if (_fadedOut || _vm->shouldQuit())
+ return;
+
+ // Fade to black
+ _vm->_palAnim->fade(0, 0, 0);
+
+ _fadedOut = true;
+}
+
+void PreGob::fadeIn() {
+ if (!_fadedOut || _vm->shouldQuit())
+ return;
+
+ // Fade to palette
+ _vm->_draw->blitInvalidated();
+ _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+
+ _fadedOut = false;
+}
+
+void PreGob::clearScreen() {
+ _vm->_draw->_backSurface->clear();
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+ _vm->_draw->blitInvalidated();
+ _vm->_video->retrace();
+}
+
+void PreGob::initScreen() {
+ _vm->_util->setFrameRate(15);
+
+ _fadedOut = true;
+
+ _vm->_draw->initScreen();
+
+ _vm->_draw->_backSurface->clear();
+ _vm->_util->clearPalette();
+
+ _vm->_draw->forceBlit();
+ _vm->_video->retrace();
+
+ _vm->_util->processInput();
+}
+
+void PreGob::setPalette(const byte *palette, uint16 size) {
+ memcpy(_vm->_draw->_vgaPalette, palette, 3 * size);
+
+ // If we didn't fade out prior, immediately set the palette
+ if (!_fadedOut)
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+}
+
+void PreGob::addCursor() {
+ CursorMan.pushCursor(0, 0, 0, 0, 0, 0);
+}
+
+void PreGob::removeCursor() {
+ CursorMan.popCursor();
+}
+
+void PreGob::setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY) {
+ CursorMan.replaceCursor(sprite.getData(), sprite.getWidth(), sprite.getHeight(), hotspotX, hotspotY, 0);
+}
+
+void PreGob::setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom,
+ int16 hotspotX, int16 hotspotY) {
+
+ const int width = right - left + 1;
+ const int height = bottom - top + 1;
+
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ Surface cursor(width, height, 1);
+
+ cursor.blit(sprite, left, top, right, bottom, 0, 0);
+
+ setCursor(cursor, hotspotX, hotspotX);
+}
+
+void PreGob::showCursor() {
+ CursorMan.showMouse(true);
+
+ _vm->_draw->_showCursor = 4;
+}
+
+void PreGob::hideCursor() {
+ CursorMan.showMouse(false);
+
+ _vm->_draw->_showCursor = 0;
+}
+
+bool PreGob::isCursorVisible() const {
+ return CursorMan.isVisible();
+}
+
+void PreGob::loadSounds(const char * const *sounds, uint soundCount) {
+ freeSounds();
+
+ _sounds.resize(soundCount);
+
+ for (uint i = 0; i < soundCount; i++)
+ loadSound(_sounds[i], sounds[i]);
+}
+
+void PreGob::freeSounds() {
+ _sounds.clear();
+}
+
+bool PreGob::loadSound(SoundDesc &sound, const Common::String &file) const {
+ return _vm->_sound->sampleLoad(&sound, SOUND_SND, file.c_str());
+}
+
+void PreGob::playSound(uint sound, int16 frequency, int16 repCount) {
+ if (sound >= _sounds.size())
+ return;
+
+ _vm->_sound->blasterPlay(&_sounds[sound], repCount, frequency);
+}
+
+void PreGob::stopSound() {
+ _vm->_sound->blasterStop(0);
+}
+
+void PreGob::playSoundFile(const Common::String &file, int16 frequency, int16 repCount, bool interruptible) {
+ stopSound();
+
+ SoundDesc sound;
+ if (!loadSound(sound, file))
+ return;
+
+ _vm->_sound->blasterPlay(&sound, repCount, frequency);
+
+ _vm->_util->forceMouseUp();
+
+ bool finished = false;
+ while (!_vm->shouldQuit() && !finished && _vm->_sound->blasterPlayingSound()) {
+ endFrame(true);
+
+ finished = hasInput();
+ }
+
+ _vm->_util->forceMouseUp();
+
+ stopSound();
+}
+
+void PreGob::beep(int16 frequency, int32 length) {
+ _vm->_sound->speakerOn(frequency, length);
+}
+
+void PreGob::endFrame(bool doInput) {
+ _vm->_draw->blitInvalidated();
+ _vm->_util->waitEndFrame();
+
+ if (doInput)
+ _vm->_util->processInput();
+}
+
+int16 PreGob::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) {
+ _vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons);
+ _vm->_util->forceMouseUp();
+
+ return _vm->_util->checkKey();
+}
+
+int16 PreGob::waitInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) {
+ bool finished = false;
+
+ int16 key = 0;
+ while (!_vm->shouldQuit() && !finished) {
+ endFrame(true);
+
+ key = checkInput(mouseX, mouseY, mouseButtons);
+
+ finished = (mouseButtons != kMouseButtonsNone) || (key != 0);
+ }
+
+ return key;
+}
+
+int16 PreGob::waitInput() {
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ return waitInput(mouseX, mouseY, mouseButtons);
+}
+
+bool PreGob::hasInput() {
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ return checkInput(mouseX, mouseY, mouseButtons) || (mouseButtons != kMouseButtonsNone);
+}
+
+void PreGob::clearAnim(ANIObject &anim) {
+ int16 left, top, right, bottom;
+
+ if (anim.clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+}
+
+void PreGob::drawAnim(ANIObject &anim) {
+ int16 left, top, right, bottom;
+
+ if (anim.draw(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ anim.advance();
+}
+
+void PreGob::redrawAnim(ANIObject &anim) {
+ clearAnim(anim);
+ drawAnim(anim);
+}
+
+void PreGob::clearAnim(const ANIList &anims) {
+ for (int i = (anims.size() - 1); i >= 0; i--)
+ clearAnim(*anims[i]);
+}
+
+void PreGob::drawAnim(const ANIList &anims) {
+ for (ANIList::const_iterator a = anims.begin(); a != anims.end(); ++a)
+ drawAnim(**a);
+}
+
+void PreGob::redrawAnim(const ANIList &anims) {
+ clearAnim(anims);
+ drawAnim(anims);
+}
+
+void PreGob::loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const {
+ freeAnims(anims);
+
+ anims.resize(count);
+ for (uint i = 0; i < count; i++) {
+ anims[i] = new ANIObject(ani);
+
+ setAnim(*anims[i], props[i]);
+ }
+}
+
+void PreGob::freeAnims(ANIList &anims) const {
+ for (ANIList::iterator a = anims.begin(); a != anims.end(); ++a)
+ delete *a;
+
+ anims.clear();
+}
+
+void PreGob::setAnim(ANIObject &anim, const AnimProperties &props) const {
+ anim.setAnimation(props.animation);
+ anim.setFrame(props.frame);
+ anim.setMode(props.mode);
+ anim.setPause(props.paused);
+ anim.setVisible(props.visible);
+
+ if (props.hasPosition)
+ anim.setPosition(props.x, props.y);
+ else
+ anim.setPosition();
+}
+
+Common::String PreGob::getLocFile(const Common::String &file) const {
+ if (_vm->_global->_language >= ARRAYSIZE(kLanguageSuffixShort))
+ return file;
+
+ return file + kLanguageSuffixShort[_vm->_global->_language];
+}
+
+TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format) const {
+ Common::SeekableReadStream *txtStream = _vm->_dataIO->getFile(txtFile);
+ if (!txtStream)
+ error("PreGob::loadTXT(): Failed to open \"%s\"", txtFile.c_str());
+
+ TXTFile *txt = new TXTFile(*txtStream, format);
+
+ delete txtStream;
+
+ fixTXTStrings(*txt);
+
+ return txt;
+}
+
+void PreGob::fixTXTStrings(TXTFile &txt) const {
+}
+
+GCTFile *PreGob::loadGCT(const Common::String &gctFile) const {
+ Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gctFile);
+ if (!gctStream)
+ error("PreGob::loadGCT(): Failed to open \"%s\"", gctFile.c_str());
+
+ GCTFile *gct = new GCTFile(*gctStream, _vm->_rnd);
+
+ delete gctStream;
+
+ return gct;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
new file mode 100644
index 0000000000..632f85b88e
--- /dev/null
+++ b/engines/gob/pregob/pregob.h
@@ -0,0 +1,194 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_PREGOB_H
+#define GOB_PREGOB_PREGOB_H
+
+#include "common/str.h"
+#include "common/array.h"
+
+#include "gob/util.h"
+#include "gob/aniobject.h"
+
+#include "gob/sound/sounddesc.h"
+
+#include "gob/pregob/txtfile.h"
+
+namespace Gob {
+
+class GobEngine;
+class Surface;
+
+class GCTFile;
+
+class PreGob {
+public:
+ PreGob(GobEngine *vm);
+ virtual ~PreGob();
+
+ virtual void run() = 0;
+
+ struct AnimProperties {
+ uint16 animation;
+ uint16 frame;
+
+ ANIObject::Mode mode;
+
+ bool visible;
+ bool paused;
+
+ bool hasPosition;
+ int16 x;
+ int16 y;
+ };
+
+protected:
+ typedef Common::Array<ANIObject *> ANIList;
+
+ static const char kLanguageSuffixShort[5];
+ static const char *kLanguageSuffixLong [5];
+
+
+ GobEngine *_vm;
+
+
+ // -- Graphics --
+
+ /** Initialize the game screen. */
+ void initScreen();
+
+ void fadeOut(); ///< Fade to black.
+ void fadeIn(); ///< Fade to the current palette.
+
+ void clearScreen();
+
+ /** Change the palette.
+ *
+ * @param palette The palette to change to.
+ * @param size Size of the palette in colors.
+ */
+ void setPalette(const byte *palette, uint16 size); ///< Change the palette
+
+ /** Add a new cursor that can be manipulated to the stack. */
+ void addCursor();
+ /** Remove the top-most cursor from the stack. */
+ void removeCursor();
+
+ /** Set the current cursor. */
+ void setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY);
+ /** Set the current cursor. */
+ void setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom,
+ int16 hotspotX, int16 hotspotY);
+
+ /** Show the cursor. */
+ void showCursor();
+ /** Hide the cursor. */
+ void hideCursor();
+
+ /** Is the cursor currently visible? */
+ bool isCursorVisible() const;
+
+ /** Remove an animation from the screen. */
+ void clearAnim(ANIObject &anim);
+ /** Draw an animation to the screen, advancing it. */
+ void drawAnim(ANIObject &anim);
+ /** Clear and draw an animation to the screen, advancing it. */
+ void redrawAnim(ANIObject &anim);
+
+ /** Remove animations from the screen. */
+ void clearAnim(const ANIList &anims);
+ /** Draw animations to the screen, advancing them. */
+ void drawAnim(const ANIList &anims);
+ /** Clear and draw animations to the screen, advancing them. */
+ void redrawAnim(const ANIList &anims);
+
+ void loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const;
+ void freeAnims(ANIList &anims) const;
+
+ void setAnim(ANIObject &anim, const AnimProperties &props) const;
+
+ /** Wait for the frame to end, handling screen updates and optionally update input. */
+ void endFrame(bool doInput);
+
+
+ // -- Sound --
+
+ /** Load all sounds that can be played interactively in the game. */
+ void loadSounds(const char * const *sounds, uint soundCount);
+ /** Free all loaded sound. */
+ void freeSounds();
+
+ /** Play a loaded sound. */
+ void playSound(uint sound, int16 frequency = 0, int16 repCount = 0);
+ /** Stop all sound playback. */
+ void stopSound();
+
+ /** Play a sound until it ends or is interrupted by a keypress. */
+ void playSoundFile(const Common::String &file, int16 frequency = 0, int16 repCount = 0, bool interruptible = true);
+
+ /** Beep the PC speaker. */
+ void beep(int16 frequency, int32 length);
+
+
+ // -- Input --
+
+ /** Check mouse and keyboard input. */
+ int16 checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
+ /** Wait for mouse or keyboard input. */
+ int16 waitInput (int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
+ /** Wait for mouse or keyboard input, but don't care about what was done with the mouse. */
+ int16 waitInput();
+ /** Did we have mouse or keyboard input? */
+ bool hasInput();
+
+
+ // -- TXT helpers --
+
+ /** Get the name of a localized file. */
+ Common::String getLocFile(const Common::String &file) const;
+ /** Open a TXT file. */
+ TXTFile *loadTXT(const Common::String &txtFile, TXTFile::Format format) const;
+
+ /** Called by loadTXT() to fix strings within the TXT file. */
+ virtual void fixTXTStrings(TXTFile &txt) const;
+
+
+ // -- GCT helpers --
+
+ GCTFile *loadGCT(const Common::String &gctFile) const;
+
+
+private:
+ /** Did we fade out? */
+ bool _fadedOut;
+
+ /** All loaded sounds. */
+ Common::Array<SoundDesc> _sounds;
+
+
+ /** Load a sound file. */
+ bool loadSound(SoundDesc &sound, const Common::String &file) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_PREGOB_H
diff --git a/engines/gob/pregob/seqfile.cpp b/engines/gob/pregob/seqfile.cpp
new file mode 100644
index 0000000000..91973bbb85
--- /dev/null
+++ b/engines/gob/pregob/seqfile.cpp
@@ -0,0 +1,384 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/str.h"
+#include "common/stream.h"
+
+#include "gob/gob.h"
+#include "gob/dataio.h"
+#include "gob/draw.h"
+#include "gob/decfile.h"
+#include "gob/anifile.h"
+#include "gob/aniobject.h"
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+SEQFile::SEQFile(GobEngine *vm, const Common::String &fileName) : _vm(vm) {
+ for (uint i = 0; i < kObjectCount; i++)
+ _objects[i].object = 0;
+
+ Common::SeekableReadStream *seq = _vm->_dataIO->getFile(Util::setExtension(fileName, ".SEQ"));
+ if (!seq) {
+ warning("SEQFile::SEQFile(): No such file \"%s\"", fileName.c_str());
+ return;
+ }
+
+ load(*seq);
+
+ delete seq;
+}
+
+SEQFile::~SEQFile() {
+ for (uint i = 0; i < kObjectCount; i++)
+ delete _objects[i].object;
+
+ for (Backgrounds::iterator b = _backgrounds.begin(); b != _backgrounds.end(); ++b)
+ delete *b;
+
+ for (Animations::iterator a = _animations.begin(); a != _animations.end(); ++a)
+ delete *a;
+}
+
+void SEQFile::load(Common::SeekableReadStream &seq) {
+ const uint16 decCount = (uint16)seq.readByte() + 1;
+ const uint16 aniCount = (uint16)seq.readByte() + 1;
+
+ // Load backgrounds
+ _backgrounds.reserve(decCount);
+ for (uint i = 0; i < decCount; i++) {
+ const Common::String dec = Util::readString(seq, 13);
+
+ if (!_vm->_dataIO->hasFile(dec)) {
+ warning("SEQFile::load(): No such background \"%s\"", dec.c_str());
+ return;
+ }
+
+ _backgrounds.push_back(new DECFile(_vm, dec, 320, 200));
+ }
+
+ // Load animations
+ _animations.reserve(aniCount);
+ for (uint i = 0; i < aniCount; i++) {
+ const Common::String ani = Util::readString(seq, 13);
+
+ if (!_vm->_dataIO->hasFile(ani)) {
+ warning("SEQFile::load(): No such animation \"%s\"", ani.c_str());
+ return;
+ }
+
+ _animations.push_back(new ANIFile(_vm, ani));
+ }
+
+ _frameRate = seq.readUint16LE();
+
+ // Load background change keys
+
+ const uint16 bgKeyCount = seq.readUint16LE();
+ _bgKeys.resize(bgKeyCount);
+
+ for (uint16 i = 0; i < bgKeyCount; i++) {
+ const uint16 frame = seq.readUint16LE();
+ const uint16 index = seq.readUint16LE();
+
+ _bgKeys[i].frame = frame;
+ _bgKeys[i].background = index < _backgrounds.size() ? _backgrounds[index] : 0;
+ }
+
+ // Load animation keys for all 4 objects
+
+ for (uint i = 0; i < kObjectCount; i++) {
+ const uint16 animKeyCount = seq.readUint16LE();
+ _animKeys.reserve(_animKeys.size() + animKeyCount);
+
+ for (uint16 j = 0; j < animKeyCount; j++) {
+ _animKeys.push_back(AnimationKey());
+
+ const uint16 frame = seq.readUint16LE();
+ const uint16 index = seq.readUint16LE();
+
+ uint16 animation;
+ const ANIFile *ani = findANI(index, animation);
+
+ _animKeys.back().object = i;
+ _animKeys.back().frame = frame;
+ _animKeys.back().ani = ani;
+ _animKeys.back().animation = animation;
+ _animKeys.back().x = seq.readSint16LE();
+ _animKeys.back().y = seq.readSint16LE();
+ _animKeys.back().order = seq.readSint16LE();
+ }
+ }
+
+}
+
+const ANIFile *SEQFile::findANI(uint16 index, uint16 &animation) {
+ animation = 0xFFFF;
+
+ // 0xFFFF = remove animation
+ if (index == 0xFFFF)
+ return 0;
+
+ for (Animations::const_iterator a = _animations.begin(); a != _animations.end(); ++a) {
+ if (index < (*a)->getAnimationCount()) {
+ animation = index;
+ return *a;
+ }
+
+ index -= (*a)->getAnimationCount();
+ }
+
+ return 0;
+}
+
+void SEQFile::play(bool abortable, uint16 endFrame, uint16 frameRate) {
+ if (_bgKeys.empty() && _animKeys.empty())
+ // Nothing to do
+ return;
+
+ // Init
+
+ _frame = 0;
+ _abortPlay = false;
+
+ for (uint i = 0; i < kObjectCount; i++) {
+ delete _objects[i].object;
+
+ _objects[i].object = 0;
+ _objects[i].order = 0;
+ }
+
+ for (Loops::iterator l = _loops.begin(); l != _loops.end(); ++l)
+ l->currentLoop = 0;
+
+ // Set the frame rate
+
+ int16 frameRateBack = _vm->_util->getFrameRate();
+
+ if (frameRate == 0)
+ frameRate = _frameRate;
+
+ _vm->_util->setFrameRate(frameRate);
+
+ _abortable = abortable;
+
+ while (!_vm->shouldQuit() && !_abortPlay) {
+ // Handle the frame contents
+ playFrame();
+
+ // Handle extra frame events
+ handleFrameEvent();
+
+ // Wait for the frame to end
+ _vm->_draw->blitInvalidated();
+ _vm->_util->waitEndFrame();
+
+ // Handle input
+
+ _vm->_util->processInput();
+
+ int16 key = _vm->_util->checkKey();
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+ _vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons);
+ _vm->_util->forceMouseUp();
+
+ handleInput(key, mouseX, mouseY, mouseButtons);
+
+ // Loop
+
+ bool looped = false;
+ for (Loops::iterator l = _loops.begin(); l != _loops.end(); ++l) {
+ if ((l->endFrame == _frame) && (l->currentLoop < l->loopCount)) {
+ _frame = l->startFrame;
+
+ l->currentLoop++;
+ looped = true;
+ }
+ }
+
+ // If we didn't loop, advance the frame and look if we should end here
+
+ if (!looped) {
+ _frame++;
+ if (_frame >= endFrame)
+ break;
+ }
+ }
+
+ // Restore the frame rate
+ _vm->_util->setFrameRate(frameRateBack);
+}
+
+void SEQFile::playFrame() {
+ // Remove the current animation frames
+ clearAnims();
+
+ // Handle background keys, directly updating the background
+ for (BackgroundKeys::const_iterator b = _bgKeys.begin(); b != _bgKeys.end(); ++b) {
+ if (!b->background || (b->frame != _frame))
+ continue;
+
+ b->background->draw(*_vm->_draw->_backSurface);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+ }
+
+ // Handle the animation keys, updating the objects
+ for (AnimationKeys::const_iterator a = _animKeys.begin(); a != _animKeys.end(); ++a) {
+ if (a->frame != _frame)
+ continue;
+
+ Object &object = _objects[a->object];
+
+ delete object.object;
+ object.object = 0;
+
+ // No valid animation => remove
+ if ((a->animation == 0xFFFF) || !a->ani)
+ continue;
+
+ // Change the animation
+
+ object.object = new ANIObject(*a->ani);
+
+ object.object->setAnimation(a->animation);
+ object.object->setPosition(a->x, a->y);
+ object.object->setVisible(true);
+ object.object->setPause(false);
+
+ object.order = a->order;
+ }
+
+ // Draw the animations
+ drawAnims();
+}
+
+// NOTE: This is really not at all efficient. However, since there's only a
+// small number of objects, it should matter. We really do need a stable
+// sort, though, so Common::sort() is out.
+SEQFile::Objects SEQFile::getOrderedObjects() {
+ int16 minOrder = (int16)0x7FFF;
+ int16 maxOrder = (int16)0x8000;
+
+ Objects objects;
+
+ // Find the span of order values
+ for (uint i = 0; i < kObjectCount; i++) {
+ if (!_objects[i].object)
+ continue;
+
+ minOrder = MIN(minOrder, _objects[i].order);
+ maxOrder = MAX(maxOrder, _objects[i].order);
+ }
+
+ // Stably sort the objects by order value
+ for (int16 o = minOrder; o <= maxOrder; o++)
+ for (uint i = 0; i < kObjectCount; i++)
+ if (_objects[i].object && (_objects[i].order == o))
+ objects.push_back(_objects[i]);
+
+ return objects;
+}
+
+void SEQFile::clearAnims() {
+ Objects objects = getOrderedObjects();
+
+ // Remove the animation frames, in reverse drawing order
+ for (Objects::iterator o = objects.reverse_begin(); o != objects.end(); --o) {
+ int16 left, top, right, bottom;
+
+ if (o->object->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ }
+}
+
+void SEQFile::drawAnims() {
+ Objects objects = getOrderedObjects();
+
+ // Draw the animation frames and advance the animation
+ for (Objects::iterator o = objects.begin(); o != objects.end(); ++o) {
+ int16 left, top, right, bottom;
+
+ if (o->object->draw(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+ o->object->advance();
+ }
+}
+
+uint16 SEQFile::getFrame() const {
+ return _frame;
+}
+
+void SEQFile::seekFrame(uint16 frame) {
+ _frame = frame;
+}
+
+uint SEQFile::addLoop(uint16 startFrame, uint16 endFrame, uint16 loopCount) {
+ _loops.resize(_loops.size() + 1);
+
+ _loops.back().startFrame = startFrame;
+ _loops.back().endFrame = endFrame;
+ _loops.back().loopCount = loopCount;
+ _loops.back().currentLoop = 0;
+ _loops.back().empty = false;
+
+ return _loops.size() - 1;
+}
+
+void SEQFile::skipLoop(uint loopID) {
+ if (loopID >= _loops.size())
+ return;
+
+ _loops[loopID].currentLoop = 0xFFFF;
+}
+
+void SEQFile::delLoop(uint loopID) {
+ if (loopID >= _loops.size())
+ return;
+
+ _loops[loopID].empty = true;
+
+ cleanLoops();
+}
+
+void SEQFile::cleanLoops() {
+ while (!_loops.empty() && _loops.back().empty)
+ _loops.pop_back();
+}
+
+void SEQFile::abortPlay() {
+ _abortPlay = true;
+}
+
+void SEQFile::handleFrameEvent() {
+}
+
+void SEQFile::handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons) {
+ if (_abortable && ((key != 0) || (mouseButtons != kMouseButtonsNone)))
+ abortPlay();
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/seqfile.h b/engines/gob/pregob/seqfile.h
new file mode 100644
index 0000000000..5e12962ef9
--- /dev/null
+++ b/engines/gob/pregob/seqfile.h
@@ -0,0 +1,193 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_SEQFILE_H
+#define GOB_PREGOB_SEQFILE_H
+
+#include "common/system.h"
+#include "common/array.h"
+#include "common/list.h"
+
+#include "gob/util.h"
+
+namespace Common {
+ class String;
+ class SeekableReadStream;
+}
+
+namespace Gob {
+
+class GobEngine;
+
+class DECFile;
+class ANIFile;
+class ANIObject;
+
+/** A SEQ file, describing a complex animation sequence.
+ *
+ * Used in early hardcoded gob games.
+ * The principle is similar to the Mult class (see mult.h), but instead
+ * of depending on all the externally loaded animations, backgrounds and
+ * objects, a SEQ file references animation and background directly by
+ * filename.
+ */
+class SEQFile {
+public:
+ SEQFile(GobEngine *vm, const Common::String &fileName);
+ virtual ~SEQFile();
+
+ /** Play the SEQ.
+ *
+ * @param abortable If true, end playback on any user input.
+ * @param endFrame The frame on where to end, or 0xFFFF for infinite playback.
+ * @param frameRate The frame rate at which to play the SEQ, or 0 for playing at
+ * the speed the SEQ itself wants to.
+ */
+ void play(bool abortable = true, uint16 endFrame = 0xFFFF, uint16 frameRate = 0);
+
+
+protected:
+ GobEngine *_vm;
+
+
+ /** Returns the current frame number. */
+ uint16 getFrame() const;
+
+ /** Seek to a specific frame. */
+ void seekFrame(uint16 frame);
+
+ /** Add a frame loop. */
+ uint addLoop(uint16 startFrame, uint16 endFrame, uint16 loopCount);
+
+ /** Skip a frame loop. */
+ void skipLoop(uint loopID);
+
+ /** Delete a frame loop. */
+ void delLoop(uint loopID);
+
+ /** Ends SEQ playback. */
+ void abortPlay();
+
+ /** Callback for special frame events. */
+ virtual void handleFrameEvent();
+ /** Callback for special user input handling. */
+ virtual void handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons);
+
+
+private:
+ /** Number of animation objects that are visible at the same time. */
+ static const uint kObjectCount = 4;
+
+ /** A key for changing the background. */
+ struct BackgroundKey {
+ uint16 frame; ///< Frame the change is to happen.
+
+ const DECFile *background; ///< The background to use.
+ };
+
+ /** A key for playing an object animation. */
+ struct AnimationKey {
+ uint object; ///< The object this key belongs to.
+
+ uint16 frame; ///< Frame the change is to happen.
+
+ const ANIFile *ani; ///< The ANI to use.
+
+ uint16 animation; ///< The animation to use.
+
+ int16 x; ///< X position of the animation.
+ int16 y; ///< Y position of the animation.
+
+ int16 order; ///< Used to determine in which order to draw the objects.
+ };
+
+ /** A managed animation object. */
+ struct Object {
+ ANIObject *object; ///< The actual animation object.
+
+ int16 order; ///< The current drawing order.
+ };
+
+ /** A frame loop. */
+ struct Loop {
+ uint16 startFrame;
+ uint16 endFrame;
+
+ uint16 loopCount;
+ uint16 currentLoop;
+
+ bool empty;
+ };
+
+ typedef Common::Array<DECFile *> Backgrounds;
+ typedef Common::Array<ANIFile *> Animations;
+
+ typedef Common::Array<BackgroundKey> BackgroundKeys;
+ typedef Common::Array<AnimationKey> AnimationKeys;
+
+ typedef Common::List<Object> Objects;
+
+ typedef Common::Array<Loop> Loops;
+
+
+ uint16 _frame; ///< The current frame.
+ bool _abortPlay; ///< Was the end of the playback requested?
+
+ uint16 _frameRate;
+
+ Backgrounds _backgrounds; ///< All backgrounds in this SEQ.
+ Animations _animations; ///< All animations in this SEQ.
+
+ BackgroundKeys _bgKeys; ///< The background change keyframes.
+ AnimationKeys _animKeys; ///< The animation change keyframes.
+
+ Object _objects[kObjectCount]; ///< The managed animation objects.
+
+ Loops _loops;
+
+ /** Whether the playback should be abortable by user input. */
+ bool _abortable;
+
+
+ // -- Loading helpers --
+
+ void load(Common::SeekableReadStream &seq);
+
+ const ANIFile *findANI(uint16 index, uint16 &animation);
+
+ // -- Playback helpers --
+
+ void playFrame();
+
+ /** Get a list of objects ordered by drawing order. */
+ Objects getOrderedObjects();
+
+ void clearAnims(); ///< Remove all animation frames.
+ void drawAnims(); ///< Draw the animation frames.
+
+ /** Look if we can compact the loop array. */
+ void cleanLoops();
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_SEQFILE_H
diff --git a/engines/gob/pregob/txtfile.cpp b/engines/gob/pregob/txtfile.cpp
new file mode 100644
index 0000000000..3ff0d4b039
--- /dev/null
+++ b/engines/gob/pregob/txtfile.cpp
@@ -0,0 +1,232 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "gob/draw.h"
+
+#include "gob/pregob/txtfile.h"
+
+namespace Gob {
+
+TXTFile::TXTFile(Common::SeekableReadStream &txt, Format format) {
+ load(txt, format);
+}
+
+TXTFile::~TXTFile() {
+}
+
+TXTFile::LineArray &TXTFile::getLines() {
+ return _lines;
+}
+
+void TXTFile::load(Common::SeekableReadStream &txt, Format format) {
+ if (format == kFormatStringPositionColorFont) {
+ int numLines = getInt(txt);
+
+ _lines.reserve(numLines);
+ }
+
+ while (!txt.eos()) {
+ Line line;
+
+ line.text = getStr(txt);
+ line.x = (format >= kFormatStringPosition) ? getInt(txt) : 0;
+ line.y = (format >= kFormatStringPosition) ? getInt(txt) : 0;
+ line.color = (format >= kFormatStringPositionColor) ? getInt(txt) : 0;
+ line.font = (format >= kFormatStringPositionColorFont) ? getInt(txt) : 0;
+
+ _lines.push_back(line);
+ }
+
+ while (!_lines.empty() && _lines.back().text.empty())
+ _lines.pop_back();
+}
+
+bool TXTFile::draw(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount, int color) {
+
+ trashBuffer();
+
+ if (!getArea(left, top, right, bottom, fonts, fontCount))
+ return false;
+
+ resizeBuffer(right - left + 1, bottom - top + 1);
+ saveScreen(surface, left, top, right, bottom);
+
+ for (LineArray::const_iterator l = _lines.begin(); l != _lines.end(); ++l) {
+ if (l->font >= fontCount)
+ continue;
+
+ fonts[l->font]->drawString(l->text, l->x, l->y, (color < 0) ? l->color : color, 0, true, surface);
+ }
+
+ return true;
+}
+
+bool TXTFile::draw(uint line, Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount, int color) {
+
+ trashBuffer();
+
+ if (!getArea(line, left, top, right, bottom, fonts, fontCount))
+ return false;
+
+ resizeBuffer(right - left + 1, bottom - top + 1);
+ saveScreen(surface, left, top, right, bottom);
+
+ const Line &l = _lines[line];
+
+ fonts[l.font]->drawString(l.text, l.x, l.y, (color < 0) ? l.color : color, 0, true, surface);
+
+ return true;
+}
+
+bool TXTFile::draw(Surface &surface, const Font * const *fonts, uint fontCount, int color) {
+ int16 left, top, right, bottom;
+
+ return draw(surface, left, top, right, bottom, fonts, fontCount, color);
+}
+
+bool TXTFile::draw(uint line, Surface &surface, const Font * const *fonts, uint fontCount, int color) {
+ int16 left, top, right, bottom;
+
+ return draw(line, surface, left, top, right, bottom, fonts, fontCount, color);
+}
+
+bool TXTFile::clear(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ return restoreScreen(surface, left, top, right, bottom);
+}
+
+bool TXTFile::getArea(int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount) const {
+
+ bool hasLine = false;
+
+ left = 0x7FFF;
+ top = 0x7FFF;
+ right = 0x0000;
+ bottom = 0x0000;
+
+ for (uint i = 0; i < _lines.size(); i++) {
+ int16 lLeft, lTop, lRight, lBottom;
+
+ if (getArea(i, lLeft, lTop, lRight, lBottom, fonts, fontCount)) {
+ left = MIN(left , lLeft );
+ top = MIN(top , lTop );
+ right = MAX(right , lRight );
+ bottom = MAX(bottom, lBottom);
+
+ hasLine = true;
+ }
+ }
+
+ return hasLine;
+}
+
+bool TXTFile::getArea(uint line, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount) const {
+
+
+ if ((line >= _lines.size()) || (_lines[line].font >= fontCount))
+ return false;
+
+ const Line &l = _lines[line];
+
+ left = l.x;
+ top = l.y;
+ right = l.x + l.text.size() * fonts[l.font]->getCharWidth() - 1;
+ bottom = l.y + fonts[l.font]->getCharHeight() - 1;
+
+ return true;
+}
+
+Common::String TXTFile::getStr(Common::SeekableReadStream &txt) {
+ // Skip all ' ', '\n' and '\r'
+ while (!txt.eos()) {
+ char c = txt.readByte();
+ if (txt.eos())
+ break;
+
+ if ((c != ' ') && (c != '\n') && (c != '\r')) {
+ txt.seek(-1, SEEK_CUR);
+ break;
+ }
+ }
+
+ if (txt.eos())
+ return "";
+
+ // Read string until ' ', '\n' or '\r'
+ Common::String string;
+ while (!txt.eos()) {
+ char c = txt.readByte();
+ if ((c == ' ') || (c == '\n') || (c == '\r'))
+ break;
+
+ string += c;
+ }
+
+ // Replace all '#' with ' ' and throw out non-printables
+ Common::String cleanString;
+
+ for (uint i = 0; i < string.size(); i++) {
+ if (string[i] == '#')
+ cleanString += ' ';
+ else if ((unsigned char)string[i] >= ' ')
+ cleanString += string[i];
+ }
+
+ return cleanString;
+}
+
+int TXTFile::getInt(Common::SeekableReadStream &txt) {
+ // Skip all [^-0-9]
+ while (!txt.eos()) {
+ char c = txt.readByte();
+ if (txt.eos())
+ break;
+
+ if ((c == '-') || ((c >= '0') && (c <= '9'))) {
+ txt.seek(-1, SEEK_CUR);
+ break;
+ }
+ }
+
+ if (txt.eos())
+ return 0;
+
+ // Read until [^-0-9]
+ Common::String string;
+ while (!txt.eos()) {
+ char c = txt.readByte();
+ if ((c != '-') && ((c < '0') || (c > '9')))
+ break;
+
+ string += c;
+ }
+
+ // Convert to integer
+ return atoi(string.c_str());
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/txtfile.h b/engines/gob/pregob/txtfile.h
new file mode 100644
index 0000000000..c623b58859
--- /dev/null
+++ b/engines/gob/pregob/txtfile.h
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GOB_PREGOB_TXTFILE_H
+#define GOB_PREGOB_TXTFILE_H
+
+#include "common/system.h"
+#include "common/str.h"
+#include "common/array.h"
+
+#include "gob/backbuffer.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Gob {
+
+class Surface;
+class Font;
+
+class TXTFile : public BackBuffer {
+public:
+ enum Format {
+ kFormatString,
+ kFormatStringPosition,
+ kFormatStringPositionColor,
+ kFormatStringPositionColorFont
+ };
+
+ struct Line {
+ Common::String text;
+ int x, y;
+ int color;
+ uint font;
+ };
+
+ typedef Common::Array<Line> LineArray;
+
+ TXTFile(Common::SeekableReadStream &txt, Format format);
+ ~TXTFile();
+
+ LineArray &getLines();
+
+ bool draw( Surface &surface, const Font * const *fonts, uint fontCount, int color = -1);
+ bool draw(uint line, Surface &surface, const Font * const *fonts, uint fontCount, int color = -1);
+
+ bool draw( Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount, int color = -1);
+ bool draw(uint line, Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount, int color = -1);
+
+ bool clear(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+private:
+ LineArray _lines;
+
+ void load(Common::SeekableReadStream &txt, Format format);
+
+ Common::String getStr(Common::SeekableReadStream &txt);
+ int getInt(Common::SeekableReadStream &txt);
+
+
+ bool getArea( int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount) const;
+ bool getArea(uint line, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_TXTFILE_H
diff --git a/engines/gob/rxyfile.cpp b/engines/gob/rxyfile.cpp
index 9702dc8c7f..2ff8c121cd 100644
--- a/engines/gob/rxyfile.cpp
+++ b/engines/gob/rxyfile.cpp
@@ -21,12 +21,19 @@
*/
#include "common/stream.h"
+#include "common/substream.h"
#include "gob/rxyfile.h"
namespace Gob {
RXYFile::RXYFile(Common::SeekableReadStream &rxy) : _width(0), _height(0) {
+ Common::SeekableSubReadStreamEndian sub(&rxy, 0, rxy.size(), false, DisposeAfterUse::NO);
+
+ load(sub);
+}
+
+RXYFile::RXYFile(Common::SeekableSubReadStreamEndian &rxy) : _width(0), _height(0) {
load(rxy);
}
@@ -64,22 +71,22 @@ const RXYFile::Coordinates &RXYFile::operator[](uint i) const {
return _coords[i];
}
-void RXYFile::load(Common::SeekableReadStream &rxy) {
+void RXYFile::load(Common::SeekableSubReadStreamEndian &rxy) {
if (rxy.size() < 2)
return;
rxy.seek(0);
- _realCount = rxy.readUint16LE();
+ _realCount = rxy.readUint16();
uint16 count = (rxy.size() - 2) / 8;
_coords.resize(count);
for (CoordArray::iterator c = _coords.begin(); c != _coords.end(); ++c) {
- c->left = rxy.readUint16LE();
- c->right = rxy.readUint16LE();
- c->top = rxy.readUint16LE();
- c->bottom = rxy.readUint16LE();
+ c->left = rxy.readUint16();
+ c->right = rxy.readUint16();
+ c->top = rxy.readUint16();
+ c->bottom = rxy.readUint16();
if (c->left != 0xFFFF) {
_width = MAX<uint16>(_width , c->right + 1);
diff --git a/engines/gob/rxyfile.h b/engines/gob/rxyfile.h
index bc9600b5b0..4fd46c5e40 100644
--- a/engines/gob/rxyfile.h
+++ b/engines/gob/rxyfile.h
@@ -28,6 +28,7 @@
namespace Common {
class SeekableReadStream;
+ class SeekableSubReadStreamEndian;
}
namespace Gob {
@@ -46,6 +47,7 @@ public:
};
RXYFile(Common::SeekableReadStream &rxy);
+ RXYFile(Common::SeekableSubReadStreamEndian &rxy);
RXYFile(uint16 width, uint16 height);
~RXYFile();
@@ -71,7 +73,7 @@ private:
uint16 _height;
- void load(Common::SeekableReadStream &rxy);
+ void load(Common::SeekableSubReadStreamEndian &rxy);
};
} // End of namespace Gob
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index 403bd632a1..63af6aeef4 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -109,7 +109,7 @@ int Sound::sampleGetNextFreeSlot() const {
return -1;
}
-bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, bool tryExist) {
+bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName) {
if (!sndDesc)
return false;
@@ -117,12 +117,15 @@ bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName,
int32 size;
byte *data = _vm->_dataIO->getFile(fileName, size);
- if (!data) {
- warning("Can't open sample file \"%s\"", fileName);
+
+ if (!data || !sndDesc->load(type, data, size)) {
+ delete data;
+
+ warning("Sound::sampleLoad(): Failed to load sound \"%s\"", fileName);
return false;
}
- return sndDesc->load(type, data, size);
+ return true;
}
void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdLib, int index) {
@@ -458,7 +461,7 @@ void Sound::blasterStop(int16 fadeLength, SoundDesc *sndDesc) {
_blaster->stopSound(fadeLength, sndDesc);
}
-void Sound::blasterPlayComposition(int16 *composition, int16 freqVal,
+void Sound::blasterPlayComposition(const int16 *composition, int16 freqVal,
SoundDesc *sndDescs, int8 sndCount) {
if (!_blaster)
return;
diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h
index 6ad0ec5483..bbc182d172 100644
--- a/engines/gob/sound/sound.h
+++ b/engines/gob/sound/sound.h
@@ -51,7 +51,7 @@ public:
const SoundDesc *sampleGetBySlot(int slot) const;
int sampleGetNextFreeSlot() const;
- bool sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, bool tryExist = true);
+ bool sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName);
void sampleFree(SoundDesc *sndDesc, bool noteAdLib = false, int index = -1);
@@ -60,7 +60,7 @@ public:
int16 frequency, int16 fadeLength = 0);
void blasterStop(int16 fadeLength, SoundDesc *sndDesc = 0);
- void blasterPlayComposition(int16 *composition, int16 freqVal,
+ void blasterPlayComposition(const int16 *composition, int16 freqVal,
SoundDesc *sndDescs = 0, int8 sndCount = kSoundsCount);
void blasterStopComposition();
void blasterRepeatComposition(int32 repCount);
diff --git a/engines/gob/sound/soundblaster.cpp b/engines/gob/sound/soundblaster.cpp
index 19c2346448..f267eee32d 100644
--- a/engines/gob/sound/soundblaster.cpp
+++ b/engines/gob/sound/soundblaster.cpp
@@ -88,7 +88,7 @@ void SoundBlaster::nextCompositionPos() {
_compositionPos = -1;
}
-void SoundBlaster::playComposition(int16 *composition, int16 freqVal,
+void SoundBlaster::playComposition(const int16 *composition, int16 freqVal,
SoundDesc *sndDescs, int8 sndCount) {
_compositionSamples = sndDescs;
diff --git a/engines/gob/sound/soundblaster.h b/engines/gob/sound/soundblaster.h
index c740ba2269..3c4968d611 100644
--- a/engines/gob/sound/soundblaster.h
+++ b/engines/gob/sound/soundblaster.h
@@ -41,7 +41,7 @@ public:
int16 frequency, int16 fadeLength = 0);
void stopSound(int16 fadeLength, SoundDesc *sndDesc = 0);
- void playComposition(int16 *composition, int16 freqVal,
+ void playComposition(const int16 *composition, int16 freqVal,
SoundDesc *sndDescs = 0, int8 sndCount = 60);
void stopComposition();
void endComposition();
diff --git a/engines/gob/surface.cpp b/engines/gob/surface.cpp
index 3eaf741be2..afbb7c3bae 100644
--- a/engines/gob/surface.cpp
+++ b/engines/gob/surface.cpp
@@ -684,6 +684,12 @@ void Surface::shadeRect(uint16 left, uint16 top, uint16 right, uint16 bottom,
}
+void Surface::recolor(uint8 from, uint8 to) {
+ for (Pixel p = get(); p.isValid(); ++p)
+ if (p.get() == from)
+ p.set(to);
+}
+
void Surface::putPixel(uint16 x, uint16 y, uint32 color) {
if ((x >= _width) || (y >= _height))
return;
diff --git a/engines/gob/surface.h b/engines/gob/surface.h
index 09be8d1a49..8f895a7910 100644
--- a/engines/gob/surface.h
+++ b/engines/gob/surface.h
@@ -156,6 +156,8 @@ public:
void shadeRect(uint16 left, uint16 top, uint16 right, uint16 bottom,
uint32 color, uint8 strength);
+ void recolor(uint8 from, uint8 to);
+
void putPixel(uint16 x, uint16 y, uint32 color);
void drawLine(uint16 x0, uint16 y0, uint16 x1, uint16 y1, uint32 color);
void drawRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uint32 color);
diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp
index 64dfcf9b12..5ac4ef024e 100644
--- a/engines/gob/util.cpp
+++ b/engines/gob/util.cpp
@@ -189,12 +189,27 @@ bool Util::getKeyFromBuffer(Common::KeyState &key) {
return true;
}
+static const uint16 kLatin1ToCP850[] = {
+ 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE,
+ 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8,
+ 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8,
+ 0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1,
+ 0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B,
+ 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98
+};
+
+int16 Util::toCP850(uint16 latin1) {
+ if ((latin1 < 0xA0) || ((latin1 - 0xA0) >= ARRAYSIZE(kLatin1ToCP850)))
+ return 0;
+
+ return kLatin1ToCP850[latin1 - 0xA0];
+}
+
int16 Util::translateKey(const Common::KeyState &key) {
static struct keyS {
int16 from;
int16 to;
} keys[] = {
- {Common::KEYCODE_INVALID, kKeyNone },
{Common::KEYCODE_BACKSPACE, kKeyBackspace},
{Common::KEYCODE_SPACE, kKeySpace },
{Common::KEYCODE_RETURN, kKeyReturn },
@@ -216,20 +231,88 @@ int16 Util::translateKey(const Common::KeyState &key) {
{Common::KEYCODE_F10, kKeyF10 }
};
+ // Translate special keys
for (int i = 0; i < ARRAYSIZE(keys); i++)
if (key.keycode == keys[i].from)
return keys[i].to;
- if ((key.keycode >= Common::KEYCODE_SPACE) &&
- (key.keycode <= Common::KEYCODE_DELETE)) {
-
- // Used as a user input in Gobliins 2 notepad, in the save dialog, ...
+ // Return the ascii value, for text input
+ if ((key.ascii >= 32) && (key.ascii <= 127))
return key.ascii;
- }
+
+ // Translate international characters into CP850 characters
+ if ((key.ascii >= 160) && (key.ascii <= 255))
+ return toCP850(key.ascii);
return 0;
}
+static const uint8 kLowerToUpper[][2] = {
+ {0x81, 0x9A},
+ {0x82, 0x90},
+ {0x83, 0xB6},
+ {0x84, 0x8E},
+ {0x85, 0xB7},
+ {0x86, 0x8F},
+ {0x87, 0x80},
+ {0x88, 0xD2},
+ {0x89, 0xD3},
+ {0x8A, 0xD4},
+ {0x8B, 0xD8},
+ {0x8C, 0xD7},
+ {0x8D, 0xDE},
+ {0x91, 0x92},
+ {0x93, 0xE2},
+ {0x94, 0x99},
+ {0x95, 0xE3},
+ {0x96, 0xEA},
+ {0x97, 0xEB},
+ {0x95, 0xE3},
+ {0x96, 0xEA},
+ {0x97, 0xEB},
+ {0x9B, 0x9D},
+ {0xA0, 0xB5},
+ {0xA1, 0xD6},
+ {0xA2, 0xE0},
+ {0xA3, 0xE9},
+ {0xA4, 0xA5},
+ {0xC6, 0xC7},
+ {0xD0, 0xD1},
+ {0xE4, 0xE5},
+ {0xE7, 0xE8},
+ {0xEC, 0xED}
+};
+
+char Util::toCP850Lower(char cp850) {
+ const uint8 cp = (unsigned char)cp850;
+ if (cp <= 32)
+ return cp850;
+
+ if (cp <= 127)
+ return tolower(cp850);
+
+ for (uint i = 0; i < ARRAYSIZE(kLowerToUpper); i++)
+ if (cp == kLowerToUpper[i][1])
+ return (char)kLowerToUpper[i][0];
+
+ return cp850;
+}
+
+char Util::toCP850Upper(char cp850) {
+ const uint8 cp = (unsigned char)cp850;
+ if (cp <= 32)
+ return cp850;
+
+ if (cp <= 127)
+ return toupper(cp850);
+
+ for (uint i = 0; i < ARRAYSIZE(kLowerToUpper); i++)
+ if (cp == kLowerToUpper[i][0])
+ return (char)kLowerToUpper[i][1];
+
+ return cp850;
+}
+
int16 Util::getKey() {
Common::KeyState key;
@@ -367,21 +450,29 @@ void Util::notifyNewAnim() {
_startFrameTime = getTimeKey();
}
-void Util::waitEndFrame() {
+void Util::waitEndFrame(bool handleInput) {
int32 time;
- _vm->_video->waitRetrace();
-
time = getTimeKey() - _startFrameTime;
if ((time > 1000) || (time < 0)) {
+ _vm->_video->retrace();
_startFrameTime = getTimeKey();
return;
}
- int32 toWait = _frameWaitTime - time;
+ int32 toWait = 0;
+ do {
+ if (toWait > 0)
+ delay(MIN<int>(toWait, 10));
+
+ if (handleInput)
+ processInput();
+
+ _vm->_video->retrace();
- if (toWait > 0)
- delay(toWait);
+ time = getTimeKey() - _startFrameTime;
+ toWait = _frameWaitTime - time;
+ } while (toWait > 0);
_startFrameTime = getTimeKey();
}
diff --git a/engines/gob/util.h b/engines/gob/util.h
index b26a78ab2c..a4984c6207 100644
--- a/engines/gob/util.h
+++ b/engines/gob/util.h
@@ -124,7 +124,7 @@ public:
int16 getFrameRate();
void setFrameRate(int16 rate);
void notifyNewAnim();
- void waitEndFrame();
+ void waitEndFrame(bool handleInput = true);
void setScrollOffset(int16 x = -1, int16 y = -1);
static void insertStr(const char *str1, char *str2, int16 pos);
@@ -143,6 +143,11 @@ public:
/** Read a constant-length string out of a stream. */
static Common::String readString(Common::SeekableReadStream &stream, int n);
+ /** Convert a character in CP850 encoding to the equivalent lower case character. */
+ static char toCP850Lower(char cp850);
+ /** Convert a character in CP850 encoding to the equivalent upper case character. */
+ static char toCP850Upper(char cp850);
+
Util(GobEngine *vm);
protected:
@@ -166,6 +171,7 @@ protected:
void addKeyToBuffer(const Common::KeyState &key);
bool getKeyFromBuffer(Common::KeyState &key);
int16 translateKey(const Common::KeyState &key);
+ int16 toCP850(uint16 latin1);
void checkJoystick();
void keyDown(const Common::Event &event);
diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp
index 3b1c6423bb..64af34cf62 100644
--- a/engines/gob/video.cpp
+++ b/engines/gob/video.cpp
@@ -84,6 +84,10 @@ uint16 Font::getCharCount() const {
return _endItem - _startItem + 1;
}
+bool Font::hasChar(uint8 c) const {
+ return (c >= _startItem) && (c <= _endItem);
+}
+
bool Font::isMonospaced() const {
return _charWidths == 0;
}
@@ -134,6 +138,23 @@ void Font::drawLetter(Surface &surf, uint8 c, uint16 x, uint16 y,
}
}
+void Font::drawString(const Common::String &str, int16 x, int16 y, int16 color1, int16 color2,
+ bool transp, Surface &dest) const {
+
+ const char *s = str.c_str();
+
+ while (*s != '\0') {
+ const int16 charRight = x + getCharWidth(*s);
+ const int16 charBottom = y + getCharHeight();
+
+ if ((x >= 0) && (y >= 0) && (charRight <= dest.getWidth()) && (charBottom <= dest.getHeight()))
+ drawLetter(dest, *s, x, y, color1, color2, transp);
+
+ x += getCharWidth(*s);
+ s++;
+ }
+}
+
const byte *Font::getCharData(uint8 c) const {
if (_endItem == 0) {
warning("Font::getCharData(): _endItem == 0");
@@ -225,7 +246,7 @@ void Video::setSize(bool defaultTo1XScaler) {
void Video::retrace(bool mouse) {
if (mouse)
- CursorMan.showMouse((_vm->_draw->_showCursor & 2) != 0);
+ CursorMan.showMouse((_vm->_draw->_showCursor & 6) != 0);
if (_vm->_global->_primarySurfDesc) {
int screenX = _screenDeltaX;
@@ -332,6 +353,10 @@ void Video::drawPackedSprite(byte *sprBuf, int16 width, int16 height,
void Video::drawPackedSprite(const char *path, Surface &dest, int width) {
int32 size;
byte *data = _vm->_dataIO->getFile(path, size);
+ if (!data) {
+ warning("Video::drawPackedSprite(): Failed to open sprite \"%s\"", path);
+ return;
+ }
drawPackedSprite(data, width, dest.getHeight(), 0, 0, 0, dest);
delete[] data;
diff --git a/engines/gob/video.h b/engines/gob/video.h
index ecbb579c5f..122c1e47d5 100644
--- a/engines/gob/video.h
+++ b/engines/gob/video.h
@@ -41,11 +41,16 @@ public:
uint8 getCharWidth () const;
uint8 getCharHeight() const;
+ bool hasChar(uint8 c) const;
+
bool isMonospaced() const;
void drawLetter(Surface &surf, uint8 c, uint16 x, uint16 y,
uint32 color1, uint32 color2, bool transp) const;
+ void drawString(const Common::String &str, int16 x, int16 y, int16 color1, int16 color2,
+ bool transp, Surface &dest) const;
+
private:
const byte *_dataPtr;
const byte *_data;
diff --git a/engines/groovie/saveload.cpp b/engines/groovie/saveload.cpp
index 14e7a09cb2..1a92c02e0e 100644
--- a/engines/groovie/saveload.cpp
+++ b/engines/groovie/saveload.cpp
@@ -103,8 +103,6 @@ Common::InSaveFile *SaveLoad::openForLoading(const Common::String &target, int s
if (descriptor) {
// Initialize the SaveStateDescriptor
descriptor->setSaveSlot(slot);
- descriptor->setDeletableFlag(true);
- descriptor->setWriteProtectedFlag(false);
// TODO: Add extra information
//setSaveDate(int year, int month, int day)
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp
index 90708163f5..bb5944acc8 100644
--- a/engines/hugo/detection.cpp
+++ b/engines/hugo/detection.cpp
@@ -244,9 +244,6 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s
Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
desc.setThumbnail(thumbnail);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
-
uint32 saveDate = file->readUint32BE();
uint16 saveTime = file->readUint16BE();
diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index 79ef11e7a9..e2162f20e2 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -1329,6 +1329,22 @@ const KYRAGameDescription adGameDescs[] = {
LOL_FLOPPY_CMP_FLAGS
},
+ { // French floppy version 1.20, bug #3552534 "KYRA: LOL Floppy FR version unknown"
+ {
+ "lol",
+ 0,
+ {
+ { "WESTWOOD.1", 0, "43857e24d1fc6731f3b13d9ed6db8c3a", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO8(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GAMEOPTION_LOL_SCROLLING, GAMEOPTION_LOL_CURSORS)
+ },
+ LOL_FLOPPY_CMP_FLAGS
+ },
+
{
{
"lol",
@@ -1397,6 +1413,23 @@ const KYRAGameDescription adGameDescs[] = {
LOL_FLOPPY_FLAGS
},
+ { // French floppy version 1.23, bug #3552534 "KYRA: LOL Floppy FR version unknown"
+ {
+ "lol",
+ "Extracted",
+ {
+ { "GENERAL.PAK", 0, "f4fd14f244bd7c7fa08d026fafe44cc5", -1 },
+ { "CHAPTER7.PAK", 0, "733e33c8444c93843dac3b683c283eaa", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO8(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GAMEOPTION_LOL_SCROLLING, GAMEOPTION_LOL_CURSORS)
+ },
+ LOL_FLOPPY_FLAGS
+ },
+
// Russian fan translation
{
{
diff --git a/engines/kyra/eobcommon.cpp b/engines/kyra/eobcommon.cpp
index a63f123258..fadb1066e0 100644
--- a/engines/kyra/eobcommon.cpp
+++ b/engines/kyra/eobcommon.cpp
@@ -770,7 +770,7 @@ void EoBCoreEngine::releaseItemsAndDecorationsShapes() {
if (_spellShapes) {
for (int i = 0; i < 4; i++) {
if (_spellShapes[i])
- delete [] _spellShapes[i];
+ delete[] _spellShapes[i];
}
delete[] _spellShapes;
}
@@ -820,7 +820,7 @@ void EoBCoreEngine::releaseItemsAndDecorationsShapes() {
if (_firebeamShapes[i])
delete[] _firebeamShapes[i];
}
- delete []_firebeamShapes;
+ delete[] _firebeamShapes;
}
delete[] _redSplatShape;
diff --git a/engines/kyra/eobcommon.h b/engines/kyra/eobcommon.h
index 050fe2b794..f60e755dd7 100644
--- a/engines/kyra/eobcommon.h
+++ b/engines/kyra/eobcommon.h
@@ -263,7 +263,7 @@ protected:
// Main Menu, Intro, Finale
virtual int mainMenu() = 0;
- virtual void seq_xdeath() {};
+ virtual void seq_xdeath() {}
virtual void seq_playFinale() = 0;
bool _playFinale;
@@ -921,8 +921,8 @@ protected:
void usePotion(int charIndex, int weaponSlot);
void useWand(int charIndex, int weaponSlot);
- virtual void turnUndeadAuto() {};
- virtual void turnUndeadAutoHit() {};
+ virtual void turnUndeadAuto() {}
+ virtual void turnUndeadAutoHit() {}
void castSpell(int spell, int weaponSlot);
void removeCharacterEffect(int spell, int charIndex, int showWarning);
diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp
index 4fd5985a09..04d805737f 100644
--- a/engines/kyra/screen.cpp
+++ b/engines/kyra/screen.cpp
@@ -141,7 +141,7 @@ bool Screen::init() {
if (!font)
error("Could not load any SJIS font, neither the original nor ScummVM's 'SJIS.FNT'");
- _fonts[FID_SJIS_FNT] = new SJISFont(this, font, _sjisInvisibleColor, _use16ColorMode, !_use16ColorMode);
+ _fonts[FID_SJIS_FNT] = new SJISFont(font, _sjisInvisibleColor, _use16ColorMode, !_use16ColorMode);
}
}
@@ -3595,8 +3595,8 @@ void AMIGAFont::unload() {
memset(_chars, 0, sizeof(_chars));
}
-SJISFont::SJISFont(Screen *s, Graphics::FontSJIS *font, const uint8 invisColor, bool is16Color, bool outlineSize)
- : _colorMap(0), _font(font), _invisColor(invisColor), _is16Color(is16Color), _screen(s) {
+SJISFont::SJISFont(Graphics::FontSJIS *font, const uint8 invisColor, bool is16Color, bool outlineSize)
+ : _colorMap(0), _font(font), _invisColor(invisColor), _is16Color(is16Color) {
assert(_font);
_font->setDrawingMode(outlineSize ? Graphics::FontSJIS::kOutlineMode : Graphics::FontSJIS::kDefaultMode);
diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h
index b064c72bb0..60bfeb3241 100644
--- a/engines/kyra/screen.h
+++ b/engines/kyra/screen.h
@@ -213,7 +213,7 @@ private:
*/
class SJISFont : public Font {
public:
- SJISFont(Screen *s, Graphics::FontSJIS *font, const uint8 invisColor, bool is16Color, bool outlineSize);
+ SJISFont(Graphics::FontSJIS *font, const uint8 invisColor, bool is16Color, bool outlineSize);
~SJISFont() { unload(); }
bool usesOverlay() const { return true; }
@@ -233,7 +233,6 @@ private:
const uint8 _invisColor;
const bool _is16Color;
- const Screen *_screen;
int _sjisWidth, _asciiWidth;
int _fontHeight;
};
diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp
index e06ca42c40..ae75c111b4 100644
--- a/engines/kyra/screen_eob.cpp
+++ b/engines/kyra/screen_eob.cpp
@@ -607,7 +607,7 @@ uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool enco
srcLineStart += SCREEN_W;
src = srcLineStart;
}
- delete [] colorMap;
+ delete[] colorMap;
}
return shp;
diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp
index 08b232f400..3726b1f4b9 100644
--- a/engines/kyra/screen_lol.cpp
+++ b/engines/kyra/screen_lol.cpp
@@ -31,7 +31,7 @@
namespace Kyra {
-Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system, vm->gameFlags().use16ColorMode ? _screenDimTable16C : _screenDimTable256C, _screenDimTableCount), _vm(vm) {
+Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system, vm->gameFlags().use16ColorMode ? _screenDimTable16C : _screenDimTable256C, _screenDimTableCount) {
_paletteOverlay1 = new uint8[0x100];
_paletteOverlay2 = new uint8[0x100];
_grayOverlay = new uint8[0x100];
diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h
index 3bba9f8b70..09496705bb 100644
--- a/engines/kyra/screen_lol.h
+++ b/engines/kyra/screen_lol.h
@@ -89,8 +89,6 @@ public:
static void convertPC98Gfx(uint8 *data, int w, int h, int pitch);
private:
- LoLEngine *_vm;
-
static const ScreenDim _screenDimTable256C[];
static const ScreenDim _screenDimTable16C[];
static const int _screenDimTableCount;
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index 427bef66e2..827a487685 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -130,7 +130,6 @@ private:
void fadeOutSoundEffects();
int _lastTrack;
- Audio::AudioStream *_currentSFX;
Audio::SoundHandle _sfxHandle;
uint8 *_musicTrackData;
diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp
index 0004395f6f..70cc304192 100644
--- a/engines/kyra/sound_midi.cpp
+++ b/engines/kyra/sound_midi.cpp
@@ -475,8 +475,8 @@ SoundMidiPC::SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *dri
::GUI::MessageDialog dialog(_("You appear to be using a General MIDI device,\n"
"but your game only supports Roland MT32 MIDI.\n"
"We try to map the Roland MT32 instruments to\n"
- "General MIDI ones. After all it might happen\n"
- "that a few tracks will not be correctly played."));
+ "General MIDI ones. It is still possible that\n"
+ "some tracks sound incorrect."));
dialog.runModal();
}
}
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 2f996de1ac..4b25db33f2 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -34,7 +34,7 @@
namespace Kyra {
SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer)
- : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0),
+ : Sound(vm, mixer), _lastTrack(-1), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0),
_sfxFileIndex((uint)-1), _musicFadeTable(0), _sfxWDTable(0), _sfxBTTable(0), _sfxChannel(0x46) {
_driver = new TownsEuphonyDriver(_mixer);
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 423b827092..00dc4f9e13 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -38,7 +38,7 @@
namespace Kyra {
-#define RESFILE_VERSION 82
+#define RESFILE_VERSION 83
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
diff --git a/engines/lastexpress/data/animation.cpp b/engines/lastexpress/data/animation.cpp
index 9d0ed532f2..7618259e69 100644
--- a/engines/lastexpress/data/animation.cpp
+++ b/engines/lastexpress/data/animation.cpp
@@ -32,10 +32,8 @@
#include "common/events.h"
#include "common/rational.h"
-#include "common/rect.h"
#include "common/stream.h"
#include "common/system.h"
-#include "common/textconsole.h"
#include "engines/engine.h"
@@ -232,7 +230,7 @@ AnimFrame *Animation::processChunkFrame(Common::SeekableReadStream *in, const Ch
i.read(str, false);
// Decode the frame
- AnimFrame *f = new AnimFrame(str, i);
+ AnimFrame *f = new AnimFrame(str, i, true);
// Delete the temporary chunk buffer
delete str;
@@ -250,7 +248,7 @@ void Animation::processChunkAudio(Common::SeekableReadStream *in, const Chunk &c
// Read Snd header
uint32 header1 = in->readUint32LE();
uint16 header2 = in->readUint16LE();
- warning("Start ADPCM: %d, %d", header1, header2);
+ debugC(4, kLastExpressDebugSound, "Start ADPCM: %d, %d", header1, header2);
size -= 6;
}
diff --git a/engines/lastexpress/data/cursor.cpp b/engines/lastexpress/data/cursor.cpp
index 205c46f667..d176d963d1 100644
--- a/engines/lastexpress/data/cursor.cpp
+++ b/engines/lastexpress/data/cursor.cpp
@@ -128,7 +128,7 @@ Common::Rect Icon::draw(Graphics::Surface *surface) {
for (int i = 0; i < 32; i++) {
// Adjust brightness
- if (_brightnessIndex == -1)
+ if (_brightnessIndex == -1 || _brightnessIndex >= ARRAYSIZE(brigthnessData))
*s = *image;
else
*s = (*image & brigthnessData[_brightnessIndex]) >> _brightnessIndex;
diff --git a/engines/lastexpress/data/font.cpp b/engines/lastexpress/data/font.cpp
index 79cf64e617..8ac1afce9a 100644
--- a/engines/lastexpress/data/font.cpp
+++ b/engines/lastexpress/data/font.cpp
@@ -149,7 +149,7 @@ uint8 Font::getCharWidth(uint16 c) const{
uint16 Font::getStringWidth(Common::String str) const {
uint16 width = 0;
for (uint i = 0; i < str.size(); i++)
- width += getCharWidth((unsigned) (int)str[i]);
+ width += getCharWidth((unsigned char)str[i]);
return width;
}
@@ -185,8 +185,8 @@ void Font::drawChar(Graphics::Surface *surface, int16 x, int16 y, uint16 c) {
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]);
+ drawChar(surface, currentX, y, (unsigned char)str[i]);
+ currentX += getCharWidth((unsigned char)str[i]);
}
return Common::Rect(x, y, x + currentX, y + (int16)_charHeight);
diff --git a/engines/lastexpress/data/scene.cpp b/engines/lastexpress/data/scene.cpp
index 8f279ffbb3..fdb1ac6d46 100644
--- a/engines/lastexpress/data/scene.cpp
+++ b/engines/lastexpress/data/scene.cpp
@@ -28,7 +28,6 @@
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
-#include "common/textconsole.h"
#include "common/stream.h"
namespace LastExpress {
@@ -122,7 +121,7 @@ bool SceneHotspot::isInside(const Common::Point &point) {
// Scene
Scene::~Scene() {
// Free the hotspots
- for (int i = 0; i < (int)_hotspots.size(); i++)
+ for (uint i = 0; i < _hotspots.size(); i++)
delete _hotspots[i];
}
@@ -172,7 +171,7 @@ bool Scene::checkHotSpot(const Common::Point &coord, SceneHotspot **hotspot) {
bool found = false;
int _location = 0;
- for (int i = 0; i < (int)_hotspots.size(); i++) {
+ for (uint i = 0; i < _hotspots.size(); i++) {
if (_hotspots[i]->isInside(coord)) {
if (_location <= _hotspots[i]->location) {
_location = _hotspots[i]->location;
@@ -224,7 +223,7 @@ Common::String Scene::toString() {
// Hotspots
if (_hotspots.size() != 0) {
output += "\nHotspots:\n";
- for (int i = 0; i < (int)_hotspots.size(); i++)
+ for (uint i = 0; i < _hotspots.size(); i++)
output += _hotspots[i]->toString() + "\n";
}
@@ -241,7 +240,7 @@ SceneLoader::~SceneLoader() {
void SceneLoader::clear() {
// Remove all scenes
- for (int i = 0; i < (int)_scenes.size(); i++)
+ for (uint i = 0; i < _scenes.size(); i++)
delete _scenes[i];
_scenes.clear();
@@ -292,9 +291,9 @@ Scene *SceneLoader::get(SceneIndex index) {
return NULL;
// Load the hotspots if needed
- _scenes[(int)index]->loadHotspots(_stream);
+ _scenes[(uint)index]->loadHotspots(_stream);
- return _scenes[(int)index];
+ return _scenes[(uint)index];
}
} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/sequence.cpp b/engines/lastexpress/data/sequence.cpp
index a62348f6c0..a5bcba84cd 100644
--- a/engines/lastexpress/data/sequence.cpp
+++ b/engines/lastexpress/data/sequence.cpp
@@ -27,7 +27,6 @@
#include "lastexpress/debug.h"
#include "common/stream.h"
-#include "common/textconsole.h"
namespace LastExpress {
@@ -77,7 +76,7 @@ void FrameInfo::read(Common::SeekableReadStream *in, bool isSequence) {
// AnimFrame
-AnimFrame::AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f) : _palette(NULL) {
+AnimFrame::AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f, bool ignoreSubtype) : _palette(NULL), _ignoreSubtype(ignoreSubtype) {
_palSize = 1;
// TODO: use just the needed rectangle
_image.create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
diff --git a/engines/lastexpress/data/sequence.h b/engines/lastexpress/data/sequence.h
index 9987eae48e..610a55cebf 100644
--- a/engines/lastexpress/data/sequence.h
+++ b/engines/lastexpress/data/sequence.h
@@ -49,8 +49,9 @@
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} - Keep previous frame while drawing
+ byte {1} - Unknown
byte {1} - Unknown
- uint16 {2} - Unknown
byte {1} - Sound action
byte {1} - Unknown
uint32 {4} - positionId
@@ -129,7 +130,7 @@ struct FrameInfo {
class AnimFrame : public Drawable {
public:
- AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f);
+ AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f, bool ignoreSubtype = false);
~AnimFrame();
Common::Rect draw(Graphics::Surface *s);
@@ -146,6 +147,7 @@ private:
uint16 _palSize;
uint16 *_palette;
Common::Rect _rect;
+ bool _ignoreSubtype;
};
class Sequence {
diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp
index a9bee6155d..a77e4a06c6 100644
--- a/engines/lastexpress/data/snd.cpp
+++ b/engines/lastexpress/data/snd.cpp
@@ -28,11 +28,9 @@
#include "lastexpress/debug.h"
#include "audio/decoders/adpcm_intern.h"
-#include "audio/audiostream.h"
#include "common/debug.h"
#include "common/memstream.h"
#include "common/system.h"
-#include "common/textconsole.h"
namespace LastExpress {
@@ -358,6 +356,8 @@ public:
Audio::ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) {
_currentFilterId = -1;
_nextFilterId = filterId;
+ _stepAdjust1 = 0;
+ _stepAdjust2 = 0;
}
int readBuffer(int16 *buffer, const int numSamples) {
@@ -378,7 +378,7 @@ public:
// Get current filter
_currentFilterId = _nextFilterId;
- _nextFilterId = -1;
+ //_nextFilterId = -1; // FIXME: the filter id should be recomputed based on the sound entry status for each block
// No filter: skip decoding
if (_currentFilterId == -1)
@@ -455,7 +455,9 @@ void SimpleSound::play(Audio::AudioStream *as) {
//////////////////////////////////////////////////////////////////////////
StreamedSound::StreamedSound() : _as(NULL), _loaded(false) {}
-StreamedSound::~StreamedSound() {}
+StreamedSound::~StreamedSound() {
+ _as = NULL;
+}
bool StreamedSound::load(Common::SeekableReadStream *stream, int32 filterId) {
if (!stream)
@@ -484,6 +486,9 @@ bool StreamedSound::isFinished() {
}
void StreamedSound::setFilterId(int32 filterId) {
+ if (!_as)
+ return;
+
((LastExpress_ADPCMStream *)_as)->setFilterId(filterId);
}
@@ -521,6 +526,7 @@ void AppendableSound::queueBuffer(Common::SeekableReadStream *bufferIn) {
// Setup the ADPCM decoder
uint32 sizeIn = (uint32)bufferIn->size();
Audio::AudioStream *adpcm = makeDecoder(bufferIn, sizeIn);
+ ((LastExpress_ADPCMStream *)adpcm)->setFilterId(16);
// Queue the stream
_as->queueAudioStream(adpcm);
diff --git a/engines/lastexpress/data/subtitle.cpp b/engines/lastexpress/data/subtitle.cpp
index 0be832cbdd..a9a8284588 100644
--- a/engines/lastexpress/data/subtitle.cpp
+++ b/engines/lastexpress/data/subtitle.cpp
@@ -32,7 +32,6 @@
#include "common/debug.h"
#include "common/rect.h"
#include "common/stream.h"
-#include "common/textconsole.h"
namespace LastExpress {
@@ -151,7 +150,7 @@ SubtitleManager::~SubtitleManager() {
}
void SubtitleManager::reset() {
- for (int i = 0; i < (int)_subtitles.size(); i++)
+ for (uint i = 0; i < _subtitles.size(); i++)
delete _subtitles[i];
_subtitles.clear();
diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp
index dc2807db63..f89ad8b80d 100644
--- a/engines/lastexpress/debug.cpp
+++ b/engines/lastexpress/debug.cpp
@@ -28,13 +28,13 @@
#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/fight/fight.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"
@@ -44,15 +44,12 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.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 {
@@ -612,7 +609,7 @@ bool Debugger::cmdPlayNis(int argc, const char **argv) {
loadArchive((ArchiveIndex)getNumber(argv[2]));
// If we got a nis filename, check that the file exists
- if (name.contains('.') && _engine->getResourceManager()->hasFile(name)) {
+ if (name.contains('.') && !_engine->getResourceManager()->hasFile(name)) {
DebugPrintf("Cannot find file: %s\n", name.c_str());
return true;
}
diff --git a/engines/lastexpress/detection.cpp b/engines/lastexpress/detection.cpp
index 82a6520522..2fdeef910a 100644
--- a/engines/lastexpress/detection.cpp
+++ b/engines/lastexpress/detection.cpp
@@ -173,7 +173,7 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
},
-
+
// The Last Express (Russian)
// expressw.exe 1999-04-05 15:33:56
// express.exe ???
@@ -211,6 +211,7 @@ public:
return "LastExpress Engine (C) 1997 Smoking Car Productions";
}
+protected:
bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
};
diff --git a/engines/lastexpress/entities/abbot.cpp b/engines/lastexpress/entities/abbot.cpp
index 301c52e142..e0fe429520 100644
--- a/engines/lastexpress/entities/abbot.cpp
+++ b/engines/lastexpress/entities/abbot.cpp
@@ -34,9 +34,7 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
@@ -417,7 +415,7 @@ IMPLEMENT_FUNCTION(22, Abbot, function22)
break;
case kActionNone:
- TIME_CHECK_SAVEPOINT(kTime1971000, params->param1, kEntityAbbot, kEntityServers0, kAction218586752);
+ Entity::timeCheckSavepoint(kTime1971000, params->param1, kEntityAbbot, kEntityServers0, kAction218586752);
if (getState()->time > kTime1989000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->inventoryItem = kItemNone;
@@ -516,7 +514,8 @@ IMPLEMENT_FUNCTION(24, Abbot, function24)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->time, 900);
+ if (!Entity::updateParameter(params->param1, getState()->time, 900))
+ break;
setup_function25();
break;
@@ -617,7 +616,8 @@ IMPLEMENT_FUNCTION(26, Abbot, function26)
break;
case kActionNone:
- UPDATE_PARAM(params->param2, getState()->time, 4500);
+ if (!Entity::updateParameter(params->param2, getState()->time, 4500))
+ break;
if (getEntities()->isSomebodyInsideRestaurantOrSalon())
setup_function27();
@@ -691,7 +691,7 @@ IMPLEMENT_FUNCTION(28, Abbot, function28)
break;
case kActionNone:
- TIME_CHECK_CALLBACK(kTime2052000, params->param1, 1, setup_function29);
+ Entity::timeCheckCallback(kTime2052000, params->param1, 1, WRAP_SETUP_FUNCTION(Abbot, setup_function29));
break;
case kActionDefault:
@@ -770,7 +770,7 @@ IMPLEMENT_FUNCTION(29, Abbot, function29)
getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122358304);
getEntities()->drawSequenceLeft(kEntityAbbot, "508B");
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -864,7 +864,8 @@ IMPLEMENT_FUNCTION(31, Abbot, function31)
if (!params->param1)
break;
- UPDATE_PARAM(params->param5, getState()->time, 450);
+ if (!Entity::updateParameter(params->param5, getState()->time, 450))
+ break;
setCallback(6);
setup_callbackActionRestaurantOrSalon();
@@ -920,7 +921,8 @@ IMPLEMENT_FUNCTION(31, Abbot, function31)
getSavePoints()->push(kEntityAbbot, kEntityAlexei, kAction122288808);
params->param1 = 1;
- UPDATE_PARAM(params->param5, getState()->time, 450);
+ if (!Entity::updateParameter(params->param5, getState()->time, 450))
+ break;
setCallback(6);
setup_callbackActionRestaurantOrSalon();
@@ -1163,7 +1165,8 @@ IMPLEMENT_FUNCTION(36, Abbot, function36)
break;
case 2:
- UPDATE_PARAM(params->param4, getState()->time, 900);
+ if (!Entity::updateParameter(params->param4, getState()->time, 900))
+ break;
getSound()->playSound(kEntityAbbot, "Abb3042");
break;
@@ -1287,7 +1290,7 @@ IMPLEMENT_FUNCTION_II(40, Abbot, function40, CarIndex, EntityPosition)
case kActionNone:
if (getEntities()->updateEntity(kEntityAbbot, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
} else if (!getEvent(kEventAbbotInvitationDrink)
&& getEntities()->isDistanceBetweenEntities(kEntityAbbot, kEntityPlayer, 1000)
&& !getEntities()->isInsideCompartments(kEntityPlayer)
@@ -1302,7 +1305,7 @@ IMPLEMENT_FUNCTION_II(40, Abbot, function40, CarIndex, EntityPosition)
case kActionDefault:
if (getEntities()->updateEntity(kEntityAbbot, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -1321,7 +1324,7 @@ IMPLEMENT_FUNCTION(41, Abbot, chapter4Handler)
break;
case kActionNone:
- TIME_CHECK_SAVEPOINT(kTime2358000, params->param1, kEntityAbbot, kEntityServers0, kAction218128129);
+ Entity::timeCheckSavepoint(kTime2358000, params->param1, kEntityAbbot, kEntityServers0, kAction218128129);
if (getState()->time > kTime2389500 && getEntities()->isSomebodyInsideRestaurantOrSalon())
setup_function42();
@@ -1425,10 +1428,12 @@ IMPLEMENT_FUNCTION(43, Abbot, function43)
}
label_callback_1:
- TIME_CHECK(kTime2466000, params->param5, setup_function44);
+ if (Entity::timeCheck(kTime2466000, params->param5, WRAP_SETUP_FUNCTION(Abbot, setup_function44)))
+ break;
if (params->param3) {
- UPDATE_PARAM(params->param6, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param6, getState()->timeTicks, 75))
+ break;
params->param2 = 1;
params->param3 = 0;
@@ -1646,14 +1651,14 @@ IMPLEMENT_FUNCTION(48, Abbot, function48)
if (ENTITY_PARAM(0, 1))
getData()->inventoryItem = kItemInvalid;
- UPDATE_PARAM_PROC(params->param1, getState()->time, 1800)
+ if (Entity::updateParameter(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);
+ Entity::timeCheckCallbackInventory(kTime2533500, params->param2, 5, WRAP_SETUP_FUNCTION(Abbot, setup_callbackActionRestaurantOrSalon));
break;
case kAction1:
@@ -1705,7 +1710,7 @@ IMPLEMENT_FUNCTION(48, Abbot, function48)
getEntities()->drawSequenceLeft(kEntityAbbot, "126B");
params->param1 = 0;
- TIME_CHECK_CALLBACK_INVENTORY(kTime2533500, params->param2, 5, setup_callbackActionRestaurantOrSalon);
+ Entity::timeCheckCallbackInventory(kTime2533500, params->param2, 5, WRAP_SETUP_FUNCTION(Abbot, setup_callbackActionRestaurantOrSalon));
break;
case 5:
@@ -1750,7 +1755,8 @@ IMPLEMENT_FUNCTION(49, Abbot, pickBomb)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->timeTicks, 150);
+ if (!Entity::updateParameter(params->param1, getState()->timeTicks, 150))
+ break;
getSavePoints()->push(kEntityAbbot, kEntityAbbot, kAction157489665);
break;
diff --git a/engines/lastexpress/entities/abbot.h b/engines/lastexpress/entities/abbot.h
index 462f5a491e..ce52bb68ce 100644
--- a/engines/lastexpress/entities/abbot.h
+++ b/engines/lastexpress/entities/abbot.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_ABBOT_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/alexei.cpp b/engines/lastexpress/entities/alexei.cpp
index 54c2d87b89..115c890f6f 100644
--- a/engines/lastexpress/entities/alexei.cpp
+++ b/engines/lastexpress/entities/alexei.cpp
@@ -31,9 +31,6 @@
#include "lastexpress/game/scenes.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.h"
-
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
@@ -207,7 +204,7 @@ IMPLEMENT_FUNCTION(13, Alexei, function13)
getData()->entityPosition = kPosition_7500;
getEntities()->clearSequences(kEntityAlexei);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -242,7 +239,7 @@ IMPLEMENT_FUNCTION(14, Alexei, function14)
getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
getEntities()->exitCompartment(kEntityAlexei, kObjectCompartment2, true);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -254,7 +251,7 @@ IMPLEMENT_FUNCTION(15, Alexei, function15)
break;
case kActionNone:
- UPDATE_PARAM_CHECK(params->param2, getState()->time, params->param1)
+ if (Entity::updateParameterCheck(params->param2, getState()->time, params->param1)) {
if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->location = kLocationOutsideCompartment;
@@ -292,7 +289,7 @@ IMPLEMENT_FUNCTION(15, Alexei, function15)
getData()->location = kLocationInsideCompartment;
getEntities()->drawSequenceLeft(kEntityAlexei, "103B");
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -312,12 +309,13 @@ IMPLEMENT_FUNCTION_IS(16, Alexei, function16, TimeValue)
getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (params->param5) {
- UPDATE_PARAM(CURRENT_PARAM(1, 1), getState()->timeTicks, 75);
+ if (!Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->timeTicks, 75))
+ break;
params->param5 = 0;
params->param6 = 1;
@@ -448,7 +446,7 @@ IMPLEMENT_FUNCTION(17, Alexei, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler)
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Alexei, setup_chapter1Handler));
break;
case kActionDefault:
@@ -485,7 +483,9 @@ IMPLEMENT_FUNCTION(18, Alexei, chapter1Handler)
}
if (params->param1) {
- UPDATE_PARAM(params->param3, getState()->timeTicks, 90);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, 90))
+ break;
+
getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
} else {
params->param3 = 0;
@@ -689,7 +689,7 @@ IMPLEMENT_FUNCTION(21, Alexei, function21)
break;
case kActionNone:
- UPDATE_PARAM_CHECK(params->param2, getState()->time, params->param1)
+ if (Entity::updateParameterCheck(params->param2, getState()->time, params->param1)) {
getData()->location = kLocationOutsideCompartment;
getData()->inventoryItem = kItemNone;
@@ -751,7 +751,7 @@ IMPLEMENT_FUNCTION(22, Alexei, function22)
break;
case kActionNone:
- UPDATE_PARAM_PROC(params->param2, getState()->time, params->param2)
+ if (Entity::updateParameter(params->param2, getState()->time, params->param2)) {
if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->location = kLocationOutsideCompartment;
getData()->inventoryItem = kItemNone;
@@ -760,7 +760,7 @@ IMPLEMENT_FUNCTION(22, Alexei, function22)
setup_updatePosition("103D", kCarRestaurant, 52);
break;
}
- UPDATE_PARAM_PROC_END
+ }
if (params->param3 == kTimeInvalid || getState()->time <= kTime1111500)
break;
@@ -978,7 +978,7 @@ IMPLEMENT_FUNCTION(26, Alexei, function26)
break;
case kActionNone:
- TIME_CHECK(kTime1512000, params->param1, setup_function27)
+ Entity::timeCheck(kTime1512000, params->param1, WRAP_SETUP_FUNCTION(Alexei, setup_function27));
break;
case kActionDefault:
@@ -1333,25 +1333,26 @@ IMPLEMENT_FUNCTION(35, Alexei, function35)
case kActionNone:
if (getEntities()->isInSalon(kEntityPlayer)) {
- UPDATE_PARAM_PROC(params->param2, getState()->time, 2700)
+ if (Entity::updateParameter(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 (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param4, getState()->time, 9000))
+ break;
setCallback(4);
setup_callbackActionRestaurantOrSalon();
@@ -1378,7 +1379,7 @@ label_callback_3:
case 2:
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 3:
@@ -1400,7 +1401,8 @@ IMPLEMENT_FUNCTION(36, Alexei, function36)
if (params->param3 || params->param2)
break;
- UPDATE_PARAM(params->param4, getState()->timeTicks, params->param1);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, params->param1))
+ break;
getEntities()->drawSequenceRight(kEntityAlexei, "124B");
@@ -1448,7 +1450,7 @@ IMPLEMENT_FUNCTION(36, Alexei, function36)
break;
case 4:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
diff --git a/engines/lastexpress/entities/alexei.h b/engines/lastexpress/entities/alexei.h
index 262826ae42..9792385863 100644
--- a/engines/lastexpress/entities/alexei.h
+++ b/engines/lastexpress/entities/alexei.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_ALEXEI_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/alouan.cpp b/engines/lastexpress/entities/alouan.cpp
index cd79870559..e834e1f7cb 100644
--- a/engines/lastexpress/entities/alouan.cpp
+++ b/engines/lastexpress/entities/alouan.cpp
@@ -28,9 +28,6 @@
#include "lastexpress/game/savepoint.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.h"
-
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
@@ -89,22 +86,22 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(6, Alouan, compartment6)
- COMPARTMENT_TO(Alouan, kObjectCompartment6, kPosition_4070, "621Cf", "621Df");
+ Entity::goToCompartment(savepoint, kObjectCompartment6, kPosition_4070, "621Cf", "621Df");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(7, Alouan, compartment8)
- COMPARTMENT_TO(Alouan, kObjectCompartment8, kPosition_2740, "621Ch", "621Dh");
+ Entity::goToCompartment(savepoint, kObjectCompartment8, kPosition_2740, "621Ch", "621Dh");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(8, Alouan, compartment6to8)
- COMPARTMENT_FROM_TO(Alouan, kObjectCompartment6, kPosition_4070, "621Bf", kObjectCompartment8, kPosition_2740, "621Ah");
+ Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment6, kPosition_4070, "621Bf", kObjectCompartment8, kPosition_2740, "621Ah");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(9, Alouan, compartment8to6)
- COMPARTMENT_FROM_TO(Alouan, kObjectCompartment8, kPosition_2740, "621Bh", kObjectCompartment6, kPosition_4070, "621Af");
+ Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment8, kPosition_2740, "621Bh", kObjectCompartment6, kPosition_4070, "621Af");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
@@ -114,7 +111,7 @@ IMPLEMENT_FUNCTION(10, Alouan, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Alouan, setup_chapter1Handler));
break;
case kActionDefault:
@@ -134,7 +131,8 @@ IMPLEMENT_FUNCTION(11, Alouan, chapter1Handler)
case kActionNone:
- TIME_CHECK_CALLBACK(kTime1096200, params->param1, 1, setup_compartment8to6);
+ if (Entity::timeCheckCallback(kTime1096200, params->param1, 1, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8to6)))
+ break;
label_callback1:
if (getState()->time > kTime1162800 && !params->param2) {
@@ -284,21 +282,28 @@ IMPLEMENT_FUNCTION(16, Alouan, chapter3Handler)
break;
case kActionNone:
- TIME_CHECK_CALLBACK(kTimeCitySalzbourg, params->param1, 1, setup_compartment8to6);
+ if (Entity::timeCheckCallback(kTimeCitySalzbourg, params->param1, 1, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8to6)))
+ break;
label_callback1:
- if (params->param2 != kTimeInvalid && getState()->time > kTime1989000)
- TIME_CHECK_CAR(kTime2119500, params->param5, 5, setup_compartment8);
+ if (params->param2 != kTimeInvalid && getState()->time > kTime1989000) {
+ if (Entity::timeCheckCar(kTime2119500, params->param5, 5, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8)))
+ break;
+ }
label_callback2:
- TIME_CHECK_CALLBACK_1(kTime2052000, params->param3, 3, setup_playSound, "Har1005");
+ if (Entity::timeCheckCallback(kTime2052000, params->param3, 3, "Har1005", WRAP_SETUP_FUNCTION_S(Alouan, setup_playSound)))
+ break;
label_callback3:
- TIME_CHECK_CALLBACK(kTime2133000, params->param4, 4, setup_compartment6to8);
+ if (Entity::timeCheckCallback(kTime2133000, params->param4, 4, WRAP_SETUP_FUNCTION(Alouan, setup_compartment6to8)))
+ break;
label_callback4:
- if (params->param5 != kTimeInvalid && getState()->time > kTime2151000)
- TIME_CHECK_CAR(kTime2241000, params->param5, 5, setup_compartment8);
+ if (params->param5 != kTimeInvalid && getState()->time > kTime2151000) {
+ if (Entity::timeCheckCar(kTime2241000, params->param5, 5, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8)))
+ break;
+ }
break;
case kActionDefault:
@@ -355,11 +360,14 @@ IMPLEMENT_FUNCTION(18, Alouan, chapter4Handler)
break;
case kActionNone:
- if (params->param1 != kTimeInvalid)
- TIME_CHECK_CAR(kTime2443500, params->param1, 1, setup_compartment8);
+ if (params->param1 != kTimeInvalid) {
+ if (Entity::timeCheckCar(kTime2443500, params->param1, 1, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8)))
+ break;
+ }
label_callback1:
- TIME_CHECK_CALLBACK(kTime2455200, params->param2, 2, setup_compartment8to6);
+ if (Entity::timeCheckCallback(kTime2455200, params->param2, 2, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8to6)))
+ break;
label_callback2:
if (getState()->time > kTime2475000 && !params->param3) {
@@ -441,7 +449,9 @@ IMPLEMENT_FUNCTION(22, Alouan, function22)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->time, 2700);
+ if (!Entity::updateParameter(params->param1, getState()->time, 2700))
+ break;
+
setup_function23();
break;
diff --git a/engines/lastexpress/entities/alouan.h b/engines/lastexpress/entities/alouan.h
index c6a6beddd9..91254a449a 100644
--- a/engines/lastexpress/entities/alouan.h
+++ b/engines/lastexpress/entities/alouan.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_ALOUAN_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/anna.cpp b/engines/lastexpress/entities/anna.cpp
index b13aa21f6d..f8768032b5 100644
--- a/engines/lastexpress/entities/anna.cpp
+++ b/engines/lastexpress/entities/anna.cpp
@@ -34,9 +34,7 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
@@ -200,16 +198,17 @@ IMPLEMENT_FUNCTION(12, Anna, function12)
params->param2 = 1;
if (params->param6) {
- UPDATE_PARAM_PROC(params->param7, getState()->timeTicks, 75)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75))
+ break;
params->param4 = 0;
params->param5 = 1;
@@ -227,7 +226,7 @@ IMPLEMENT_FUNCTION(12, Anna, function12)
case kActionEndSound:
if (params->param2) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -289,7 +288,7 @@ IMPLEMENT_FUNCTION(12, Anna, function12)
getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -424,12 +423,13 @@ IMPLEMENT_FUNCTION_IS(15, Anna, function15, TimeValue)
getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (params->param5) {
- UPDATE_PARAM(params->param8, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75))
+ break;
params->param5 = 0;
params->param6 = 1;
@@ -547,7 +547,7 @@ IMPLEMENT_FUNCTION(16, Anna, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Anna, setup_chapter1Handler));
break;
case kActionDefault:
@@ -577,7 +577,7 @@ IMPLEMENT_FUNCTION_II(17, Anna, function17, uint32, uint32)
if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -615,7 +615,7 @@ IMPLEMENT_FUNCTION_II(17, Anna, function17, uint32, uint32)
}
if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -664,20 +664,21 @@ IMPLEMENT_FUNCTION_I(18, Anna, function18, TimeValue)
case kActionNone:
if (params->param1 && params->param1 < getState()->time && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (params->param5 && !params->param4) {
- UPDATE_PARAM_PROC(params->param6, getState()->time, 900)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param7, getState()->timeTicks, 90))
+ break;
getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
} else {
@@ -757,7 +758,7 @@ IMPLEMENT_FUNCTION_I(18, Anna, function18, TimeValue)
case kAction259136835:
case kAction268773672:
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -1151,15 +1152,16 @@ IMPLEMENT_FUNCTION(29, Anna, function29)
case kActionNone:
if (params->param2) {
- UPDATE_PARAM_PROC(params->param3, getState()->time, 900)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, 90))
+ break;
getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
} else {
@@ -1281,7 +1283,9 @@ IMPLEMENT_FUNCTION(30, Anna, function30)
}
if (params->param1) {
- UPDATE_PARAM(params->param5, getState()->timeTicks, 90);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 90))
+ break;
+
getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
} else {
params->param5 = 0;
@@ -1411,15 +1415,15 @@ IMPLEMENT_FUNCTION(34, Anna, function34)
case kActionNone:
if (!params->param1 && getEntities()->isPlayerPosition(kCarRedSleeping, 60)) {
- UPDATE_PARAM_PROC(params->param2, getState()->time, 150)
+ if (Entity::updateParameter(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);
+ Entity::timeCheck(kTime1489500, params->param3, WRAP_SETUP_FUNCTION(Anna, setup_function35));
break;
case kActionKnock:
@@ -1485,7 +1489,8 @@ IMPLEMENT_FUNCTION(35, Anna, function35)
if (!params->param1)
break;
- UPDATE_PARAM(params->param3, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, 75))
+ break;
switch (params->param2) {
default:
@@ -1666,7 +1671,7 @@ IMPLEMENT_FUNCTION_II(39, Anna, function39, CarIndex, EntityPosition)
if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -1687,7 +1692,7 @@ IMPLEMENT_FUNCTION_II(39, Anna, function39, CarIndex, EntityPosition)
if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -1799,7 +1804,8 @@ IMPLEMENT_FUNCTION(41, Anna, function41)
break;
case kActionNone:
- UPDATE_PARAM(params->param2, getState()->time, 2700);
+ if (!Entity::updateParameter(params->param2, getState()->time, 2700))
+ break;
params->param5++;
switch (params->param5) {
@@ -1985,7 +1991,7 @@ IMPLEMENT_FUNCTION_I(45, Anna, function45, bool)
case 2:
getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF, true);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2092,11 +2098,11 @@ IMPLEMENT_FUNCTION(48, Anna, function48)
break;
if (params->param3 != kTimeInvalid && getState()->time > kTime1969200) {
- UPDATE_PARAM_PROC_TIME(kTime1983600, (!getEntities()->isInRestaurant(kEntityPlayer) || getSoundQueue()->isBuffered(kEntityBoutarel)), params->param3, 150)
+ if (Entity::updateParameterTime(kTime1983600, (!getEntities()->isInRestaurant(kEntityPlayer) || getSoundQueue()->isBuffered(kEntityBoutarel)), params->param3, 150)) {
setCallback(3);
setup_playSound("Aug3007A");
break;
- UPDATE_PARAM_PROC_END
+ }
}
label_callback_4:
@@ -2195,7 +2201,7 @@ IMPLEMENT_FUNCTION(49, Anna, leaveTableWithAugust)
getSavePoints()->push(kEntityAnna, kEntityTables3, kActionDrawTablesWithChairs, "010M");
getEntities()->clearSequences(kEntityAugust);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -2386,22 +2392,23 @@ IMPLEMENT_FUNCTION(53, Anna, function53)
case kActionNone:
if (getProgress().field_48 && params->param5 != kTimeInvalid) {
- UPDATE_PARAM_PROC_TIME(kTime2065500, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param5, 150)
+ if (Entity::updateParameterTime(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)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param7, getState()->timeTicks, 75))
+ break;
CursorStyle cursor = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal;
@@ -2537,17 +2544,19 @@ IMPLEMENT_FUNCTION(54, Anna, function54)
case kActionNone:
if (params->param3) {
- TIME_CHECK(kTime2079000, params->param5, setup_function55);
+ if (Entity::timeCheck(kTime2079000, params->param5, WRAP_SETUP_FUNCTION(Anna, setup_function55)))
+ break;
- UPDATE_PARAM_PROC(params->param6, getState()->time, 9000)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param7, getState()->timeTicks, 75))
+ break;
CursorStyle cursor = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal;
@@ -2894,7 +2903,8 @@ IMPLEMENT_FUNCTION(59, Anna, function59)
}
if (params->param1) {
- UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75))
+ break;
CursorStyle style = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal;
getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, style);
@@ -3040,7 +3050,7 @@ IMPLEMENT_FUNCTION(60, Anna, function60)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityAnna);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3268,7 +3278,8 @@ IMPLEMENT_FUNCTION(67, Anna, chapter4Handler)
case kActionNone:
if (getEntities()->isPlayerPosition(kCarRedSleeping, 46)) {
- UPDATE_PARAM_GOTO(params->param4, getState()->timeTicks, 30, label_next);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, 30))
+ goto label_next;
getScenes()->loadSceneFromPosition(kCarRedSleeping, 8);
}
@@ -3277,7 +3288,8 @@ IMPLEMENT_FUNCTION(67, Anna, chapter4Handler)
label_next:
if (params->param1) {
- UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 1;
@@ -3407,7 +3419,8 @@ IMPLEMENT_FUNCTION(69, Anna, function69)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM(params->param2, getState()->time, 4500);
+ if (!Entity::updateParameter(params->param2, getState()->time, 4500))
+ break;
getData()->car = kCarRedSleeping;
getData()->entityPosition = kPosition_9270;
@@ -3417,7 +3430,7 @@ IMPLEMENT_FUNCTION(69, Anna, function69)
break;
}
- TIME_CHECK_CALLBACK(kTime2535300, params->param3, 4, setup_callbackActionRestaurantOrSalon);
+ Entity::timeCheckCallback(kTime2535300, params->param3, 4, WRAP_SETUP_FUNCTION(Anna, setup_callbackActionRestaurantOrSalon));
break;
case kActionDefault:
@@ -3533,7 +3546,7 @@ IMPLEMENT_FUNCTION(71, Anna, function71)
getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF);
getData()->entityPosition = kPosition_4070;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -3589,7 +3602,7 @@ IMPLEMENT_FUNCTION_II(72, Anna, function72, CarIndex, EntityPosition)
if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -3602,7 +3615,7 @@ IMPLEMENT_FUNCTION_II(72, Anna, function72, CarIndex, EntityPosition)
case kActionDefault:
if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
} else if (!getEvent(kEventAnnaTired))
getData()->inventoryItem = kItemInvalid;
break;
@@ -3911,7 +3924,8 @@ IMPLEMENT_FUNCTION(80, Anna, function80)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->timeTicks, 450);
+ if (!Entity::updateParameter(params->param1, getState()->timeTicks, 450))
+ break;
getSound()->playSound(kEntityPlayer, "Kro5001", kFlagDefault);
break;
@@ -3980,7 +3994,8 @@ IMPLEMENT_FUNCTION(81, Anna, finalSequence)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->timeTicks, 180);
+ if (!Entity::updateParameter(params->param1, getState()->timeTicks, 180))
+ break;
getSound()->playSound(kEntityTrain, "LIB069");
getLogic()->gameOver(kSavegameTypeIndex, 2, kSceneNone, true);
diff --git a/engines/lastexpress/entities/anna.h b/engines/lastexpress/entities/anna.h
index 72c6db4bd9..205ff9d42c 100644
--- a/engines/lastexpress/entities/anna.h
+++ b/engines/lastexpress/entities/anna.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_ANNA_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/august.cpp b/engines/lastexpress/entities/august.cpp
index cfde8a2d6f..67d810fde2 100644
--- a/engines/lastexpress/entities/august.cpp
+++ b/engines/lastexpress/entities/august.cpp
@@ -36,9 +36,7 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
@@ -150,7 +148,7 @@ IMPLEMENT_FUNCTION_END
IMPLEMENT_FUNCTION_SI(7, August, enterExitCompartment3, ObjectIndex)
if (savepoint.action == kAction4) {
getEntities()->exitCompartment(kEntityAugust, (ObjectIndex)params->param4);
- CALLBACK_ACTION();
+ callbackAction();
return;
}
@@ -177,7 +175,7 @@ IMPLEMENT_FUNCTION_IIS(10, August, callSavepointNoDrawing, EntityIndex, ActionIn
if (!params->param6)
getSavePoints()->call(kEntityAugust, (EntityIndex)params->param1, (ActionIndex)params->param2, (char *)&params->seq);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kAction10:
@@ -233,7 +231,7 @@ IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue)
case kActionNone:
if (params->param1 < getState()->time && !params->param2) {
params->param2 = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -262,7 +260,7 @@ IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue)
case 1:
if (ENTITY_PARAM(0, 1)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -272,7 +270,7 @@ IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue)
case 2:
case 3:
if (ENTITY_PARAM(0, 1)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -289,7 +287,7 @@ IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue)
case 5:
if (ENTITY_PARAM(0, 1)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -308,7 +306,7 @@ IMPLEMENT_FUNCTION_II(18, August, updateEntity2, CarIndex, EntityPosition)
case kActionNone:
if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
} else if (getEntities()->isDistanceBetweenEntities(kEntityAugust, kEntityPlayer, 1000)
&& !getEntities()->isInGreenCarEntrance(kEntityPlayer)
&& !getEntities()->isInsideCompartments(kEntityPlayer)
@@ -316,14 +314,14 @@ IMPLEMENT_FUNCTION_II(18, August, updateEntity2, CarIndex, EntityPosition)
if (getData()->car == kCarGreenSleeping || getData()->car == kCarRedSleeping) {
ENTITY_PARAM(0, 1) = 1;
- CALLBACK_ACTION();
+ callbackAction();
}
}
break;
case kActionDefault:
if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -407,7 +405,7 @@ IMPLEMENT_FUNCTION_II(19, August, function19, bool, bool)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityAugust);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -503,7 +501,7 @@ IMPLEMENT_FUNCTION_I(20, August, function20, bool)
getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
getEntities()->exitCompartment(kEntityAugust, kObjectCompartment3, true);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -520,12 +518,13 @@ IMPLEMENT_FUNCTION_I(21, August, function21, TimeValue)
getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (params->param2) {
- UPDATE_PARAM_GOTO(params->param8, getState()->timeTicks, 75, label_continue);
+ if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75))
+ goto label_continue;
params->param2 = 0;
params->param3 = 1;
@@ -540,10 +539,10 @@ label_continue:
break;
if (params->param6) {
- UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->time, 6300)
+ if (Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->time, 6300)) {
params->param6 = 0;
CURRENT_PARAM(1, 1) = 0;
- UPDATE_PARAM_PROC_END
+ }
}
if (!params->param4
@@ -753,7 +752,7 @@ IMPLEMENT_FUNCTION(22, August, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(August, setup_chapter1Handler));
break;
case kActionDefault:
@@ -786,7 +785,7 @@ IMPLEMENT_FUNCTION_I(23, August, function23, TimeValue)
} else {
getEntities()->exitCompartment(kEntityAugust, kObjectCompartment1, true);
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -806,7 +805,7 @@ IMPLEMENT_FUNCTION_I(23, August, function23, TimeValue)
}
label_callback_8:
- UPDATE_PARAM_PROC(CURRENT_PARAM(1, 4), getState()->timeTicks, 75)
+ if (Entity::updateParameter(CURRENT_PARAM(1, 4), getState()->timeTicks, 75)) {
getEntities()->exitCompartment(kEntityAugust, kObjectCompartment1, true);
if (getProgress().eventCorpseMovedFromFloor) {
@@ -822,7 +821,7 @@ label_callback_8:
setup_savegame(kSavegameTypeEvent, kEventAugustFindCorpse);
}
break;
- UPDATE_PARAM_PROC_END
+ }
label_callback_9:
if (params->param3 && params->param1 < getState()->time && !CURRENT_PARAM(1, 5)) {
@@ -842,7 +841,8 @@ label_callback_9:
break;
if (getObjects()->get(kObjectCompartment1).location == kObjectLocation1) {
- UPDATE_PARAM(CURRENT_PARAM(1, 2), getState()->timeTicks, 75);
+ if (!Entity::updateParameter(CURRENT_PARAM(1, 2), getState()->timeTicks, 75))
+ break;
getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
@@ -867,7 +867,7 @@ label_callback_9:
if (params->param8 >= 3) {
getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -959,7 +959,7 @@ label_callback_9:
case 2:
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 3:
@@ -986,7 +986,7 @@ label_callback_9:
getScenes()->loadScene(kScene41);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 5:
@@ -1028,7 +1028,7 @@ label_callback_9:
case 12:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 13:
@@ -1056,7 +1056,7 @@ label_callback_9:
getScenes()->loadScene(kScene41);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 15:
@@ -1096,7 +1096,7 @@ IMPLEMENT_FUNCTION(24, August, dinner)
getScenes()->loadSceneFromPosition(kCarRestaurant, 61);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -1485,7 +1485,8 @@ IMPLEMENT_FUNCTION(30, August, restaurant)
break;
case kActionNone:
- UPDATE_PARAM(params->param3, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, 75))
+ break;
getData()->inventoryItem = kItemInvalid;
break;
@@ -1634,9 +1635,9 @@ IMPLEMENT_FUNCTION(32, August, function32)
break;
case kActionNone:
- UPDATE_PARAM_PROC_TIME(kTime1179000, (!getEntities()->isInSalon(kEntityAnna) || getEntities()->isInSalon(kEntityPlayer)), params->param6, 0);
+ if (Entity::updateParameterTime(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) {
@@ -1645,18 +1646,19 @@ IMPLEMENT_FUNCTION(32, August, function32)
}
if (params->param7 != kTimeInvalid && params->param4 < getState()->time) {
- UPDATE_PARAM_PROC_TIME(params->param5, getEntities()->isInSalon(kEntityPlayer), params->param7, 0);
+ if (Entity::updateParameterTime((TimeValue)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);
+ if (!Entity::updateParameter(params->param8, getState()->timeTicks, 90))
+ break;
getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
} else {
@@ -1813,7 +1815,7 @@ IMPLEMENT_FUNCTION(36, August, chapter2Handler)
break;
case kActionNone:
- TIME_CHECK_SAVEPOINT(kTime1755000, params->param2, kEntityAugust, kEntityServers0, kAction252568704);
+ Entity::timeCheckSavepoint(kTime1755000, params->param2, kEntityAugust, kEntityServers0, kAction252568704);
if (getState()->time > kTime1773000 && params->param1 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->inventoryItem = kItemNone;
@@ -1904,7 +1906,7 @@ IMPLEMENT_FUNCTION(37, August, function37)
break;
case kActionNone:
- TIME_CHECK_CALLBACK_1(kTime1791000, params->param2, 5, setup_function20, true);
+ Entity::timeCheckCallback(kTime1791000, params->param2, 5, true, WRAP_SETUP_FUNCTION_B(August, setup_function20));
break;
case kActionDefault:
@@ -1962,9 +1964,9 @@ IMPLEMENT_FUNCTION(38, August, function38)
break;
case kActionNone:
- TIME_CHECK_SAVEPOINT(kTime1801800, params->param1, kEntityAugust, kEntityRebecca, kAction155980128);
+ Entity::timeCheckSavepoint(kTime1801800, params->param1, kEntityAugust, kEntityRebecca, kAction155980128);
- TIME_CHECK_CALLBACK(kTime1820700, params->param2, 3, setup_callbackActionRestaurantOrSalon);
+ Entity::timeCheckCallback(kTime1820700, params->param2, 3, WRAP_SETUP_FUNCTION(August, setup_callbackActionRestaurantOrSalon));
break;
case kActionDefault:
@@ -2110,7 +2112,7 @@ IMPLEMENT_FUNCTION_II(41, August, function41, CarIndex, EntityPosition)
getData()->inventoryItem = kItemNone;
if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -2147,7 +2149,7 @@ IMPLEMENT_FUNCTION_II(41, August, function41, CarIndex, EntityPosition)
case kActionDefault:
if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -2172,7 +2174,7 @@ IMPLEMENT_FUNCTION_III(42, August, function42, CarIndex, EntityPosition, bool)
if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -2191,7 +2193,7 @@ IMPLEMENT_FUNCTION_III(42, August, function42, CarIndex, EntityPosition, bool)
case kActionDefault:
if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -2212,7 +2214,7 @@ IMPLEMENT_FUNCTION(43, August, chapter3Handler)
break;
case kActionNone:
- TIME_CHECK_SAVEPOINT(kTime1953000, params->param2, kEntityAugust, kEntityAnna, kAction291662081);
+ Entity::timeCheckSavepoint(kTime1953000, params->param2, kEntityAugust, kEntityAnna, kAction291662081);
// Set as same position as Anna
if (params->param1) {
@@ -2402,7 +2404,7 @@ IMPLEMENT_FUNCTION_END
IMPLEMENT_FUNCTION(46, August, function46)
switch (savepoint.action) {
default:
- TIME_CHECK_CALLBACK(kTime2088000, params->param1, 1, setup_function47);
+ Entity::timeCheckCallback(kTime2088000, params->param1, 1, WRAP_SETUP_FUNCTION(August, setup_function47));
break;
case kActionNone:
@@ -2473,7 +2475,7 @@ IMPLEMENT_FUNCTION(47, August, function47)
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2487,7 +2489,7 @@ IMPLEMENT_FUNCTION(48, August, function48)
break;
case kActionNone:
- TIME_CHECK(kTimeCityLinz, params->param1, setup_function49);
+ Entity::timeCheck(kTimeCityLinz, params->param1, WRAP_SETUP_FUNCTION(August, setup_function49));
break;
case kActionKnock:
@@ -2770,7 +2772,8 @@ IMPLEMENT_FUNCTION(54, August, function54)
getData()->inventoryItem = kItemInvalid;
if (!params->param2 && params->param1) {
- UPDATE_PARAM(params->param5, getState()->time, params->param1);
+ if (!Entity::updateParameter(params->param5, getState()->time, params->param1))
+ break;
getData()->inventoryItem = kItemNone;
setup_function55();
@@ -3046,7 +3049,8 @@ IMPLEMENT_FUNCTION(60, August, function60)
if (!params->param1)
break;
- UPDATE_PARAM(params->param3, getState()->time, 9000);
+ if (!Entity::updateParameter(params->param3, getState()->time, 9000))
+ break;
setCallback(1);
setup_callbackActionRestaurantOrSalon();
@@ -3142,7 +3146,8 @@ IMPLEMENT_FUNCTION(62, August, function62)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->time, 900);
+ if (!Entity::updateParameter(params->param1, getState()->time, 900))
+ break;
getSound()->playSound(kEntityAugust, "Aug4003A");
@@ -3220,9 +3225,9 @@ IMPLEMENT_FUNCTION(63, August, function63)
break;
case kActionNone:
- UPDATE_PARAM_PROC(params->param3, getState()->time, 1800)
+ if (Entity::updateParameter(params->param3, getState()->time, 1800)) {
getData()->inventoryItem = kItemInvalid;
- UPDATE_PARAM_PROC_END
+ }
if (getState()->time > kTime2488500 && !params->param4) {
params->param4 = 1;
@@ -3231,7 +3236,8 @@ IMPLEMENT_FUNCTION(63, August, function63)
break;
}
- UPDATE_PARAM(params->param5, getState()->timeTicks, params->param1);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, params->param1))
+ break;
params->param2 = (params->param6 < 1 ? 1 : 0);
@@ -3388,7 +3394,8 @@ IMPLEMENT_FUNCTION(68, August, function68)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM(params->param4, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 1;
diff --git a/engines/lastexpress/entities/august.h b/engines/lastexpress/entities/august.h
index 2cbb31b968..606321955b 100644
--- a/engines/lastexpress/entities/august.h
+++ b/engines/lastexpress/entities/august.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_AUGUST_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/boutarel.cpp b/engines/lastexpress/entities/boutarel.cpp
index 315b12a69e..219ddf901b 100644
--- a/engines/lastexpress/entities/boutarel.cpp
+++ b/engines/lastexpress/entities/boutarel.cpp
@@ -32,9 +32,7 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
@@ -231,7 +229,7 @@ IMPLEMENT_FUNCTION_I(11, Boutarel, function11, bool)
case 7:
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -249,7 +247,7 @@ IMPLEMENT_FUNCTION(12, Boutarel, enterTableWithMmeBoutarel)
getSavePoints()->push(kEntityBoutarel, kEntityTables2, kAction136455232);
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -276,7 +274,7 @@ IMPLEMENT_FUNCTION(13, Boutarel, leaveTableWithMmeBoutarel)
getSavePoints()->push(kEntityBoutarel, kEntityTables2, kActionDrawTablesWithChairs, "008F");
getEntities()->clearSequences(kEntityMmeBoutarel);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -358,7 +356,7 @@ IMPLEMENT_FUNCTION_I(14, Boutarel, function14, bool)
getEntities()->clearSequences(kEntityBoutarel);
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -416,7 +414,7 @@ IMPLEMENT_FUNCTION_IS(15, Boutarel, function15, bool)
case 5:
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -464,7 +462,7 @@ IMPLEMENT_FUNCTION_IS(16, Boutarel, function16, bool)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityBoutarel);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -478,10 +476,13 @@ IMPLEMENT_FUNCTION_IS(17, Boutarel, function17, TimeValue)
break;
case kActionNone:
- TIME_CHECK_CALLBACK_ACTION(params->param1, params->param6);
+ if (Entity::timeCheckCallbackAction((TimeValue)params->param1, params->param6))
+ break;
if (params->param5) {
- UPDATE_PARAM(params->param7, getState()->timeTicks, 90)
+ if (!Entity::updateParameter(params->param7, getState()->timeTicks, 90))
+ break;
+
getScenes()->loadSceneFromPosition(kCarRestaurant, 51);
} else {
params->param7 = 0;
@@ -511,12 +512,13 @@ IMPLEMENT_FUNCTION_I(18, Boutarel, function18, TimeValue)
getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (params->param2) {
- UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75))
+ break;
params->param2 = 0;
params->param3 = 1;
@@ -615,7 +617,7 @@ IMPLEMENT_FUNCTION(19, Boutarel, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Boutarel, setup_chapter1Handler));
break;
case kActionDefault:
@@ -644,14 +646,14 @@ IMPLEMENT_FUNCTION(20, Boutarel, function20)
break;
if (!params->param2) {
- UPDATE_PARAM_PROC(params->param3, getState()->time, 4500)
+ if (Entity::updateParameter(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);
+ Entity::timeCheckCallback(kTime1138500, params->param4, 4, false, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14));
break;
case kActionDefault:
@@ -676,13 +678,13 @@ IMPLEMENT_FUNCTION(20, Boutarel, function20)
break;
case 3:
- TIME_CHECK_CALLBACK_1(kTime1138500, params->param4, 4, setup_function14, false);
+ Entity::timeCheckCallback(kTime1138500, params->param4, 4, false, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14));
break;
case 4:
getSavePoints()->push(kEntityBoutarel, kEntityCooks, kAction224849280);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -834,7 +836,7 @@ IMPLEMENT_FUNCTION(24, Boutarel, chapter2Handler)
break;
case kActionNone:
- TIME_CHECK_CALLBACK_1(kTime1759500, params->param2, 1, setup_function14, false);
+ Entity::timeCheckCallback(kTime1759500, params->param2, 1, false, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14));
break;
case kActionDefault:
@@ -934,9 +936,9 @@ IMPLEMENT_FUNCTION(29, Boutarel, function29)
break;
case kActionNone:
- UPDATE_PARAM_PROC(params->param2, getState()->time, 450)
+ if (Entity::updateParameter(params->param2, getState()->time, 450)) {
getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848);
- UPDATE_PARAM_PROC_END
+ }
if (!params->param1)
break;
@@ -959,7 +961,7 @@ IMPLEMENT_FUNCTION(29, Boutarel, function29)
}
}
- TIME_CHECK_CALLBACK_1(kTime2002500, params->param4, 1, setup_function14, true);
+ Entity::timeCheckCallback(kTime2002500, params->param4, 1, true, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14));
break;
case kActionDefault:
@@ -972,7 +974,7 @@ IMPLEMENT_FUNCTION(29, Boutarel, function29)
break;
case 1:
- TIME_CHECK_CALLBACK_1(kTime2002500, params->param4, 1, setup_function14, true);
+ Entity::timeCheckCallback(kTime2002500, params->param4, 1, true, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14));
break;
case 2:
@@ -1045,7 +1047,7 @@ IMPLEMENT_FUNCTION(32, Boutarel, chapter4Handler)
break;
case kActionNone:
- TIME_CHECK(kTime2367000, params->param1, setup_function33);
+ Entity::timeCheck(kTime2367000, params->param1, WRAP_SETUP_FUNCTION(Boutarel, setup_function33));
break;
case kActionDefault:
@@ -1063,7 +1065,7 @@ IMPLEMENT_FUNCTION(33, Boutarel, function33)
case kActionNone:
if (params->param1)
- TIME_CHECK_CALLBACK_1(kTime2389500, params->param2, 3, setup_function14, false);
+ Entity::timeCheckCallback(kTime2389500, params->param2, 3, false, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14));
break;
case kActionDefault:
@@ -1111,7 +1113,8 @@ IMPLEMENT_FUNCTION(34, Boutarel, function34)
break;
case kActionNone:
- TIME_CHECK(kTime2470500, params->param1, setup_function35);
+ if (Entity::timeCheck(kTime2470500, params->param1, WRAP_SETUP_FUNCTION(Boutarel, setup_function35)))
+ break;
if (getState()->time > kTime2457000 && getEvent(kEventAugustDrink)) {
getSavePoints()->push(kEntityBoutarel, kEntityAbbot, kAction159003408);
diff --git a/engines/lastexpress/entities/boutarel.h b/engines/lastexpress/entities/boutarel.h
index 5eb264631c..04838f6527 100644
--- a/engines/lastexpress/entities/boutarel.h
+++ b/engines/lastexpress/entities/boutarel.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_BOUTAREL_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/chapters.cpp b/engines/lastexpress/entities/chapters.cpp
index 4ef2dc50e8..a2f3a3d871 100644
--- a/engines/lastexpress/entities/chapters.cpp
+++ b/engines/lastexpress/entities/chapters.cpp
@@ -63,11 +63,9 @@
#include "lastexpress/game/state.h"
#include "lastexpress/menu/menu.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
@@ -152,7 +150,7 @@ IMPLEMENT_FUNCTION(5, Chapters, resetMainEntities)
RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_reset);
RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_reset);
- CALLBACK_ACTION();
+ callbackAction();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
@@ -191,7 +189,7 @@ IMPLEMENT_FUNCTION(6, Chapters, chapter1End)
getScenes()->loadScene(kScene41);
- CALLBACK_ACTION();
+ callbackAction();
} else {
getSound()->playSound(kEntityPlayer, "LIB014");
getSound()->playSound(kEntityPlayer, "LIB015", kFlagDefault, 15);
@@ -386,12 +384,6 @@ IMPLEMENT_FUNCTION(7, Chapters, chapter1Init)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-#define PLAY_STEAM() { \
- getSoundQueue()->resetState(); \
- getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4)); \
- ENTITY_PARAM(0, 2) = 0; \
- }
-
IMPLEMENT_FUNCTION(8, Chapters, chapter1Handler)
switch (savepoint.action) {
default:
@@ -401,21 +393,28 @@ IMPLEMENT_FUNCTION(8, Chapters, chapter1Handler)
if (!getProgress().isTrainRunning || getState()->time >= kTime1458000)
goto label_processStations;
- UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, params->param2)
+ if (Entity::updateParameter(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);
+ if (getState()->time > kTime1039500 && !params->param7) {
+ params->param7 = 1;
+ setCallback(1);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+
+ break;
+ }
label_enter_epernay:
// Entering Epernay station
- TIME_CHECK_CALLBACK_2(kTimeEnterEpernay, params->param8, 1, setup_enterStation, "Epernay", kCityEpernay);
+ if (timeCheckEnterStation(kTimeEnterEpernay, params->param8, 1, "Epernay", kCityEpernay))
+ break;
label_exit_epernay:
// Exiting Epernay station
@@ -445,19 +444,23 @@ label_enter_chalons:
goto label_exit_strasbourg;
// Entering Chalons station
- TIME_CHECK_CALLBACK_2(kTimeEnterChalons, CURRENT_PARAM(1, 3), 5, setup_enterStation, "Chalons", kCityChalons);
+ if (timeCheckEnterStation(kTimeEnterChalons, CURRENT_PARAM(1, 3), 5, "Chalons", kCityChalons))
+ break;
label_exit_chalons:
// Exiting Chalons station
- TIME_CHECK_CALLBACK_1(kTimeExitChalons, CURRENT_PARAM(1, 4), 6, setup_exitStation, "Chalons");
+ if (timeCheckExitStation(kTimeExitChalons, CURRENT_PARAM(1, 4), 6, "Chalons"))
+ break;
label_enter_barleduc:
// Entering Bar-Le-Duc station
- TIME_CHECK_CALLBACK_2(kTimeCityBarLeDuc, CURRENT_PARAM(1, 5), 7, setup_enterStation, "BarLeDuc", kCityBarleduc);
+ if (timeCheckEnterStation(kTimeCityBarLeDuc, CURRENT_PARAM(1, 5), 7, "BarLeDuc", kCityBarleduc))
+ break;
label_exit_barleduc:
// Exiting Bar-Le-Duc station
- TIME_CHECK_CALLBACK_1(kTimeExitBarLeDuc, CURRENT_PARAM(1, 6), 8, setup_exitStation, "BarLeDuc");
+ if (timeCheckExitStation(kTimeExitBarLeDuc, CURRENT_PARAM(1, 6), 8, "BarLeDuc"))
+ break;
label_enter_nancy:
if (getState()->time > kTime1260000 && !CURRENT_PARAM(1, 7)) {
@@ -466,50 +469,67 @@ label_enter_nancy:
}
// Entering Nancy station
- TIME_CHECK_CALLBACK_2(kTimeCityNancy, CURRENT_PARAM(1, 8), 9, setup_enterStation, "Nancy", kCityNancy);
+ if (timeCheckEnterStation(kTimeCityNancy, CURRENT_PARAM(1, 8), 9, "Nancy", kCityNancy))
+ break;
label_exit_nancy:
// Exiting Nancy station
- TIME_CHECK_CALLBACK_1(kTimeExitNancy, CURRENT_PARAM(2, 1), 10, setup_exitStation, "Nancy");
+ if (timeCheckExitStation(kTimeExitNancy, CURRENT_PARAM(2, 1), 10, "Nancy"))
+ break;
label_enter_luneville:
// Entering Luneville station
- TIME_CHECK_CALLBACK_2(kTimeCityLuneville, CURRENT_PARAM(2, 2), 11, setup_enterStation, "Luneville", kCityLuneville);
+ if (timeCheckEnterStation(kTimeCityLuneville, CURRENT_PARAM(2, 2), 11, "Luneville", kCityLuneville))
+ break;
label_exit_luneville:
// Exiting Luneville station
- TIME_CHECK_CALLBACK_1(kTimeExitLuneville, CURRENT_PARAM(2, 3), 12, setup_exitStation, "Luneville");
+ if (timeCheckExitStation(kTimeExitLuneville, CURRENT_PARAM(2, 3), 12, "Luneville"))
+ break;
label_enter_avricourt:
// Entering Avricourt station
- TIME_CHECK_CALLBACK_2(kTimeCityAvricourt, CURRENT_PARAM(2, 4), 13, setup_enterStation, "Avricourt", kCityAvricourt);
+ if (timeCheckEnterStation(kTimeCityAvricourt, CURRENT_PARAM(2, 4), 13, "Avricourt", kCityAvricourt))
+ break;
label_exit_avricourt:
// Exiting Avricourt station
- TIME_CHECK_CALLBACK_1(kTimeExitAvricourt, CURRENT_PARAM(2, 5), 14, setup_exitStation, "Avricourt");
+ if (timeCheckExitStation(kTimeExitAvricourt, CURRENT_PARAM(2, 5), 14, "Avricourt"))
+ break;
label_enter_deutschavricourt:
// Entering Deutsch-Avricourt station
- TIME_CHECK_CALLBACK_2(kTimeCityDeutschAvricourt, CURRENT_PARAM(2, 6), 15, setup_enterStation, "DeutschA", kCityDeutschAvricourt);
+ if (timeCheckEnterStation(kTimeCityDeutschAvricourt, CURRENT_PARAM(2, 6), 15, "DeutschA", kCityDeutschAvricourt))
+ break;
label_exit_deutschavricourt:
// Exiting Avricourt station
- TIME_CHECK_CALLBACK_1(kTimeExitDeutschAvricourt, CURRENT_PARAM(2, 7), 16, setup_exitStation, "DeutschA");
+ if (timeCheckExitStation(kTimeExitDeutschAvricourt, CURRENT_PARAM(2, 7), 16, "DeutschA"))
+ break;
label_enter_strasbourg:
- TIME_CHECK_CALLBACK_2(kTimeCityStrasbourg, CURRENT_PARAM(2, 8), 17, setup_savegame, kSavegameTypeTime, kTimeNone);
+ if (getState()->time > kTimeCityStrasbourg && !CURRENT_PARAM(2, 8)) {
+ CURRENT_PARAM(2, 8) = 1;
+ setCallback(17);
+ setup_savegame(kSavegameTypeTime, kTimeNone);
+
+ break;
+ }
label_exit_strasbourg:
// Exiting Strasbourg station
- TIME_CHECK_CALLBACK_1(kTimeExitStrasbourg, CURRENT_PARAM(3, 1), 19, setup_exitStation, "Strasbou");
+ if (timeCheckExitStation(kTimeExitStrasbourg, CURRENT_PARAM(3, 1), 19, "Strasbou"))
+ break;
label_enter_badenoos:
// Entering Baden Oos station
- TIME_CHECK_CALLBACK_2(kTimeCityBadenOos, CURRENT_PARAM(3, 2), 20, setup_enterStation, "BadenOos", kCityBadenOos);
+ if (timeCheckEnterStation(kTimeCityBadenOos, CURRENT_PARAM(3, 2), 20, "BadenOos", kCityBadenOos))
+ break;
label_exit_badenoos:
// Exiting Baden Oos station
- TIME_CHECK_CALLBACK_1(kTimeExitBadenOos, CURRENT_PARAM(3, 3), 21, setup_exitStation, "BadenOos");
+ if (timeCheckExitStation(kTimeExitBadenOos, CURRENT_PARAM(3, 3), 21, "BadenOos"))
+ break;
label_chapter1_next:
if (getState()->time > kTimeChapter1End3 && ! CURRENT_PARAM(3, 4)) {
@@ -524,43 +544,43 @@ label_chapter1_next:
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) {
- PLAY_STEAM();
+ playSteam();
break;
}
if (getEntities()->isOutsideAlexeiWindow()) {
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
- PLAY_STEAM();
+ playSteam();
break;
}
if (getEntities()->isOutsideAnnaWindow()) {
getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
- PLAY_STEAM();
+ playSteam();
break;
}
CarIndex car = getEntityData(kEntityPlayer)->car;
if (car < kCarRedSleeping || car > kCarCoalTender) {
if (car < kCarBaggageRear || car > kCarGreenSleeping) {
- PLAY_STEAM();
+ playSteam();
break;
}
if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
- PLAY_STEAM();
+ playSteam();
break;
}
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
- PLAY_STEAM();
+ playSteam();
break;
}
getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
- PLAY_STEAM();
+ playSteam();
break;
}
@@ -817,7 +837,8 @@ IMPLEMENT_FUNCTION(12, Chapters, chapter2Handler)
if (!getProgress().isTrainRunning)
break;
- UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, params->param1))
+ break;
getSound()->playLocomotiveSound();
@@ -903,15 +924,15 @@ IMPLEMENT_FUNCTION(15, Chapters, chapter3Handler)
case kActionNone:
if (getProgress().isTrainRunning) {
- UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, params->param1)
+ if (Entity::updateParameter(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)
+ if (Entity::updateParameter(params->param5, getState()->timeTicks, params->param2)) {
switch (rnd(2)) {
default:
break;
@@ -927,30 +948,38 @@ IMPLEMENT_FUNCTION(15, Chapters, chapter3Handler)
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);
+ if (timeCheckEnterStation(kTimeEnterSalzbourg, params->param6, 1, "Salzburg", kCitySalzbourg))
+ break;
label_callback_1:
- TIME_CHECK_CALLBACK_1(kTimeExitSalzbourg, params->param7, 2, setup_exitStation, "Salzburg");
+ if (timeCheckExitStation(kTimeExitSalzbourg, params->param7, 2, "Salzburg"))
+ break;
label_callback_2:
- TIME_CHECK_CALLBACK_2(kTimeEnterAttnangPuchheim, params->param8, 3, setup_enterStation, "Attnang", kCityAttnangPuchheim);
+ if (timeCheckEnterStation(kTimeEnterAttnangPuchheim, params->param8, 3, "Attnang", kCityAttnangPuchheim))
+ break;
label_callback_3:
- TIME_CHECK_CALLBACK_1(kTimeExitAttnangPuchheim, CURRENT_PARAM(1, 1), 4, setup_exitStation, "Attnang");
+ if (timeCheckExitStation(kTimeExitAttnangPuchheim, CURRENT_PARAM(1, 1), 4, "Attnang"))
+ break;
label_callback_4:
- TIME_CHECK_CALLBACK_2(kTimeEnterWels, CURRENT_PARAM(1, 2), 5, setup_enterStation, "Wels", kCityWels);
+ if (timeCheckEnterStation(kTimeEnterWels, CURRENT_PARAM(1, 2), 5, "Wels", kCityWels))
+ break;
label_callback_5:
- TIME_CHECK_CALLBACK_1(kTimeEnterWels, CURRENT_PARAM(1, 3), 6, setup_exitStation, "Wels");
+ if (timeCheckExitStation(kTimeEnterWels, CURRENT_PARAM(1, 3), 6, "Wels"))
+ break;
label_callback_6:
- TIME_CHECK_CALLBACK_2(kTimeEnterLinz, CURRENT_PARAM(1, 4), 7, setup_enterStation, "Linz", kCityLinz);
+ if (timeCheckEnterStation(kTimeEnterLinz, CURRENT_PARAM(1, 4), 7, "Linz", kCityLinz))
+ break;
label_callback_7:
- TIME_CHECK_CALLBACK_1(kTimeCityLinz, CURRENT_PARAM(1, 5), 8, setup_exitStation, "Linz");
+ if (timeCheckExitStation(kTimeCityLinz, CURRENT_PARAM(1, 5), 8, "Linz"))
+ break;
label_callback_8:
if (getState()->time > kTime2187000 && !CURRENT_PARAM(1, 6)) {
@@ -958,7 +987,7 @@ label_callback_8:
getState()->timeDelta = 5;
}
- TIME_CHECK_CALLBACK_2(kTimeCityVienna, CURRENT_PARAM(1, 7), 9, setup_enterStation, "Vienna", kCityVienna);
+ timeCheckEnterStation(kTimeCityVienna, CURRENT_PARAM(1, 7), 9, "Vienna", kCityVienna);
break;
case kActionEndSound:
@@ -1202,15 +1231,15 @@ IMPLEMENT_FUNCTION(19, Chapters, chapter4Handler)
case kActionNone:
if (getProgress().isTrainRunning) {
- UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, params->param4);
+ if (Entity::updateParameter(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)
+ if (Entity::updateParameter(params->param7, getState()->timeTicks, params->param5)) {
switch (rnd(2)) {
default:
break;
@@ -1226,12 +1255,14 @@ IMPLEMENT_FUNCTION(19, Chapters, chapter4Handler)
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);
+ if (timeCheckEnterStation(kTimeEnterPoszony, params->param8, 1, "Pozsony", kCityPoszony))
+ break;
label_exitPozsony:
- TIME_CHECK_CALLBACK_1(kTimeExitPoszony, CURRENT_PARAM(1, 1), 2, setup_exitStation, "Pozsony");
+ if (timeCheckExitStation(kTimeExitPoszony, CURRENT_PARAM(1, 1), 2, "Pozsony"))
+ break;
label_enterGalanta:
if (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) {
@@ -1244,10 +1275,12 @@ label_enterGalanta:
if (params->param1)
goto label_callback_4;
- TIME_CHECK_CALLBACK_2(kTimeEnterGalanta, CURRENT_PARAM(1, 3), 3, setup_enterStation, "Galanta", kCityGalanta);
+ if (timeCheckEnterStation(kTimeEnterGalanta, CURRENT_PARAM(1, 3), 3, "Galanta", kCityGalanta))
+ break;
label_exitGalanta:
- TIME_CHECK_CALLBACK_1(kTimeExitGalanta, CURRENT_PARAM(1, 4), 4, setup_exitStation, "Galanta");
+ if (timeCheckExitStation(kTimeExitGalanta, CURRENT_PARAM(1, 4), 4, "Galanta"))
+ break;
label_callback_4:
if (getState()->time > kTime2470500 && !CURRENT_PARAM(1, 5)) {
@@ -1280,43 +1313,43 @@ label_callback_4:
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) {
- PLAY_STEAM();
+ playSteam();
break;
}
if (getEntities()->isOutsideAlexeiWindow()) {
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
- PLAY_STEAM();
+ playSteam();
break;
}
if (getEntities()->isOutsideAnnaWindow()) {
getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
- PLAY_STEAM();
+ playSteam();
break;
}
CarIndex car = getEntityData(kEntityPlayer)->car;
if (car < kCarRedSleeping || car > kCarCoalTender) {
if (car < kCarBaggageRear || car > kCarGreenSleeping) {
- PLAY_STEAM();
+ playSteam();
break;
}
if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
- PLAY_STEAM();
+ playSteam();
break;
}
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
- PLAY_STEAM();
+ playSteam();
break;
}
getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
- PLAY_STEAM();
+ playSteam();
break;
}
@@ -1815,7 +1848,37 @@ void Chapters::enterExitHelper(bool isEnteringStation) {
ENTITY_PARAM(0, 3) = 1;
}
- CALLBACK_ACTION();
+ callbackAction();
+}
+
+void Chapters::playSteam() {
+ getSoundQueue()->resetState();
+ getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4));
+ ENTITY_PARAM(0, 2) = 0;
+}
+
+bool Chapters::timeCheckEnterStation(TimeValue timeValue, uint &parameter, byte callback, const char *sequence, CityIndex cityIndex) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ setCallback(callback);
+ setup_enterStation(sequence, cityIndex);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Chapters::timeCheckExitStation(TimeValue timeValue, uint &parameter, byte callback, const char *sequence) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ setCallback(callback);
+ setup_exitStation(sequence);
+
+ return true;
+ }
+
+ return false;
}
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/chapters.h b/engines/lastexpress/entities/chapters.h
index 353d3a6b5b..ddb3de3bea 100644
--- a/engines/lastexpress/entities/chapters.h
+++ b/engines/lastexpress/entities/chapters.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_CHAPTERS_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
@@ -154,8 +153,11 @@ public:
DECLARE_FUNCTION(chapter5Handler)
private:
+ bool timeCheckEnterStation(TimeValue timeValue, uint &parameter, byte callback, const char *sequence, CityIndex cityIndex);
+ bool timeCheckExitStation(TimeValue timeValue, uint &parameter, byte callback, const char *sequence);
void enterExitStation(const SavePoint &savepoint, bool isEnteringStation);
void enterExitHelper(bool isEnteringStation);
+ void playSteam();
};
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/cooks.cpp b/engines/lastexpress/entities/cooks.cpp
index 42e888cc7c..5e8a2df8cb 100644
--- a/engines/lastexpress/entities/cooks.cpp
+++ b/engines/lastexpress/entities/cooks.cpp
@@ -29,9 +29,7 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
@@ -96,7 +94,7 @@ IMPLEMENT_FUNCTION(3, Cooks, function3)
case kActionDrawScene:
if (!getEntities()->isInKitchen(kEntityPlayer)) {
getEntities()->clearSequences(kEntityCooks);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -108,7 +106,7 @@ IMPLEMENT_FUNCTION(3, Cooks, function3)
if (!getEntities()->hasValidFrame(kEntityCooks)) {
getSound()->playSound(kEntityCooks, "LIB015");
getEntities()->clearSequences(kEntityCooks);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -122,7 +120,7 @@ IMPLEMENT_FUNCTION(3, Cooks, function3)
if (params->param1 && !getEntities()->hasValidFrame(kEntityCooks)) {
getSound()->playSound(kEntityCooks, "LIB015");
getEntities()->clearSequences(kEntityCooks);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -182,7 +180,7 @@ IMPLEMENT_FUNCTION(4, Cooks, function4)
case kActionDrawScene:
if (!getEntities()->isInKitchen(kEntityPlayer)) {
getEntities()->clearSequences(kEntityCooks);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -194,7 +192,7 @@ IMPLEMENT_FUNCTION(4, Cooks, function4)
if (!getEntities()->hasValidFrame(kEntityCooks)) {
getSound()->playSound(kEntityCooks, "LIB015");
getEntities()->clearSequences(kEntityCooks);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -208,7 +206,7 @@ IMPLEMENT_FUNCTION(4, Cooks, function4)
if (params->param1 && !getEntities()->hasValidFrame(kEntityCooks)) {
getSound()->playSound(kEntityCooks, "LIB015");
getEntities()->clearSequences(kEntityCooks);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -241,7 +239,7 @@ IMPLEMENT_FUNCTION(5, Cooks, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Cooks, setup_chapter1Handler));
break;
case kActionDefault:
@@ -262,7 +260,8 @@ IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler)
break;
case kActionNone:
- UPDATE_PARAM(params->param4, getState()->time, params->param2);
+ if (!Entity::updateParameter(params->param4, getState()->time, params->param2))
+ break;
// Broken plate sound
getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks));
@@ -375,7 +374,8 @@ IMPLEMENT_FUNCTION(9, Cooks, chapter2Handler)
break;
case kActionNone:
- UPDATE_PARAM(params->param3, getState()->time, params->param1);
+ if (!Entity::updateParameter(params->param3, getState()->time, params->param1))
+ break;
// Broken plate sound
getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks));
@@ -434,12 +434,12 @@ IMPLEMENT_FUNCTION(11, Cooks, chapter3Handler)
break;
case kActionNone:
- UPDATE_PARAM_PROC(params->param4, getState()->time, params->param2)
+ if (Entity::updateParameter(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;
@@ -526,7 +526,8 @@ IMPLEMENT_FUNCTION(13, Cooks, chapter4Handler)
break;
case kActionNone:
- UPDATE_PARAM(params->param3, getState()->time, params->param1)
+ if (!Entity::updateParameter(params->param3, getState()->time, params->param1))
+ break;
// Broken plate sound
getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks));
diff --git a/engines/lastexpress/entities/cooks.h b/engines/lastexpress/entities/cooks.h
index 3ab7d35161..f01d0b2ca0 100644
--- a/engines/lastexpress/entities/cooks.h
+++ b/engines/lastexpress/entities/cooks.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_COOKS_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/coudert.cpp b/engines/lastexpress/entities/coudert.cpp
index c3e7e37b88..b604277903 100644
--- a/engines/lastexpress/entities/coudert.cpp
+++ b/engines/lastexpress/entities/coudert.cpp
@@ -32,22 +32,11 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.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);
@@ -126,11 +115,11 @@ IMPLEMENT_FUNCTION_S(2, Coudert, bloodJacket)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -153,7 +142,7 @@ IMPLEMENT_FUNCTION_SI(3, Coudert, enterExitCompartment, ObjectIndex)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
return;
case kActionCallback:
@@ -175,15 +164,15 @@ IMPLEMENT_FUNCTION(4, Coudert, callbackActionOnDirection)
case kActionNone:
if (getData()->direction != kDirectionRight) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -202,7 +191,7 @@ IMPLEMENT_FUNCTION_SIII(5, Coudert, enterExitCompartment2, ObjectIndex, EntityPo
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
return;
case kActionCallback:
@@ -223,11 +212,11 @@ IMPLEMENT_FUNCTION_S(6, Coudert, playSound)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionEndSound:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -252,11 +241,11 @@ IMPLEMENT_FUNCTION_NOSETUP(7, Coudert, playSound16)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionEndSound:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -296,7 +285,7 @@ IMPLEMENT_FUNCTION_II(9, Coudert, updateEntity, CarIndex, EntityPosition)
if (getEntities()->updateEntity(kEntityCoudert, (CarIndex)params->param1, (EntityPosition)params->param2)) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -332,7 +321,7 @@ IMPLEMENT_FUNCTION_II(9, Coudert, updateEntity, CarIndex, EntityPosition)
params->param3 = kItemInvalid;
if (getEntities()->updateEntity(kEntityCoudert, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -365,11 +354,12 @@ IMPLEMENT_FUNCTION_I(10, Coudert, updateFromTime, uint32)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
- UPDATE_PARAM(params->param2, getState()->time, params->param1);
+ if (!Entity::updateParameter(params->param2, getState()->time, params->param1))
+ break;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -388,11 +378,12 @@ IMPLEMENT_FUNCTION_I(11, Coudert, updateFromTicks, uint32)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
- UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, params->param1))
+ break;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -412,7 +403,7 @@ IMPLEMENT_FUNCTION_I(12, Coudert, excuseMe, EntityIndex)
return;
if (getSoundQueue()->isBuffered(kEntityCoudert)) {
- CALLBACK_ACTION();
+ callbackAction();
return;
}
@@ -452,7 +443,7 @@ IMPLEMENT_FUNCTION_I(12, Coudert, excuseMe, EntityIndex)
getSound()->playSound(kEntityCoudert, "JAC1112E");
}
- CALLBACK_ACTION();
+ callbackAction();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
@@ -462,7 +453,7 @@ IMPLEMENT_FUNCTION_II(13, Coudert, function13, bool, EntityIndex)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
if (!params->param2 && !params->param3) {
@@ -487,7 +478,8 @@ IMPLEMENT_FUNCTION_II(13, Coudert, function13, bool, EntityIndex)
}
}
- UPDATE_PARAM(params->param5, getState()->timeTicks, 225);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 225))
+ break;
getData()->inventoryItem = kItemNone;
setCallback(5);
@@ -561,7 +553,7 @@ IMPLEMENT_FUNCTION_II(13, Coudert, function13, bool, EntityIndex)
case 5:
case 6:
case 7:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 9:
@@ -584,7 +576,7 @@ IMPLEMENT_FUNCTION_I(14, Coudert, function14, EntityIndex)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionDefault:
@@ -629,7 +621,7 @@ IMPLEMENT_FUNCTION_I(14, Coudert, function14, EntityIndex)
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -706,7 +698,7 @@ IMPLEMENT_FUNCTION_I(15, Coudert, function15, bool)
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -724,7 +716,7 @@ IMPLEMENT_FUNCTION(16, Coudert, function16)
ENTITY_PARAM(2, 1) = 0;
getInventory()->setLocationAndProcess(kItem5, kObjectLocation1);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -743,7 +735,7 @@ IMPLEMENT_FUNCTION(16, Coudert, function16)
if (!getEntities()->isPlayerPosition(kCarRedSleeping, 2))
getData()->entityPosition = kPosition_2088;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -761,7 +753,7 @@ IMPLEMENT_FUNCTION_I(17, Coudert, function17, bool)
if (ENTITY_PARAM(2, 1)) {
ENTITY_PARAM(2, 1) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -789,7 +781,7 @@ IMPLEMENT_FUNCTION_I(17, Coudert, function17, bool)
case 1:
case 2:
case 3:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -817,7 +809,7 @@ IMPLEMENT_FUNCTION(18, Coudert, function18)
getEntities()->drawSequenceLeft(kEntityCoudert, "627K");
getScenes()->loadSceneFromItemPosition(kItem5);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -849,7 +841,7 @@ IMPLEMENT_FUNCTION(18, Coudert, function18)
break;
case 2:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 3:
@@ -857,7 +849,7 @@ IMPLEMENT_FUNCTION(18, Coudert, function18)
ENTITY_PARAM(0, 1) = 0;
getSavePoints()->push(kEntityCoudert, kEntityCoudert, kActionDrawScene);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -876,14 +868,14 @@ IMPLEMENT_FUNCTION_I(19, Coudert, function19, bool)
|| ENTITY_PARAM(2, 4) || ENTITY_PARAM(2, 6)) {
getInventory()->setLocationAndProcess(kItem5, kObjectLocation1);
ENTITY_PARAM(2, 1) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (ENTITY_PARAM(0, 3) || ENTITY_PARAM(0, 5) || ENTITY_PARAM(0, 4)) {
getScenes()->loadSceneFromItemPosition(kItem5);
ENTITY_PARAM(2, 1) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -903,7 +895,7 @@ IMPLEMENT_FUNCTION_I(19, Coudert, function19, bool)
getEntities()->drawSequenceLeft(kEntityCoudert, ENTITY_PARAM(0, 2) ? "627B" : "627E");
ENTITY_PARAM(0, 1) = 0;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -916,11 +908,12 @@ IMPLEMENT_FUNCTION_II(20, Coudert, function20, ObjectIndex, ObjectIndex)
break;
case kActionNone:
- UPDATE_PARAM_PROC(CURRENT_PARAM(1, 3), getState()->time, 300)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(CURRENT_PARAM(1, 4), getState()->time, 900))
+ break;
getObjects()->updateLocation2((ObjectIndex)params->param1, kObjectLocation1);
@@ -930,7 +923,7 @@ IMPLEMENT_FUNCTION_II(20, Coudert, function20, ObjectIndex, ObjectIndex)
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();
+ callbackAction();
break;
case kActionKnock:
@@ -999,7 +992,8 @@ IMPLEMENT_FUNCTION(21, Coudert, function21)
case kActionNone:
if (!params->param1) {
- UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75))
+ break;
setCallback(3);
setup_enterExitCompartment("627Zh", kObjectCompartmentH);
@@ -1044,7 +1038,7 @@ IMPLEMENT_FUNCTION(21, Coudert, function21)
case 5:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -1073,7 +1067,7 @@ IMPLEMENT_FUNCTION(21, Coudert, function21)
getData()->location = kLocationOutsideCompartment;
getSavePoints()->push(kEntityCoudert, kEntityIvo, kAction123852928);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1100,7 +1094,8 @@ IMPLEMENT_FUNCTION(22, Coudert, function22)
case kActionNone:
if (!params->param1) {
- UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75))
+ break;
setCallback(3);
setup_enterExitCompartment("627Rg", kObjectCompartmentG);
@@ -1145,7 +1140,7 @@ IMPLEMENT_FUNCTION(22, Coudert, function22)
case 5:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -1174,7 +1169,7 @@ IMPLEMENT_FUNCTION(22, Coudert, function22)
getData()->location = kLocationOutsideCompartment;
getSavePoints()->push(kEntityCoudert, kEntityMilos, kAction123852928);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1225,7 +1220,7 @@ IMPLEMENT_FUNCTION(23, Coudert, function23)
case 3:
getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentF, true);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1296,7 +1291,7 @@ IMPLEMENT_FUNCTION(25, Coudert, function25)
getData()->location = kLocationOutsideCompartment;
getSavePoints()->push(kEntityCoudert, kEntityRebecca, kAction123852928);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1311,7 +1306,8 @@ IMPLEMENT_FUNCTION(26, Coudert, function26)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75))
+ break;
setCallback(3);
setup_enterExitCompartment2("627Zd", kObjectCompartmentD, kPosition_5790, kPosition_6130);
@@ -1357,7 +1353,7 @@ IMPLEMENT_FUNCTION(26, Coudert, function26)
case 5:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -1375,7 +1371,7 @@ IMPLEMENT_FUNCTION(26, Coudert, function26)
getData()->location = kLocationOutsideCompartment;
getSavePoints()->push(kEntityCoudert, kEntityMmeBoutarel, kAction123852928);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1402,7 +1398,8 @@ IMPLEMENT_FUNCTION(27, Coudert, function27)
case kActionNone:
if (!params->param1) {
- UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75))
+ break;
setCallback(3);
setup_enterExitCompartment2("627Rc", kObjectCompartmentC, kPosition_6470, kPosition_6130);
@@ -1446,7 +1443,7 @@ IMPLEMENT_FUNCTION(27, Coudert, function27)
case 5:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -1473,7 +1470,7 @@ IMPLEMENT_FUNCTION(27, Coudert, function27)
getData()->location = kLocationOutsideCompartment;
getSavePoints()->push(kEntityCoudert, kEntityBoutarel, kAction123852928);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1515,7 +1512,7 @@ IMPLEMENT_FUNCTION_I(30, Coudert, function30, ObjectIndex)
case kActionDefault:
switch (parameters->param1) {
default:
- CALLBACK_ACTION();
+ callbackAction();
// Stop processing here
return;
@@ -1615,7 +1612,7 @@ IMPLEMENT_FUNCTION_I(30, Coudert, function30, ObjectIndex)
break;
case 6:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1654,7 +1651,7 @@ IMPLEMENT_FUNCTION_I(31, Coudert, function31, uint32)
case 2:
case 3:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1699,7 +1696,7 @@ IMPLEMENT_FUNCTION(32, Coudert, function32)
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1726,7 +1723,7 @@ IMPLEMENT_FUNCTION(33, Coudert, function33)
setup_updateEntity(kCarRedSleeping, kPosition_540);
}
} else {
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -1763,7 +1760,7 @@ IMPLEMENT_FUNCTION(33, Coudert, function33)
case 4:
ENTITY_PARAM(2, 6) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 5:
@@ -1808,7 +1805,7 @@ IMPLEMENT_FUNCTION(33, Coudert, function33)
case 10:
ENTITY_PARAM(2, 6) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1882,7 +1879,7 @@ IMPLEMENT_FUNCTION_I(34, Coudert, function34, bool)
break;
case 7:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1902,7 +1899,8 @@ IMPLEMENT_FUNCTION_I(35, Coudert, function35, bool)
getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
}
- UPDATE_PARAM(params->param2, getState()->time, 2700);
+ if (!Entity::updateParameter(params->param2, getState()->time, 2700))
+ break;
getSavePoints()->push(kEntityCoudert, kEntityMax, kActionMaxFreeFromCage);
@@ -1951,7 +1949,7 @@ IMPLEMENT_FUNCTION_I(35, Coudert, function35, bool)
break;
case 4:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1965,7 +1963,7 @@ IMPLEMENT_FUNCTION(36, Coudert, chapter1)
break;
case kActionNone:
- TIME_CHECK_CALLBACK(kTimeChapter1, params->param1, 1, setup_chapter1Handler)
+ Entity::timeCheckCallback(kTimeChapter1, params->param1, 1, WRAP_SETUP_FUNCTION(Coudert, setup_chapter1Handler));
break;
case kActionDefault:
@@ -2174,7 +2172,7 @@ IMPLEMENT_FUNCTION(39, Coudert, function39)
getSavePoints()->push(kEntityCoudert, kEntityVerges, kAction167854368);
ENTITY_PARAM(2, 2) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2283,22 +2281,22 @@ label_callback_9:
label_callback_10:
if (getState()->time > kTime1189800 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
- UPDATE_PARAM_PROC(params->param3, getState()->time, 2700);
+ if (Entity::updateParameter(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);
+ timeCheckObject(kTime1107000, params->param4, kObject111, kObjectLocation2);
+ timeCheckObject(kTime1161000, params->param5, kObject111, kObjectLocation3);
+ timeCheckObject(kTime1206000, params->param6, kObject111, kObjectLocation4);
break;
case kAction1:
@@ -2536,7 +2534,7 @@ IMPLEMENT_FUNCTION(41, Coudert, function41)
case 18:
getSavePoints()->push(kEntityCoudert, kEntityMilos, kAction208228224);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2827,28 +2825,34 @@ label_callback_12:
}
label_callback_13:
- TIME_CHECK_CALLBACK(kTime2088900, params->param1, 14, setup_function32);
+ if (Entity::timeCheckCallback(kTime2088900, params->param1, 14, WRAP_SETUP_FUNCTION(Coudert, setup_function32)))
+ break;
label_callback_14:
- TIME_CHECK_CALLBACK(kTime2119500, params->param2, 15, setup_function32);
+ if (Entity::timeCheckCallback(kTime2119500, params->param2, 15, WRAP_SETUP_FUNCTION(Coudert, setup_function32)))
+ break;
label_callback_15:
- TIME_CHECK_CALLBACK(kTime2138400, params->param3, 16, setup_function32);
+ if (Entity::timeCheckCallback(kTime2138400, params->param3, 16, WRAP_SETUP_FUNCTION(Coudert, setup_function32)))
+ break;
label_callback_16:
- TIME_CHECK_CALLBACK(kTime2147400, params->param4, 17, setup_function32);
+ if (Entity::timeCheckCallback(kTime2147400, params->param4, 17, WRAP_SETUP_FUNCTION(Coudert, setup_function32)))
+ break;
label_callback_17:
- TIME_CHECK_CALLBACK(kTime2160000, params->param5, 18, setup_function32);
+ if (Entity::timeCheckCallback(kTime2160000, params->param5, 18, WRAP_SETUP_FUNCTION(Coudert, setup_function32)))
+ break;
label_callback_18:
- TIME_CHECK_CALLBACK(kTime2205000, params->param6, 19, setup_function32);
+ if (Entity::timeCheckCallback(kTime2205000, params->param6, 19, WRAP_SETUP_FUNCTION(Coudert, setup_function32)))
+ break;
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);
+ timeCheckObject(kTime2025000, params->param7, kObject111, kObjectLocation7);
+ timeCheckObject(kTime2133000, params->param8, kObject111, kObjectLocation8);
+ timeCheckObject(kTime2173500, CURRENT_PARAM(1, 1), kObject111, kObjectLocation9);
}
break;
@@ -3051,7 +3055,7 @@ IMPLEMENT_FUNCTION(46, Coudert, function46)
break;
case 11:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3116,7 +3120,7 @@ IMPLEMENT_FUNCTION_I(47, Coudert, function47, bool)
break;
case 7:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3164,7 +3168,7 @@ IMPLEMENT_FUNCTION(48, Coudert, function48)
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3261,7 +3265,7 @@ IMPLEMENT_FUNCTION(49, Coudert, function49)
break;
case 11:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3347,7 +3351,7 @@ IMPLEMENT_FUNCTION(50, Coudert, function50)
break;
case 9:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3541,11 +3545,11 @@ label_callback_1:
params->param2 = (uint)(getState()->time + 4500);
if (params->param3 != kTimeInvalid) {
- UPDATE_PARAM_PROC_TIME(params->param2, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param3, 0)
+ if (Entity::updateParameterTime((TimeValue)params->param2, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param3, 0)) {
setCallback(2);
setup_function55();
break;
- UPDATE_PARAM_PROC_END
+ }
}
}
@@ -3558,18 +3562,22 @@ label_callback_2:
label_callback_3:
if (!params->param1) {
- TIME_CHECK_CALLBACK(kTime2394000, params->param4, 4, setup_function56);
+ if (Entity::timeCheckCallback(kTime2394000, params->param4, 4, WRAP_SETUP_FUNCTION(Coudert, setup_function56)))
+ break;
label_callback_4:
- TIME_CHECK_CALLBACK(kTime2434500, params->param5, 5, setup_function32);
+ if (Entity::timeCheckCallback(kTime2434500, params->param5, 5, WRAP_SETUP_FUNCTION(Coudert, setup_function32)))
+ break;
label_callback_5:
- TIME_CHECK_CALLBACK(kTime2448000, params->param6, 6, setup_function32);
+ if (Entity::timeCheckCallback(kTime2448000, params->param6, 6, WRAP_SETUP_FUNCTION(Coudert, setup_function32)))
+ break;
}
label_callback_6:
if (getState()->time > kTime2538000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
- UPDATE_PARAM(params->param7, getState()->time, 2700);
+ if (!Entity::updateParameter(params->param7, getState()->time, 2700))
+ break;
ENTITY_PARAM(0, 2) = 0;
ENTITY_PARAM(0, 1) = 1;
@@ -3696,7 +3704,7 @@ IMPLEMENT_FUNCTION(54, Coudert, function54)
break;
case 3:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3764,7 +3772,7 @@ IMPLEMENT_FUNCTION(55, Coudert, function55)
break;
case 7:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3868,7 +3876,7 @@ IMPLEMENT_FUNCTION(56, Coudert, function56)
break;
case 16:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -4034,7 +4042,8 @@ IMPLEMENT_FUNCTION(62, Coudert, function62)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM(params->param4, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 1;
@@ -4168,7 +4177,7 @@ void Coudert::visitCompartment(const SavePoint &savepoint, EntityPosition positi
case 6:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
diff --git a/engines/lastexpress/entities/coudert.h b/engines/lastexpress/entities/coudert.h
index 45d13ce9bb..8303c80a32 100644
--- a/engines/lastexpress/entities/coudert.h
+++ b/engines/lastexpress/entities/coudert.h
@@ -24,8 +24,6 @@
#define LASTEXPRESS_COUDERT_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
-
namespace LastExpress {
class LastExpressEngine;
diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp
index e136ca4776..2deca291f6 100644
--- a/engines/lastexpress/entities/entity.cpp
+++ b/engines/lastexpress/entities/entity.cpp
@@ -22,23 +22,13 @@
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
-
#include "lastexpress/data/sequence.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/object.h"
#include "lastexpress/game/savegame.h"
-#include "lastexpress/game/savepoint.h"
-#include "lastexpress/game/state.h"
-
-#include "lastexpress/sound/sound.h"
-
-#include "lastexpress/helpers.h"
-#include "lastexpress/lastexpress.h"
+#include "lastexpress/game/scenes.h"
namespace LastExpress {
@@ -55,6 +45,17 @@ EntityData::EntityCallData::~EntityCallData() {
SAFE_DELETE(sequence3);
}
+void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, int length) {
+ char seqName[13];
+ memset(&seqName, 0, length);
+
+ if (s.isSaving()) strcpy((char *)&seqName, string.c_str());
+ s.syncBytes((byte *)&seqName, length);
+
+ if (s.isLoading())
+ string = seqName;
+}
+
void EntityData::EntityCallData::saveLoadWithSerializer(Common::Serializer &s) {
for (uint i = 0; i < ARRAYSIZE(callbacks); i++)
s.syncAsByte(callbacks[i]);
@@ -81,23 +82,19 @@ void EntityData::EntityCallData::saveLoadWithSerializer(Common::Serializer &s) {
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
+ syncString(s, sequenceName, 13);
+ syncString(s, sequenceName2, 13);
+ syncString(s, sequenceNamePrefix, 7);
+ syncString(s, sequenceNameCopy, 13);
// Skip pointers to frame & sequences
- s.skip(5 * 4);
+ // (we are using a compressed stream, so we cannot seek on load)
+ if (s.isLoading()) {
+ byte empty[5 * 4];
+ s.syncBytes(empty, 5 * 4);
+ } else {
+ s.skip(5 * 4);
+ }
}
//////////////////////////////////////////////////////////////////////////
@@ -246,16 +243,38 @@ void Entity::savegame(const SavePoint &savepoint) {
break;
case kActionNone:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
getSaveLoad()->saveGame((SavegameType)params->param1, _entityIndex, (EventIndex)params->param2);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
}
+void Entity::savegameBloodJacket() {
+ if (getProgress().jacket == kJacketBlood
+ && getEntities()->isDistanceBetweenEntities(_entityIndex, kEntityPlayer, 1000)
+ && !getEntities()->isInsideCompartments(kEntityPlayer)
+ && !getEntities()->checkFields10(kEntityPlayer)) {
+ setCallback(1);
+
+ switch (_entityIndex) {
+ default:
+ break;
+
+ case kEntityCoudert:
+ setup_savegame(kSavegameTypeEvent, kEventCoudertBloodJacket);
+ break;
+
+ case kEntityMertens:
+ setup_savegame(kSavegameTypeEvent, kEventCoudertBloodJacket);
+ break;
+ }
+ }
+}
+
void Entity::playSound(const SavePoint &savepoint, bool resetItem, SoundFlag flag) {
EXPOSE_PARAMS(EntityData::EntityParametersSIIS)
@@ -264,7 +283,7 @@ void Entity::playSound(const SavePoint &savepoint, bool resetItem, SoundFlag fla
break;
case kActionEndSound:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -284,7 +303,7 @@ void Entity::draw(const SavePoint &savepoint, bool handleExcuseMe) {
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMeCath:
@@ -308,7 +327,7 @@ void Entity::draw2(const SavePoint &savepoint) {
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -326,8 +345,10 @@ void Entity::updateFromTicks(const SavePoint &savepoint) {
break;
case kActionNone:
- UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1)
- CALLBACK_ACTION();
+ if (Entity::updateParameter(params->param2, getState()->timeTicks, params->param1))
+ break;
+
+ callbackAction();
break;
}
}
@@ -340,8 +361,10 @@ void Entity::updateFromTime(const SavePoint &savepoint) {
break;
case kActionNone:
- UPDATE_PARAM(params->param2, getState()->time, params->param1)
- CALLBACK_ACTION();
+ if (Entity::updateParameter(params->param2, getState()->time, params->param1))
+ break;
+
+ callbackAction();
break;
}
}
@@ -352,12 +375,12 @@ void Entity::callbackActionOnDirection(const SavePoint &savepoint) {
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
if (getData()->direction != kDirectionRight)
- CALLBACK_ACTION();
+ callbackAction();
break;
}
}
@@ -370,7 +393,7 @@ void Entity::callbackActionRestaurantOrSalon(const SavePoint &savepoint) {
case kActionNone:
case kActionDefault:
if (getEntities()->isSomebodyInsideRestaurantOrSalon())
- CALLBACK_ACTION();
+ callbackAction();
break;
}
}
@@ -395,7 +418,7 @@ void Entity::updateEntity(const SavePoint &savepoint, bool handleExcuseMe) {
case kActionNone:
case kActionDefault:
if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
}
}
@@ -410,7 +433,7 @@ void Entity::callSavepoint(const SavePoint &savepoint, bool handleExcuseMe) {
case kActionExitCompartment:
if (!CURRENT_PARAM(1, 1))
getSavePoints()->call(_entityIndex, (EntityIndex)params->param4, (ActionIndex)params->param5, (char *)&params->seq2);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMeCath:
@@ -448,7 +471,7 @@ void Entity::enterExitCompartment(const SavePoint &savepoint, EntityPosition pos
if (updateLocation)
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -468,6 +491,74 @@ void Entity::enterExitCompartment(const SavePoint &savepoint, EntityPosition pos
}
}
+void Entity::goToCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, Common::String sequenceTo) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = positionFrom;
+ setCallback(1);
+ setup_enterExitCompartment(sequenceFrom.c_str(), compartmentFrom);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_enterExitCompartment(sequenceTo.c_str(), compartmentFrom);
+ break;
+
+ case 2:
+ getData()->entityPosition = positionFrom;
+ getEntities()->clearSequences(_entityIndex);
+ callbackAction();
+ break;
+ }
+ break;
+ }
+}
+
+void Entity::goToCompartmentFromCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, ObjectIndex compartmentTo, EntityPosition positionTo, Common::String sequenceTo) {
+ switch (savepoint.action) {
+ default:
+ break;
+
+ case kActionDefault:
+ getData()->entityPosition = positionFrom;
+ getData()->location = kLocationOutsideCompartment;
+ setCallback(1);
+ setup_enterExitCompartment(sequenceFrom.c_str(), compartmentFrom);
+ break;
+
+ case kActionCallback:
+ switch (getCallback()) {
+ default:
+ break;
+
+ case 1:
+ setCallback(2);
+ setup_updateEntity(kCarGreenSleeping, positionTo);
+ break;
+
+ case 2:
+ setCallback(3);
+ setup_enterExitCompartment(sequenceTo.c_str(), compartmentTo);
+ break;
+
+ case 3:
+ getData()->location = kLocationInsideCompartment;
+ getEntities()->clearSequences(_entityIndex);
+ callbackAction();
+ break;
+ }
+ break;
+ }
+}
+
void Entity::updatePosition(const SavePoint &savepoint, bool handleExcuseMe) {
EXPOSE_PARAMS(EntityData::EntityParametersSIII)
@@ -477,7 +568,7 @@ void Entity::updatePosition(const SavePoint &savepoint, bool handleExcuseMe) {
case kActionExitCompartment:
getEntities()->updatePositionExit(_entityIndex, (CarIndex)params->param4, (Position)params->param5);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMeCath:
@@ -494,4 +585,385 @@ void Entity::updatePosition(const SavePoint &savepoint, bool handleExcuseMe) {
}
}
+void Entity::callbackAction() {
+ if (getData()->currentCall == 0)
+ error("[Entity::callbackAction] currentCall is already 0, cannot proceed");
+
+ getData()->currentCall--;
+
+ getSavePoints()->setCallback(_entityIndex, _callbacks[_data->getCurrentCallback()]);
+
+ getSavePoints()->call(_entityIndex, _entityIndex, kActionCallback);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Setup functions
+//////////////////////////////////////////////////////////////////////////
+void Entity::setup(const char *name, uint index) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s()", name);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersIIII>();
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupI(const char *name, uint index, uint param1) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%u)", name, param1);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersIIII>();
+
+ EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters();
+ params->param1 = (unsigned int)param1;
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupII(const char *name, uint index, uint param1, uint param2) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u)", name, param1, param2);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersIIII>();
+
+ EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters();
+ params->param1 = param1;
+ params->param2 = param2;
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupIII(const char *name, uint index, uint param1, uint param2, uint param3) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %u)", name, param1, param2, param3);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersIIII>();
+
+ EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters();
+ params->param1 = param1;
+ params->param2 = param2;
+ params->param3 = param3;
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupS(const char *name, uint index, const char *seq1) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%s)", name, seq1);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersSIIS>();
+
+ EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters();
+ strncpy(params->seq1, seq1, 12);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupSS(const char *name, uint index, const char *seq1, const char *seq2) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %s)", name, seq1, seq2);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersSSII>();
+
+ EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII*)_data->getCurrentParameters();
+ strncpy(params->seq1, seq1, 12);
+ strncpy(params->seq2, seq2, 12);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupSI(const char *name, uint index, const char *seq1, uint param4) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u)", name, seq1, param4);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersSIIS>();
+
+ EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS *)_data->getCurrentParameters();
+ strncpy(params->seq1, seq1, 12);
+ params->param4 = param4;
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupSII(const char *name, uint index, const char *seq1, uint param4, uint param5) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u)", name, seq1, param4, param5);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersSIIS>();
+
+ EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS *)_data->getCurrentParameters();
+ strncpy(params->seq1, seq1, 12);
+ params->param4 = param4;
+ params->param5 = param5;
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupSIII(const char *name, uint index, const char *seq, uint param4, uint param5, uint param6) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u, %u)", name, seq, param4, param5, param6);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersSIII>();
+
+ EntityData::EntityParametersSIII *params = (EntityData::EntityParametersSIII *)_data->getCurrentParameters();
+ strncpy(params->seq, seq, 12);
+ params->param4 = param4;
+ params->param5 = param5;
+ params->param6 = param6;
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupSIIS(const char *name, uint index, const char *seq1, uint param4, uint param5, const char *seq2) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u, %s)", name, seq1, param4, param5, seq2);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersSIIS>();
+
+ EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS *)_data->getCurrentParameters();
+ strncpy(params->seq1, seq1, 12);
+ params->param4 = param4;
+ params->param5 = param5;
+ strncpy(params->seq2, seq2, 12);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupSSI(const char *name, uint index, const char *seq1, const char *seq2, uint param7) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %s, %u)", name, seq1, seq2, param7);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersSSII>();
+
+ EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII *)_data->getCurrentParameters();
+ strncpy(params->seq1, seq1, 12);
+ strncpy(params->seq2, seq2, 12);
+ params->param7 = param7;
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupIS(const char *name, uint index, uint param1, const char *seq) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %s)", name, param1, seq);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersISII>();
+
+ EntityData::EntityParametersISII *params = (EntityData::EntityParametersISII *)_data->getCurrentParameters();
+ params->param1 = (unsigned int)param1;
+ strncpy(params->seq, seq, 12);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupISS(const char *name, uint index, uint param1, const char *seq1, const char *seq2) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %s, %s)", name, param1, seq1, seq2);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersISSI>();
+
+ EntityData::EntityParametersISSI *params = (EntityData::EntityParametersISSI *)_data->getCurrentParameters();
+ params->param1 = param1;
+ strncpy(params->seq1, seq1, 12);
+ strncpy(params->seq2, seq2, 12);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupIIS(const char *name, uint index, uint param1, uint param2, const char *seq) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %s)", name, param1, param2, seq);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersIISI>();
+
+ EntityData::EntityParametersIISI *params = (EntityData::EntityParametersIISI *)_data->getCurrentParameters();
+ params->param1 = param1;
+ params->param2 = param2;
+ strncpy(params->seq, seq, 12);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+void Entity::setupIISS(const char *name, uint index, uint param1, uint param2, const char *seq1, const char *seq2) {
+ debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %s, %s)", name, param1, param2, seq1, seq2);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]);
+ _data->setCurrentCallback(index);
+ _data->resetCurrentParameters<EntityData::EntityParametersIISS>();
+
+ EntityData::EntityParametersIISS *params = (EntityData::EntityParametersIISS *)_data->getCurrentParameters();
+ params->param1 = param1;
+ params->param2 = param2;
+ strncpy(params->seq1, seq1, 12);
+ strncpy(params->seq2, seq2, 12);
+
+ _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Helper functions
+//////////////////////////////////////////////////////////////////////////
+
+bool Entity::updateParameter(uint &parameter, uint timeType, uint delta) {
+ if (!parameter)
+ parameter = (uint)(timeType + delta);
+
+ if (parameter >= timeType)
+ return false;
+
+ parameter = kTimeInvalid;
+
+ return true;
+}
+
+bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint &parameter, uint delta) {
+ if (getState()->time <= timeValue) {
+ if (check || !parameter)
+ parameter = (uint)(getState()->time + delta);
+ }
+
+ if (parameter >= getState()->time && getState()->time <= timeValue)
+ return false;
+
+ parameter = kTimeInvalid;
+
+ return true;
+}
+
+bool Entity::updateParameterCheck(uint &parameter, uint timeType, uint delta) {
+ if (parameter && parameter >= timeType)
+ return false;
+
+ if (!parameter)
+ parameter = (uint)(timeType + delta);
+
+ return true;
+}
+
+bool Entity::timeCheck(TimeValue timeValue, uint &parameter, Common::Functor0<void> *function) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ (*function)();
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Entity::timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *function) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ setCallback(callback);
+ (*function)();
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Entity::timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, const char *str, Common::Functor1<const char *, void> *function) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ setCallback(callback);
+ (*function)(str);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Entity::timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, bool check, Common::Functor1<bool, void> *function) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ setCallback(callback);
+ (*function)(check);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Entity::timeCheckCallbackInventory(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *function) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ getData()->inventoryItem = kItemNone;
+ setCallback(callback);
+ (*function)();
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Entity::timeCheckCar(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *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)();
+
+ return true;
+ }
+
+ return false;
+}
+
+void Entity::timeCheckSavepoint(TimeValue timeValue, uint &parameter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ getSavePoints()->push(entity1, entity2, action);
+ }
+}
+
+void Entity::timeCheckObject(TimeValue timeValue, uint &parameter, ObjectIndex object, ObjectLocation location) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ getObjects()->updateLocation2(object, location);
+ }
+}
+
+bool Entity::timeCheckCallbackAction(TimeValue timeValue, uint &parameter) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ callbackAction();
+ return true;
+ }
+
+ return false;
+}
+
+bool Entity::timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint &parameter, byte callback, const char* sound, EntityPosition position) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ getData()->entityPosition = position;
+ setCallback(callback);
+ setup_playSound(sound);
+ return true;
+ }
+
+ return false;
+}
+
+
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h
index 039f461c7b..3601f34f6f 100644
--- a/engines/lastexpress/entities/entity.h
+++ b/engines/lastexpress/entities/entity.h
@@ -25,8 +25,13 @@
#include "lastexpress/shared.h"
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/savepoint.h"
+#include "lastexpress/game/state.h"
+
#include "lastexpress/sound/sound.h"
+#include "lastexpress/lastexpress.h"
#include "lastexpress/helpers.h"
#include "common/array.h"
@@ -41,10 +46,229 @@ class Sequence;
class SequenceFrame;
struct SavePoint;
+//////////////////////////////////////////////////////////////////////////
+// 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();
+
+//////////////////////////////////////////////////////////////////////////
+// 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));
+
+#define WRAP_SETUP_FUNCTION(className, method) \
+ new Common::Functor0Mem<void, className>(this, &className::method)
+
+#define WRAP_SETUP_FUNCTION_S(className, method) \
+ new Common::Functor1Mem<const char *, void, className>(this, &className::method)
+
+#define WRAP_SETUP_FUNCTION_B(className, method) \
+ new Common::Functor1Mem<bool, void, className>(this, &className::method)
+
+//////////////////////////////////////////////////////////////////////////
+// Parameters macros
+//////////////////////////////////////////////////////////////////////////
+#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
+
+//////////////////////////////////////////////////////////////////////////
+// Misc
+//////////////////////////////////////////////////////////////////////////
+#define RESET_ENTITY_STATE(entity, class, function) \
+ getEntities()->resetState(entity); \
+ ((class *)getEntities()->get(entity))->function();
+
+//////////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////////
+
+// Expose parameters and check validity
+#define EXPOSE_PARAMS(type) \
+ type *params = (type *)_data->getCurrentParameters(); \
+ if (!params) \
+ error("[EXPOSE_PARAMS] 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) \
+ void class::setup_##name() { \
+ Entity::setup(#class "::setup_" #name, index); \
+ } \
+ void class::name(const SavePoint &savepoint) { \
+ EXPOSE_PARAMS(EntityData::EntityParametersIIII) \
+ debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "() - action: %s", ACTION_NAME(savepoint.action));
+
+#define IMPLEMENT_FUNCTION_END }
+
+// nullfunction call
+#define IMPLEMENT_NULL_FUNCTION(index, class) \
+ void class::setup_nullfunction() { \
+ Entity::setup(#class "::setup_nullfunction", index); \
+ }
+
+// setup with one uint parameter
+#define IMPLEMENT_FUNCTION_I(index, class, name, paramType) \
+ void class::setup_##name(paramType param1) { \
+ Entity::setupI(#class "::setup_" #name, index, param1); \
+ } \
+ 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) { \
+ Entity::setupII(#class "::setup_" #name, index, param1, param2); \
+ } \
+ 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) { \
+ Entity::setupIII(#class "::setup_" #name, index, param1, param2, param3); \
+ } \
+ 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) { \
+ Entity::setupS(#class "::setup_" #name, index, seq1); \
+ } \
+ 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) { \
+ Entity::setupSI(#class "::setup_" #name, index, seq1, param4); \
+ } \
+ 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) { \
+ Entity::setupSII(#class "::setup_" #name, index, seq1, param4, param5); \
+ } \
+ 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) { \
+ Entity::setupSIII(#class "::setup_" #name, index, seq, param4, param5, param6); \
+ } \
+ 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) { \
+ Entity::setupSIIS(#class "::setup_" #name, index, seq1, param4, param5, seq2); \
+ } \
+ 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) { \
+ Entity::setupSS(#class "::setup_" #name, index, seq1, seq2); \
+ } \
+ 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) { \
+ Entity::setupSSI(#class "::setup_" #name, index, seq1, seq2, param7); \
+ } \
+ 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) { \
+ Entity::setupIS(#class "::setup_" #name, index, param1, seq); \
+ } \
+ 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) { \
+ Entity::setupISS(#class "::setup_" #name, index, param1, seq1, seq2); \
+ } \
+ 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) { \
+ Entity::setupIIS(#class "::setup_" #name, index, param1, param2, seq); \
+ } \
+ 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) { \
+ Entity::setupIISS(#class "::setup_" #name, index, param1, param2, seq1, seq2); \
+ } \
+ 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));
+
+
+//////////////////////////////////////////////////////////////////////////
class EntityData : Common::Serializable {
public:
- struct EntityParameters : Common::Serializable{
+ struct EntityParameters : Common::Serializable {
virtual ~EntityParameters() {}
virtual Common::String toString() = 0;
@@ -596,6 +820,15 @@ public:
return str;
}
+ /**
+ * Synchronizes a string.
+ *
+ * @param s The Common::Serializer to use.
+ * @param string The string.
+ * @param length Length of the string.
+ */
+ void syncString(Common::Serializer &s, Common::String &string, int length);
+
// Serializable
void saveLoadWithSerializer(Common::Serializer &s);
};
@@ -611,32 +844,30 @@ public:
params->parameters[i] = new T();
}
- EntityCallData *getCallData() { return &_data; }
+ EntityCallData *getCallData() { return &_data; }
- EntityParameters *getParameters(uint callback, byte index) const;
- EntityParameters *getCurrentParameters(byte index = 0) { return getParameters(_data.currentCall, index); }
+ EntityParameters *getParameters(uint callback, byte index) const;
+ EntityParameters *getCurrentParameters(byte index = 0) { return getParameters(_data.currentCall, index); }
+ EntityCallParameters *getCurrentCallParameters() { return &_parameters[_data.currentCall]; }
- 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); }
+ 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;
+ void updateParameters(uint32 index) const;
// Serializable
- void saveLoadWithSerializer(Common::Serializer &ser);
+ void saveLoadWithSerializer(Common::Serializer &ser);
private:
- EntityCallData _data;
+ EntityCallData _data;
EntityCallParameters _parameters[9];
};
class Entity : Common::Serializable {
public:
-
- typedef Common::Functor1<const SavePoint&, void> Callback;
-
Entity(LastExpressEngine *engine, EntityIndex index);
virtual ~Entity();
@@ -657,6 +888,12 @@ public:
virtual void setup_chapter4() = 0;
virtual void setup_chapter5() = 0;
+ // Shared functions
+ virtual void setup_savegame(SavegameType, uint32) { error("[Entity::setup_savegame] Trying to call the parent setup function. Use the specific entity function directly"); }
+ virtual void setup_enterExitCompartment(const char *, ObjectIndex) { error("[Entity::setup_enterExitCompartment] Trying to call the parent setup function. Use the specific entity function directly"); }
+ virtual void setup_updateEntity(CarIndex, EntityPosition) { error("[Entity::setup_updateEntity] Trying to call the parent setup function. Use the specific entity function directly"); }
+ virtual void setup_playSound(const char*) { error("[Entity::setup_playSound] Trying to call the parent setup function. Use the specific entity function directly"); }
+
// Serializable
void saveLoadWithSerializer(Common::Serializer &ser) { _data->saveLoadWithSerializer(ser); }
@@ -664,10 +901,11 @@ public:
protected:
LastExpressEngine *_engine;
+ typedef Common::Functor1<const SavePoint&, void> Callback;
- EntityIndex _entityIndex;
- EntityData *_data;
- Common::Array<Callback *> _callbacks;
+ EntityIndex _entityIndex;
+ EntityData *_data;
+ Common::Array<Callback *> _callbacks;
/**
* Saves the game
@@ -679,6 +917,13 @@ protected:
void savegame(const SavePoint &savepoint);
/**
+ * Saves the game before being found out with a blood covered jacket.
+ *
+ * @param saveFunction The setup function to call to save the game
+ */
+ void savegameBloodJacket();
+
+ /**
* Play sound
*
* @param savepoint The savepoint
@@ -782,15 +1027,83 @@ protected:
void enterExitCompartment(const SavePoint &savepoint, EntityPosition position1 = kPositionNone, EntityPosition position2 = kPositionNone, CarIndex car = kCarNone, ObjectIndex compartment = kObjectNone, bool alternate = false, bool updateLocation = false);
/**
+ * Go to compartment.
+ *
+ * @param savepoint The savepoint.
+ * @param compartmentFrom The compartment from.
+ * @param positionFrom The position from.
+ * @param sequenceFrom The sequence from.
+ * @param sequenceTo The sequence to.
+ */
+ void goToCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, Common::String sequenceTo);
+
+ /**
+ * Go to compartment from compartment.
+ *
+ * @param savepoint The savepoint.
+ * @param compartmentFrom The compartment from.
+ * @param positionFrom The position from.
+ * @param sequenceFrom The sequence from.
+ * @param compartmentTo The compartment to.
+ * @param positionTo The position to.
+ * @param sequenceTo The sequence to.
+ */
+ void goToCompartmentFromCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, ObjectIndex compartmentTo, EntityPosition positionTo, Common::String sequenceTo);
+
+ /**
* Updates the position
*
- * @param savepoint The savepoint
+ * @param savepoint The savepoint
* - Sequence name
* - CarIndex
* - Position
* @param handleExcuseMe true to handle excuseMe actions
*/
void updatePosition(const SavePoint &savepoint, bool handleExcuseMe = false);
+
+ /**
+ * Store the current callback information and perform the callback action
+ */
+ void callbackAction();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Setup functions
+ //////////////////////////////////////////////////////////////////////////
+ void setup(const char *name, uint index);
+ void setupI(const char *name, uint index, uint param1);
+ void setupII(const char *name, uint index, uint param1, uint param2);
+ void setupIII(const char *name, uint index, uint param1, uint param2, uint param3);
+ void setupS(const char *name, uint index, const char *seq1);
+ void setupSS(const char *name, uint index, const char *seq1, const char *seq2);
+ void setupSI(const char *name, uint index, const char *seq1, uint param4);
+ void setupSII(const char *name, uint index, const char *seq1, uint param4, uint param5);
+ void setupSIII(const char *name, uint index, const char *seq, uint param4, uint param5, uint param6);
+ void setupSIIS(const char *name, uint index, const char *seq1, uint param4, uint param5, const char *seq2);
+ void setupSSI(const char *name, uint index, const char *seq1, const char *seq2, uint param7);
+ void setupIS(const char *name, uint index, uint param1, const char *seq);
+ void setupISS(const char *name, uint index, uint param1, const char *seq1, const char *seq2);
+ void setupIIS(const char *name, uint index, uint param1, uint param2, const char *seq);
+ void setupIISS(const char *name, uint index, uint param1, uint param2, const char *seq1, const char *seq2);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Helper functions
+ //////////////////////////////////////////////////////////////////////////
+
+ bool updateParameter(uint &parameter, uint timeType, uint delta);
+ bool updateParameterCheck(uint &parameter, uint timeType, uint delta);
+ bool updateParameterTime(TimeValue timeValue, bool check, uint &parameter, uint delta);
+
+ bool timeCheck(TimeValue timeValue, uint &parameter, Common::Functor0<void> *function);
+ bool timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *function);
+ bool timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, const char *str, Common::Functor1<const char *, void> *function);
+ bool timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, bool check, Common::Functor1<bool, void> *function);
+ bool timeCheckCallbackInventory(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *function);
+ bool timeCheckCar(TimeValue timeValue, uint &parameter, byte callback, Common::Functor0<void> *function);
+ void timeCheckSavepoint(TimeValue timeValue, uint &parameter, EntityIndex entity1, EntityIndex entity2, ActionIndex action);
+ void timeCheckObject(TimeValue timeValue, uint &parameter, ObjectIndex index, ObjectLocation location);
+ bool timeCheckCallbackAction(TimeValue timeValue, uint &parameter);
+ bool timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint &parameter, byte callback, const char* sound, EntityPosition position);
+
};
diff --git a/engines/lastexpress/entities/entity39.cpp b/engines/lastexpress/entities/entity39.cpp
index e786d153a0..1786cd2201 100644
--- a/engines/lastexpress/entities/entity39.cpp
+++ b/engines/lastexpress/entities/entity39.cpp
@@ -28,7 +28,6 @@
#include "lastexpress/game/savepoint.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/entity39.h b/engines/lastexpress/entities/entity39.h
index 4335a9566e..54b65408c7 100644
--- a/engines/lastexpress/entities/entity39.h
+++ b/engines/lastexpress/entities/entity39.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_ENTITY39_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
@@ -72,4 +71,4 @@ private:
} // End of namespace LastExpress
-#endif // LASTEXPRESS_##define##_H
+#endif // LASTEXPRESS_ENTITY39_H
diff --git a/engines/lastexpress/entities/entity_intern.h b/engines/lastexpress/entities/entity_intern.h
index 2da0da15b3..fd803676a9 100644
--- a/engines/lastexpress/entities/entity_intern.h
+++ b/engines/lastexpress/entities/entity_intern.h
@@ -25,502 +25,6 @@
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, _callbacks[index]); \
- _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("[EXPOSE_PARAMS] 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));
-
-#define IMPLEMENT_FUNCTION_END }
-
-// 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
diff --git a/engines/lastexpress/entities/francois.cpp b/engines/lastexpress/entities/francois.cpp
index 46cd790ffb..d2bbc9854c 100644
--- a/engines/lastexpress/entities/francois.cpp
+++ b/engines/lastexpress/entities/francois.cpp
@@ -32,7 +32,6 @@
#include "lastexpress/sound/queue.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
@@ -114,7 +113,7 @@ IMPLEMENT_FUNCTION_II(8, Francois, updateEntity, CarIndex, EntityPosition)
case kActionNone:
if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
} else {
if (!getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000)
|| !getInventory()->hasItem(kItemFirebird)
@@ -169,7 +168,7 @@ IMPLEMENT_FUNCTION_II(8, Francois, updateEntity, CarIndex, EntityPosition)
case kActionDefault:
if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -225,7 +224,7 @@ IMPLEMENT_FUNCTION(9, Francois, function9)
case 2:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -263,7 +262,7 @@ IMPLEMENT_FUNCTION(10, Francois, function10)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityFrancois);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -279,7 +278,7 @@ IMPLEMENT_FUNCTION_I(11, Francois, function11, TimeValue)
case kActionNone:
if (!getSoundQueue()->isBuffered(kEntityFrancois)) {
- UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->timeTicks, params->param6)
+ if (Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->timeTicks, params->param6)) {
switch (rnd(7)) {
default:
break;
@@ -312,7 +311,7 @@ IMPLEMENT_FUNCTION_I(11, Francois, function11, TimeValue)
params->param6 = 15 * rnd(7);
CURRENT_PARAM(1, 1) = 0;
- UPDATE_PARAM_PROC_END
+ }
}
if (!getEntities()->hasValidFrame(kEntityFrancois) || !getEntities()->isWalkingOppositeToPlayer(kEntityFrancois))
@@ -442,7 +441,7 @@ label_callback:
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -465,7 +464,7 @@ label_callback:
getData()->field_4A3 = 30;
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kAction205346192:
@@ -524,7 +523,7 @@ IMPLEMENT_FUNCTION(12, Francois, function12)
break;
case 7:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -609,7 +608,7 @@ IMPLEMENT_FUNCTION(13, Francois, function13)
break;
case 11:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -708,7 +707,7 @@ IMPLEMENT_FUNCTION_IIS(14, Francois, function14, ObjectIndex, EntityPosition)
break;
case 13:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -764,7 +763,7 @@ IMPLEMENT_FUNCTION(15, Francois, function15)
case 7:
if (!getEntities()->isInsideCompartment(kEntityMmeBoutarel, kCarRedSleeping, kPosition_5790)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -773,7 +772,7 @@ IMPLEMENT_FUNCTION(15, Francois, function15)
break;
case 8:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -830,7 +829,7 @@ IMPLEMENT_FUNCTION(16, Francois, function16)
getData()->entityPosition = kPosition_5790;
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -849,7 +848,7 @@ IMPLEMENT_FUNCTION(17, Francois, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Francois, setup_chapter1Handler));
break;
case kActionDefault:
@@ -867,7 +866,7 @@ IMPLEMENT_FUNCTION(18, Francois, chapter1Handler)
break;
case kActionNone:
- TIME_CHECK_CALLBACK_1(kTimeParisEpernay, params->param1, 1, setup_function11, kTime1093500);
+ timeCheckCallback(kTimeParisEpernay, params->param1, 1, kTime1093500);
break;
case kActionCallback:
@@ -884,7 +883,7 @@ IMPLEMENT_FUNCTION(19, Francois, function19)
break;
case kActionNone:
- TIME_CHECK_CALLBACK(kTime1161000, params->param1, 2, setup_function12);
+ Entity::timeCheckCallback(kTime1161000, params->param1, 2, WRAP_SETUP_FUNCTION(Francois, setup_function12));
break;
case kAction101107728:
@@ -979,17 +978,21 @@ IMPLEMENT_FUNCTION(23, Francois, function23)
}
label_callback_1:
- TIME_CHECK_CALLBACK_1(kTime1764000, params->param1, 2, setup_playSound, "Fra2011");
+ if (Entity::timeCheckCallback(kTime1764000, params->param1, 2, "Fra2011", WRAP_SETUP_FUNCTION_S(Francois, setup_playSound)))
+ break;
label_callback_2:
- TIME_CHECK_CALLBACK(kTime1800000, params->param2, 3, setup_function13);
+ if (Entity::timeCheckCallback(kTime1800000, params->param2, 3, WRAP_SETUP_FUNCTION(Francois, setup_function13)))
+ break;
label_callback_3:
if (!getInventory()->hasItem(kItemWhistle) && getInventory()->get(kItemWhistle)->location != kObjectLocation3) {
- TIME_CHECK_CALLBACK_1(kTime1768500, params->param3, 4, setup_function11, kTime1773000);
+ if (timeCheckCallback(kTime1768500, params->param3, 4, kTime1773000))
+ break;
label_callback_4:
- TIME_CHECK_CALLBACK_1(kTime1827000, params->param4, 5, setup_function11, kTime1831500);
+ if (timeCheckCallback(kTime1827000, params->param4, 5, kTime1831500))
+ break;
}
label_callback_5:
@@ -999,18 +1002,19 @@ label_callback_5:
}
if (params->param5 != kTimeInvalid) {
- UPDATE_PARAM_PROC_TIME(kTimeEnd, !getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000), params->param5, 75);
+ if (Entity::updateParameterTime(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");
+ if (timeCheckCallbackCompartment(kTime1782000, params->param6, 7, kObjectCompartmentC, kPosition_6470, "c"))
+ break;
label_callback_7:
- TIME_CHECK_CALLBACK_3(kTime1813500, params->param7, 8, setup_function14, kObjectCompartmentF, kPosition_4070, "f");
+ timeCheckCallbackCompartment(kTime1813500, params->param7, 8, kObjectCompartmentF, kPosition_4070, "f");
break;
case kActionCallback:
@@ -1086,32 +1090,41 @@ IMPLEMENT_FUNCTION(25, Francois, chapter3Handler)
}
label_callback_2:
- TIME_CHECK_CALLBACK(kTime2025000, params->param3, 3, setup_function12);
+ if (Entity::timeCheckCallback(kTime2025000, params->param3, 3, WRAP_SETUP_FUNCTION(Francois, setup_function12)))
+ break;
label_callback_3:
- TIME_CHECK_CALLBACK(kTime2052000, params->param4, 4, setup_function12);
+ if (Entity::timeCheckCallback(kTime2052000, params->param4, 4, WRAP_SETUP_FUNCTION(Francois, setup_function12)))
+ break;
label_callback_4:
- TIME_CHECK_CALLBACK(kTime2079000, params->param5, 5, setup_function12);
+ if (Entity::timeCheckCallback(kTime2079000, params->param5, 5, WRAP_SETUP_FUNCTION(Francois, setup_function12)))
+ break;
label_callback_5:
- TIME_CHECK_CALLBACK(kTime2092500, params->param6, 6, setup_function12);
+ if (Entity::timeCheckCallback(kTime2092500, params->param6, 6, WRAP_SETUP_FUNCTION(Francois, setup_function12)))
+ break;
label_callback_6:
- TIME_CHECK_CALLBACK(kTime2173500, params->param7, 7, setup_function12);
+ if (Entity::timeCheckCallback(kTime2173500, params->param7, 7, WRAP_SETUP_FUNCTION(Francois, setup_function12)))
+ break;
label_callback_7:
- TIME_CHECK_CALLBACK(kTime2182500, params->param8, 8, setup_function12);
+ if (Entity::timeCheckCallback(kTime2182500, params->param8, 8, WRAP_SETUP_FUNCTION(Francois, setup_function12)))
+ break;
label_callback_8:
- TIME_CHECK_CALLBACK(kTime2241000, CURRENT_PARAM(1, 1), 9, setup_function12);
+ if (Entity::timeCheckCallback(kTime2241000, CURRENT_PARAM(1, 1), 9, WRAP_SETUP_FUNCTION(Francois, setup_function12)))
+ break;
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);
+ if (timeCheckCallback(kTime2011500, CURRENT_PARAM(1, 2), 10, kTime2016000))
+ break;
label_callback_10:
- TIME_CHECK_CALLBACK_1(kTime2115000, CURRENT_PARAM(1, 3), 11, setup_function11, kTime2119500);
+ if (timeCheckCallback(kTime2115000, CURRENT_PARAM(1, 3), 11, kTime2119500))
+ break;
}
label_callback_11:
@@ -1129,13 +1142,15 @@ label_callback_11:
}
label_callback_12:
- TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 5), 13, setup_function14, kObjectCompartmentE, kPosition_4840, "e");
+ if (timeCheckCallbackCompartment(kTime2040300, CURRENT_PARAM(1, 5), 13, kObjectCompartmentE, kPosition_4840, "e"))
+ break;
label_callback_13:
- TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 6), 14, setup_function14, kObjectCompartmentF, kPosition_4070, "f");
+ if (timeCheckCallbackCompartment(kTime2040300, CURRENT_PARAM(1, 6), 14, kObjectCompartmentF, kPosition_4070, "f"))
+ break;
label_callback_14:
- TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 7), 15, setup_function14, kObjectCompartmentB, kPosition_7500, "b");
+ timeCheckCallbackCompartment(kTime2040300, CURRENT_PARAM(1, 7), 15, kObjectCompartmentB, kPosition_7500, "b");
}
}
break;
@@ -1291,4 +1306,33 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_NULL_FUNCTION(31, Francois)
+
+//////////////////////////////////////////////////////////////////////////
+// Helper functions
+//////////////////////////////////////////////////////////////////////////
+bool Francois::timeCheckCallbackCompartment(TimeValue timeValue, uint &parameter, byte callback, ObjectIndex compartment, EntityPosition position, const char* sequenceSuffix) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ setCallback(callback);
+ setup_function14(compartment, position, sequenceSuffix);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Francois::timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, TimeValue timeValue2) {
+ if (getState()->time > timeValue && !parameter) {
+ parameter = 1;
+ setCallback(callback);
+ setup_function11(timeValue2);
+
+ return true;
+ }
+
+ return false;
+}
+
+
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/francois.h b/engines/lastexpress/entities/francois.h
index 19eca6fb50..51270fa4b6 100644
--- a/engines/lastexpress/entities/francois.h
+++ b/engines/lastexpress/entities/francois.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_FRANCOIS_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
@@ -160,6 +159,10 @@ public:
DECLARE_FUNCTION(function30)
DECLARE_NULL_FUNCTION()
+
+private:
+ bool timeCheckCallbackCompartment(TimeValue timeValue, uint &parameter, byte callback, ObjectIndex compartment, EntityPosition position, const char* sequenceSuffix);
+ bool timeCheckCallback(TimeValue timeValue, uint &parameter, byte callback, TimeValue timeValue2);
};
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/gendarmes.cpp b/engines/lastexpress/entities/gendarmes.cpp
index daa50956d3..a912fa4ecb 100644
--- a/engines/lastexpress/entities/gendarmes.cpp
+++ b/engines/lastexpress/entities/gendarmes.cpp
@@ -31,7 +31,6 @@
#include "lastexpress/game/state.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -67,7 +66,7 @@ IMPLEMENT_FUNCTION(2, Gendarmes, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Gendarmes, setup_chapter1Handler));
break;
case kActionDefault:
@@ -195,7 +194,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
break;
case 1:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 2:
@@ -233,7 +232,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
case 6:
getData()->location = kLocationOutsideCompartment;
getEntities()->exitCompartment(kEntityGendarmes, (ObjectIndex)parameters2->param5);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -267,11 +266,12 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje
getSound()->playSound(kEntityGendarmes, "POL1046A", kFlagDefault);
}
- UPDATE_PARAM(params->param7, getState()->timeTicks, 300);
+ if (!Entity::updateParameter(params->param7, getState()->timeTicks, 300))
+ break;
if (!params->param4 && getEntities()->isOutsideAlexeiWindow()) {
getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
} else {
if (getEntities()->isOutsideAlexeiWindow())
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
@@ -322,7 +322,7 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje
getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true);
getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 4:
@@ -330,7 +330,7 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje
getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true);
getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 5:
@@ -552,13 +552,14 @@ void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundFl
case kActionNone:
if (checkCallback) {
EXPOSE_PARAMS(EntityData::EntityParametersIIII);
- TIME_CHECK_CALLBACK_ACTION(params->param1, params->param2);
+ if (Entity::timeCheckCallbackAction((TimeValue)params->param1, params->param2))
+ break;
}
if (shouldUpdateEntity) {
EXPOSE_PARAMS(EntityData::EntityParametersIIII);
if (getEntities()->updateEntity(kEntityGendarmes, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
}
@@ -582,7 +583,7 @@ void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundFl
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -599,7 +600,7 @@ void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundFl
if (shouldUpdateEntity) {
EXPOSE_PARAMS(EntityData::EntityParametersIIII);
if (getEntities()->updateEntity(kEntityGendarmes, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
}
diff --git a/engines/lastexpress/entities/gendarmes.h b/engines/lastexpress/entities/gendarmes.h
index d999cfc1fd..a761643531 100644
--- a/engines/lastexpress/entities/gendarmes.h
+++ b/engines/lastexpress/entities/gendarmes.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_GENDARMES_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
#include "lastexpress/sound/sound.h"
diff --git a/engines/lastexpress/entities/hadija.cpp b/engines/lastexpress/entities/hadija.cpp
index 8ec972b939..e9abcd888a 100644
--- a/engines/lastexpress/entities/hadija.cpp
+++ b/engines/lastexpress/entities/hadija.cpp
@@ -28,10 +28,7 @@
#include "lastexpress/game/savepoint.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.h"
-
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -89,22 +86,22 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(6, Hadija, compartment6)
- COMPARTMENT_TO(Hadija, kObjectCompartment6, kPosition_4070, "619Cf", "619Df");
+ Entity::goToCompartment(savepoint, kObjectCompartment6, kPosition_4070, "619Cf", "619Df");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(7, Hadija, compartment8)
- COMPARTMENT_TO(Hadija, kObjectCompartment8, kPosition_2740, "619Ch", "619Dh");
+ Entity::goToCompartment(savepoint, kObjectCompartment8, kPosition_2740, "619Ch", "619Dh");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(8, Hadija, compartment6to8)
- COMPARTMENT_FROM_TO(Hadija, kObjectCompartment6, kPosition_4070, "619Bf", kObjectCompartment8, kPosition_2740, "619Ah");
+ Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment6, kPosition_4070, "619Bf", kObjectCompartment8, kPosition_2740, "619Ah");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(9, Hadija, compartment8to6)
- COMPARTMENT_FROM_TO(Hadija, kObjectCompartment8, kPosition_2740, "619Bh", kObjectCompartment6, kPosition_4070, "619Af");
+ Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment8, kPosition_2740, "619Bh", kObjectCompartment6, kPosition_4070, "619Af");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
@@ -114,7 +111,7 @@ IMPLEMENT_FUNCTION(10, Hadija, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Hadija, setup_chapter1Handler));
break;
case kActionDefault:
@@ -133,10 +130,12 @@ IMPLEMENT_FUNCTION(11, Hadija, chapter1Handler)
break;
case kActionNone:
- TIME_CHECK_PLAYSOUND_UPDATEPOSITION(kTimeParisEpernay, params->param1, 1, "Har1100", kPosition_4840);
+ if (Entity::timeCheckPlaySoundUpdatePosition(kTimeParisEpernay, params->param1, 1, "Har1100", kPosition_4840))
+ break;
label_callback1:
- TIME_CHECK_CALLBACK(kTime1084500, params->param2, 2, setup_compartment6to8);
+ if (Entity::timeCheckCallback(kTime1084500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8)))
+ break;
label_callback2:
if (params->param3 != kTimeInvalid && getState()->time > kTime1093500) {
@@ -164,7 +163,8 @@ label_callback2:
}
label_callback3:
- TIME_CHECK_CALLBACK(kTime1156500, params->param4, 4, setup_compartment8to6);
+ if (Entity::timeCheckCallback(kTime1156500, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)))
+ break;
label_callback4:
if (params->param5 != kTimeInvalid && getState()->time > kTime1165500) {
@@ -254,7 +254,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler)
}
if (params->param2 == kTimeInvalid || getState()->time <= kTime1786500) {
- TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6);
+ Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6));
break;
}
@@ -264,7 +264,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler)
params->param2 = (uint)getState()->time + 75;
if (params->param2 >= getState()->time) {
- TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6);
+ Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6));
break;
}
}
@@ -281,7 +281,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler)
break;
case 1:
- TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6);
+ Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6));
break;
case 2:
@@ -321,20 +321,26 @@ IMPLEMENT_FUNCTION(16, Hadija, chapter3Handler)
break;
case kActionNone:
- TIME_CHECK_CALLBACK(kTime1998000, params->param1, 1, setup_compartment6to8);
+ if (Entity::timeCheckCallback(kTime1998000, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8)))
+ break;
label_callback1:
- TIME_CHECK_CALLBACK(kTime2020500, params->param2, 2, setup_compartment8to6);
+ if (Entity::timeCheckCallback(kTime2020500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)))
+ break;
label_callback2:
- TIME_CHECK_CALLBACK(kTime2079000, params->param3, 3, setup_compartment6to8);
+ if (Entity::timeCheckCallback(kTime2079000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8)))
+ break;
label_callback3:
- TIME_CHECK_CALLBACK(kTime2187000, params->param4, 4, setup_compartment8to6);
+ if (Entity::timeCheckCallback(kTime2187000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)))
+ break;
label_callback4:
- if (params->param5 != kTimeInvalid && getState()->time > kTime2196000)
- TIME_CHECK_CAR(kTime2254500, params->param5, 5, setup_compartment6);
+ if (params->param5 != kTimeInvalid && getState()->time > kTime2196000) {
+ if (Entity::timeCheckCar(kTime2254500, params->param5, 5, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6)))
+ break;
+ }
break;
case kActionDefault:
@@ -387,18 +393,24 @@ IMPLEMENT_FUNCTION(18, Hadija, chapter4Handler)
break;
case kActionNone:
- if (params->param1 != kTimeInvalid)
- TIME_CHECK_CAR(kTime1714500, params->param1, 1, setup_compartment6);
+ if (params->param1 != kTimeInvalid) {
+ if (Entity::timeCheckCar(kTime1714500, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6)))
+ break;
+ }
label_callback1:
- TIME_CHECK_CALLBACK(kTime2367000, params->param2, 2, setup_compartment6to8);
+ if (Entity::timeCheckCallback(kTime2367000, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8)))
+ break;
label_callback2:
- TIME_CHECK_CALLBACK(kTime2421000, params->param3, 3, setup_compartment8to6);
+ if (Entity::timeCheckCallback(kTime2421000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)))
+ break;
label_callback3:
- if (params->param4 != kTimeInvalid && getState()->time > kTime2425500)
- TIME_CHECK_CAR(kTime2484000, params->param4, 4, setup_compartment6);
+ if (params->param4 != kTimeInvalid && getState()->time > kTime2425500) {
+ if (Entity::timeCheckCar(kTime2484000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6)))
+ break;
+ }
break;
case kActionCallback:
@@ -468,7 +480,9 @@ IMPLEMENT_FUNCTION(22, Hadija, function22)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->time, 2700);
+ if (!Entity::updateParameter(params->param1, getState()->time, 2700))
+ break;
+
setup_function23();
break;
diff --git a/engines/lastexpress/entities/hadija.h b/engines/lastexpress/entities/hadija.h
index d2495955e0..545f21ee03 100644
--- a/engines/lastexpress/entities/hadija.h
+++ b/engines/lastexpress/entities/hadija.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_HADIJA_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/ivo.cpp b/engines/lastexpress/entities/ivo.cpp
index f2261b438c..c53f4689fb 100644
--- a/engines/lastexpress/entities/ivo.cpp
+++ b/engines/lastexpress/entities/ivo.cpp
@@ -32,10 +32,7 @@
#include "lastexpress/game/scenes.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.h"
-
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -184,7 +181,7 @@ IMPLEMENT_FUNCTION(11, Ivo, function11)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityIvo);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 4:
@@ -193,7 +190,7 @@ IMPLEMENT_FUNCTION(11, Ivo, function11)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityIvo);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -210,7 +207,7 @@ IMPLEMENT_FUNCTION(12, Ivo, sitAtTableWithSalko)
getEntities()->clearSequences(kEntitySalko);
getSavePoints()->push(kEntityIvo, kEntityTables2, kAction136455232);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -231,7 +228,7 @@ IMPLEMENT_FUNCTION(13, Ivo, leaveTableWithSalko)
getSavePoints()->push(kEntityIvo, kEntityTables2, kActionDrawTablesWithChairs, "009E");
getEntities()->clearSequences(kEntitySalko);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -249,7 +246,7 @@ IMPLEMENT_FUNCTION(14, Ivo, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Ivo, setup_chapter1Handler));
break;
case kActionDefault:
@@ -374,7 +371,7 @@ IMPLEMENT_FUNCTION(18, Ivo, chapter2)
break;
case kActionNone:
- TIME_CHECK(kTime1777500, params->param1, setup_function19);
+ Entity::timeCheck(kTime1777500, params->param1, WRAP_SETUP_FUNCTION(Ivo, setup_function19));
break;
case kActionDefault:
diff --git a/engines/lastexpress/entities/ivo.h b/engines/lastexpress/entities/ivo.h
index cd5cb7b6be..75814336e0 100644
--- a/engines/lastexpress/entities/ivo.h
+++ b/engines/lastexpress/entities/ivo.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_IVO_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/kahina.cpp b/engines/lastexpress/entities/kahina.cpp
index 2918b1e8bd..7860836a26 100644
--- a/engines/lastexpress/entities/kahina.cpp
+++ b/engines/lastexpress/entities/kahina.cpp
@@ -32,10 +32,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -90,7 +88,7 @@ IMPLEMENT_FUNCTION_END
IMPLEMENT_FUNCTION_I(4, Kahina, updateFromTime, uint32)
if (savepoint.action == kAction137503360) {
ENTITY_PARAM(0, 2) = 1;
- CALLBACK_ACTION();
+ callbackAction();
}
Entity::updateFromTime(savepoint);
@@ -111,7 +109,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue)
if (params->param1 < getState()->time && !params->param2) {
params->param2 = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -141,7 +139,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue)
case 1:
if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -151,7 +149,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue)
case 2:
case 3:
if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -163,7 +161,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue)
case 4:
if (ENTITY_PARAM(0, 2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -173,7 +171,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue)
case 5:
if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -185,7 +183,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue)
case kAction137503360:
ENTITY_PARAM(0, 2) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -198,12 +196,12 @@ IMPLEMENT_FUNCTION_II(7, Kahina, updateEntity2, CarIndex, EntityPosition)
case kActionNone:
if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
} else if (getEntities()->isDistanceBetweenEntities(kEntityKahina, kEntityPlayer, 1000)
&& !getEntities()->isInGreenCarEntrance(kEntityPlayer)
&& !getEntities()->isInsideCompartments(kEntityPlayer)
@@ -211,14 +209,14 @@ IMPLEMENT_FUNCTION_II(7, Kahina, updateEntity2, CarIndex, EntityPosition)
if (getData()->car == kCarGreenSleeping || getData()->car == kCarRedSleeping) {
ENTITY_PARAM(0, 1) = 1;
- CALLBACK_ACTION();
+ callbackAction();
}
}
break;
case kAction137503360:
ENTITY_PARAM(0, 2) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -249,7 +247,7 @@ IMPLEMENT_FUNCTION(10, Kahina, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Kahina, setup_chapter1Handler));
break;
case kActionDefault:
@@ -269,7 +267,7 @@ IMPLEMENT_FUNCTION(11, Kahina, chapter1Handler)
return;
if (getProgress().jacket != kJacketOriginal)
- TIME_CHECK_SAVEPOINT(kTime1107000, params->param1, kEntityKahina, kEntityMertens, kAction238732837);
+ Entity::timeCheckSavepoint(kTime1107000, params->param1, kEntityKahina, kEntityMertens, kAction238732837);
if (getProgress().eventMertensKronosInvitation)
setup_function12();
@@ -282,7 +280,7 @@ IMPLEMENT_FUNCTION(12, Kahina, function12)
break;
case kActionNone:
- TIME_CHECK(kTime1485000, params->param2, setup_function13);
+ Entity::timeCheck(kTime1485000, params->param2, WRAP_SETUP_FUNCTION(Kahina, setup_function13));
break;
case kActionKnock:
@@ -372,12 +370,12 @@ IMPLEMENT_FUNCTION(14, Kahina, function14)
case kActionExitCompartment:
getEntities()->exitCompartment(kEntityKahina, kObjectCompartmentF);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kAction4:
getEntities()->exitCompartment(kEntityKahina, kObjectCompartmentF);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -396,10 +394,10 @@ IMPLEMENT_FUNCTION(15, Kahina, function15)
case kActionNone:
if (params->param2 != kTimeInvalid) {
- UPDATE_PARAM_PROC_TIME(params->param1, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param2, 0)
+ if (Entity::updateParameterTime((TimeValue)params->param1, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param2, 0)) {
setCallback(9);
setup_updateEntity(kCarRedSleeping, kPosition_4070);
- UPDATE_PARAM_PROC_END
+ }
}
break;
@@ -542,7 +540,7 @@ IMPLEMENT_FUNCTION(15, Kahina, function15)
case 17:
getEntities()->clearSequences(kEntityKahina);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -582,18 +580,18 @@ IMPLEMENT_FUNCTION(17, Kahina, chapter2Handler)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM_PROC(params->param2, getState()->time, 9000)
+ if (Entity::updateParameter(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)
+ if (Entity::updateParameter(params->param3, getState()->time, 900)) {
setCallback(1);
setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird);
break;
- UPDATE_PARAM_PROC_END
+ }
}
label_callback_3:
@@ -729,7 +727,7 @@ IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition)
RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function22);
if (getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMeCath:
@@ -745,7 +743,7 @@ IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition)
case kActionDefault:
if (getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -787,16 +785,17 @@ label_callback_2:
}
if (!params->param1) {
- UPDATE_PARAM_PROC(params->param3, getState()->time, 9000)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param4, getState()->time, 900))
+ break;
setCallback(3);
setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird);
@@ -928,11 +927,11 @@ IMPLEMENT_FUNCTION(21, Kahina, function21)
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)
+ if (Entity::updateParameterTime((TimeValue)params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param5, 0)) {
setCallback(2);
setup_function23();
break;
- UPDATE_PARAM_PROC_END
+ }
}
}
@@ -943,14 +942,14 @@ label_callback_2:
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)
+ if (Entity::updateParameterTime((TimeValue)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
+ }
}
}
@@ -1125,7 +1124,7 @@ IMPLEMENT_FUNCTION(23, Kahina, function23)
case 7:
getEntities()->clearSequences(kEntityKahina);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1262,7 +1261,7 @@ IMPLEMENT_FUNCTION(25, Kahina, function25)
getProgress().field_78 = 1;
ENTITY_PARAM(0, 3) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -1303,7 +1302,7 @@ IMPLEMENT_FUNCTION(25, Kahina, function25)
case 13:
getEntities()->clearSequences(kEntityKahina);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -1387,7 +1386,7 @@ IMPLEMENT_FUNCTION(26, Kahina, function26)
getInventory()->setLocationAndProcess(kItemBriefcase, kObjectLocation2);
getProgress().field_78 = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -1429,7 +1428,7 @@ IMPLEMENT_FUNCTION(26, Kahina, function26)
case 9:
getEntities()->clearSequences(kEntityKahina);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
diff --git a/engines/lastexpress/entities/kahina.h b/engines/lastexpress/entities/kahina.h
index b25053e339..7479cf76f9 100644
--- a/engines/lastexpress/entities/kahina.h
+++ b/engines/lastexpress/entities/kahina.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_KAHINA_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/kronos.cpp b/engines/lastexpress/entities/kronos.cpp
index 134dce9c81..26ce3ca424 100644
--- a/engines/lastexpress/entities/kronos.cpp
+++ b/engines/lastexpress/entities/kronos.cpp
@@ -39,10 +39,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -128,7 +126,7 @@ IMPLEMENT_FUNCTION(7, Kronos, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Kronos, setup_chapter1Handler));
break;
case kActionDefault:
@@ -149,7 +147,7 @@ IMPLEMENT_FUNCTION(8, Kronos, chapter1Handler)
break;
case kActionNone:
- TIME_CHECK(kTime1489500, params->param2, setup_function11);
+ Entity::timeCheck(kTime1489500, params->param2, WRAP_SETUP_FUNCTION(Kronos, setup_function11));
break;
case kAction171849314:
@@ -191,7 +189,7 @@ IMPLEMENT_FUNCTION(10, Kronos, function10)
break;
case kActionNone:
- TIME_CHECK(kTime1489500, params->param1, setup_function11);
+ Entity::timeCheck(kTime1489500, params->param1, WRAP_SETUP_FUNCTION(Kronos, setup_function11));
break;
case kActionDefault:
@@ -295,10 +293,10 @@ IMPLEMENT_FUNCTION(15, Kronos, function15)
case kActionNone:
if (params->param1 && !getEntities()->isInSalon(kEntityBoutarel)) {
- UPDATE_PARAM_PROC(params->param2, getState()->timeTicks, 75)
+ if (Entity::updateParameter(params->param2, getState()->timeTicks, 75)) {
setup_function16();
break;
- UPDATE_PARAM_PROC_END
+ }
}
if (params->param3 != kTimeInvalid && getState()->time > kTime2002500) {
@@ -407,8 +405,7 @@ IMPLEMENT_FUNCTION(18, Kronos, function18)
params->param2 = 1;
}
- TIME_CHECK(kTime2106000, params->param3, setup_function19)
- else {
+ if (!Entity::timeCheck(kTime2106000, params->param3, WRAP_SETUP_FUNCTION(Kronos, setup_function19))) {
if (params->param1 && getEntities()->isInKronosSanctum(kEntityPlayer)) {
setCallback(1);
setup_savegame(kSavegameTypeEvent, kEventKahinaPunchSuite4);
@@ -528,9 +525,9 @@ IMPLEMENT_FUNCTION(20, Kronos, function20)
}
if (CURRENT_PARAM(1, 2) != kTimeInvalid && params->param7 < getState()->time) {
- UPDATE_PARAM_PROC_TIME(params->param8, !params->param1, CURRENT_PARAM(1, 2), 450)
+ if (Entity::updateParameterTime((TimeValue)params->param8, !params->param1, CURRENT_PARAM(1, 2), 450)) {
getSavePoints()->push(kEntityKronos, kEntityKahina, kAction237555748);
- UPDATE_PARAM_PROC_END
+ }
}
if (!params->param1)
diff --git a/engines/lastexpress/entities/kronos.h b/engines/lastexpress/entities/kronos.h
index 4c61b98620..a7693fcd46 100644
--- a/engines/lastexpress/entities/kronos.h
+++ b/engines/lastexpress/entities/kronos.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_KRONOS_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/mahmud.cpp b/engines/lastexpress/entities/mahmud.cpp
index 0e67b45cd2..af86ef8cdd 100644
--- a/engines/lastexpress/entities/mahmud.cpp
+++ b/engines/lastexpress/entities/mahmud.cpp
@@ -34,10 +34,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -86,7 +84,8 @@ IMPLEMENT_FUNCTION_SIII(4, Mahmud, enterExitCompartment2, ObjectIndex, uint32, O
break;
case kActionNone:
- UPDATE_PARAM(params->param7, getState()->timeTicks, params->param5);
+ if (!Entity::updateParameter(params->param7, getState()->timeTicks, params->param5))
+ break;
if (!getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp))
getScenes()->loadSceneFromObject((ObjectIndex)params->param6, true);
@@ -95,7 +94,7 @@ IMPLEMENT_FUNCTION_SIII(4, Mahmud, enterExitCompartment2, ObjectIndex, uint32, O
case kActionExitCompartment:
getEntities()->exitCompartment(kEntityMahmud, (ObjectIndex)params->param4);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -146,7 +145,8 @@ IMPLEMENT_FUNCTION_II(10, Mahmud, function10, ObjectIndex, bool)
break;
case kActionNone:
- UPDATE_PARAM(params->param6, getState()->time, 13500);
+ if (!Entity::updateParameter(params->param6, getState()->time, 13500))
+ break;
getObjects()->update(kObjectCompartment5, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartment6, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand);
@@ -267,7 +267,7 @@ IMPLEMENT_FUNCTION_II(10, Mahmud, function10, ObjectIndex, bool)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityMahmud);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -392,7 +392,7 @@ IMPLEMENT_FUNCTION(11, Mahmud, function11)
getEntities()->clearSequences(kEntityMahmud);
getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -471,7 +471,7 @@ IMPLEMENT_FUNCTION(12, Mahmud, function12)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityMahmud);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -537,7 +537,7 @@ IMPLEMENT_FUNCTION(13, Mahmud, function13)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityMahmud);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -560,7 +560,8 @@ IMPLEMENT_FUNCTION(14, Mahmud, chaptersHandler)
if (!params->param2 && getProgress().chapter == kChapter1) {
- TIME_CHECK_CALLBACK(kTime1098000, params->param6, 1, setup_function13);
+ if (Entity::timeCheckCallback(kTime1098000, params->param6, 1, WRAP_SETUP_FUNCTION(Mahmud, setup_function13)))
+ break;
if (!getSoundQueue()->isBuffered("HAR1104") && getState()->time > kTime1167300 && !params->param7) {
params->param7 = 1;
@@ -572,7 +573,8 @@ IMPLEMENT_FUNCTION(14, Mahmud, chaptersHandler)
}
if (params->param5) {
- UPDATE_PARAM(params->param8, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75))
+ break;
params->param4 = 1;
params->param5 = 0;
@@ -732,7 +734,7 @@ IMPLEMENT_FUNCTION(15, Mahmud, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chaptersHandler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Mahmud, setup_chaptersHandler));
break;
case kActionDefault:
diff --git a/engines/lastexpress/entities/mahmud.h b/engines/lastexpress/entities/mahmud.h
index 5feb95cba5..685100f078 100644
--- a/engines/lastexpress/entities/mahmud.h
+++ b/engines/lastexpress/entities/mahmud.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_MAHMUD_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/max.cpp b/engines/lastexpress/entities/max.cpp
index eacc38bf60..abd2aae9e4 100644
--- a/engines/lastexpress/entities/max.cpp
+++ b/engines/lastexpress/entities/max.cpp
@@ -31,10 +31,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -91,7 +89,8 @@ IMPLEMENT_FUNCTION(6, Max, chapter12_handler)
break;
case kActionNone:
- UPDATE_PARAM(params->param2, getState()->time, params->param1);
+ if (!Entity::updateParameter(params->param2, getState()->time, params->param1))
+ break;
if (!getSoundQueue()->isBuffered(kEntityMax))
getSound()->playSound(kEntityMax, "Max1122");
@@ -125,7 +124,8 @@ IMPLEMENT_FUNCTION(7, Max, function7)
break;
case kActionNone:
- UPDATE_PARAM(params->param2, getState()->time, params->param1)
+ if (!Entity::updateParameter(params->param2, getState()->time, params->param1))
+ break;
if (!getSoundQueue()->isBuffered(kEntityMax))
getSound()->playSound(kEntityMax, "Max1122");
@@ -186,7 +186,7 @@ IMPLEMENT_FUNCTION(7, Max, function7)
case kAction101687594:
getEntities()->clearSequences(kEntityMax);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kAction122358304:
@@ -195,7 +195,7 @@ IMPLEMENT_FUNCTION(7, Max, function7)
getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject53, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kAction158007856:
@@ -214,7 +214,8 @@ IMPLEMENT_FUNCTION(8, Max, chapter4Handler)
break;
case kActionNone:
- UPDATE_PARAM(params->param3, getState()->time, params->param2);
+ if (!Entity::updateParameter(params->param3, getState()->time, params->param2))
+ break;
if (!getSoundQueue()->isBuffered(kEntityMax))
getSound()->playSound(kEntityMax, "Max3101");
@@ -323,7 +324,7 @@ IMPLEMENT_FUNCTION(10, Max, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter12_handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Max, setup_chapter12_handler));
break;
case kActionDefault:
@@ -392,7 +393,8 @@ IMPLEMENT_FUNCTION(13, Max, chapter3Handler)
break;
}
- UPDATE_PARAM(params->param3, getState()->time, params->param1);
+ if (!Entity::updateParameter(params->param3, getState()->time, params->param1))
+ break;
if (!getSoundQueue()->isBuffered(kEntityMax))
getSound()->playSound(kEntityMax, "Max1122");
@@ -514,7 +516,8 @@ IMPLEMENT_FUNCTION(15, Max, function15)
}
if (!params->param1) {
- UPDATE_PARAM(params->param3, getState()->time, 900);
+ if (!Entity::updateParameter(params->param3, getState()->time, 900))
+ break;
getSavePoints()->push(kEntityMax, kEntityCoudert, kAction157026693);
}
diff --git a/engines/lastexpress/entities/max.h b/engines/lastexpress/entities/max.h
index 17b58475aa..acd8235e89 100644
--- a/engines/lastexpress/entities/max.h
+++ b/engines/lastexpress/entities/max.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_MAX_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/mertens.cpp b/engines/lastexpress/entities/mertens.cpp
index d88962fce2..97dd293793 100644
--- a/engines/lastexpress/entities/mertens.cpp
+++ b/engines/lastexpress/entities/mertens.cpp
@@ -32,21 +32,11 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/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);
@@ -117,11 +107,11 @@ IMPLEMENT_FUNCTION_S(2, Mertens, bloodJacket)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -144,7 +134,7 @@ IMPLEMENT_FUNCTION_SI(3, Mertens, enterExitCompartment, ObjectIndex)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
return;
case kActionCallback:
@@ -165,12 +155,12 @@ IMPLEMENT_FUNCTION_SI(4, Mertens, enterExitCompartment2, ObjectIndex)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
return;
case kAction4:
getEntities()->exitCompartment(kEntityMertens, (ObjectIndex)params->param4);
- CALLBACK_ACTION();
+ callbackAction();
return;
case kActionCallback:
@@ -191,13 +181,13 @@ IMPLEMENT_FUNCTION_SIII(5, Mertens, enterExitCompartment3, ObjectIndex, EntityPo
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionExitCompartment:
getEntities()->exitCompartment(_entityIndex, (ObjectIndex)params->param4);
getData()->entityPosition = (EntityPosition)params->param5;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -229,15 +219,15 @@ IMPLEMENT_FUNCTION(6, Mertens, callbackActionOnDirection)
case kActionNone:
if (getData()->direction != kDirectionRight) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -256,11 +246,11 @@ IMPLEMENT_FUNCTION_S(7, Mertens, playSound)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionEndSound:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -283,11 +273,11 @@ IMPLEMENT_FUNCTION_S(8, Mertens, playSound16)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionEndSound:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -310,14 +300,6 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
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;
@@ -333,7 +315,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition)
|| getEntities()->checkFields10(kEntityPlayer)) {
if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2)) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -364,7 +346,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition)
if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2)) {
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -395,7 +377,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition)
params->param3 = 1;
if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -416,7 +398,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition)
ENTITY_PARAM(0, 7) = 0;
if (params->param1 != 3 || (params->param2 != kPosition_8200 && params->param2 != kPosition_9510)) {
- LOADSCENE_FROM_POSITION();
+ loadSceneFromPosition();
break;
}
@@ -428,7 +410,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition)
getEntities()->updateEntity(kEntityMertens, kCarGreenSleeping, kPosition_2000);
getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750));
- CALLBACK_ACTION();
+ callbackAction();
break;
case 3:
@@ -444,35 +426,33 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition)
getEntities()->updateEntity(kEntityMertens, kCarGreenSleeping, kPosition_2000);
getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750));
- CALLBACK_ACTION();
+ callbackAction();
break;
}
- LOADSCENE_FROM_POSITION();
+ loadSceneFromPosition();
break;
case 4:
getAction()->playAnimation(kEventMertensKronosConcertInvitation);
ENTITY_PARAM(2, 4) = 0;
- LOADSCENE_FROM_POSITION();
+ loadSceneFromPosition();
break;
case 5:
getAction()->playAnimation(getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition ? kEventMertensAskTylerCompartmentD : kEventMertensAskTylerCompartment);
- LOADSCENE_FROM_POSITION();
+ loadSceneFromPosition();
break;
case 6:
getAction()->playAnimation(kEventMertensDontMakeBed);
- LOADSCENE_FROM_POSITION();
+ loadSceneFromPosition();
ENTITY_PARAM(0, 4) = 0;
break;
}
break;
}
-
-#undef LOADSCENE_FROM_POSITION
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
@@ -482,11 +462,12 @@ IMPLEMENT_FUNCTION_I(11, Mertens, function11, uint32)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
- UPDATE_PARAM(params->param2, getState()->time, params->param1)
+ if (!Entity::updateParameter(params->param2, getState()->time, params->param1))
+ break;
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionCallback:
@@ -506,7 +487,7 @@ IMPLEMENT_FUNCTION_I(12, Mertens, bonsoir, EntityIndex)
return;
if (getSoundQueue()->isBuffered(kEntityMertens)) {
- CALLBACK_ACTION();
+ callbackAction();
return;
}
@@ -540,7 +521,7 @@ IMPLEMENT_FUNCTION_I(12, Mertens, bonsoir, EntityIndex)
getSound()->playSound(kEntityMertens, "CON1112G");
}
- CALLBACK_ACTION();
+ callbackAction();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
@@ -550,23 +531,23 @@ IMPLEMENT_FUNCTION_II(13, Mertens, function13, bool, bool)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
if (!params->param2 && !params->param3) {
- UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, 75)
+ if (Entity::updateParameter(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)
+ if (Entity::updateParameter(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)
@@ -640,7 +621,7 @@ IMPLEMENT_FUNCTION_II(13, Mertens, function13, bool, bool)
case 6:
case 9:
case 10:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 7:
@@ -672,7 +653,7 @@ IMPLEMENT_FUNCTION_I(14, Mertens, function14, EntityIndex)
break;
case kActionNone:
- SAVEGAME_BLOOD_JACKET();
+ Entity::savegameBloodJacket();
break;
case kActionDefault:
@@ -719,7 +700,7 @@ IMPLEMENT_FUNCTION_I(14, Mertens, function14, EntityIndex)
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -783,7 +764,7 @@ IMPLEMENT_FUNCTION_I(15, Mertens, function15, bool)
break;
case 6:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -860,7 +841,7 @@ IMPLEMENT_FUNCTION_I(16, Mertens, function16, bool)
break;
case 6:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -888,7 +869,7 @@ IMPLEMENT_FUNCTION(17, Mertens, function17)
getScenes()->loadSceneFromItemPosition(kItem7);
ENTITY_PARAM(2, 1) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -926,7 +907,7 @@ IMPLEMENT_FUNCTION(17, Mertens, function17)
break;
case 2:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 3:
@@ -944,7 +925,7 @@ IMPLEMENT_FUNCTION(17, Mertens, function17)
getSavePoints()->push(kEntityMertens, kEntityMertens, kActionDrawScene);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -970,7 +951,7 @@ IMPLEMENT_FUNCTION(18, Mertens, function18)
getInventory()->setLocationAndProcess(kItem7, kObjectLocation1);
ENTITY_PARAM(2, 1) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -978,7 +959,7 @@ IMPLEMENT_FUNCTION(18, Mertens, function18)
getScenes()->loadSceneFromItemPosition(kItem7);
ENTITY_PARAM(2, 1) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -1009,7 +990,7 @@ IMPLEMENT_FUNCTION(18, Mertens, function18)
ENTITY_PARAM(0, 1) = 0;
getData()->inventoryItem = kItemNone;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -1025,7 +1006,7 @@ IMPLEMENT_FUNCTION(19, Mertens, function19)
if (ENTITY_PARAM(2, 1)) {
getInventory()->setLocationAndProcess(kItem7, kObjectLocation1);
ENTITY_PARAM(2, 1) = 0;
- CALLBACK_ACTION();
+ callbackAction();
} else {
setCallback(1);
setup_bloodJacket("601C");
@@ -1039,7 +1020,7 @@ IMPLEMENT_FUNCTION(19, Mertens, function19)
if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2))
getData()->entityPosition = kPosition_2088;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -1057,7 +1038,7 @@ IMPLEMENT_FUNCTION(20, Mertens, function20)
if (ENTITY_PARAM(2, 1)) {
ENTITY_PARAM(2, 1) = 0;
- CALLBACK_ACTION();
+ callbackAction();
} else {
setCallback(1);
setup_bloodJacket("601C");
@@ -1066,7 +1047,7 @@ IMPLEMENT_FUNCTION(20, Mertens, function20)
case kActionCallback:
if (getCallback() == 1)
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -1078,11 +1059,12 @@ IMPLEMENT_FUNCTION_II(21, Mertens, function21, ObjectIndex, ObjectIndex)
break;
case kActionNone:
- UPDATE_PARAM_PROC(CURRENT_PARAM(1, 4), getState()->time, 300)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(CURRENT_PARAM(1, 5), getState()->time, 900))
+ break;
// Update objects
getObjects()->updateLocation2((ObjectIndex)params->param1, kObjectLocation1);
@@ -1092,7 +1074,7 @@ IMPLEMENT_FUNCTION_II(21, Mertens, function21, ObjectIndex, ObjectIndex)
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();
+ callbackAction();
break;
case kActionKnock:
@@ -1222,7 +1204,7 @@ IMPLEMENT_FUNCTION(22, Mertens, function22)
break;
case 9:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1291,7 +1273,7 @@ IMPLEMENT_FUNCTION(23, Mertens, function23)
case 6:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1306,7 +1288,8 @@ IMPLEMENT_FUNCTION(24, Mertens, function24)
case kActionNone:
if (!params->param1) {
- UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75))
+ break;
setCallback(3);
setup_enterExitCompartment3("601Rc", kObjectCompartment3, kPosition_6470, kPosition_6130);
@@ -1351,7 +1334,7 @@ IMPLEMENT_FUNCTION(24, Mertens, function24)
case 5:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -1380,7 +1363,7 @@ IMPLEMENT_FUNCTION(24, Mertens, function24)
break;
case 9:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1409,7 +1392,8 @@ IMPLEMENT_FUNCTION(25, Mertens, function25)
case kActionNone:
if (!params->param1) {
- UPDATE_PARAM(params->param2, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75))
+ break;
setCallback(3);
setup_enterExitCompartment3("601Zb", kObjectCompartment2, kPosition_7500, kPositionNone);
@@ -1458,7 +1442,7 @@ IMPLEMENT_FUNCTION(25, Mertens, function25)
case 5:
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -1492,7 +1476,7 @@ IMPLEMENT_FUNCTION(25, Mertens, function25)
break;
case 9:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1547,7 +1531,7 @@ IMPLEMENT_FUNCTION_I(26, Mertens, function26, bool)
case 2:
getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 3:
@@ -1613,7 +1597,7 @@ IMPLEMENT_FUNCTION_I(26, Mertens, function26, bool)
getData()->location = kLocationOutsideCompartment;
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1628,17 +1612,17 @@ IMPLEMENT_FUNCTION_I(27, Mertens, tylerCompartment, MertensActionType)
case kActionNone:
if (getProgress().field_14 == 29) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
- UPDATE_PARAM_PROC(params->param2, getState()->timeTicks, 150)
+ if (Entity::updateParameter(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)
@@ -1646,7 +1630,8 @@ label_callback10:
if (params->param3 >= getState()->timeTicks) {
label_callback11:
- UPDATE_PARAM(params->param4, getState()->timeTicks, 375);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, 375))
+ break;
getSound()->playSound(kEntityPlayer, "LIB033");
@@ -1680,7 +1665,7 @@ label_callback11:
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadScene(kScene41);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
} else {
@@ -1738,7 +1723,7 @@ label_callback11:
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadScene(kScene41);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
} else {
@@ -1763,7 +1748,7 @@ label_callback11:
default:
getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 1:
@@ -1821,7 +1806,7 @@ label_callback11:
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadScene(kScene41);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
} else {
@@ -1930,7 +1915,7 @@ label_callback11:
getData()->location = kLocationOutsideCompartment;
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 8:
@@ -1957,7 +1942,7 @@ label_callback11:
case 19:
case 22:
case 28:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 15:
@@ -1969,7 +1954,7 @@ label_callback11:
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadScene(kScene41);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 16:
@@ -1981,27 +1966,27 @@ label_callback11:
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadScene(kScene41);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 23:
getProgress().eventMertensAugustWaiting = true;
getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 24:
getProgress().eventMertensKronosInvitation = true;
getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 25:
getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2053,7 +2038,7 @@ IMPLEMENT_FUNCTION_S(28, Mertens, function28)
break;
case 4:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2115,7 +2100,7 @@ IMPLEMENT_FUNCTION_SS(29, Mertens, function29)
break;
case 4:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2140,14 +2125,14 @@ IMPLEMENT_FUNCTION_I(30, Mertens, function30, MertensActionType)
case kActionDefault:
switch (params->param1) {
default:
- CALLBACK_ACTION();
+ callbackAction();
return;
case 1:
params->param2 = kPosition_8200;
if (getProgress().field_14) {
- CALLBACK_ACTION();
+ callbackAction();
return;
}
@@ -2273,7 +2258,7 @@ IMPLEMENT_FUNCTION_I(30, Mertens, function30, MertensActionType)
break;
case 9:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2312,7 +2297,7 @@ IMPLEMENT_FUNCTION_I(31, Mertens, function31, MertensActionType)
case 2:
case 3:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2360,7 +2345,7 @@ IMPLEMENT_FUNCTION(32, Mertens, function32)
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2382,7 +2367,7 @@ IMPLEMENT_FUNCTION(33, Mertens, function33)
setCallback(ENTITY_PARAM(0, 8) ? 1 : 3);
setup_updateEntity(kCarGreenSleeping, ENTITY_PARAM(0, 8) ? kPosition_1500 : kPosition_540);
} else {
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -2401,7 +2386,7 @@ IMPLEMENT_FUNCTION(33, Mertens, function33)
case 2:
ENTITY_PARAM(1, 8) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 3:
@@ -2480,7 +2465,7 @@ IMPLEMENT_FUNCTION(33, Mertens, function33)
break;
}
- CALLBACK_ACTION();
+ callbackAction();
break;
case 12:
@@ -2493,13 +2478,13 @@ IMPLEMENT_FUNCTION(33, Mertens, function33)
break;
}
- CALLBACK_ACTION();
+ callbackAction();
break;
case 13:
ENTITY_PARAM(2, 2) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2513,7 +2498,7 @@ IMPLEMENT_FUNCTION(34, Mertens, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Mertens, setup_chapter1Handler));
break;
case kActionDefault:
@@ -2548,7 +2533,7 @@ IMPLEMENT_FUNCTION(35, Mertens, function35)
case kActionDefault:
if (getProgress().field_14 == 29) {
- CALLBACK_ACTION();
+ callbackAction();
break;
} else {
getProgress().field_14 = 3;
@@ -2589,7 +2574,7 @@ IMPLEMENT_FUNCTION(35, Mertens, function35)
break;
case 4:
- CALLBACK_ACTION();
+ callbackAction();
break;
case 5:
@@ -2611,7 +2596,7 @@ IMPLEMENT_FUNCTION(35, Mertens, function35)
break;
case 7:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2626,7 +2611,7 @@ IMPLEMENT_FUNCTION(36, Mertens, function36)
case kActionDefault:
if (getProgress().field_14 == 29) {
- CALLBACK_ACTION();
+ callbackAction();
} else {
getProgress().field_14 = 3;
@@ -2712,7 +2697,7 @@ IMPLEMENT_FUNCTION(36, Mertens, function36)
case 6:
case 9:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2767,7 +2752,7 @@ IMPLEMENT_FUNCTION(37, Mertens, function37)
break;
case 4:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2791,12 +2776,12 @@ IMPLEMENT_FUNCTION(38, Mertens, function38)
case kActionDefault:
if (!ENTITY_PARAM(0, 4)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (getProgress().field_14 == 29) {
- CALLBACK_ACTION();
+ callbackAction();
} else {
setCallback(1);
setup_updateEntity(kCarGreenSleeping, kPosition_8200);
@@ -2810,7 +2795,7 @@ IMPLEMENT_FUNCTION(38, Mertens, function38)
case 1:
if (!ENTITY_PARAM(0, 4)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -2820,7 +2805,7 @@ IMPLEMENT_FUNCTION(38, Mertens, function38)
case 2:
ENTITY_PARAM(0, 4) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2894,7 +2879,7 @@ IMPLEMENT_FUNCTION(39, Mertens, function39)
break;
case 10:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -2940,7 +2925,7 @@ IMPLEMENT_FUNCTION(40, Mertens, function40)
case 5:
ENTITY_PARAM(0, 6) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -3013,7 +2998,7 @@ IMPLEMENT_FUNCTION(42, Mertens, function42)
getData()->inventoryItem = kItemInvalid;
if (!params->param2) {
- TIME_CHECK_SAVEPOINT(kTime1125000, params->param3, kEntityMertens, kEntityMahmud, kAction170483072);
+ Entity::timeCheckSavepoint(kTime1125000, params->param3, kEntityMertens, kEntityMahmud, kAction170483072);
if (params->param4 != kTimeInvalid && getState()->time > kTimeCityChalons) {
@@ -3040,11 +3025,11 @@ IMPLEMENT_FUNCTION(42, Mertens, function42)
label_callback_8:
if (getState()->time > kTime1215000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
- UPDATE_PARAM_PROC(params->param5, getState()->time, 2700)
+ if (Entity::updateParameter(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)) {
@@ -3547,19 +3532,23 @@ label_callback_5:
}
label_callback_6:
- TIME_CHECK_CALLBACK_1(kTime1971000, params->param1, 7, setup_function28, "CON3012");
+ if (Entity::timeCheckCallback(kTime1971000, params->param1, 7, "CON3012", WRAP_SETUP_FUNCTION_S(Mertens, setup_function28)))
+ break;
label_callback_7:
- TIME_CHECK_CALLBACK(kTime2117700, params->param2, 8, setup_function32);
+ if (Entity::timeCheckCallback(kTime2117700, params->param2, 8, WRAP_SETUP_FUNCTION(Mertens, setup_function32)))
+ break;
label_callback_8:
- TIME_CHECK_CALLBACK_1(kTime2124000, params->param3, 9, setup_function28, "CON2010");
+ if (Entity::timeCheckCallback(kTime2124000, params->param3, 9, "CON2010", WRAP_SETUP_FUNCTION_S(Mertens, setup_function28)))
+ break;
label_callback_9:
- TIME_CHECK_CALLBACK(kTime2146500, params->param4, 10, setup_function32);
+ if (Entity::timeCheckCallback(kTime2146500, params->param4, 10, WRAP_SETUP_FUNCTION(Mertens, setup_function32)))
+ break;
label_callback_10:
- TIME_CHECK_CALLBACK(kTime2169000, params->param5, 11, setup_function32);
+ Entity::timeCheckCallback(kTime2169000, params->param5, 11, WRAP_SETUP_FUNCTION(Mertens, setup_function32));
break;
case kAction11:
@@ -3742,21 +3731,26 @@ label_callback_3:
label_callback_4:
if (!params->param1) {
- TIME_CHECK_CALLBACK(kTime2403000, params->param2, 5, setup_function49);
+ if (Entity::timeCheckCallback(kTime2403000, params->param2, 5, WRAP_SETUP_FUNCTION(Mertens, setup_function49)))
+ break;
label_callback_5:
- TIME_CHECK_CALLBACK(kTime2430000, params->param3, 6, setup_function32);
+ if (Entity::timeCheckCallback(kTime2430000, params->param3, 6, WRAP_SETUP_FUNCTION(Mertens, setup_function32)))
+ break;
label_callback_6:
- TIME_CHECK_CALLBACK(kTime2439000, params->param4, 7, setup_function32);
+ if (Entity::timeCheckCallback(kTime2439000, params->param4, 7, WRAP_SETUP_FUNCTION(Mertens, setup_function32)))
+ break;
label_callback_7:
- TIME_CHECK_CALLBACK(kTime2448000, params->param5, 8, setup_function32);
+ if (Entity::timeCheckCallback(kTime2448000, params->param5, 8, WRAP_SETUP_FUNCTION(Mertens, setup_function32)))
+ break;
}
label_callback_8:
if (getState()->time > kTime2538000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) {
- UPDATE_PARAM(params->param6, getState()->time, 2700);
+ if (!Entity::updateParameter(params->param6, getState()->time, 2700))
+ break;
getEntities()->drawSequenceLeft(kEntityMertens, "601E");
@@ -3913,7 +3907,7 @@ IMPLEMENT_FUNCTION(49, Mertens, function49)
break;
case 11:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -4010,7 +4004,8 @@ IMPLEMENT_FUNCTION(53, Mertens, function53)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM(params->param4, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 0;
@@ -4108,4 +4103,15 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_NULL_FUNCTION(54, Mertens)
+//////////////////////////////////////////////////////////////////////////
+// Helper functions
+//////////////////////////////////////////////////////////////////////////
+
+void Mertens::loadSceneFromPosition() {
+ if (getData()->direction != kDirectionUp)
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750));
+ else
+ getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition - 750), true);
+}
+
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/mertens.h b/engines/lastexpress/entities/mertens.h
index 31b7a97dcd..4cc58fd4ba 100644
--- a/engines/lastexpress/entities/mertens.h
+++ b/engines/lastexpress/entities/mertens.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_MERTENS_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
@@ -210,6 +209,9 @@ public:
DECLARE_FUNCTION(function53)
DECLARE_NULL_FUNCTION()
+
+private:
+ void loadSceneFromPosition();
};
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/milos.cpp b/engines/lastexpress/entities/milos.cpp
index ff3d2b6744..519a613497 100644
--- a/engines/lastexpress/entities/milos.cpp
+++ b/engines/lastexpress/entities/milos.cpp
@@ -36,10 +36,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -135,7 +133,7 @@ IMPLEMENT_FUNCTION_II(10, Milos, enterCompartmentDialog, CarIndex, EntityPositio
case kActionNone:
case kActionDefault:
if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMeCath:
@@ -173,16 +171,16 @@ IMPLEMENT_FUNCTION_I(11, Milos, function11, TimeValue)
if (!params->param5 && params->param1 < getState()->time && !params->param7) {
params->param7 = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (params->param2) {
- UPDATE_PARAM_PROC(params->param8, getState()->timeTicks, 75)
+ if (Entity::updateParameter(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;
@@ -191,10 +189,10 @@ IMPLEMENT_FUNCTION_I(11, Milos, function11, TimeValue)
break;
if (params->param6) {
- UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->time, 4500)
+ if (Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->time, 4500)) {
params->param6 = 0;
CURRENT_PARAM(1, 1) = 0;
- UPDATE_PARAM_PROC_END
+ }
}
if (!getProgress().field_CC) {
@@ -364,7 +362,7 @@ IMPLEMENT_FUNCTION(12, Milos, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Milos, setup_chapter1Handler));
break;
case kActionDefault:
@@ -394,7 +392,7 @@ IMPLEMENT_FUNCTION(13, Milos, function13)
getEntities()->clearSequences(kEntityIvo);
getEntities()->clearSequences(kEntitySalko);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -422,7 +420,7 @@ IMPLEMENT_FUNCTION(14, Milos, function14)
getEntities()->exitCompartment(kEntityMilos, kObjectCompartment1, true);
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -436,7 +434,8 @@ IMPLEMENT_FUNCTION(14, Milos, function14)
if (CURRENT_PARAM(1, 1) < getState()->timeTicks) {
if (getObjects()->get(kObjectCompartment1).location == kObjectLocation1) {
- UPDATE_PARAM(CURRENT_PARAM(1, 2), getState()->timeTicks, 75);
+ if (!Entity::updateParameter(CURRENT_PARAM(1, 2), getState()->timeTicks, 75))
+ break;
getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal);
@@ -474,7 +473,7 @@ IMPLEMENT_FUNCTION(14, Milos, function14)
getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
} else {
@@ -507,7 +506,8 @@ IMPLEMENT_FUNCTION(14, Milos, function14)
}
label_callback_12:
- UPDATE_PARAM(CURRENT_PARAM(1, 4), getState()->timeTicks, 75);
+ if (!Entity::updateParameter(CURRENT_PARAM(1, 4), getState()->timeTicks, 75))
+ break;
getEntities()->exitCompartment(kEntityMilos, kObjectCompartment1, true);
@@ -593,7 +593,7 @@ label_callback_12:
getData()->location = kLocationOutsideCompartment;
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 2:
@@ -633,7 +633,7 @@ label_callback_12:
getScenes()->loadScene(kScene41);
getData()->location = kLocationOutsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -722,7 +722,7 @@ IMPLEMENT_FUNCTION(15, Milos, chapter1Handler)
break;
case kActionNone:
- TIME_CHECK_SAVEPOINT(kTime1071000, params->param3, kEntityMilos, kEntityServers1, kAction223002560);
+ Entity::timeCheckSavepoint(kTime1071000, params->param3, kEntityMilos, kEntityServers1, kAction223002560);
if (getState()->time > kTime1089000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
setup_function16();
@@ -730,15 +730,16 @@ IMPLEMENT_FUNCTION(15, Milos, chapter1Handler)
}
if (getEntities()->isPlayerPosition(kCarRestaurant, 61) && !params->param1) {
- UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, 45)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 45))
+ break;
setCallback(2);
setup_draw("009C");
@@ -953,7 +954,8 @@ IMPLEMENT_FUNCTION(21, Milos, function21)
break;
case kActionNone:
- UPDATE_PARAM(params->param2, getState()->time, 4500);
+ if (!Entity::updateParameter(params->param2, getState()->time, 4500))
+ break;
params->param1 = 1;
break;
@@ -1118,7 +1120,8 @@ IMPLEMENT_FUNCTION(24, Milos, function24)
}
if (params->param1) {
- UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 1;
@@ -1284,14 +1287,15 @@ IMPLEMENT_FUNCTION(25, Milos, function25)
case kActionNone:
if (!getEvent(kEventMilosCompartmentVisitTyler) && !getProgress().field_54 && !ENTITY_PARAM(0, 4)) {
- UPDATE_PARAM_PROC(params->param3, getState()->time, 13500)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 1;
@@ -1386,7 +1390,7 @@ IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue)
case kActionNone:
if (params->param1 < getState()->time && !params->param2) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -1415,7 +1419,7 @@ IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue)
case 1:
if (ENTITY_PARAM(0, 2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -1425,7 +1429,7 @@ IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue)
case 2:
case 3:
if (ENTITY_PARAM(0, 2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -1442,7 +1446,7 @@ IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue)
case 5:
if (ENTITY_PARAM(0, 2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -1461,7 +1465,7 @@ IMPLEMENT_FUNCTION_II(27, Milos, function27, CarIndex, EntityPosition)
case kActionNone:
if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
@@ -1472,14 +1476,14 @@ IMPLEMENT_FUNCTION_II(27, Milos, function27, CarIndex, EntityPosition)
if (getData()->car == kCarRedSleeping || getData()->car == kCarGreenSleeping) {
ENTITY_PARAM(0, 2) = 1;
- CALLBACK_ACTION();
+ callbackAction();
}
}
break;
case kActionDefault:
if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -1536,7 +1540,7 @@ IMPLEMENT_FUNCTION(29, Milos, chapter4Handler)
TIME_CHECK_PLAYSOUND_MILOS(kTime2370600, params->param5, "Mil4015");
- TIME_CHECK_SAVEPOINT(kTime2407500, params->param6, kEntityMilos, kEntityVesna, kAction55996766);
+ Entity::timeCheckSavepoint(kTime2407500, params->param6, kEntityMilos, kEntityVesna, kAction55996766);
break;
case kActionCallback:
diff --git a/engines/lastexpress/entities/milos.h b/engines/lastexpress/entities/milos.h
index d58d717f8a..e8f95dc5ff 100644
--- a/engines/lastexpress/entities/milos.h
+++ b/engines/lastexpress/entities/milos.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_MILOS_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/mmeboutarel.cpp b/engines/lastexpress/entities/mmeboutarel.cpp
index 9ca10ca374..950644cb8f 100644
--- a/engines/lastexpress/entities/mmeboutarel.cpp
+++ b/engines/lastexpress/entities/mmeboutarel.cpp
@@ -31,10 +31,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -124,7 +122,7 @@ IMPLEMENT_FUNCTION_S(8, MmeBoutarel, function8)
if (!getEntities()->isPlayerPosition(kCarRedSleeping, 2))
getData()->entityPosition = kPosition_2088;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -211,7 +209,7 @@ IMPLEMENT_FUNCTION(9, MmeBoutarel, function9)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityMmeBoutarel);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 5:
@@ -220,7 +218,7 @@ IMPLEMENT_FUNCTION(9, MmeBoutarel, function9)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityMmeBoutarel);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -246,7 +244,7 @@ IMPLEMENT_FUNCTION(10, MmeBoutarel, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(MmeBoutarel, setup_chapter1Handler));
break;
case kActionDefault:
@@ -312,7 +310,7 @@ IMPLEMENT_FUNCTION(11, MmeBoutarel, function11)
break;
case 4:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -402,7 +400,7 @@ IMPLEMENT_FUNCTION(13, MmeBoutarel, function13)
case kActionNone:
if (!getSoundQueue()->isBuffered(kEntityMmeBoutarel) && params->param6 != kTimeInvalid) {
- UPDATE_PARAM_PROC_TIME(params->param1, !getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 2000), params->param6, 0)
+ if (Entity::updateParameterTime((TimeValue)params->param1, !getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 2000), params->param6, 0)) {
getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal);
@@ -414,22 +412,24 @@ IMPLEMENT_FUNCTION(13, MmeBoutarel, function13)
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)
+ if (Entity::updateParameterTime(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 (Entity::timeCheck(kTime1094400, params->param8, WRAP_SETUP_FUNCTION(MmeBoutarel, setup_function14)))
+ break;
if (params->param4) {
- UPDATE_PARAM(CURRENT_PARAM(1, 1), getState()->timeTicks, 75);
+ if (!Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->timeTicks, 75))
+ break;
params->param3 = 1;
params->param4 = 0;
@@ -589,7 +589,8 @@ IMPLEMENT_FUNCTION(15, MmeBoutarel, function15)
label_callback_5:
if (params->param2) {
- UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75))
+ break;
params->param1 = 1;
params->param2 = 0;
@@ -1018,7 +1019,8 @@ IMPLEMENT_FUNCTION(23, MmeBoutarel, chapter4Handler)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM(params->param2, getState()->time, 900);
+ if (!Entity::updateParameter(params->param2, getState()->time, 900))
+ break;
getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
@@ -1064,10 +1066,12 @@ IMPLEMENT_FUNCTION(24, MmeBoutarel, function24)
break;
case kActionNone:
- TIME_CHECK(kTime2470500, params->param4, setup_function25);
+ if (Entity::timeCheck(kTime2470500, params->param4, WRAP_SETUP_FUNCTION(MmeBoutarel, setup_function25)))
+ break;
if (params->param2) {
- UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75))
+ break;
params->param1 = 1;
params->param2 = 0;
@@ -1210,7 +1214,8 @@ IMPLEMENT_FUNCTION(28, MmeBoutarel, function28)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM(params->param3, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 1;
diff --git a/engines/lastexpress/entities/mmeboutarel.h b/engines/lastexpress/entities/mmeboutarel.h
index 772451ba15..0f6e6349fe 100644
--- a/engines/lastexpress/entities/mmeboutarel.h
+++ b/engines/lastexpress/entities/mmeboutarel.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_MMEBOUTAREL_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/pascale.cpp b/engines/lastexpress/entities/pascale.cpp
index a191273702..6e9f992390 100644
--- a/engines/lastexpress/entities/pascale.cpp
+++ b/engines/lastexpress/entities/pascale.cpp
@@ -30,10 +30,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -171,7 +169,7 @@ IMPLEMENT_FUNCTION(8, Pascale, welcomeSophieAndRebecca)
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(0, 4) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -185,8 +183,8 @@ IMPLEMENT_FUNCTION(9, Pascale, sitSophieAndRebecca)
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
- break;
+ callbackAction();
+ break;
case kActionDefault:
getEntities()->drawSequenceLeft(kEntityPascale, "012C1");
@@ -217,7 +215,7 @@ IMPLEMENT_FUNCTION(10, Pascale, welcomeCath)
getScenes()->loadSceneFromPosition(kCarRestaurant, 69);
}
- CALLBACK_ACTION();
+ callbackAction();
break;
case kAction4:
@@ -239,7 +237,7 @@ IMPLEMENT_FUNCTION(10, Pascale, welcomeCath)
getScenes()->loadSceneFromPosition(kCarRestaurant, 69);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -283,7 +281,7 @@ IMPLEMENT_FUNCTION(11, Pascale, function11)
getEntities()->clearSequences(kEntityPascale);
getData()->entityPosition = kPosition_5900;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -298,7 +296,7 @@ IMPLEMENT_FUNCTION(12, Pascale, chapter1)
case kActionNone:
setup_chapter1Handler();
- break;
+ break;
case kActionDefault:
getSavePoints()->addData(kEntityPascale, kAction239072064, 0);
@@ -366,7 +364,7 @@ IMPLEMENT_FUNCTION(13, Pascale, getMessageFromAugustToTyler)
getSavePoints()->push(kEntityPascale, kEntityVerges, kActionDeliverMessageToTyler);
ENTITY_PARAM(0, 1) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -382,7 +380,7 @@ IMPLEMENT_FUNCTION(14, Pascale, sitAnna)
case kActionExitCompartment:
getEntities()->updatePositionExit(kEntityPascale, kCarRestaurant, 62);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -433,7 +431,7 @@ IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna)
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(0, 2) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -486,7 +484,7 @@ IMPLEMENT_FUNCTION(16, Pascale, serveTatianaVassili)
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(0, 3) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -648,7 +646,7 @@ IMPLEMENT_FUNCTION(21, Pascale, chapter3)
case kActionNone:
setup_chapter3Handler();
- break;
+ break;
case kActionDefault:
getEntities()->clearSequences(kEntityPascale);
@@ -685,7 +683,7 @@ label_callback:
setCallback(2);
setup_welcomeSophieAndRebecca();
}
- break;
+ break;
case kActionCallback:
if (getCallback() == 1)
@@ -727,7 +725,7 @@ IMPLEMENT_FUNCTION(23, Pascale, function23)
ENTITY_PARAM(0, 7) = 0;
getEntities()->clearSequences(kEntityPascale);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -748,7 +746,7 @@ IMPLEMENT_FUNCTION(24, Pascale, welcomeAbbot)
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kAction10:
@@ -771,7 +769,7 @@ IMPLEMENT_FUNCTION(25, Pascale, chapter4)
case kActionNone:
setup_chapter4Handler();
- break;
+ break;
case kActionDefault:
getEntities()->clearSequences(kEntityPascale);
@@ -953,7 +951,7 @@ IMPLEMENT_FUNCTION(27, Pascale, function27)
ENTITY_PARAM(1, 1) = 0;
ENTITY_PARAM(1, 2) = 1;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -999,7 +997,7 @@ IMPLEMENT_FUNCTION(28, Pascale, messageFromAnna)
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(1, 2) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1037,7 +1035,7 @@ IMPLEMENT_FUNCTION(29, Pascale, function29)
case 2:
getData()->entityPosition = kPosition_850;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1075,7 +1073,7 @@ IMPLEMENT_FUNCTION(30, Pascale, function30)
case 2:
getData()->entityPosition = kPosition_5900;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1090,7 +1088,7 @@ IMPLEMENT_FUNCTION(31, Pascale, chapter5)
case kActionNone:
setup_chapter5Handler();
- break;
+ break;
case kActionDefault:
getEntities()->clearSequences(kEntityPascale);
@@ -1117,18 +1115,19 @@ IMPLEMENT_FUNCTION(33, Pascale, function33)
case kActionNone:
if (params->param4) {
- UPDATE_PARAM_PROC(params->param5, getState()->time, 4500)
+ if (Entity::updateParameter(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);
+ if (!Entity::updateParameter(params->param6, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 2;
diff --git a/engines/lastexpress/entities/pascale.h b/engines/lastexpress/entities/pascale.h
index 333ebcae3e..eaf0f3ba0c 100644
--- a/engines/lastexpress/entities/pascale.h
+++ b/engines/lastexpress/entities/pascale.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_PASCALE_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/rebecca.cpp b/engines/lastexpress/entities/rebecca.cpp
index b1a176b47e..5bcb6aef85 100644
--- a/engines/lastexpress/entities/rebecca.cpp
+++ b/engines/lastexpress/entities/rebecca.cpp
@@ -30,10 +30,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -179,7 +177,7 @@ IMPLEMENT_FUNCTION(15, Rebecca, function15)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityRebecca);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -261,7 +259,7 @@ IMPLEMENT_FUNCTION_I(16, Rebecca, function16, bool)
getSavePoints()->push(kEntityRebecca, kEntityTables3, kAction136455232);
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -334,7 +332,7 @@ IMPLEMENT_FUNCTION_I(17, Rebecca, function17, bool)
case 5:
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -343,7 +341,7 @@ IMPLEMENT_FUNCTION_I(17, Rebecca, function17, bool)
getData()->location = kLocationInsideCompartment;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -397,7 +395,7 @@ IMPLEMENT_FUNCTION(18, Rebecca, function18)
case 2:
case 3:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -473,7 +471,7 @@ IMPLEMENT_FUNCTION(19, Rebecca, function19)
case 5:
case 6:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -493,21 +491,21 @@ IMPLEMENT_FUNCTION_I(20, Rebecca, function20, TimeValue)
getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (!params->param2) {
params->param6 = 0;
} else {
- UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, 75)
+ if (Entity::updateParameter(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)) {
@@ -657,7 +655,7 @@ IMPLEMENT_FUNCTION(21, Rebecca, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Rebecca, setup_chapter1Handler));
break;
case kActionDefault:
@@ -685,7 +683,8 @@ IMPLEMENT_FUNCTION(22, Rebecca, chapter1Handler)
break;
case kActionNone:
- TIME_CHECK_CALLBACK_1(kTime1084500, params->param3, 1, setup_playSound, "REB1015");
+ if (Entity::timeCheckCallback(kTime1084500, params->param3, 1, "REB1015", WRAP_SETUP_FUNCTION_S(Rebecca, setup_playSound)))
+ break;
if (params->param4 == kTimeInvalid)
goto label_callback_4;
@@ -699,7 +698,7 @@ IMPLEMENT_FUNCTION(22, Rebecca, chapter1Handler)
if (params->param4 >= getState()->time) {
label_callback_4:
if (params->param1) {
- UPDATE_PARAM_CHECK(params->param5, getState()->time, 900)
+ if (Entity::updateParameterCheck(params->param5, getState()->time, 900)) {
if (getEntities()->isInSalon(kEntityPlayer)) {
setCallback(5);
setup_playSound("REB1013");
@@ -710,7 +709,9 @@ label_callback_4:
label_callback_5:
if (params->param2) {
- UPDATE_PARAM(params->param6, getState()->timeTicks, 90);
+ if (!Entity::updateParameter(params->param6, getState()->timeTicks, 90))
+ break;
+
getScenes()->loadSceneFromPosition(kCarRestaurant, 55);
} else {
params->param6 = 0;
@@ -774,7 +775,13 @@ IMPLEMENT_FUNCTION(23, Rebecca, function23)
break;
case kActionNone:
- TIME_CHECK_CALLBACK_2(kTime1111500, params->param2, 3, setup_enterExitCompartment, "623De", kObjectCompartmentE);
+ if (getState()->time > kTime1111500 && !params->param2) {
+ params->param2 = 1;
+ setCallback(3);
+ setup_enterExitCompartment("623De", kObjectCompartmentE);
+
+ break;
+ }
break;
case kActionDefault:
@@ -843,12 +850,13 @@ IMPLEMENT_FUNCTION(24, Rebecca, function24)
break;
case kActionNone:
- TIME_CHECK_SAVEPOINT(kTime1134000, params->param2, kEntityRebecca, kEntityServers0, kAction223712416);
+ Entity::timeCheckSavepoint(kTime1134000, params->param2, kEntityRebecca, kEntityServers0, kAction223712416);
if (!params->param1)
break;
- TIME_CHECK_CALLBACK(kTime1165500, params->param3, 6, setup_function19);
+ if (Entity::timeCheckCallback(kTime1165500, params->param3, 6, WRAP_SETUP_FUNCTION(Rebecca, setup_function19)))
+ break;
if (params->param4 != kTimeInvalid) {
if (getState()->time <= kTime1161000) {
@@ -965,10 +973,16 @@ IMPLEMENT_FUNCTION(26, Rebecca, function26)
break;
case kActionNone:
- TIME_CHECK_CALLBACK_3(kTime1224000, params->param2, 1, setup_updatePosition, "118H", kCarRestaurant, 52);
+ if (getState()->time > kTime1224000 && !params->param2) {
+ params->param2 = 1;
+ setCallback(1);
+ setup_updatePosition("118H", kCarRestaurant, 52);
+ break;
+ }
if (params->param1) {
- UPDATE_PARAM(params->param3, getState()->timeTicks, 90);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, 90))
+ break;
getScenes()->loadSceneFromPosition(kCarRestaurant, 51);
}
@@ -1223,7 +1237,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34)
params->param2 = (uint)getState()->time;
if (params->param2 >= getState()->time) {
- TIME_CHECK_CALLBACK(kTime2052000, params->param3, 1, setup_function19);
+ Entity::timeCheckCallback(kTime2052000, params->param3, 1, WRAP_SETUP_FUNCTION(Rebecca, setup_function19));
break;
}
}
@@ -1233,7 +1247,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34)
getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction223712416);
}
- TIME_CHECK_CALLBACK(kTime2052000, params->param3, 1, setup_function19);
+ Entity::timeCheckCallback(kTime2052000, params->param3, 1, WRAP_SETUP_FUNCTION(Rebecca, setup_function19));
break;
case kActionEndSound:
@@ -1632,7 +1646,7 @@ label_next:
label_callback_2:
if (params->param2)
- TIME_CHECK_CALLBACK(kTime2443500, params->param5, 3, setup_function19);
+ Entity::timeCheckCallback(kTime2443500, params->param5, 3, WRAP_SETUP_FUNCTION(Rebecca, setup_function19));
break;
case kActionEndSound:
@@ -1755,7 +1769,8 @@ IMPLEMENT_FUNCTION(48, Rebecca, function48)
case kActionNone:
if (params->param1) {
- UPDATE_PARAM(params->param3, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, 75))
+ break;
params->param1 = 0;
params->param2 = 1;
diff --git a/engines/lastexpress/entities/rebecca.h b/engines/lastexpress/entities/rebecca.h
index e91ee30d4d..885632f884 100644
--- a/engines/lastexpress/entities/rebecca.h
+++ b/engines/lastexpress/entities/rebecca.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_REBECCA_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/salko.cpp b/engines/lastexpress/entities/salko.cpp
index 63d995dc42..e8b4b4247b 100644
--- a/engines/lastexpress/entities/salko.cpp
+++ b/engines/lastexpress/entities/salko.cpp
@@ -33,10 +33,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -137,7 +135,7 @@ IMPLEMENT_FUNCTION_II(7, Salko, function7, CarIndex, EntityPosition)
break;
case kAction123668192:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -158,7 +156,7 @@ IMPLEMENT_FUNCTION(9, Salko, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Salko, setup_chapter1Handler));
break;
case kActionDefault:
@@ -301,7 +299,8 @@ IMPLEMENT_FUNCTION(15, Salko, chapter3Handler)
case kActionNone:
if (getState()->time < kTime2200500) {
- UPDATE_PARAM(params->param1, getState()->time, 81000);
+ if (!Entity::updateParameter(params->param1, getState()->time, 81000))
+ break;
setCallback(1);
setup_function16();
@@ -331,7 +330,8 @@ IMPLEMENT_FUNCTION(16, Salko, function16)
}
label_callback3:
- UPDATE_PARAM(params->param1, getState()->time, 4500);
+ if (!Entity::updateParameter(params->param1, getState()->time, 4500))
+ break;
getSavePoints()->push(kEntitySalko, kEntitySalko, kAction101169464);
break;
@@ -390,7 +390,7 @@ label_callback3:
getData()->entityPosition = kPosition_2740;
getEntities()->clearSequences(kEntitySalko);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
diff --git a/engines/lastexpress/entities/salko.h b/engines/lastexpress/entities/salko.h
index 6308211053..6ca73e39f6 100644
--- a/engines/lastexpress/entities/salko.h
+++ b/engines/lastexpress/entities/salko.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_SALKO_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/servers0.cpp b/engines/lastexpress/entities/servers0.cpp
index 989bddd662..73e0d34722 100644
--- a/engines/lastexpress/entities/servers0.cpp
+++ b/engines/lastexpress/entities/servers0.cpp
@@ -28,10 +28,7 @@
#include "lastexpress/game/savepoint.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.h"
-
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -113,11 +110,11 @@ IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection)
case kActionNone:
if (getData()->direction != kDirectionRight)
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMeCath:
@@ -163,7 +160,7 @@ IMPLEMENT_FUNCTION(7, Servers0, function7)
case 2:
getEntities()->clearSequences(kEntityServers0);
getData()->entityPosition = kPosition_5900;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -220,7 +217,7 @@ IMPLEMENT_FUNCTION(9, Servers0, function9)
ENTITY_PARAM(2, 2) = 0;
ENTITY_PARAM(1, 6) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -315,17 +312,17 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler)
case kActionNone:
if (params->param2) {
- UPDATE_PARAM_PROC(params->param3, getState()->time, 2700);
+ if (Entity::updateParameter(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)
+ if (Entity::updateParameter(params->param4, getState()->time, 4500)) {
ENTITY_PARAM(0, 5) = 1;
params->param1 = 0;
- UPDATE_PARAM_PROC_END
+ }
}
if (!getEntities()->isInKitchen(kEntityServers0) && !getEntities()->isSomebodyInsideRestaurantOrSalon())
@@ -486,7 +483,7 @@ IMPLEMENT_FUNCTION(25, Servers0, function25)
getEntities()->clearSequences(kEntityServers0);
ENTITY_PARAM(1, 3) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -647,7 +644,7 @@ IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder)
getEntities()->clearSequences(kEntityServers0);
ENTITY_PARAM(1, 5) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -693,7 +690,7 @@ IMPLEMENT_FUNCTION(30, Servers0, function30)
getEntities()->clearSequences(kEntityServers0);
ENTITY_PARAM(2, 4) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -736,10 +733,10 @@ IMPLEMENT_FUNCTION(32, Servers0, chapter4Handler)
break;
case kActionNone:
- UPDATE_PARAM_PROC(params->param2, getState()->time, 3600)
+ if (Entity::updateParameter(params->param2, getState()->time, 3600)) {
ENTITY_PARAM(1, 8) = 1;
params->param1 = 0;
- UPDATE_PARAM_PROC_END
+ }
if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
break;
@@ -859,7 +856,7 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak)
getEntities()->clearSequences(kEntityServers0);
ENTITY_PARAM(1, 7) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -902,7 +899,7 @@ IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck)
getEntities()->clearSequences(kEntityServers0);
ENTITY_PARAM(1, 8) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -972,7 +969,7 @@ void Servers0::handleServer(const SavePoint &savepoint, const char *name, Entity
getSavePoints()->push(kEntityServers0, entity, action);
*parameter = 0;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -1027,7 +1024,7 @@ void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
getEntities()->clearSequences(kEntityServers0);
*parameter = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
diff --git a/engines/lastexpress/entities/servers0.h b/engines/lastexpress/entities/servers0.h
index 2e9165a410..4c35637d65 100644
--- a/engines/lastexpress/entities/servers0.h
+++ b/engines/lastexpress/entities/servers0.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_SERVERS0_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/servers1.cpp b/engines/lastexpress/entities/servers1.cpp
index 995fbbc01b..a8f4c0233c 100644
--- a/engines/lastexpress/entities/servers1.cpp
+++ b/engines/lastexpress/entities/servers1.cpp
@@ -28,10 +28,7 @@
#include "lastexpress/game/savepoint.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.h"
-
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -143,7 +140,7 @@ IMPLEMENT_FUNCTION(7, Servers1, function7)
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(1, 2) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -219,7 +216,7 @@ IMPLEMENT_FUNCTION(9, Servers1, function9)
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(0, 1) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -265,7 +262,7 @@ IMPLEMENT_FUNCTION(10, Servers1, function10)
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(0, 2) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -469,7 +466,7 @@ IMPLEMENT_FUNCTION(20, Servers1, function20)
getEntities()->drawSequenceLeft(kEntityServers1, "BLANK");
ENTITY_PARAM(0, 7) = 0;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -566,10 +563,10 @@ IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler)
case kActionNone:
if (params->param2) {
- UPDATE_PARAM_PROC(params->param2, getState()->time, 900)
+ if (Entity::updateParameter(params->param2, getState()->time, 900)) {
ENTITY_PARAM(1, 5) = 1;
params->param1 = 0;
- UPDATE_PARAM_PROC_END
+ }
}
if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
@@ -705,7 +702,7 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
if (parameter2 != NULL)
*parameter2 = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -775,7 +772,7 @@ void Servers1::serveSalon(const SavePoint &savepoint, const char *seq1, const ch
getData()->entityPosition = kPosition_5900;
*parameter = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
diff --git a/engines/lastexpress/entities/servers1.h b/engines/lastexpress/entities/servers1.h
index 13b30696f0..c8f667ec5c 100644
--- a/engines/lastexpress/entities/servers1.h
+++ b/engines/lastexpress/entities/servers1.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_SERVERS1_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/sophie.cpp b/engines/lastexpress/entities/sophie.cpp
index 57bd491949..170090005f 100644
--- a/engines/lastexpress/entities/sophie.cpp
+++ b/engines/lastexpress/entities/sophie.cpp
@@ -27,38 +27,10 @@
#include "lastexpress/game/savepoint.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.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);
@@ -123,7 +95,7 @@ IMPLEMENT_FUNCTION_II(2, Sophie, updateEntity, CarIndex, EntityPosition)
break;
case kAction123668192:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -207,7 +179,7 @@ IMPLEMENT_FUNCTION(4, Sophie, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chaptersHandler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Sophie, setup_chaptersHandler));
break;
case kActionDefault:
@@ -220,27 +192,27 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(5, Sophie, function5)
- DEFAULT_ACTION_IMPLEMENTATION()
+ handleAction(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(6, Sophie, chapter2)
- CHAPTER_IMPLEMENTATION()
+ handleChapter(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(7, Sophie, chapter3)
- CHAPTER_IMPLEMENTATION()
+ handleChapter(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(8, Sophie, chapter4)
- CHAPTER_IMPLEMENTATION()
+ handleChapter(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(9, Sophie, function9)
- DEFAULT_ACTION_IMPLEMENTATION()
+ handleAction(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
@@ -274,4 +246,37 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_NULL_FUNCTION(12, Sophie)
+//////////////////////////////////////////////////////////////////////////
+// Helpers functions
+//////////////////////////////////////////////////////////////////////////
+
+void Sophie::handleAction(const SavePoint &savepoint) {
+ if (savepoint.action == kActionDefault) {
+ getData()->entityPosition = kPosition_4840;
+ getData()->location = kLocationInsideCompartment;
+ getData()->car = kCarRedSleeping;
+ getEntities()->clearSequences(kEntitySophie);
+ }
+}
+
+void Sophie::handleChapter(const SavePoint &savepoint) {
+ 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;
+ }
+}
+
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/sophie.h b/engines/lastexpress/entities/sophie.h
index c2ca348027..188788bb9b 100644
--- a/engines/lastexpress/entities/sophie.h
+++ b/engines/lastexpress/entities/sophie.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_SOPHIE_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
@@ -88,6 +87,10 @@ public:
DECLARE_FUNCTION(chapter5Handler)
DECLARE_NULL_FUNCTION()
+
+private:
+ void handleAction(const SavePoint &savepoint);
+ void handleChapter(const SavePoint &savepoint);
};
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/tables.cpp b/engines/lastexpress/entities/tables.cpp
index 06ea4c597c..4f8d2b954d 100644
--- a/engines/lastexpress/entities/tables.cpp
+++ b/engines/lastexpress/entities/tables.cpp
@@ -29,10 +29,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/tables.h b/engines/lastexpress/entities/tables.h
index 7fcfc0499e..c213aac978 100644
--- a/engines/lastexpress/entities/tables.h
+++ b/engines/lastexpress/entities/tables.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_TABLES_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/tatiana.cpp b/engines/lastexpress/entities/tatiana.cpp
index c8901b3e30..432def6253 100644
--- a/engines/lastexpress/entities/tatiana.cpp
+++ b/engines/lastexpress/entities/tatiana.cpp
@@ -35,10 +35,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -192,7 +190,7 @@ IMPLEMENT_FUNCTION(14, Tatiana, function14)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityTatiana);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -228,7 +226,7 @@ IMPLEMENT_FUNCTION(15, Tatiana, function15)
getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentB, true);
getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -246,12 +244,13 @@ IMPLEMENT_FUNCTION_I(16, Tatiana, function16, uint32)
getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (params->param2) {
- UPDATE_PARAM(params->param5, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75))
+ break;
params->param2 = 0;
params->param3 = 1;
@@ -342,7 +341,7 @@ IMPLEMENT_FUNCTION(17, Tatiana, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Tatiana, setup_chapter1Handler));
break;
case kActionDefault:
@@ -375,10 +374,10 @@ IMPLEMENT_FUNCTION(18, Tatiana, function18)
}
if (!params->param1) {
- UPDATE_PARAM_PROC(params->param3, getState()->time, 4500)
+ if (Entity::updateParameter(params->param3, getState()->time, 4500)) {
getEntities()->drawSequenceRight(kEntityTatiana, "806DS");
params->param1 = 1;
- UPDATE_PARAM_PROC_END
+ }
}
}
@@ -386,14 +385,14 @@ IMPLEMENT_FUNCTION(18, Tatiana, function18)
getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction157159392);
getEntities()->clearSequences(kEntityTatiana);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
case kActionExitCompartment:
getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction188784532);
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -425,27 +424,29 @@ IMPLEMENT_FUNCTION(19, Tatiana, chapter1Handler)
if (getSoundQueue()->isBuffered(kEntityTatiana) || !params->param4 || params->param3 == 2 || getSoundQueue()->isBuffered("TAT1066"))
goto label_tatiana_chapter1_2;
- UPDATE_PARAM_PROC(params->param5, getState()->timeTicks, 450)
+ if (Entity::updateParameter(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)
+ if (Entity::updateParameter(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);
+ Entity::timeCheckSavepoint(kTime1084500, params->param7, kEntityTatiana, kEntityPascale, kAction257489762);
if (params->param1) {
- UPDATE_PARAM(params->param8, getState()->timeTicks, 90);
+ if (!Entity::updateParameter(params->param8, getState()->timeTicks, 90))
+ break;
+
getScenes()->loadSceneFromPosition(kCarRestaurant, 65);
} else {
params->param8 = 0;
@@ -614,7 +615,7 @@ IMPLEMENT_FUNCTION(22, Tatiana, function22)
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)
+ if (Entity::updateParameterTime(kTime1233000, ((!getEvent(kEventTatianaAskMatchSpeakRussian) && !getEvent(kEventTatianaAskMatch)) || getEntities()->isInGreenCarEntrance(kEntityPlayer)), params->param1, 0)) {
label_update:
if (!getEvent(kEventTatianaAskMatchSpeakRussian)
&& !getEvent(kEventTatianaAskMatch)
@@ -623,7 +624,7 @@ label_update:
getObjects()->update(kObject25, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorForward);
getObjects()->update(kObjectTrainTimeTable, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorForward);
}
- UPDATE_PARAM_PROC_END
+ }
params->param1 = kTimeInvalid;
@@ -1022,7 +1023,7 @@ IMPLEMENT_FUNCTION(32, Tatiana, chapter3Handler)
}
if (parameters->param4 && parameters->param5) {
- UPDATE_PARAM_CHECK(parameters->param4, getState()->time, 6300)
+ if (Entity::updateParameterCheck(parameters->param4, getState()->time, 6300)) {
if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->location = kLocationOutsideCompartment;
@@ -1283,18 +1284,19 @@ IMPLEMENT_FUNCTION(37, Tatiana, function37)
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)
+ if (Entity::updateParameterTime(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);
+ if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75))
+ break;
getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal);
@@ -1403,7 +1405,8 @@ IMPLEMENT_FUNCTION(38, Tatiana, function38)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->time, 450);
+ if (!Entity::updateParameter(params->param1, getState()->time, 450))
+ break;
getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentF, true);
@@ -1535,7 +1538,7 @@ IMPLEMENT_FUNCTION(40, Tatiana, function40)
if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)
|| getData()->car != getEntityData(kEntityPlayer)->car
|| getEntities()->updateEntity(kEntityTatiana, kCarKronos, kPosition_9270))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMe:
@@ -1547,7 +1550,7 @@ IMPLEMENT_FUNCTION(40, Tatiana, function40)
case kActionDefault:
if (getEntities()->updateEntity(kEntityTatiana, kCarKronos, kPosition_9270))
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -1595,7 +1598,7 @@ IMPLEMENT_FUNCTION(41, Tatiana, function41)
}
getEntities()->clearSequences(kEntityTatiana);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -1629,7 +1632,7 @@ IMPLEMENT_FUNCTION(41, Tatiana, function41)
case 6:
getEntities()->clearSequences(kEntityTatiana);
- CALLBACK_ACTION();
+ callbackAction();
break;
case 4:
@@ -1952,7 +1955,8 @@ IMPLEMENT_FUNCTION(48, Tatiana, function48)
if (!params->param1 || getSoundQueue()->isBuffered(kEntityTatiana))
goto label_end;
- UPDATE_PARAM_GOTO(params->param2, getState()->timeTicks, 5 * (3 * rnd(5) + 30), label_end);
+ if (!Entity::updateParameter(params->param2, getState()->timeTicks, 5 * (3 * rnd(5) + 30)))
+ goto label_end;
getSound()->playSound(kEntityTatiana, "LIB012", kFlagDefault);
params->param2 = 0;
@@ -2199,7 +2203,8 @@ IMPLEMENT_FUNCTION(54, Tatiana, function54)
}
if (params->param1 > 3) {
- UPDATE_PARAM(params->param3, getState()->timeTicks, 225);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, 225))
+ break;
params->param1 = 0;
params->param3 = 0;
diff --git a/engines/lastexpress/entities/tatiana.h b/engines/lastexpress/entities/tatiana.h
index c457d49b1e..8ec69db5e9 100644
--- a/engines/lastexpress/entities/tatiana.h
+++ b/engines/lastexpress/entities/tatiana.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_TATIANA_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/train.cpp b/engines/lastexpress/entities/train.cpp
index bced1da62b..e3f530ef25 100644
--- a/engines/lastexpress/entities/train.cpp
+++ b/engines/lastexpress/entities/train.cpp
@@ -32,10 +32,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -269,18 +267,20 @@ IMPLEMENT_FUNCTION(8, Train, process)
if ((getEntities()->isPlayerInCar(kCarGreenSleeping) || getEntities()->isPlayerInCar(kCarRedSleeping))
&& params->param4 && !params->param5) {
- params->param4 -= 1;
+ params->param4 -= 1;
- if (!params->param4 && getProgress().jacket == kJacketGreen) {
+ if (!params->param4 && getProgress().jacket == kJacketGreen) {
- getAction()->playAnimation(isNight() ? kEventCathSmokeNight : kEventCathSmokeDay);
- params->param5 = 1;
- getScenes()->processScene();
- }
+ getAction()->playAnimation(isNight() ? kEventCathSmokeNight : kEventCathSmokeDay);
+ params->param5 = 1;
+ getScenes()->processScene();
+ }
}
if (params->param6) {
- UPDATE_PARAM_GOTO(params1->param7, getState()->time, 900, label_process);
+ if (!Entity::updateParameter(params1->param7, getState()->time, 900))
+ goto label_process;
+
getScenes()->loadSceneFromPosition(kCarRestaurant, 58);
}
@@ -552,7 +552,7 @@ void Train::handleCompartmentAction() {
ENTITY_PARAM(0, 8) = params->param1;
- CALLBACK_ACTION();
+ callbackAction();
}
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/lastexpress/entities/train.h b/engines/lastexpress/entities/train.h
index ea9e1d7a07..4b8bc10c1a 100644
--- a/engines/lastexpress/entities/train.h
+++ b/engines/lastexpress/entities/train.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_TRAIN_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/vassili.cpp b/engines/lastexpress/entities/vassili.cpp
index 22f41afa92..4695f8831f 100644
--- a/engines/lastexpress/entities/vassili.cpp
+++ b/engines/lastexpress/entities/vassili.cpp
@@ -35,10 +35,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -85,7 +83,7 @@ IMPLEMENT_FUNCTION(4, Vassili, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Vassili, setup_chapter1Handler));
break;
case kActionDefault:
@@ -146,7 +144,8 @@ IMPLEMENT_FUNCTION(6, Vassili, function6)
case kActionNone:
if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
- UPDATE_PARAM_GOTO(params->param3, getState()->timeTicks, params->param1, label_function7);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, params->param1))
+ goto label_function7;
setCallback(1);
setup_draw("303B");
@@ -402,7 +401,8 @@ IMPLEMENT_FUNCTION(13, Vassili, sleeping)
case kActionNone:
if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
- UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, params->param1))
+ break;
setCallback(1);
setup_draw("303B");
@@ -461,7 +461,8 @@ IMPLEMENT_FUNCTION(15, Vassili, stealEgg)
case kActionNone:
if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
- UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, params->param1))
+ break;
setCallback(1);
setup_draw("303B");
@@ -545,7 +546,8 @@ IMPLEMENT_FUNCTION(17, Vassili, chapter4Handler)
case kActionNone:
if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) {
- UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1);
+ if (!Entity::updateParameter(params->param3, getState()->timeTicks, params->param1))
+ break;
setCallback(1);
setup_draw("303B");
diff --git a/engines/lastexpress/entities/vassili.h b/engines/lastexpress/entities/vassili.h
index 843a065174..d006770f7b 100644
--- a/engines/lastexpress/entities/vassili.h
+++ b/engines/lastexpress/entities/vassili.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_VASSILI_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/verges.cpp b/engines/lastexpress/entities/verges.cpp
index 8246f85145..867f122d8f 100644
--- a/engines/lastexpress/entities/verges.cpp
+++ b/engines/lastexpress/entities/verges.cpp
@@ -32,10 +32,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -102,11 +100,11 @@ IMPLEMENT_FUNCTION(3, Verges, callbackActionOnDirection)
case kActionNone:
if (getData()->direction != kDirectionRight)
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExitCompartment:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMeCath:
@@ -219,7 +217,7 @@ switch (savepoint.action) {
break;
case 6:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -241,12 +239,13 @@ IMPLEMENT_FUNCTION_IIS(10, Verges, function10, CarIndex, EntityPosition)
}
if (getEntities()->updateEntity(kEntityVerges, (CarIndex)params->param1, (EntityPosition)params->param2)) {
- CALLBACK_ACTION();
+ callbackAction();
break;
}
if (params->param6) {
- UPDATE_PARAM(params->param8, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75))
+ break;
getSound()->playSound(kEntityVerges, (char *)&params->seq);
@@ -266,7 +265,7 @@ IMPLEMENT_FUNCTION_IIS(10, Verges, function10, CarIndex, EntityPosition)
}
if (getEntities()->updateEntity(kEntityVerges, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -337,7 +336,7 @@ IMPLEMENT_FUNCTION(11, Verges, function11)
getObjects()->update(kObject104, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
getObjects()->update(kObject105, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
}
@@ -397,7 +396,7 @@ IMPLEMENT_FUNCTION(12, Verges, function12)
getData()->entityPosition = kPosition_850;
getEntities()->clearSequences(kEntityVerges);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -438,7 +437,7 @@ IMPLEMENT_FUNCTION_I(13, Verges, function13, bool)
getEntities()->clearSequences(kEntityVerges);
getScenes()->loadSceneFromPosition(kCarBaggage, 91);
- CALLBACK_ACTION();
+ callbackAction();
}
break;
}
@@ -462,7 +461,7 @@ IMPLEMENT_FUNCTION_IS(15, Verges, function15, EntityIndex)
if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2) && !getEntities()->isPlayerPosition(kCarRedSleeping, 2))
getData()->entityPosition = kPosition_2088;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -499,7 +498,7 @@ IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex)
if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2) && !getEntities()->isPlayerPosition(kCarRedSleeping, 2))
getData()->entityPosition = kPosition_2088;
- CALLBACK_ACTION();
+ callbackAction();
}
break;
@@ -559,7 +558,7 @@ IMPLEMENT_FUNCTION(17, Verges, function17)
case 4:
ENTITY_PARAM(0, 3) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -573,7 +572,7 @@ IMPLEMENT_FUNCTION(18, Verges, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Verges, setup_chapter1Handler));
break;
case kActionDefault:
@@ -651,7 +650,7 @@ IMPLEMENT_FUNCTION(22, Verges, function22)
break;
case 5:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -697,7 +696,7 @@ IMPLEMENT_FUNCTION(24, Verges, policeGettingOffTrain)
break;
case kActionEndSound:
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionDefault:
@@ -818,7 +817,7 @@ IMPLEMENT_FUNCTION(25, Verges, function25)
case 11:
ENTITY_PARAM(0, 7) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
case 6:
@@ -908,10 +907,12 @@ label_callback3:
if (params->param6)
goto label_callback12;
- TIME_CHECK_CALLBACK_1(kTimeChapter1, params->param7, 4, setup_function9, "TRA1001");
+ if (Entity::timeCheckCallback(kTimeChapter1, params->param7, 4, "TRA1001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback4:
- TIME_CHECK_CALLBACK(kTime1089000, params->param8, 5, setup_function12);
+ if (Entity::timeCheckCallback(kTime1089000, params->param8, 5, WRAP_SETUP_FUNCTION(Verges, setup_function12)))
+ break;
params->param8 = 1;
@@ -922,16 +923,20 @@ label_callback4:
}
label_callback8:
- TIME_CHECK_CALLBACK_1(kTime1107000, CURRENT_PARAM(1, 1), 9, setup_function9, "TRA1001A");
+ if (Entity::timeCheckCallback(kTime1107000, CURRENT_PARAM(1, 1), 9, "TRA1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback9:
- TIME_CHECK_CALLBACK_1(kTime1134000, CURRENT_PARAM(1, 2), 10, setup_function9, "TRA1002");
+ if (Entity::timeCheckCallback(kTime1134000, CURRENT_PARAM(1, 2), 10, "TRA1002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback10:
- TIME_CHECK_CALLBACK_1(kTime1165500, CURRENT_PARAM(1, 3), 11, setup_function9, "TRA1003");
+ if (Entity::timeCheckCallback(kTime1165500, CURRENT_PARAM(1, 3), 11, "TRA1003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback11:
- TIME_CHECK_CALLBACK_1(kTime1225800, CURRENT_PARAM(1, 4), 12, setup_function9, "TRA1004");
+ if (Entity::timeCheckCallback(kTime1225800, CURRENT_PARAM(1, 4), 12, "TRA1004", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback12:
if (ENTITY_PARAM(0, 5) && !params->param2) {
@@ -1083,7 +1088,8 @@ IMPLEMENT_FUNCTION(28, Verges, chapter2Handler)
}
label_callback_1:
- TIME_CHECK_CALLBACK_1(kTime1818900, params->param1, 2, setup_function9, "Tra2177");
+ if (Entity::timeCheckCallback(kTime1818900, params->param1, 2, "Tra2177", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_2:
if (params->param2 == kTimeInvalid || !getState()->time)
@@ -1224,7 +1230,7 @@ IMPLEMENT_FUNCTION_S(30, Verges, function30)
break;
case 4:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1266,7 +1272,7 @@ IMPLEMENT_FUNCTION(31, Verges, function31)
getProgress().field_48 = 1;
ENTITY_PARAM(0, 4) = 0;
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1280,7 +1286,12 @@ IMPLEMENT_FUNCTION(32, Verges, function32)
break;
case kActionNone:
- TIME_CHECK_CALLBACK_3(kTime2263500, params->param1, 5, setup_function10, kCarRedSleeping, kPosition_9460, "TRA3006");
+ if (getState()->time > kTime2263500 && !params->param1) {
+ params->param1 = 1;
+ setCallback(5);
+ setup_function10(kCarRedSleeping, kPosition_9460, "TRA3006");
+ break;
+ }
break;
case kActionDefault:
@@ -1343,7 +1354,7 @@ IMPLEMENT_FUNCTION(32, Verges, function32)
break;
case 6:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1440,25 +1451,31 @@ label_callback_2:
}
label_callback_3:
- TIME_CHECK_CALLBACK_1(kTime1971000, params->param1, 4, setup_function9, "Tra3001");
+ if (Entity::timeCheckCallback(kTime1971000, params->param1, 4, "Tra3001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_4:
- TIME_CHECK_CALLBACK_1(kTime1998000, params->param2, 5, setup_function9, "Tra3010a");
+ if (Entity::timeCheckCallback(kTime1998000, params->param2, 5, "Tra3010a", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_5:
- TIME_CHECK_CALLBACK(kTime2016000, params->param3, 6, setup_function35);
+ if (Entity::timeCheckCallback(kTime2016000, params->param3, 6, WRAP_SETUP_FUNCTION(Verges, setup_function35)))
+ break;
label_callback_6:
- TIME_CHECK_CALLBACK_1(kTime2070000, params->param4, 7, setup_function9, "Tra3002");
+ if (Entity::timeCheckCallback(kTime2070000, params->param4, 7, "Tra3002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_7:
- TIME_CHECK_CALLBACK_1(kTime2142000, params->param5, 8, setup_function9, "Tra3003");
+ if (Entity::timeCheckCallback(kTime2142000, params->param5, 8, "Tra3003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_8:
- TIME_CHECK_CALLBACK_1(kTime2173500, params->param6, 9, setup_function30, "Tra3012");
+ if (Entity::timeCheckCallback(kTime2173500, params->param6, 9, "Tra3012", WRAP_SETUP_FUNCTION_S(Verges, setup_function30)))
+ break;
label_callback_9:
- TIME_CHECK_CALLBACK(kTime2218500, params->param7, 10, setup_function32);
+ Entity::timeCheckCallback(kTime2218500, params->param7, 10, WRAP_SETUP_FUNCTION(Verges, setup_function32));
break;
case kActionOpenDoor:
@@ -1548,7 +1565,7 @@ IMPLEMENT_FUNCTION(35, Verges, function35)
break;
case 6:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1605,27 +1622,32 @@ label_callback_1:
}
label_callback_2:
- TIME_CHECK_CALLBACK_1(kTime2349000, params->param1, 3, setup_function9, "Tra1001");
+ if (Entity::timeCheckCallback(kTime2349000, params->param1, 3, "Tra1001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_3:
- TIME_CHECK_CALLBACK_1(kTime2378700, params->param2, 4, setup_function9, "Tra4001");
+ if (Entity::timeCheckCallback(kTime2378700, params->param2, 4, "Tra4001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_4:
- TIME_CHECK_CALLBACK_1(kTime2403000, params->param3, 5, setup_function9, "Tra1001A");
+ if (Entity::timeCheckCallback(kTime2403000, params->param3, 5, "Tra1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_5:
- TIME_CHECK_CALLBACK_1(kTime2414700, params->param4, 6, setup_function9, "Tra4002");
+ if (Entity::timeCheckCallback(kTime2414700, params->param4, 6, "Tra4002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_6:
- TIME_CHECK_CALLBACK_1(kTime2484000, params->param5, 7, setup_function9, "Tra4003");
+ if (Entity::timeCheckCallback(kTime2484000, params->param5, 7, "Tra4003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
label_callback_7:
- TIME_CHECK_CALLBACK_1(kTime2511000, params->param6, 8, setup_function9, "Tra4004");
+ if (Entity::timeCheckCallback(kTime2511000, params->param6, 8, "Tra4004", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)))
+ break;
}
label_callback_8:
- TIME_CHECK_CALLBACK_1(kTime2538000, params->param7, 9, setup_function9, "Tra4005");
-
+ Entity::timeCheckCallback(kTime2538000, params->param7, 9, "Tra4005", WRAP_SETUP_FUNCTION_S(Verges, setup_function9));
break;
case kActionOpenDoor:
@@ -1887,7 +1909,7 @@ void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *so
break;
case 6:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
diff --git a/engines/lastexpress/entities/verges.h b/engines/lastexpress/entities/verges.h
index 17a3c8ac40..82381043d3 100644
--- a/engines/lastexpress/entities/verges.h
+++ b/engines/lastexpress/entities/verges.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_VERGES_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/vesna.cpp b/engines/lastexpress/entities/vesna.cpp
index 7a1f1d3195..f29bce8b2b 100644
--- a/engines/lastexpress/entities/vesna.cpp
+++ b/engines/lastexpress/entities/vesna.cpp
@@ -32,10 +32,7 @@
#include "lastexpress/game/scenes.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.h"
-
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -134,7 +131,7 @@ IMPLEMENT_FUNCTION_II(7, Vesna, updateEntity2, CarIndex, EntityPosition)
break;
case kAction123668192:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -165,7 +162,8 @@ IMPLEMENT_FUNCTION(11, Vesna, function11)
case kActionNone:
if (parameters->param3) {
- UPDATE_PARAM(parameters->param7, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(parameters->param7, getState()->timeTicks, 75))
+ break;
parameters->param2 = 1;
parameters->param3 = 0;
@@ -245,7 +243,7 @@ IMPLEMENT_FUNCTION(11, Vesna, function11)
case kAction55996766:
case kAction101687594:
- CALLBACK_ACTION();
+ callbackAction();
break;
}
IMPLEMENT_FUNCTION_END
@@ -257,7 +255,7 @@ IMPLEMENT_FUNCTION(12, Vesna, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Vesna, setup_chapter1Handler));
break;
case kActionDefault:
@@ -458,7 +456,7 @@ IMPLEMENT_FUNCTION(18, Vesna, function18)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityVesna);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -514,7 +512,8 @@ IMPLEMENT_FUNCTION(20, Vesna, chapter3Handler)
}
if (parameters->param2) {
- UPDATE_PARAM(parameters->param8, getState()->timeTicks, 75);
+ if (!Entity::updateParameter(parameters->param8, getState()->timeTicks, 75))
+ break;
parameters->param1 = 1;
parameters->param2 = 0;
@@ -711,7 +710,7 @@ IMPLEMENT_FUNCTION(21, Vesna, function21)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityVesna);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -1083,13 +1082,14 @@ IMPLEMENT_FUNCTION(30, Vesna, function30)
case kActionNone:
if (!params->param1) {
- UPDATE_PARAM_PROC(params->param3, getState()->timeTicks, 120)
+ if (Entity::updateParameter(params->param3, getState()->timeTicks, 120)) {
getSound()->playSound(kEntityVesna, "Ves50001", kFlagDefault);
params->param1 = 1;
- UPDATE_PARAM_PROC_END
+ }
}
- UPDATE_PARAM(params->param4, getState()->timeTicks, 180);
+ if (!Entity::updateParameter(params->param4, getState()->timeTicks, 180))
+ break;
setCallback(1);
setup_savegame(kSavegameTypeEvent, kEventCathVesnaTrainTopKilled);
diff --git a/engines/lastexpress/entities/vesna.h b/engines/lastexpress/entities/vesna.h
index a09664096d..025d45882e 100644
--- a/engines/lastexpress/entities/vesna.h
+++ b/engines/lastexpress/entities/vesna.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_VESNA_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/entities/yasmin.cpp b/engines/lastexpress/entities/yasmin.cpp
index 45e5e11568..1d280f51e0 100644
--- a/engines/lastexpress/entities/yasmin.cpp
+++ b/engines/lastexpress/entities/yasmin.cpp
@@ -28,10 +28,8 @@
#include "lastexpress/game/savepoint.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
namespace LastExpress {
@@ -132,7 +130,7 @@ IMPLEMENT_FUNCTION(6, Yasmin, function6)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityYasmin);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -172,7 +170,7 @@ IMPLEMENT_FUNCTION(7, Yasmin, function7)
getData()->location = kLocationInsideCompartment;
getEntities()->clearSequences(kEntityYasmin);
- CALLBACK_ACTION();
+ callbackAction();
break;
}
break;
@@ -186,7 +184,7 @@ IMPLEMENT_FUNCTION(8, Yasmin, chapter1)
break;
case kActionNone:
- TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler);
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Yasmin, setup_chapter1Handler));
break;
case kActionDefault:
@@ -204,12 +202,22 @@ IMPLEMENT_FUNCTION(9, Yasmin, chapter1Handler)
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);
+ if (Entity::timeCheckCallback(kTime1093500, params->param1, 1, WRAP_SETUP_FUNCTION(Yasmin, setup_function6)))
+ break;
+
+ if (Entity::timeCheckCallback(kTime1161000, params->param2, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function7)))
+ break;
+
+ if (Entity::timeCheckPlaySoundUpdatePosition(kTime1162800, params->param3, 4, "Har1102", kPosition_4070))
+ break;
+
+ if (Entity::timeCheckCallback(kTime1165500, params->param4, 5, "Har1104", WRAP_SETUP_FUNCTION_S(Yasmin, setup_playSound)))
+ break;
+
+ if (Entity::timeCheckCallback(kTime1174500, params->param5, 6, "Har1106", WRAP_SETUP_FUNCTION_S(Yasmin, setup_playSound)))
+ break;
+
+ Entity::timeCheckCallback(kTime1183500, params->param6, 7, WRAP_SETUP_FUNCTION(Yasmin, setup_function6));
break;
case kActionCallback:
@@ -224,23 +232,27 @@ IMPLEMENT_FUNCTION(9, Yasmin, chapter1Handler)
break;
case 2:
- TIME_CHECK_CALLBACK(kTime1161000, params->param2, 3, setup_function7);
+ if (Entity::timeCheckCallback(kTime1161000, params->param2, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function7)))
+ break;
// Fallback to case 3
case 3:
- TIME_CHECK_PLAYSOUND_UPDATEPOSITION(kTime1162800, params->param3, 4, "Har1102", kPosition_4070);
+ if (Entity::timeCheckPlaySoundUpdatePosition(kTime1162800, params->param3, 4, "Har1102", kPosition_4070))
+ break;
// Fallback to case 4
case 4:
- TIME_CHECK_CALLBACK_1(kTime1165500, params->param4, 5, setup_playSound, "Har1104");
+ if (Entity::timeCheckCallback(kTime1165500, params->param4, 5, "Har1104", WRAP_SETUP_FUNCTION_S(Yasmin, setup_playSound)))
+ break;
// Fallback to case 5
case 5:
- TIME_CHECK_CALLBACK_1(kTime1174500, params->param5, 6, setup_playSound, "Har1106");
+ if (Entity::timeCheckCallback(kTime1174500, params->param5, 6, "Har1106", WRAP_SETUP_FUNCTION_S(Yasmin, setup_playSound)))
+ break;
// Fallback to case 6
case 6:
- TIME_CHECK_CALLBACK(kTime1183500, params->param6, 7, setup_function6);
+ Entity::timeCheckCallback(kTime1183500, params->param6, 7, WRAP_SETUP_FUNCTION(Yasmin, setup_function6));
break;
}
break;
@@ -281,7 +293,8 @@ IMPLEMENT_FUNCTION(12, Yasmin, chapter2Handler)
break;
case kActionNone:
- TIME_CHECK_CALLBACK(kTime1759500, params->param1, 1, setup_function7);
+ if (Entity::timeCheckCallback(kTime1759500, params->param1, 1, WRAP_SETUP_FUNCTION(Yasmin, setup_function7)))
+ break;
if (getState()->time > kTime1800000 && !params->param2) {
params->param2 = 1;
@@ -334,9 +347,13 @@ IMPLEMENT_FUNCTION(14, Yasmin, chapter3Handler)
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);
+ if (Entity::timeCheckCallback(kTime2062800, params->param1, 1, WRAP_SETUP_FUNCTION(Yasmin, setup_function6)))
+ break;
+
+ if (Entity::timeCheckCallback(kTime2106000, params->param2, 2, WRAP_SETUP_FUNCTION(Yasmin, setup_function7)))
+ break;
+
+ Entity::timeCheckCallback(kTime2160000, params->param3, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function6));
break;
case kActionCallback:
@@ -345,11 +362,12 @@ IMPLEMENT_FUNCTION(14, Yasmin, chapter3Handler)
break;
case 1:
- TIME_CHECK_CALLBACK(kTime2106000, params->param2, 2, setup_function7);
+ if (Entity::timeCheckCallback(kTime2106000, params->param2, 2, WRAP_SETUP_FUNCTION(Yasmin, setup_function7)))
+ break;
// Fallback to case 2
case 2:
- TIME_CHECK_CALLBACK(kTime2160000, params->param3, 3, setup_function6);
+ Entity::timeCheckCallback(kTime2160000, params->param3, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function6));
break;
}
break;
@@ -381,8 +399,10 @@ IMPLEMENT_FUNCTION(16, Yasmin, chapter4Handler)
break;
case kActionNone:
- TIME_CHECK_CALLBACK(kTime2457000, params->param1, 1, setup_function7);
- TIME_CHECK_CALLBACK(kTime2479500, params->param2, 3, setup_function6);
+ if (Entity::timeCheckCallback(kTime2457000, params->param1, 1, WRAP_SETUP_FUNCTION(Yasmin, setup_function7)))
+ break;
+
+ Entity::timeCheckCallback(kTime2479500, params->param2, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function6));
break;
case kActionCallback:
@@ -397,7 +417,7 @@ IMPLEMENT_FUNCTION(16, Yasmin, chapter4Handler)
break;
case 2:
- TIME_CHECK_CALLBACK(kTime2479500, params->param2, 3, setup_function6);
+ Entity::timeCheckCallback(kTime2479500, params->param2, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function6));
break;
}
break;
@@ -445,7 +465,9 @@ IMPLEMENT_FUNCTION(20, Yasmin, function20)
break;
case kActionNone:
- UPDATE_PARAM(params->param1, getState()->time, 2700);
+ if (!Entity::updateParameter(params->param1, getState()->time, 2700))
+ break;
+
setup_function21();
break;
@@ -472,7 +494,7 @@ IMPLEMENT_FUNCTION(21, Yasmin, function21)
case kActionNone:
case kActionDefault:
if (getEntities()->updateEntity(kEntityYasmin, (CarIndex)params->param1, (EntityPosition)params->param2))
- CALLBACK_ACTION();
+ callbackAction();
break;
case kActionExcuseMeCath:
diff --git a/engines/lastexpress/entities/yasmin.h b/engines/lastexpress/entities/yasmin.h
index e943a8b158..b1413f5c2f 100644
--- a/engines/lastexpress/entities/yasmin.h
+++ b/engines/lastexpress/entities/yasmin.h
@@ -24,7 +24,6 @@
#define LASTEXPRESS_YASMIN_H
#include "lastexpress/entities/entity.h"
-#include "lastexpress/entities/entity_intern.h"
namespace LastExpress {
diff --git a/engines/lastexpress/fight/fight.cpp b/engines/lastexpress/fight/fight.cpp
index b832d46a60..b00c1732e7 100644
--- a/engines/lastexpress/fight/fight.cpp
+++ b/engines/lastexpress/fight/fight.cpp
@@ -31,6 +31,7 @@
#include "lastexpress/data/cursor.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"
@@ -38,6 +39,7 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
+#include "lastexpress/sound/sound.h"
#include "lastexpress/graphics.h"
#include "lastexpress/helpers.h"
@@ -53,6 +55,8 @@ Fight::FightData::FightData() {
index = 0;
isFightRunning = false;
+
+ memset(&sequences, 0, sizeof(sequences));
}
Fight::FightData::~FightData() {
@@ -399,6 +403,9 @@ end_load:
}
void Fight::setOpponents() {
+ if (!_data)
+ error("[Fight::setOpponents] Data not initialized");
+
_data->player->setOpponent(_data->opponent);
_data->opponent->setOpponent(_data->player);
diff --git a/engines/lastexpress/fight/fighter.cpp b/engines/lastexpress/fight/fighter.cpp
index bae7728a2b..4b1cddabd4 100644
--- a/engines/lastexpress/fight/fighter.cpp
+++ b/engines/lastexpress/fight/fighter.cpp
@@ -53,20 +53,20 @@ Fighter::Fighter(LastExpressEngine *engine) : _engine(engine) {
}
Fighter::~Fighter() {
- clearSequences();
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Cleanup
-//////////////////////////////////////////////////////////////////////////
-void Fighter::clearSequences() {
// The original game resets the function pointers to default values, just before deleting the struct
getScenes()->removeAndRedraw(&_frame, false);
// Free sequences
- for (int i = 0; i < (int)_sequences.size(); i++)
+ for (uint i = 0; i < _sequences.size(); i++)
SAFE_DELETE(_sequences[i]);
+
+ // Zero-out passed pointers
+ _sequence = NULL;
+ _opponent = NULL;
+ _fight = NULL;
+
+ _engine = NULL;
}
//////////////////////////////////////////////////////////////////////////
@@ -113,6 +113,9 @@ void Fighter::draw() {
// Processing
//////////////////////////////////////////////////////////////////////////
void Fighter::process() {
+ if (!_fight)
+ error("[Fighter::handleAction] Fighter not initialized properly");
+
if (!_sequence) {
if (_frame) {
getScenes()->removeFromQueue(_frame);
@@ -188,6 +191,9 @@ void Fighter::process() {
// Default actions
//////////////////////////////////////////////////////////////////////////
void Fighter::handleAction(FightAction action) {
+ if (!_opponent || !_fight)
+ error("[Fighter::handleAction] Fighter not initialized properly");
+
switch (action) {
default:
return;
@@ -243,7 +249,10 @@ void Opponent::update() {
// Helpers
//////////////////////////////////////////////////////////////////////////
bool Fighter::checkFrame(uint32 val) {
- return (_frame->getInfo()->field_33 & val);
+ if (!_frame)
+ error("[Fighter::checkFrame] Invalid current frame");
+
+ return (bool)(_frame->getInfo()->field_33 & val);
}
} // End of namespace LastExpress
diff --git a/engines/lastexpress/fight/fighter.h b/engines/lastexpress/fight/fighter.h
index e37fe49d86..dad95af186 100644
--- a/engines/lastexpress/fight/fighter.h
+++ b/engines/lastexpress/fight/fighter.h
@@ -99,9 +99,6 @@ protected:
void draw();
void process();
- // Cleanup
- void clearSequences();
-
// Helpers
bool checkFrame(uint32 val);
};
diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp
index 98d74dd1a7..60a309518a 100644
--- a/engines/lastexpress/game/action.cpp
+++ b/engines/lastexpress/game/action.cpp
@@ -29,7 +29,6 @@
#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"
@@ -42,9 +41,7 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
@@ -332,6 +329,22 @@ static const struct {
{"8042A", 600}
};
+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;
+};
+
Action::Action(LastExpressEngine *engine) : _engine(engine) {
ADD_ACTION(dummy);
ADD_ACTION(inventory);
@@ -407,7 +420,7 @@ SceneIndex Action::processHotspot(const SceneHotspot &hotspot) {
//////////////////////////////////////////////////////////////////////////
// Action 0
IMPLEMENT_ACTION(dummy)
- warning("[Action::action_dummy] Dummy action function called (hotspot action: %d)", hotspot.action);
+ error("[Action::action_dummy] Dummy action function called (hotspot action: %d)", hotspot.action);
return kSceneInvalid;
}
@@ -1742,14 +1755,14 @@ CursorStyle Action::getCursor(const SceneHotspot &hotspot) const {
return kCursorBackward;
case SceneHotspot::kActionKnockOnDoor:
- warning("================================= DOOR %03d =================================", object);
+ debugC(2, kLastExpressDebugScenes, "================================= DOOR %03d =================================", object);
if (object >= kObjectMax)
return kCursorNormal;
else
return (CursorStyle)getObjects()->get(object).cursor;
case SceneHotspot::kAction12:
- warning("================================= OBJECT %03d =================================", object);
+ debugC(2, kLastExpressDebugScenes, "================================= OBJECT %03d =================================", object);
if (object >= kObjectMax)
return kCursorNormal;
@@ -1759,7 +1772,7 @@ CursorStyle Action::getCursor(const SceneHotspot &hotspot) const {
return kCursorNormal;
case SceneHotspot::kActionPickItem:
- warning("================================= ITEM %03d =================================", object);
+ debugC(2, kLastExpressDebugScenes, "================================= ITEM %03d =================================", object);
if (object >= kObjectCompartmentA)
return kCursorNormal;
@@ -1770,7 +1783,7 @@ CursorStyle Action::getCursor(const SceneHotspot &hotspot) const {
return kCursorNormal;
case SceneHotspot::kActionDropItem:
- warning("================================= ITEM %03d =================================", object);
+ debugC(2, kLastExpressDebugScenes, "================================= ITEM %03d =================================", object);
if (object >= kObjectCompartmentA)
return kCursorNormal;
@@ -1887,7 +1900,7 @@ LABEL_KEY:
// Handle compartment action
case SceneHotspot::kActionCompartment:
case SceneHotspot::kActionExitCompartment:
- warning("================================= DOOR %03d =================================", object);
+ debugC(2, kLastExpressDebugScenes, "================================= DOOR %03d =================================", object);
if (object >= kObjectMax)
return kCursorNormal;
diff --git a/engines/lastexpress/game/beetle.cpp b/engines/lastexpress/game/beetle.cpp
index ab707ddae9..2a72459697 100644
--- a/engines/lastexpress/game/beetle.cpp
+++ b/engines/lastexpress/game/beetle.cpp
@@ -27,7 +27,6 @@
#include "lastexpress/game/scenes.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
@@ -337,26 +336,13 @@ void Beetle::drawUpdate() {
}
}
-#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();
+ invertDirection();
SequenceFrame *frame = new SequenceFrame(_data->currentSequence, (uint16)_data->currentFrame);
updateFrame(frame);
- INVERT_Y();
+ invertDirection();
getScenes()->addToQueue(frame);
@@ -364,6 +350,21 @@ void Beetle::drawUpdate() {
_data->frame = frame;
}
+void Beetle::invertDirection() {
+ switch (_data->indexes[_data->offset]) {
+ default:
+ break;
+
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ _data->coordY = -_data->coordY;
+ break;
+ }
+}
+
void Beetle::move() {
if (!_data)
error("[Beetle::move] Sequences have not been loaded");
diff --git a/engines/lastexpress/game/beetle.h b/engines/lastexpress/game/beetle.h
index d3c47f39e5..034ebbd557 100644
--- a/engines/lastexpress/game/beetle.h
+++ b/engines/lastexpress/game/beetle.h
@@ -111,6 +111,7 @@ private:
void updateFrame(SequenceFrame *frame) const;
void updateData(uint32 index);
void drawUpdate();
+ void invertDirection();
};
} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp
index f27087a609..51db635bed 100644
--- a/engines/lastexpress/game/entities.cpp
+++ b/engines/lastexpress/game/entities.cpp
@@ -27,8 +27,6 @@
#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"
@@ -71,10 +69,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/graphics.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
@@ -673,11 +669,12 @@ void Entities::executeCallbacks() {
//////////////////////////////////////////////////////////////////////////
// Processing
//////////////////////////////////////////////////////////////////////////
-#define INCREMENT_DIRECTION_COUNTER() { \
- data->doProcessEntity = false; \
- if (data->direction == kDirectionRight || (data->direction == kDirectionSwitch && data->directionSwitch == kDirectionRight)) \
- ++data->field_4A1; \
- }
+void Entities::incrementDirectionCounter(EntityData::EntityCallData *data) {
+ 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);
@@ -696,7 +693,7 @@ void Entities::processEntity(EntityIndex entityIndex) {
getScenes()->removeAndRedraw(&data->frame, false);
getScenes()->removeAndRedraw(&data->frame1, false);
- INCREMENT_DIRECTION_COUNTER();
+ incrementDirectionCounter(data);
return;
}
@@ -726,7 +723,7 @@ label_nosequence:
processFrame(entityIndex, false, true);
if (!getFlags()->flag_entities_0 && !data->doProcessEntity) {
- INCREMENT_DIRECTION_COUNTER();
+ incrementDirectionCounter(data);
return;
}
} else {
@@ -744,7 +741,7 @@ label_nosequence:
data->position = 0;
}
- INCREMENT_DIRECTION_COUNTER();
+ incrementDirectionCounter(data);
}
return;
}
@@ -754,46 +751,44 @@ label_nosequence:
if (data->frame->getInfo()->field_30 > (data->field_49B + 1) || (data->direction == kDirectionLeft && data->sequence->count() == 1)) {
++data->field_49B;
- } else {
- if (data->frame->getInfo()->field_30 > data->field_49B && !data->frame->getInfo()->keepPreviousFrame) {
- ++data->field_49B;
- } else {
- if (data->frame->getInfo()->keepPreviousFrame == 1)
- keepPreviousFrame = true;
-
- // Increment current frame
- ++data->currentFrame;
+ } else if (data->frame->getInfo()->field_30 <= data->field_49B || data->frame->getInfo()->keepPreviousFrame) {
+ if (data->frame->getInfo()->keepPreviousFrame == 1)
+ keepPreviousFrame = true;
- if (data->currentFrame > (int16)(data->sequence->count() - 1) || (data->field_4A9 && checkSequenceFromPosition(entityIndex))) {
+ // Increment current frame
+ ++data->currentFrame;
- if (data->direction == kDirectionLeft) {
- data->currentFrame = 0;
- } else {
- keepPreviousFrame = true;
- drawNextSequence(entityIndex);
+ if (data->currentFrame > (int16)(data->sequence->count() - 1) || (data->field_4A9 && checkSequenceFromPosition(entityIndex))) {
- if (getFlags()->flag_entities_0 || data->doProcessEntity)
- return;
+ if (data->direction == kDirectionLeft) {
+ data->currentFrame = 0;
+ } else {
+ keepPreviousFrame = true;
+ drawNextSequence(entityIndex);
- if (!data->sequence2) {
- updateEntityPosition(entityIndex);
- data->doProcessEntity = false;
- return;
- }
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
- copySequenceData(entityIndex);
+ if (!data->sequence2) {
+ updateEntityPosition(entityIndex);
+ data->doProcessEntity = false;
+ return;
}
+ copySequenceData(entityIndex);
}
- processFrame(entityIndex, keepPreviousFrame, false);
-
- if (getFlags()->flag_entities_0 || data->doProcessEntity)
- return;
}
+
+ processFrame(entityIndex, keepPreviousFrame, false);
+
+ if (getFlags()->flag_entities_0 || data->doProcessEntity)
+ return;
+ } else {
+ ++data->field_49B;
}
- INCREMENT_DIRECTION_COUNTER();
+ incrementDirectionCounter(data);
}
void Entities::computeCurrentFrame(EntityIndex entityIndex) const {
@@ -2283,7 +2278,7 @@ label_process_entity:
if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)) {
getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMeCath);
- } else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) || getScenes()->checkCurrentPosition(false)){
+ } else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) || getScenes()->checkCurrentPosition(false)) {
getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMe);
if (getScenes()->checkCurrentPosition(false))
diff --git a/engines/lastexpress/game/entities.h b/engines/lastexpress/game/entities.h
index eb5eae461f..a9de7931f0 100644
--- a/engines/lastexpress/game/entities.h
+++ b/engines/lastexpress/game/entities.h
@@ -344,6 +344,7 @@ private:
uint _positions[_positionsCount];
void executeCallbacks();
+ void incrementDirectionCounter(EntityData::EntityCallData *data);
void processEntity(EntityIndex entity);
void drawSequence(EntityIndex entity, const char *sequence, EntityDirection direction) const;
diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp
index e417b1ec0d..52c00ece31 100644
--- a/engines/lastexpress/game/inventory.cpp
+++ b/engines/lastexpress/game/inventory.cpp
@@ -26,7 +26,9 @@
#include "lastexpress/data/scene.h"
#include "lastexpress/data/snd.h"
+#include "lastexpress/game/entities.h"
#include "lastexpress/game/logic.h"
+#include "lastexpress/game/savegame.h"
#include "lastexpress/game/scenes.h"
#include "lastexpress/game/state.h"
@@ -44,7 +46,7 @@
namespace LastExpress {
Inventory::Inventory(LastExpressEngine *engine) : _engine(engine), _selectedItem(kItemNone), _highlightedItemIndex(0), _itemsShown(0),
- _showingHourGlass(false), _blinkingEgg(false), _blinkingTime(0), _blinkingInterval(_defaultBlinkingInterval), _blinkingBrightness(1),
+ _showingHourGlass(false), _blinkingDirection(1), _blinkingBrightness(0),
_useMagnifier(false), _portraitHighlighted(false), _isOpened(false), _eggHightlighted(false), _itemScene(NULL) {
//_inventoryRect = Common::Rect(0, 0, 32, 32);
@@ -162,13 +164,11 @@ void Inventory::handleMouseEvent(const Common::Event &ev) {
getMenu()->show(true, kSavegameTypeIndex, 0);
- } else if (ev.type == Common::EVENT_RBUTTONDOWN) {
- if (getGlobalTimer()) {
- if (getSoundQueue()->isBuffered("TIMER"))
- getSoundQueue()->removeFromQueue("TIMER");
+ } else if (ev.type == Common::EVENT_RBUTTONDOWN && getGlobalTimer()) {
+ if (getSoundQueue()->isBuffered("TIMER"))
+ getSoundQueue()->removeFromQueue("TIMER");
- setGlobalTimer(900);
- }
+ setGlobalTimer(900);
}
}
@@ -180,7 +180,7 @@ void Inventory::handleMouseEvent(const Common::Event &ev) {
if (_highlightedItemIndex)
drawHighlight(_highlightedItemIndex, true);
} else {
- // The user released the mouse button, we need to update the inventory state (clear hightlight and items)
+ // The user released the mouse button, we need to update the inventory state (clear highlight and items)
drawItem((CursorStyle)getProgress().portrait, 0, 0, 1);
_engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(0, 44, 32, (int16)(40 * _itemsShown + 40)));
_isOpened = false;
@@ -226,12 +226,11 @@ void Inventory::handleMouseEvent(const Common::Event &ev) {
if (getFlags()->mouseLeftPressed) {
if (getState()->sceneUseBackup) {
- if (getState()->sceneBackup2
- && getFirstExaminableItem() == _selectedItem) {
- SceneIndex sceneIndex = getState()->sceneBackup2;
- getState()->sceneBackup2 = kSceneNone;
+ if (getState()->sceneBackup2 && getFirstExaminableItem() == _selectedItem) {
+ SceneIndex sceneIndex = getState()->sceneBackup2;
+ getState()->sceneBackup2 = kSceneNone;
- getScenes()->loadScene(sceneIndex);
+ getScenes()->loadScene(sceneIndex);
}
} else {
getState()->sceneBackup = getState()->scene;
@@ -261,7 +260,7 @@ void Inventory::handleMouseEvent(const Common::Event &ev) {
// Change item highlight on list
if (getFlags()->mouseLeftPressed) {
- uint32 index = ev.mouse.y / 40;
+ uint32 index = (uint16)ev.mouse.y / 40;
if (_highlightedItemIndex && _highlightedItemIndex != index)
drawHighlight(_highlightedItemIndex, true);
@@ -418,12 +417,12 @@ void Inventory::show() {
drawEgg();
}
-void Inventory::setPortrait(InventoryItem item) {
+void Inventory::setPortrait(InventoryItem item) const {
getProgress().portrait = item;
drawItem((CursorStyle)getProgress().portrait, 0, 0);
}
-void Inventory::showHourGlass(){
+void Inventory::showHourGlass() const {
if (!getMenu()->isShown())
drawItem(kCursorHourGlass, 608, 448);
@@ -613,7 +612,7 @@ void Inventory::examine(InventoryItem item) {
}
}
-void Inventory::drawEgg() {
+void Inventory::drawEgg() const {
if (!getMenu()->isShown())
drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, _eggHightlighted ? 0 : 1);
@@ -621,40 +620,51 @@ void Inventory::drawEgg() {
}
// Blinking egg: we need to blink the egg for delta time, with the blinking getting faster until it's always lit.
-void Inventory::drawBlinkingEgg() {
+void Inventory::drawBlinkingEgg(uint ticks) {
+ uint globalTimer = getGlobalTimer();
+ uint timerValue = (getProgress().jacket == kJacketGreen) ? 450 : 225;
- warning("[Inventory::drawBlinkingEgg] Blinking not implemented");
+ if (globalTimer == timerValue || globalTimer == 900) {
+ _blinkingBrightness = 0;
+ _blinkingDirection = 1;
+ }
- //// TODO show egg (with or without mouseover)
+ globalTimer = globalTimer <= ticks ? 0 : globalTimer - ticks;
+ setGlobalTimer(globalTimer);
- //// Play timer sound
- //if (getGlobalTimer() < 90) {
- // if (getGlobalTimer() + ticks >= 90)
- // getSound()->playSoundWithSubtitles("TIMER.SND", 50331664, kEntityPlayer);
+ if (getFlags()->flag_0
+ || (globalTimer % 5) == 0
+ || (globalTimer <= 500 && (globalTimer % ((globalTimer + 100) / 100)) == 0))
+ blinkEgg();
- // if (getSoundQueue()->isBuffered("TIMER"))
- // setGlobalTimer(0);
- //}
+ if (globalTimer < 90) {
+ if ((globalTimer + ticks) >= 90)
+ getSound()->playSoundWithSubtitles("TIMER", (SoundFlag)(kFlagType13|kFlagDefault), kEntityPlayer);
- //// Restore egg to standard brightness
- //if (!getGlobalTimer()) {
- //
- //}
+ if (!getSoundQueue()->isBuffered("TIMER"))
+ setGlobalTimer(0);
+ }
+ if (globalTimer == 0) {
+ drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, _menuEggRect.contains(getCoords()) ? 1 : -1);
- //drawItem(608, 448, getMenu()->getGameId() + 39, _blinkingBrightness)
+ askForRedraw();
- //// TODO if delta time > _blinkingInterval, update egg & ask for redraw then adjust blinking time and remaining time
- //
+ getSaveLoad()->saveGame(kSavegameTypeAuto, kEntityChapters, 0);
+ }
+}
- //// Reset values and stop blinking
- //if (_blinkingTime == 0)
- // blinkEgg(false);
+void Inventory::blinkEgg() {
+ drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, (_blinkingBrightness == 0) ? -1 : _blinkingBrightness);
askForRedraw();
+
+ _blinkingBrightness += _blinkingDirection;
+ if (_blinkingBrightness == 0 || _blinkingBrightness == 3)
+ _blinkingDirection = -_blinkingDirection;
}
-void Inventory::drawItem(CursorStyle id, uint16 x, uint16 y, int16 brightnessIndex) {
+void Inventory::drawItem(CursorStyle id, uint16 x, uint16 y, int16 brightnessIndex) const {
Icon icon(id);
icon.setPosition(x, y);
@@ -678,7 +688,7 @@ void Inventory::drawSelectedItem() {
}
}
-void Inventory::clearSelectedItem() {
+void Inventory::clearSelectedItem() const {
_engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(44, 0, 44 + 32, 32));
}
@@ -733,7 +743,7 @@ void Inventory::drawHighlight(uint32 currentIndex, bool reset) {
}
}
-uint32 Inventory::getItemIndex(uint32 currentIndex) {
+uint32 Inventory::getItemIndex(uint32 currentIndex) const {
uint32 count = 0;
for (uint32 i = 1; i < ARRAYSIZE(_entries); i++) {
diff --git a/engines/lastexpress/game/inventory.h b/engines/lastexpress/game/inventory.h
index b1995adce3..b1019a43c6 100644
--- a/engines/lastexpress/game/inventory.h
+++ b/engines/lastexpress/game/inventory.h
@@ -106,11 +106,10 @@ public:
// UI Control
void show();
- void blinkEgg(bool enabled);
- void showHourGlass();
- void setPortrait(InventoryItem item);
- void drawEgg();
- void drawBlinkingEgg();
+ void showHourGlass() const;
+ void setPortrait(InventoryItem item) const;
+ void drawEgg() const;
+ void drawBlinkingEgg(uint ticks = 1);
// Handle inventory UI events.
void handleMouseEvent(const Common::Event &ev);
@@ -133,8 +132,6 @@ public:
Common::String toString();
private:
- static const uint32 _defaultBlinkingInterval = 250; ///< Default blinking interval in ms
-
LastExpressEngine *_engine;
InventoryEntry _entries[32];
@@ -144,9 +141,7 @@ private:
uint32 _itemsShown;
bool _showingHourGlass;
- bool _blinkingEgg;
- uint32 _blinkingTime;
- uint32 _blinkingInterval;
+ int16 _blinkingDirection;
uint16 _blinkingBrightness;
// Flags
@@ -157,8 +152,6 @@ private:
Scene *_itemScene;
- // Important rects
- //Common::Rect _inventoryRect;
Common::Rect _menuEggRect;
Common::Rect _selectedItemRect;
@@ -168,14 +161,15 @@ private:
void close();
void examine(InventoryItem item);
void drawHighlight(uint32 currentIndex, bool reset);
- uint32 getItemIndex(uint32 currentIndex);
+ uint32 getItemIndex(uint32 currentIndex) const;
bool isItemSceneParameter(InventoryItem item) const;
- void drawItem(CursorStyle id, uint16 x, uint16 y, int16 brighnessIndex = -1);
+ void drawItem(CursorStyle id, uint16 x, uint16 y, int16 brighnessIndex = -1) const;
+ void blinkEgg();
void drawSelectedItem();
- void clearSelectedItem();
+ void clearSelectedItem() const;
};
} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/logic.cpp b/engines/lastexpress/game/logic.cpp
index aeac8cff98..1696f100ff 100644
--- a/engines/lastexpress/game/logic.cpp
+++ b/engines/lastexpress/game/logic.cpp
@@ -47,10 +47,8 @@
#include "lastexpress/menu/menu.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/graphics.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
@@ -88,16 +86,6 @@ Logic::~Logic() {
//////////////////////////////////////////////////////////////////////////
// Event Handling
//////////////////////////////////////////////////////////////////////////
-#define REDRAW_CURSOR() { \
- if (getInventory()->isMagnifierInUse()) \
- _engine->getCursor()->setStyle(kCursorMagnifier); \
- if (getInventory()->isPortraitHighlighted() \
- || getInventory()->isOpened() \
- || getInventory()->isEggHighlighted()) \
- _engine->getCursor()->setStyle(kCursorNormal); \
- return; \
-}
-
void Logic::eventMouse(const Common::Event &ev) {
bool hotspotHandled = false;
@@ -168,7 +156,9 @@ void Logic::eventMouse(const Common::Event &ev) {
getInventory()->unselectItem();
}
- REDRAW_CURSOR()
+ redrawCursor();
+
+ return;
}
// Handle match case
@@ -194,7 +184,9 @@ void Logic::eventMouse(const Common::Event &ev) {
getScenes()->processScene();
}
- REDRAW_CURSOR()
+ redrawCursor();
+
+ return;
}
// Handle entity item case
@@ -315,7 +307,7 @@ void Logic::eventTick(const Common::Event &) {
//////////////////////////////////////////////////////////////////////////
// Draw the blinking egg if needed
if (getGlobalTimer() && !getFlags()->shouldDrawEggOrHourGlass)
- getInventory()->drawBlinkingEgg();
+ getInventory()->drawBlinkingEgg(ticks);
//////////////////////////////////////////////////////////////////////////
// Adjust time and save game if needed
@@ -411,9 +403,12 @@ void Logic::eventTick(const Common::Event &) {
* Resets the game state.
*/
void Logic::resetState() {
- getState()->scene = kSceneDefault;
+ getScenes()->setCoordinates(Common::Rect(80, 0, 559, 479));
+
+ SAFE_DELETE(_entities);
+ _entities = new Entities(_engine);
- warning("[Logic::resetState] Not implemented! You need to restart the engine until this is implemented.");
+ _state->reset();
}
/**
@@ -595,4 +590,14 @@ void Logic::updateCursor(bool) const { /* the cursor is always updated, even whe
_engine->getCursor()->setStyle(style);
}
+void Logic::redrawCursor() const {
+ if (getInventory()->isMagnifierInUse())
+ _engine->getCursor()->setStyle(kCursorMagnifier);
+
+ if (getInventory()->isPortraitHighlighted()
+ || getInventory()->isOpened()
+ || getInventory()->isEggHighlighted())
+ _engine->getCursor()->setStyle(kCursorNormal);
+}
+
} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/logic.h b/engines/lastexpress/game/logic.h
index 8b7dcef942..efb8f1e1a3 100644
--- a/engines/lastexpress/game/logic.h
+++ b/engines/lastexpress/game/logic.h
@@ -25,8 +25,6 @@
#include "lastexpress/shared.h"
-#include "lastexpress/game/entities.h"
-
#include "lastexpress/eventhandler.h"
#include "common/events.h"
@@ -75,6 +73,7 @@ private:
void switchChapter() const;
void showCredits() const;
+ void redrawCursor() const;
// Flags & Members
bool _flagActionPerformed;
diff --git a/engines/lastexpress/game/object.cpp b/engines/lastexpress/game/object.cpp
index d9e9e4279a..48df91ea6d 100644
--- a/engines/lastexpress/game/object.cpp
+++ b/engines/lastexpress/game/object.cpp
@@ -22,11 +22,11 @@
#include "lastexpress/game/object.h"
+#include "lastexpress/game/entities.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 {
diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp
index 9c464feb6e..360e99146a 100644
--- a/engines/lastexpress/game/savegame.cpp
+++ b/engines/lastexpress/game/savegame.cpp
@@ -22,6 +22,7 @@
#include "lastexpress/game/savegame.h"
+#include "lastexpress/game/entities.h"
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/object.h"
@@ -34,13 +35,13 @@
#include "lastexpress/debug.h"
#include "lastexpress/lastexpress.h"
-#include "lastexpress/helpers.h"
#include "common/file.h"
-#include "common/system.h"
namespace LastExpress {
+#define DISABLE_COMPRESSION 1
+
// Names of savegames
static const struct {
const char *saveFile;
@@ -54,6 +55,296 @@ static const struct {
};
//////////////////////////////////////////////////////////////////////////
+// SavegameStream
+//////////////////////////////////////////////////////////////////////////
+
+uint32 SavegameStream::write(const void *dataPtr, uint32 dataSize) {
+#if !DISABLE_COMPRESSION
+ if (_enableCompression)
+ return writeCompressed(dataPtr, dataSize);
+#endif
+
+ return Common::MemoryWriteStreamDynamic::write(dataPtr, dataSize);
+}
+
+uint32 SavegameStream::read(void *dataPtr, uint32 dataSize) {
+#if !DISABLE_COMPRESSION
+ if (_enableCompression)
+ return readCompressed(dataPtr, dataSize);
+#endif
+
+ return readUncompressed(dataPtr, dataSize);
+}
+
+uint32 SavegameStream::readUncompressed(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;
+}
+
+void SavegameStream::writeBuffer(uint8 value, bool onlyValue) {
+ if (_bufferOffset == -1)
+ _bufferOffset = 0;
+
+ if (_bufferOffset == 256) {
+ _bufferOffset = 0;
+ Common::MemoryWriteStreamDynamic::write(_buffer, 256);
+ }
+
+ if (onlyValue || value < 0xFB)
+ _buffer[_bufferOffset] = value;
+ else
+ _buffer[_bufferOffset] = 0xFE;
+
+ _offset++;
+ _bufferOffset++;
+
+ if (!onlyValue && value >= 0xFB)
+ {
+ if (_bufferOffset == 256) {
+ _bufferOffset = 0;
+ Common::MemoryWriteStreamDynamic::write(_buffer, 256);
+ }
+
+ _buffer[_bufferOffset] = value;
+
+ _bufferOffset++;
+ _offset++;
+ }
+}
+
+uint8 SavegameStream::readBuffer() {
+ if (_bufferOffset == -1 || _bufferOffset >= 256) {
+ readUncompressed(_buffer, 256);
+ _bufferOffset = 0;
+ }
+
+ byte val = _buffer[_bufferOffset];
+ _bufferOffset++;
+
+ return val;
+}
+
+uint32 SavegameStream::process() {
+ _enableCompression = !_enableCompression;
+
+#if DISABLE_COMPRESSION
+ return 0;
+#else
+ switch (_status) {
+ default:
+ break;
+
+ case kStatusReading:
+ _status = kStatusReady;
+ if (_bufferOffset != -1 && _bufferOffset != 256) {
+ seek(_bufferOffset - 256, SEEK_CUR);
+ _bufferOffset = -1;
+ }
+ break;
+
+ case kStatusWriting:
+ switch (_valueCount) {
+ default:
+ break;
+
+ case 1:
+ writeBuffer(_previousValue, false);
+ break;
+
+ case 2:
+ if (_previousValue) {
+ writeBuffer(0xFF);
+ writeBuffer(_repeatCount);
+ writeBuffer(_previousValue);
+ break;
+ }
+
+ if (_repeatCount == 3) {
+ writeBuffer(0xFB);
+ break;
+ }
+
+ if (_repeatCount == 255) {
+ writeBuffer(0xFC);
+ break;
+ }
+
+ writeBuffer(0xFD);
+ writeBuffer(_repeatCount);
+ break;
+ }
+
+ if (_bufferOffset != -1 && _bufferOffset != 0) {
+ Common::MemoryWriteStreamDynamic::write(_buffer, _bufferOffset);
+ _bufferOffset = -1;
+ }
+ break;
+ }
+
+ _status = kStatusReady;
+ _valueCount = 0;
+ uint32 offset = _offset;
+ _offset = 0;
+
+ return offset;
+#endif
+}
+
+uint32 SavegameStream::writeCompressed(const void *dataPtr, uint32 dataSize) {
+ if (_status == kStatusReading)
+ error("[SavegameStream::writeCompressed] Error: Compression buffer is in read mode.");
+
+ _status = kStatusWriting;
+ const byte *data = (const byte *)dataPtr;
+
+ while (dataSize) {
+ switch (_valueCount) {
+ default:
+ error("[SavegameStream::writeCompressed] Invalid value count (%d)", _valueCount);
+
+ case 0:
+ _previousValue = *data++;
+ _valueCount = 1;
+ break;
+
+ case 1:
+ if (*data != _previousValue) {
+ writeBuffer(_previousValue, false);
+ _previousValue = *data;
+ } else {
+ _valueCount = 2;
+ _repeatCount = 2;
+ }
+
+ ++data;
+ break;
+
+ case 2:
+ if (*data != _previousValue || _repeatCount >= 255) {
+ if (_previousValue) {
+ writeBuffer(0xFF, true);
+ writeBuffer(_repeatCount, true);
+ writeBuffer(_previousValue, true);
+
+ _previousValue = *data++;
+ _valueCount = 1;
+ break;
+ }
+
+ if (_repeatCount == 3) {
+ writeBuffer(0xFB, true);
+
+ _previousValue = *data++;
+ _valueCount = 1;
+ break;
+ }
+
+ if (_repeatCount == -1) {
+ writeBuffer(0xFC, true);
+
+ _previousValue = *data++;
+ _valueCount = 1;
+ break;
+ }
+
+ writeBuffer(0xFD, true);
+ writeBuffer(_repeatCount, true);
+
+ _previousValue = *data++;
+ _valueCount = 1;
+ }
+
+ ++data;
+ ++_repeatCount;
+ break;
+ }
+
+ --dataSize;
+ }
+
+ return _offset;
+}
+
+uint32 SavegameStream::readCompressed(void *dataPtr, uint32 dataSize) {
+ if (_status == kStatusWriting)
+ error("[SavegameStream::writeCompressed] Error: Compression buffer is in write mode.");
+
+ _status = kStatusReady;
+ byte *data = (byte *)dataPtr;
+
+ while (dataSize) {
+ switch (_valueCount) {
+ default:
+ error("[SavegameStream::readCompressed] Invalid value count (%d)", _valueCount);
+
+ case 0:
+ case 1: {
+ // Read control code
+ byte control = readBuffer();
+
+ switch (control) {
+ default:
+ // Data value
+ *data++ = control;
+ break;
+
+ case 0xFB:
+ _repeatCount = 2;
+ _previousValue = 0;
+ *data++ = 0;
+ _valueCount = 2;
+ break;
+
+ case 0xFC:
+ _repeatCount = 254;
+ _previousValue = 0;
+ *data++ = 0;
+ _valueCount = 2;
+ break;
+
+ case 0xFD:
+ _repeatCount = readBuffer() - 1;
+ _previousValue = 0;
+ *data++ = 0;
+ _valueCount = 2;
+ break;
+
+ case 0xFE:
+ *data++ = readBuffer();
+ break;
+
+ case 0xFF:
+ _repeatCount = readBuffer() - 1;
+ _previousValue = readBuffer();
+ *data++ = _previousValue;
+ _valueCount = 2;
+ break;
+ }
+ }
+ break;
+
+ case 2:
+ *data++ = _previousValue;
+ _repeatCount--;
+ if (!_repeatCount)
+ _valueCount = 1;
+ break;
+ }
+
+ --dataSize;
+ }
+
+ return _offset;
+}
+
+//////////////////////////////////////////////////////////////////////////
// Constructors
//////////////////////////////////////////////////////////////////////////
@@ -81,6 +372,7 @@ void SaveLoad::flushStream(GameId id) {
error("[SaveLoad::flushStream] Savegame stream is invalid");
save->write(_savegame->getData(), (uint32)_savegame->size());
+ save->finalize();
delete save;
}
@@ -258,7 +550,7 @@ void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) {
entry.saveLoadWithSerializer(ser);
if (!entry.isValid()) {
- warning("[SaveLoad::saveGame] Invalid entry. This savegame might be corrupted");
+ error("[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!
@@ -341,16 +633,46 @@ bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *he
//////////////////////////////////////////////////////////////////////////
// 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); \
+uint32 SaveLoad::writeValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size) {
+ debugC(kLastExpressDebugSavegame, "Savegame: Writing %s: %u bytes", name, size);
+
+ uint32 prevPosition = (uint32)_savegame->pos();
+
+ // Serialize data into our buffer
+ (*function)(ser);
+
+ uint32 count = (uint32)_savegame->pos() - prevPosition;
+
+#if DISABLE_COMPRESSION
+ if (count != size)
+ error("[SaveLoad::writeValue] %s - Number of bytes written (%d) differ from expected count (%d)", name, count, size);
+#endif
+
+ return count;
}
+uint32 SaveLoad::readValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size) {
+ debugC(kLastExpressDebugSavegame, "Savegame: Reading %s: %u bytes", name, size);
+
+ uint32 prevPosition = (uint32)_savegame->pos();
+
+ (*function)(ser);
+
+ uint32 count = (uint32)_savegame->pos() - prevPosition;
+
+#if DISABLE_COMPRESSION
+ if (size != 0 && count != size)
+ error("[SaveLoad::readValue] %s - Number of bytes read (%d) differ from expected count (%d)", name, count, size);
+#endif
+
+ return count;
+}
+
+void SaveLoad::syncEntity(Common::Serializer &ser) {
+ ser.syncAsUint32LE(_entity);
+}
+
+void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
if (!_savegame)
error("[SaveLoad::writeEntry] Savegame stream is invalid");
@@ -369,18 +691,22 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
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", getSoundQueue()->saveLoadWithSerializer(ser), 3 * 4 + getSoundQueue()->count() * 64);
- WRITE_ENTRY("savepoints", getSavePoints()->saveLoadWithSerializer(ser), 128 * 16 + 4 + getSavePoints()->count() * 16);
+ _entity = entity;
+
+ _savegame->process();
+ writeValue(ser, "entity index", WRAP_SYNC_FUNCTION(this, SaveLoad, syncEntity), 4);
+ writeValue(ser, "state", WRAP_SYNC_FUNCTION(getState(), State::GameState, saveLoadWithSerializer), 4 + 4 + 4 + 4 + 1 + 4 + 4);
+ writeValue(ser, "selected item", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveSelectedItem), 4);
+ writeValue(ser, "positions", WRAP_SYNC_FUNCTION(getEntities(), Entities, savePositions), 4 * 1000);
+ writeValue(ser, "compartments", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveCompartments), 4 * 16 * 2);
+ writeValue(ser, "progress", WRAP_SYNC_FUNCTION(&getProgress(), State::GameProgress, saveLoadWithSerializer), 4 * 128);
+ writeValue(ser, "events", WRAP_SYNC_FUNCTION(getState(), State::GameState, syncEvents), 512);
+ writeValue(ser, "inventory", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveLoadWithSerializer), 7 * 32);
+ writeValue(ser, "objects", WRAP_SYNC_FUNCTION(getObjects(), Objects, saveLoadWithSerializer), 5 * 128);
+ writeValue(ser, "entities", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveLoadWithSerializer), 1262 * 40);
+ writeValue(ser, "sound", WRAP_SYNC_FUNCTION(getSoundQueue(), SoundQueue, saveLoadWithSerializer), 3 * 4 + getSoundQueue()->count() * 64);
+ writeValue(ser, "savepoints", WRAP_SYNC_FUNCTION(getSavePoints(), SavePoints, saveLoadWithSerializer), 128 * 16 + 4 + getSavePoints()->count() * 16);
+ _savegame->process();
header.offset = (uint32)_savegame->pos() - (originalPosition + 32);
@@ -406,22 +732,6 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
}
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");
@@ -444,20 +754,23 @@ void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, b
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", getSoundQueue()->saveLoadWithSerializer(ser));
- LOAD_ENTRY_ONLY("savepoints", getSavePoints()->saveLoadWithSerializer(ser));
+ _savegame->process();
+ readValue(ser, "entity index", WRAP_SYNC_FUNCTION(this, SaveLoad, syncEntity), 4);
+ readValue(ser, "state", WRAP_SYNC_FUNCTION(getState(), State::GameState, saveLoadWithSerializer), 4 + 4 + 4 + 4 + 1 + 4 + 4);
+ readValue(ser, "selected item", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveSelectedItem), 4);
+ readValue(ser, "positions", WRAP_SYNC_FUNCTION(getEntities(), Entities, savePositions), 4 * 1000);
+ readValue(ser, "compartments", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveCompartments), 4 * 16 * 2);
+ readValue(ser, "progress", WRAP_SYNC_FUNCTION(&getProgress(), State::GameProgress, saveLoadWithSerializer), 4 * 128);
+ readValue(ser, "events", WRAP_SYNC_FUNCTION(getState(), State::GameState, syncEvents), 512);
+ readValue(ser, "inventory", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveLoadWithSerializer), 7 * 32);
+ readValue(ser, "objects", WRAP_SYNC_FUNCTION(getObjects(), Objects, saveLoadWithSerializer), 5 * 128);
+ readValue(ser, "entities", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveLoadWithSerializer), 1262 * 40);
+ readValue(ser, "sound", WRAP_SYNC_FUNCTION(getSoundQueue(), SoundQueue, saveLoadWithSerializer));
+ readValue(ser, "savepoints", WRAP_SYNC_FUNCTION(getSavePoints(), SavePoints, saveLoadWithSerializer));
+ _savegame->process();
// Update chapter
+ *entity = _entity;
getProgress().chapter = entry.chapter;
// Skip padding
@@ -567,7 +880,7 @@ Common::InSaveFile *SaveLoad::openForLoading(GameId id) {
}
Common::OutSaveFile *SaveLoad::openForSaving(GameId id) {
- Common::OutSaveFile *save = g_system->getSavefileManager()->openForSaving(getFilename(id));
+ Common::OutSaveFile *save = g_system->getSavefileManager()->openForSaving(getFilename(id), false); // TODO Enable compression again
if (!save)
debugC(2, kLastExpressDebugSavegame, "Cannot open savegame for writing: %s", getFilename(id).c_str());
diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h
index 6f0408487f..8656b2ee86 100644
--- a/engines/lastexpress/game/savegame.h
+++ b/engines/lastexpress/game/savegame.h
@@ -80,11 +80,68 @@
namespace LastExpress {
// Savegame signatures
-#define SAVEGAME_SIGNATURE 0x12001200
-#define SAVEGAME_ENTRY_SIGNATURE 0xE660E660
+#define SAVEGAME_SIGNATURE 0x12001200 // 301994496
+#define SAVEGAME_ENTRY_SIGNATURE 0xE660E660 // 3865110112
+
+#define WRAP_SYNC_FUNCTION(instance, className, method) \
+ new Common::Functor1Mem<Common::Serializer &, void, className>(instance, &className::method)
class LastExpressEngine;
+class SavegameStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream {
+public:
+ SavegameStream() : MemoryWriteStreamDynamic(DisposeAfterUse::YES), _eos(false) {
+ _enableCompression = false;
+ _bufferOffset = -1;
+ _valueCount = 0;
+ _previousValue = 0;
+ _repeatCount = 0;
+ _offset = 0;
+ _status = kStatusReady;
+
+ memset(_buffer, 0, 256);
+ }
+
+ 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);
+ uint32 write(const void *dataPtr, uint32 dataSize);
+
+ uint32 process();
+
+private:
+ enum CompressedStreamStatus {
+ kStatusReady,
+ kStatusReading,
+ kStatusWriting
+ };
+
+ uint32 readUncompressed(void *dataPtr, uint32 dataSize);
+
+ // Compressed data
+ uint32 writeCompressed(const void *dataPtr, uint32 dataSize);
+ uint32 readCompressed(void *dataPtr, uint32 dataSize);
+
+ void writeBuffer(uint8 value, bool onlyValue = true);
+ uint8 readBuffer();
+
+private:
+ bool _eos;
+
+ // Compression handling
+ bool _enableCompression;
+ int16 _bufferOffset;
+ byte _valueCount;
+ byte _previousValue;
+ int16 _repeatCount;
+ uint32 _offset;
+ CompressedStreamStatus _status;
+
+ byte _buffer[256];
+};
+
class SaveLoad {
public:
SaveLoad(LastExpressEngine *engine);
@@ -116,30 +173,6 @@ public:
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 {
@@ -268,6 +301,9 @@ private:
void writeEntry(SavegameType type, EntityIndex entity, uint32 val);
void readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex);
+ uint32 writeValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size);
+ uint32 readValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size = 0);
+
SavegameEntryHeader *getEntry(uint32 index);
// Opening save files
@@ -279,6 +315,10 @@ private:
void initStream();
void loadStream(GameId id);
void flushStream(GameId id);
+
+ // Misc
+ EntityIndex _entity;
+ void syncEntity(Common::Serializer &ser);
};
} // End of namespace LastExpress
diff --git a/engines/lastexpress/game/savepoint.cpp b/engines/lastexpress/game/savepoint.cpp
index 64ae26c2be..6b2dfc5930 100644
--- a/engines/lastexpress/game/savepoint.cpp
+++ b/engines/lastexpress/game/savepoint.cpp
@@ -26,7 +26,6 @@
#include "lastexpress/game/logic.h"
#include "lastexpress/game/state.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
@@ -95,7 +94,7 @@ void SavePoints::process() {
if (!updateEntityFromData(savepoint)) {
// Call requested callback
- Entity::Callback *callback = getCallback(savepoint.entity1);
+ 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);
@@ -126,7 +125,7 @@ void SavePoints::addData(EntityIndex entity, ActionIndex action, uint32 param) {
//////////////////////////////////////////////////////////////////////////
// Callbacks
//////////////////////////////////////////////////////////////////////////
-void SavePoints::setCallback(EntityIndex index, Entity::Callback *callback) {
+void SavePoints::setCallback(EntityIndex index, Callback *callback) {
if (index >= 40)
error("[SavePoints::setCallback] Attempting to use an invalid entity index. Valid values 0-39, was %d", index);
@@ -136,7 +135,7 @@ void SavePoints::setCallback(EntityIndex index, Entity::Callback *callback) {
_callbacks[index] = callback;
}
-Entity::Callback *SavePoints::getCallback(EntityIndex index) const {
+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);
@@ -150,7 +149,7 @@ void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex acti
point.entity2 = entity2;
point.param.intValue = param;
- Entity::Callback *callback = getCallback(entity1);
+ 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);
@@ -164,7 +163,7 @@ void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex acti
point.entity2 = entity2;
strcpy((char *)&point.param.charValue, param);
- Entity::Callback *callback = getCallback(entity1);
+ 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);
@@ -181,7 +180,7 @@ void SavePoints::callAndProcess() {
bool isRunning = getFlags()->isGameRunning;
while (isRunning) {
- Entity::Callback *callback = getCallback(index);
+ Callback *callback = getCallback(index);
if (callback != NULL && callback->isValid()) {
(*callback)(savepoint);
isRunning = getFlags()->isGameRunning;
@@ -243,7 +242,15 @@ void SavePoints::saveLoadWithSerializer(Common::Serializer &s) {
}
// Skip uninitialized data if any
- s.skip((_savePointsMaxSize - dataSize) * 16);
+ // (we are using a compressed stream, so we cannot seek on load)
+ uint32 unusedDataSize = (_savePointsMaxSize - dataSize) * 16;
+ if (s.isLoading()) {
+ byte *empty = (byte *)malloc(unusedDataSize);
+ s.syncBytes(empty, unusedDataSize);
+ free(empty);
+ } else {
+ s.skip(unusedDataSize);
+ }
// Number of savepoints
uint32 numSavepoints = _savepoints.size();
diff --git a/engines/lastexpress/game/savepoint.h b/engines/lastexpress/game/savepoint.h
index a3303b4b8a..005133891a 100644
--- a/engines/lastexpress/game/savepoint.h
+++ b/engines/lastexpress/game/savepoint.h
@@ -23,9 +23,8 @@
#ifndef LASTEXPRESS_SAVEPOINT_H
#define LASTEXPRESS_SAVEPOINT_H
-#include "lastexpress/entities/entity.h"
-
#include "lastexpress/helpers.h"
+#include "lastexpress/shared.h"
#include "common/array.h"
#include "common/list.h"
@@ -74,10 +73,9 @@ struct SavePoint {
}
};
-class SavePoints : Common::Serializable {
-private:
- typedef Common::Functor1<const SavePoint&, void> Callback;
+typedef Common::Functor1<const SavePoint&, void> Callback;
+class SavePoints : Common::Serializable {
public:
struct SavePointData {
@@ -112,7 +110,7 @@ public:
void addData(EntityIndex entity, ActionIndex action, uint32 param);
// Callbacks
- void setCallback(EntityIndex index, Entity::Callback *callback);
+ void setCallback(EntityIndex index, 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;
diff --git a/engines/lastexpress/game/scenes.cpp b/engines/lastexpress/game/scenes.cpp
index b886951e0b..3cda900757 100644
--- a/engines/lastexpress/game/scenes.cpp
+++ b/engines/lastexpress/game/scenes.cpp
@@ -22,8 +22,6 @@
#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"
@@ -34,10 +32,8 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/graphics.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
@@ -493,7 +489,7 @@ bool SceneManager::checkCurrentPosition(bool doCheckOtherCars) const {
if (position == 99)
return true;
- switch (car){
+ switch (car) {
default:
break;
@@ -743,24 +739,31 @@ void SceneManager::resetQueue() {
_queue.clear();
}
-void SceneManager::setCoordinates(SequenceFrame *frame) {
+void SceneManager::setCoordinates(Common::Rect rect) {
+ _flagCoordinates = true;
- if (!frame || frame->getInfo()->subType == 3)
- return;
+ if (_coords.right > rect.right)
+ _coords.right = rect.right;
- _flagCoordinates = true;
+ if (_coords.bottom > rect.bottom)
+ _coords.bottom = rect.bottom;
+
+ if (_coords.left < rect.left)
+ _coords.left = rect.left;
- if (_coords.right > (int)frame->getInfo()->xPos1)
- _coords.right = (int16)frame->getInfo()->xPos1;
+ if (_coords.top < rect.top)
+ _coords.top = rect.top;
+}
- if (_coords.bottom > (int)frame->getInfo()->yPos1)
- _coords.bottom = (int16)frame->getInfo()->yPos1;
+void SceneManager::setCoordinates(SequenceFrame *frame) {
- if (_coords.left < (int)frame->getInfo()->xPos2)
- _coords.left = (int16)frame->getInfo()->xPos2;
+ if (!frame || frame->getInfo()->subType == 3)
+ return;
- if (_coords.top < (int)frame->getInfo()->yPos2)
- _coords.top = (int16)frame->getInfo()->yPos2;
+ setCoordinates(Common::Rect((int16)frame->getInfo()->xPos1,
+ (int16)frame->getInfo()->yPos1,
+ (int16)frame->getInfo()->xPos2,
+ (int16)frame->getInfo()->yPos2));
}
void SceneManager::resetCoordinates() {
diff --git a/engines/lastexpress/game/scenes.h b/engines/lastexpress/game/scenes.h
index 172dde2683..a866c65111 100644
--- a/engines/lastexpress/game/scenes.h
+++ b/engines/lastexpress/game/scenes.h
@@ -79,6 +79,7 @@ public:
void removeAndRedraw(SequenceFrame **frame, bool doRedraw);
void resetQueue();
void setCoordinates(SequenceFrame *frame);
+ void setCoordinates(Common::Rect rect);
// Helpers
SceneIndex getSceneIndexFromPosition(CarIndex car, Position position, int param3 = -1);
diff --git a/engines/lastexpress/game/state.cpp b/engines/lastexpress/game/state.cpp
index f3fd9720b1..02ede25595 100644
--- a/engines/lastexpress/game/state.cpp
+++ b/engines/lastexpress/game/state.cpp
@@ -49,6 +49,18 @@ State::~State() {
_engine = NULL;
}
+void State::reset() {
+ SAFE_DELETE(_inventory);
+ SAFE_DELETE(_objects);
+ SAFE_DELETE(_savepoints);
+ SAFE_DELETE(_state);
+
+ _inventory = new Inventory(_engine);
+ _objects = new Objects(_engine);
+ _savepoints = new SavePoints(_engine);
+ _state = new GameState();
+}
+
bool State::isNightTime() const {
return (_state->progress.chapter == kChapter1
|| _state->progress.chapter == kChapter4
diff --git a/engines/lastexpress/game/state.h b/engines/lastexpress/game/state.h
index c937fdce9f..2c484f6976 100644
--- a/engines/lastexpress/game/state.h
+++ b/engines/lastexpress/game/state.h
@@ -621,6 +621,8 @@ public:
State(LastExpressEngine *engine);
~State();
+ void reset();
+
// Accessors
Inventory *getGameInventory() { return _inventory; }
Objects *getGameObjects() { return _objects; }
diff --git a/engines/lastexpress/helpers.h b/engines/lastexpress/helpers.h
index 7f3f1e246c..02454be13d 100644
--- a/engines/lastexpress/helpers.h
+++ b/engines/lastexpress/helpers.h
@@ -27,6 +27,8 @@
// Misc helpers
//////////////////////////////////////////////////////////////////////////
+#define LOW_BYTE(w) ((unsigned char)(((unsigned long)(w)) & 0xff))
+
// Misc
#define getArchive(name) _engine->getResourceManager()->getFileStream(name)
#define rnd(value) _engine->getRandom().getRandomNumber(value - 1)
diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp
index 250fa0f2d0..01d2634dec 100644
--- a/engines/lastexpress/lastexpress.cpp
+++ b/engines/lastexpress/lastexpress.cpp
@@ -54,18 +54,17 @@ const char *g_entityNames[] = { "Player", "Anna", "August", "Mertens", "Coudert"
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),
+ Engine(syst), _gameDescription(gd),
+ _debugger(NULL), _random("lastexpress"), _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),
- _random("lastexpress")
+ _eventMouseBackup(NULL), _eventTickBackup(NULL)
{
// Setup mixer
- syncSoundSettings();
+ Engine::syncSoundSettings();
// Adding the default directories
const Common::FSNode gameDataDir(ConfMan.get("path"));
diff --git a/engines/lastexpress/menu/menu.cpp b/engines/lastexpress/menu/menu.cpp
index f1a8bebe94..6a453aee99 100644
--- a/engines/lastexpress/menu/menu.cpp
+++ b/engines/lastexpress/menu/menu.cpp
@@ -30,6 +30,7 @@
#include "lastexpress/fight/fight.h"
+#include "lastexpress/game/entities.h"
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/savegame.h"
@@ -41,10 +42,8 @@
#include "lastexpress/menu/trainline.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/sound/sound.h"
#include "lastexpress/graphics.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
@@ -865,7 +864,7 @@ void Menu::init(bool doSavegame, SavegameType type, uint32 value) {
doSavegame = false;
} else {
- // TODO rename saves?
+ warning("[Menu::initGame] Renaming saves not implemented");
}
// Create a new savegame if needed
@@ -876,7 +875,7 @@ void Menu::init(bool doSavegame, SavegameType type, uint32 value) {
getSaveLoad()->saveGame(kSavegameTypeEvent2, kEntityPlayer, kEventNone);
if (!getGlobalTimer()) {
- // TODO: remove existing savegame temp file
+ warning("[Menu::initGame] Removing temporary saves not implemented");
}
// Init savegame & menu values
diff --git a/engines/lastexpress/resource.cpp b/engines/lastexpress/resource.cpp
index ee4885e34e..1d010355ac 100644
--- a/engines/lastexpress/resource.cpp
+++ b/engines/lastexpress/resource.cpp
@@ -31,7 +31,6 @@
#include "common/debug.h"
#include "common/file.h"
-#include "common/textconsole.h"
namespace LastExpress {
@@ -129,13 +128,10 @@ bool ResourceManager::loadArchive(const Common::String &name) {
// 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) {
+Common::SeekableReadStream *ResourceManager::getFileStream(const Common::String &name) const {
// 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;
}
diff --git a/engines/lastexpress/resource.h b/engines/lastexpress/resource.h
index f2f5d63bce..90ac9b87ad 100644
--- a/engines/lastexpress/resource.h
+++ b/engines/lastexpress/resource.h
@@ -42,7 +42,7 @@ public:
// Loading
bool loadArchive(ArchiveIndex type);
static bool isArchivePresent(ArchiveIndex type);
- Common::SeekableReadStream *getFileStream(const Common::String &name);
+ Common::SeekableReadStream *getFileStream(const Common::String &name) const;
// Archive functions
bool hasFile(const Common::String &name) const;
diff --git a/engines/lastexpress/shared.h b/engines/lastexpress/shared.h
index d60a498447..56cf730e24 100644
--- a/engines/lastexpress/shared.h
+++ b/engines/lastexpress/shared.h
@@ -80,7 +80,8 @@ enum SoundFlag {
kFlagMusic = 0x5000010,
kFlagType3 = 0x6000000,
kFlagLoop = 0x6001008,
- kFlagType9 = 0x7000000
+ kFlagType9 = 0x7000000,
+ kFlagNIS = 0x7002010
};
enum SoundState {
@@ -1732,62 +1733,6 @@ enum ActionIndex {
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/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp
index 44cc68a57b..f2a063e45f 100644
--- a/engines/lastexpress/sound/entry.cpp
+++ b/engines/lastexpress/sound/entry.cpp
@@ -30,11 +30,9 @@
#include "lastexpress/sound/sound.h"
#include "lastexpress/graphics.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
-#include "common/stream.h"
namespace LastExpress {
@@ -47,6 +45,8 @@ namespace LastExpress {
SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) {
_type = kSoundTypeNone;
+ _currentDataPtr = NULL;
+
_blockCount = 0;
_time = 0;
@@ -71,7 +71,13 @@ SoundEntry::~SoundEntry() {
// Entries that have been queued will have their streamed disposed automatically
if (!_soundStream)
SAFE_DELETE(_stream);
- delete _soundStream;
+
+ SAFE_DELETE(_soundStream);
+
+ free(_currentDataPtr);
+
+ _subtitle = NULL;
+ _stream = NULL;
// Zero passed pointers
_engine = NULL;
@@ -111,7 +117,7 @@ void SoundEntry::close() {
void SoundEntry::play() {
if (!_stream) {
- warning("[SoundEntry::play] stream has been disposed");
+ error("[SoundEntry::play] stream has been disposed");
return;
}
@@ -277,7 +283,7 @@ bool SoundEntry::updateSound() {
int l = strlen(sub) + 1;
if (l - 1 > 4)
- sub[l - 1 - 4] = 0;
+ sub[l - (1 + 4)] = 0;
showSubtitle(sub);
}
} else {
@@ -393,6 +399,10 @@ SubtitleEntry::SubtitleEntry(LastExpressEngine *engine) : _engine(engine) {
SubtitleEntry::~SubtitleEntry() {
SAFE_DELETE(_data);
+
+ // Zero-out passed pointers
+ _sound = NULL;
+ _engine = NULL;
}
void SubtitleEntry::load(Common::String filename, SoundEntry *soundEntry) {
@@ -423,6 +433,9 @@ void SubtitleEntry::loadData() {
}
void SubtitleEntry::setupAndDraw() {
+ if (!_sound)
+ error("[SubtitleEntry::setupAndDraw] Sound entry not initialized");
+
if (!_data) {
_data = new SubtitleManager(_engine->getFont());
_data->load(getArchive(_filename));
diff --git a/engines/lastexpress/sound/queue.cpp b/engines/lastexpress/sound/queue.cpp
index 33b4c06793..d72acfd8a0 100644
--- a/engines/lastexpress/sound/queue.cpp
+++ b/engines/lastexpress/sound/queue.cpp
@@ -26,6 +26,7 @@
#include "lastexpress/game/state.h"
#include "lastexpress/sound/entry.h"
+#include "lastexpress/sound/sound.h"
#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
@@ -39,6 +40,7 @@ SoundQueue::SoundQueue(LastExpressEngine *engine) : _engine(engine) {
_subtitlesFlag = 0;
_currentSubtitle = NULL;
+ //_soundCacheData = NULL;
}
SoundQueue::~SoundQueue() {
@@ -51,6 +53,7 @@ SoundQueue::~SoundQueue() {
_subtitles.clear();
_currentSubtitle = NULL;
+ //SAFE_DELETE(_soundCacheData);
// Zero passed pointers
_engine = NULL;
@@ -134,7 +137,7 @@ void SoundQueue::updateQueue() {
// Original update the current entry, loading another set of samples to be decoded
- getFlags()->flag_3 = 0;
+ getFlags()->flag_3 = false;
--_flag;
}
@@ -340,13 +343,14 @@ void SoundQueue::updateSubtitles() {
return;
}
+ if (!subtitle)
+ return;
+
if (_subtitlesFlag & 1)
subtitle->drawOnScreen();
- if (subtitle) {
- subtitle->loadData();
- subtitle->setupAndDraw();
- }
+ subtitle->loadData();
+ subtitle->setupAndDraw();
}
//////////////////////////////////////////////////////////////////////////
@@ -368,7 +372,15 @@ void SoundQueue::saveLoadWithSerializer(Common::Serializer &s) {
(*i)->saveLoadWithSerializer(s);
} else {
warning("[Sound::saveLoadWithSerializer] Loading not implemented");
- s.skip(numEntries * 64);
+
+ uint32 unusedDataSize = numEntries * 64;
+ if (s.isLoading()) {
+ byte *empty = (byte *)malloc(unusedDataSize);
+ s.syncBytes(empty, unusedDataSize);
+ free(empty);
+ } else {
+ s.skip(unusedDataSize);
+ }
}
}
diff --git a/engines/lastexpress/sound/queue.h b/engines/lastexpress/sound/queue.h
index 75fe06883a..e1f9be1cf7 100644
--- a/engines/lastexpress/sound/queue.h
+++ b/engines/lastexpress/sound/queue.h
@@ -106,7 +106,7 @@ private:
// Entries
Common::List<SoundEntry *> _soundList; ///< List of all sound entries
- void *_soundCacheData;
+ //void *_soundCacheData;
// Subtitles
int _subtitlesFlag;
diff --git a/engines/lastexpress/sound/sound.cpp b/engines/lastexpress/sound/sound.cpp
index 2f7bb4a601..319f7cd4f4 100644
--- a/engines/lastexpress/sound/sound.cpp
+++ b/engines/lastexpress/sound/sound.cpp
@@ -33,7 +33,6 @@
#include "lastexpress/sound/entry.h"
#include "lastexpress/sound/queue.h"
-#include "lastexpress/helpers.h"
#include "lastexpress/graphics.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
@@ -675,7 +674,7 @@ const char *SoundManager::getDialogName(EntityIndex entity) const {
//////////////////////////////////////////////////////////////////////////
// Letters & Messages
//////////////////////////////////////////////////////////////////////////
-void SoundManager::readText(int id){
+void SoundManager::readText(int id) {
if (!_queue->isBuffered(kEntityTables4))
return;
@@ -1330,23 +1329,23 @@ void SoundManager::playLoopingSound(int param) {
}
} else {
switch (getEntityData(kEntityPlayer)->car) {
- case 1:
- case 6:
+ case kCarBaggageRear:
+ case kCarBaggage:
partNumber = 4;
break;
- case 2:
- case 3:
- case 4:
- case 5:
+ case kCarKronos:
+ case kCarGreenSleeping:
+ case kCarRedSleeping:
+ case kCarRestaurant:
partNumber = 1;
break;
- case 7:
+ case kCarCoalTender:
partNumber = 5;
break;
- case 8:
+ case kCarLocomotive:
partNumber = 99;
break;
- case 9:
+ case kCar9:
partNumber = 3;
break;
default:
@@ -1357,13 +1356,13 @@ void SoundManager::playLoopingSound(int param) {
}
if (partNumber != 99)
- sprintf(tmp, "LOOP%d%c.SND", partNumber, _engine->getRandom().getRandomNumber(numLoops[partNumber] - 1) + 'A');
+ sprintf(tmp, "LOOP%d%c.SND", partNumber, (char)(_engine->getRandom().getRandomNumber(numLoops[partNumber] - 1) + 'A'));
}
if (getFlags()->flag_3)
fnameLen = 5;
- if (!entry || scumm_strnicmp(entry->getName2().c_str(), tmp, fnameLen)) {
+ if (!entry || scumm_strnicmp(entry->getName2().c_str(), tmp, (uint)fnameLen)) {
_loopingSoundDuration = _engine->getRandom().getRandomNumber(319) + 260;
if (partNumber != 99) {
diff --git a/engines/lure/surface.cpp b/engines/lure/surface.cpp
index 4d63647af5..0f13d87fbc 100644
--- a/engines/lure/surface.cpp
+++ b/engines/lure/surface.cpp
@@ -1360,8 +1360,8 @@ bool CopyProtectionDialog::show() {
(*tmpHotspot)->copyTo(&screen.screen());
screen.update();
- } else if ((events.event().kbd.keycode >= Common::KEYCODE_0) &&
- (events.event().kbd.keycode <= Common::KEYCODE_9)) {
+ } else if ((events.event().kbd.ascii >= '0') &&
+ (events.event().kbd.ascii <= '9')) {
HotspotsList::iterator tmpHotspot = _hotspots.begin();
for (int i = 0; i < _charIndex + 3; i++)
++tmpHotspot;
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index f0c657897d..5664929948 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -167,7 +167,7 @@ public:
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- return detectGameFilebased(allFiles, Mohawk::fileBased);
+ return detectGameFilebased(allFiles, fslist, Mohawk::fileBased);
}
virtual const char *getName() const {
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index 5acc1bb179..55814af1c3 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -204,24 +204,6 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Myst Masterpiece Edition
- // English Windows
- // From clone2727
- {
- {
- "myst",
- "Masterpiece Edition",
- AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"),
- Common::EN_ANY,
- Common::kPlatformMacintosh,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_MYST,
- GF_ME,
- 0,
- },
-
- // Myst Masterpiece Edition
// German Windows
// From DrMcCoy (Included in "Myst: Die Trilogie")
{
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 708478a6d8..a0671d18d5 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -3378,11 +3378,10 @@ void LBLiveTextItem::readData(uint16 type, uint16 size, Common::MemoryReadStream
LiveTextWord word;
word.bounds = _vm->readRect(stream);
word.soundId = stream->readUint16();
- // TODO: unknowns
- uint16 unknown1 = stream->readUint16();
- uint16 unknown2 = stream->readUint16();
- debug(4, "Word: (%d, %d) to (%d, %d), sound %d, unknowns %04x, %04x",
- word.bounds.left, word.bounds.top, word.bounds.right, word.bounds.bottom, word.soundId, unknown1, unknown2);
+ word.itemType = stream->readUint16();
+ word.itemId = stream->readUint16();
+ debug(4, "Word: (%d, %d) to (%d, %d), sound %d, item %d (type %d)",
+ word.bounds.left, word.bounds.top, word.bounds.right, word.bounds.bottom, word.soundId, word.itemId, word.itemType);
_words.push_back(word);
}
@@ -3461,6 +3460,12 @@ void LBLiveTextItem::update() {
uint16 soundId = _words[_currentWord].soundId;
if (soundId && !_vm->_sound->isPlaying(soundId)) {
paletteUpdate(_currentWord, false);
+
+ // TODO: check this in RE
+ LBItem *item = _vm->getItemById(_words[_currentWord].itemId);
+ if (item)
+ item->togglePlaying(false, true);
+
_currentWord = 0xFFFF;
}
}
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index 91d6a8cd30..76da7d8219 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -537,6 +537,9 @@ protected:
struct LiveTextWord {
Common::Rect bounds;
uint16 soundId;
+
+ uint16 itemType;
+ uint16 itemId;
};
struct LiveTextPhrase {
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index 0efd412bd0..9c0e642203 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -98,11 +98,6 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
_view.soundListVolume = NULL;
_view.scriptResCount = 0;
_view.scriptResources = NULL;
-
- if ((getFeatures() & GF_ME) && getPlatform() == Common::kPlatformMacintosh) {
- const Common::FSNode gameDataDir(ConfMan.get("path"));
- SearchMan.addSubDirectoryMatching(gameDataDir, "CD Data");
- }
}
MohawkEngine_Myst::~MohawkEngine_Myst() {
@@ -205,11 +200,6 @@ static const char *mystFiles[] = {
// qtw/myst/libelev.mov: libup.mov is basically the same with sound
Common::String MohawkEngine_Myst::wrapMovieFilename(const Common::String &movieName, uint16 stack) {
- // The Macintosh release of Myst ME stores its videos in a different folder
- // WORKAROUND: The gear rotation videos are not in the CD Data folder. See above comments.
- if ((getFeatures() & GF_ME) && getPlatform() == Common::kPlatformMacintosh && !movieName.matchString("cl1wg?"))
- return Common::String("CD Data/m/") + movieName + ".mov";
-
Common::String prefix;
switch (stack) {
@@ -498,52 +488,32 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
if (!_mhk[0]->openFile(mystFiles[_curStack]))
error("Could not open %s", mystFiles[_curStack]);
- if (getPlatform() == Common::kPlatformMacintosh)
- _gfx->loadExternalPictureFile(_curStack);
-
_runExitScript = false;
// Clear the resource cache and the image cache
_cache.clear();
_gfx->clearCache();
- // Play Flyby Entry Movie on Masterpiece Edition. The Macintosh version is currently hooked
- // up to the Cinepak versions of the video (the 'c' suffix) until the SVQ1 decoder is completed.
+ // Play Flyby Entry Movie on Masterpiece Edition.
const char *flyby = 0;
if (getFeatures() & GF_ME) {
switch (_curStack) {
case kSeleniticStack:
- if (getPlatform() == Common::kPlatformMacintosh)
- flyby = "FLY_SEc";
- else
- flyby = "selenitic flyby";
+ flyby = "selenitic flyby";
break;
case kStoneshipStack:
- if (getPlatform() == Common::kPlatformMacintosh)
- flyby = "FLY_STc";
- else
- flyby = "stoneship flyby";
+ flyby = "stoneship flyby";
break;
// Myst Flyby Movie not used in Original Masterpiece Edition Engine
case kMystStack:
- if (_tweaksEnabled) {
- if (getPlatform() == Common::kPlatformMacintosh)
- flyby = "FLY_MYc";
- else
- flyby = "myst flyby";
- }
+ if (_tweaksEnabled)
+ flyby = "myst flyby";
break;
case kMechanicalStack:
- if (getPlatform() == Common::kPlatformMacintosh)
- flyby = "FLY_MEc";
- else
- flyby = "mech age flyby";
+ flyby = "mech age flyby";
break;
case kChannelwoodStack:
- if (getPlatform() == Common::kPlatformMacintosh)
- flyby = "FLY_CHc";
- else
- flyby = "channelwood flyby";
+ flyby = "channelwood flyby";
break;
default:
break;
diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp
index ae80dd5538..2df0f7e6ba 100644
--- a/engines/mohawk/myst_graphics.cpp
+++ b/engines/mohawk/myst_graphics.cpp
@@ -49,8 +49,6 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) {
if (_pixelFormat.bytesPerPixel == 1)
error("Myst requires greater than 256 colors to run");
- _pictureFile.entries = NULL;
-
// Initialize our buffer
_backBuffer = new Graphics::Surface();
_backBuffer->create(_vm->_system->getWidth(), _vm->_system->getHeight(), _pixelFormat);
@@ -61,122 +59,50 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) {
MystGraphics::~MystGraphics() {
delete _bmpDecoder;
- delete[] _pictureFile.entries;
_backBuffer->free();
delete _backBuffer;
}
-static const char *s_picFileNames[] = {
- "CHpics",
- "",
- "",
- "DUpics",
- "INpics",
- "",
- "MEpics",
- "MYpics",
- "SEpics",
- "",
- "",
- "STpics"
-};
-
-void MystGraphics::loadExternalPictureFile(uint16 stack) {
- if (_vm->getPlatform() != Common::kPlatformMacintosh)
- return;
-
- if (_pictureFile.picFile.isOpen())
- _pictureFile.picFile.close();
- delete[] _pictureFile.entries;
-
- if (!scumm_stricmp(s_picFileNames[stack], ""))
- return;
-
- if (!_pictureFile.picFile.open(s_picFileNames[stack]))
- error ("Could not open external picture file \'%s\'", s_picFileNames[stack]);
-
- _pictureFile.pictureCount = _pictureFile.picFile.readUint32BE();
- _pictureFile.entries = new PictureFile::PictureEntry[_pictureFile.pictureCount];
-
- for (uint32 i = 0; i < _pictureFile.pictureCount; i++) {
- _pictureFile.entries[i].offset = _pictureFile.picFile.readUint32BE();
- _pictureFile.entries[i].size = _pictureFile.picFile.readUint32BE();
- _pictureFile.entries[i].id = _pictureFile.picFile.readUint16BE();
- _pictureFile.entries[i].type = _pictureFile.picFile.readUint16BE();
- _pictureFile.entries[i].width = _pictureFile.picFile.readUint16BE();
- _pictureFile.entries[i].height = _pictureFile.picFile.readUint16BE();
+MohawkSurface *MystGraphics::decodeImage(uint16 id) {
+ // We need to grab the image from the current stack archive, however, we don't know
+ // if it's a PICT or WDIB resource. If it's Myst ME it's most likely a PICT, and if it's
+ // original it's definitely a WDIB. However, Myst ME throws us another curve ball in
+ // that PICT resources can contain WDIB's instead of PICT's.
+ Common::SeekableReadStream *dataStream = NULL;
+
+ if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) {
+ // The PICT resource exists. However, it could still contain a MystBitmap
+ // instead of a PICT image...
+ dataStream = _vm->getResource(ID_PICT, id);
+ } else {
+ // No PICT, so the WDIB must exist. Let's go grab it.
+ dataStream = _vm->getResource(ID_WDIB, id);
}
-}
-MohawkSurface *MystGraphics::decodeImage(uint16 id) {
- MohawkSurface *mhkSurface = 0;
+ bool isPict = false;
- // Myst ME uses JPEG/PICT images instead of compressed Windows Bitmaps for room images,
- // though there are a few weird ones that use that format. For further nonsense with images,
- // the Macintosh version stores images in external "picture files." We check them before
- // going to check for a PICT resource.
- if (_vm->getFeatures() & GF_ME && _vm->getPlatform() == Common::kPlatformMacintosh && _pictureFile.picFile.isOpen()) {
- for (uint32 i = 0; i < _pictureFile.pictureCount; i++)
- if (_pictureFile.entries[i].id == id) {
- if (_pictureFile.entries[i].type == 0) {
- Graphics::JPEGDecoder jpeg;
- Common::SeekableSubReadStream subStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size);
-
- if (!jpeg.loadStream(subStream))
- error("Could not decode Myst ME Mac JPEG");
-
- mhkSurface = new MohawkSurface(jpeg.getSurface()->convertTo(_pixelFormat));
- } else if (_pictureFile.entries[i].type == 1) {
- Graphics::PICTDecoder pict;
- Common::SeekableSubReadStream subStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size);
-
- if (!pict.loadStream(subStream))
- error("Could not decode Myst ME Mac PICT");
-
- mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat));
- } else
- error ("Unknown Picture File type %d", _pictureFile.entries[i].type);
- break;
- }
+ if (_vm->getFeatures() & GF_ME) {
+ // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap
+ // would be compressed, there's no way to detect for the BM without a hack.
+ // So, we search for the PICT version opcode for detection.
+ dataStream->seek(512 + 10); // 512 byte pict header
+ isPict = (dataStream->readUint32BE() == 0x001102FF);
+ dataStream->seek(0);
}
- // We're not using the external Mac files, so it's time to delve into the main Mohawk
- // archives. However, we still don't know if it's a PICT or WDIB resource. If it's Myst
- // ME it's most likely a PICT, and if it's original it's definitely a WDIB. However,
- // Myst ME throws us another curve ball in that PICT resources can contain WDIB's instead
- // of PICT's.
- if (!mhkSurface) {
- bool isPict = false;
- Common::SeekableReadStream *dataStream = NULL;
-
- if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) {
- // The PICT resource exists. However, it could still contain a MystBitmap
- // instead of a PICT image...
- dataStream = _vm->getResource(ID_PICT, id);
- } else // No PICT, so the WDIB must exist. Let's go grab it.
- dataStream = _vm->getResource(ID_WDIB, id);
-
- if (_vm->getFeatures() & GF_ME) {
- // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap
- // would be compressed, there's no way to detect for the BM without a hack.
- // So, we search for the PICT version opcode for detection.
- dataStream->seek(512 + 10); // 512 byte pict header
- isPict = (dataStream->readUint32BE() == 0x001102FF);
- dataStream->seek(0);
- }
+ MohawkSurface *mhkSurface = 0;
- if (isPict) {
- Graphics::PICTDecoder pict;
+ if (isPict) {
+ Graphics::PICTDecoder pict;
- if (!pict.loadStream(*dataStream))
- error("Could not decode Myst ME PICT");
+ if (!pict.loadStream(*dataStream))
+ error("Could not decode Myst ME PICT");
- mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat));
- } else {
- mhkSurface = _bmpDecoder->decodeImage(dataStream);
- mhkSurface->convertToTrueColor();
- }
+ mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat));
+ } else {
+ mhkSurface = _bmpDecoder->decodeImage(dataStream);
+ mhkSurface->convertToTrueColor();
}
assert(mhkSurface);
diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h
index 20fd46c5b9..de8fe521e6 100644
--- a/engines/mohawk/myst_graphics.h
+++ b/engines/mohawk/myst_graphics.h
@@ -43,7 +43,6 @@ public:
MystGraphics(MohawkEngine_Myst*);
~MystGraphics();
- void loadExternalPictureFile(uint16 stack);
void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest);
void copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest);
void copyImageToScreen(uint16 image, Common::Rect dest);
@@ -66,20 +65,6 @@ private:
MohawkEngine_Myst *_vm;
MystBitmap *_bmpDecoder;
- struct PictureFile {
- uint32 pictureCount;
- struct PictureEntry {
- uint32 offset;
- uint32 size;
- uint16 id;
- uint16 type;
- uint16 width;
- uint16 height;
- } *entries;
-
- Common::File picFile;
- } _pictureFile;
-
Graphics::Surface *_backBuffer;
Graphics::PixelFormat _pixelFormat;
Common::Rect _viewport;
diff --git a/engines/mohawk/myst_stacks/dni.cpp b/engines/mohawk/myst_stacks/dni.cpp
index cae165ccf0..d103105c2d 100644
--- a/engines/mohawk/myst_stacks/dni.cpp
+++ b/engines/mohawk/myst_stacks/dni.cpp
@@ -109,7 +109,7 @@ void Dni::o_handPage(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_vm->setMainCursor(kDefaultMystCursor);
// Play movie end (atrus leaving)
- _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), Audio::Timestamp(0xFFFFFFFF));
+ _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), _vm->_video->getDuration(atrus));
_vm->_video->setVideoLooping(atrus, false);
_atrusLeft = true;
diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp
index a5f608dbbf..545b97d956 100644
--- a/engines/mohawk/myst_stacks/intro.cpp
+++ b/engines/mohawk/myst_stacks/intro.cpp
@@ -100,12 +100,8 @@ void Intro::introMovies_run() {
switch (_introStep) {
case 0:
- // Play the Mattel (or UbiSoft) logo in the Myst ME Mac version
- if ((_vm->getFeatures() & GF_ME) && _vm->getPlatform() == Common::kPlatformMacintosh) {
- _vm->_video->playMovie(_vm->wrapMovieFilename("mattel", kIntroStack));
- _introStep = 1;
- } else
- _introStep = 2;
+ _introStep = 1;
+ _vm->_video->playMovie(_vm->wrapMovieFilename("broder", kIntroStack));
break;
case 1:
if (!_vm->_video->isVideoPlaying())
@@ -113,10 +109,7 @@ void Intro::introMovies_run() {
break;
case 2:
_introStep = 3;
- if ((_vm->getFeatures() & GF_ME) && _vm->getPlatform() == Common::kPlatformMacintosh)
- _vm->_video->playMovie(_vm->wrapMovieFilename("presto", kIntroStack));
- else
- _vm->_video->playMovie(_vm->wrapMovieFilename("broder", kIntroStack));
+ _vm->_video->playMovie(_vm->wrapMovieFilename("cyanlogo", kIntroStack));
break;
case 3:
if (!_vm->_video->isVideoPlaying())
@@ -124,21 +117,13 @@ void Intro::introMovies_run() {
break;
case 4:
_introStep = 5;
- _vm->_video->playMovie(_vm->wrapMovieFilename("cyanlogo", kIntroStack));
- break;
- case 5:
- if (!_vm->_video->isVideoPlaying())
- _introStep = 6;
- break;
- case 6:
- _introStep = 7;
if (!(_vm->getFeatures() & GF_DEMO)) // The demo doesn't have the intro video
_vm->_video->playMovie(_vm->wrapMovieFilename("intro", kIntroStack));
break;
- case 7:
+ case 5:
if (!_vm->_video->isVideoPlaying())
- _introStep = 8;
+ _introStep = 6;
break;
default:
if (_vm->getFeatures() & GF_DEMO)
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index e54d6fefa2..32613c6185 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -646,7 +646,7 @@ Common::String MohawkEngine_Riven::getName(uint16 nameResource, uint16 nameID) {
}
delete nameStream;
- delete [] stringOffsets;
+ delete[] stringOffsets;
return name;
}
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index 18d609c513..0ed4f38b53 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -29,6 +29,7 @@
#include "common/textconsole.h"
#include "common/system.h"
+#include "graphics/palette.h"
#include "graphics/surface.h"
#include "video/qt_decoder.h"
@@ -43,13 +44,12 @@ void VideoEntry::clear() {
loop = false;
enabled = false;
start = Audio::Timestamp(0, 1);
- end = Audio::Timestamp(0xFFFFFFFF, 1); // Largest possible, there is an endOfVideo() check anyway
filename.clear();
id = -1;
}
bool VideoEntry::endOfVideo() {
- return !video || video->endOfVideo() || video->getTime() >= (uint)end.msecs();
+ return !video || video->endOfVideo();
}
VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) {
@@ -207,7 +207,7 @@ bool VideoManager::updateMovies() {
// Remove any videos that are over
if (_videoStreams[i].endOfVideo()) {
if (_videoStreams[i].loop) {
- _videoStreams[i]->seekToTime(_videoStreams[i].start);
+ _videoStreams[i]->seek(_videoStreams[i].start);
} else {
// Check the video time one last time before deleting it
_vm->doVideoTimer(i, true);
@@ -239,7 +239,7 @@ bool VideoManager::updateMovies() {
frame = convertedFrame;
} else if (pixelFormat.bytesPerPixel == 1 && _videoStreams[i]->hasDirtyPalette()) {
// Set the palette when running in 8bpp mode only
- _videoStreams[i]->setSystemPalette();
+ _vm->_system->getPaletteManager()->setPalette(_videoStreams[i]->getPalette(), 0, 256);
}
// Clip the width/height to make sure we stay on the screen (Myst does this a few times)
@@ -394,6 +394,8 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool
entry.loop = loop;
entry.enabled = true;
+ entry->start();
+
// Search for any deleted videos so we can take a formerly used slot
for (uint32 i = 0; i < _videoStreams.size(); i++)
if (!_videoStreams[i].video) {
@@ -430,6 +432,7 @@ VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint
entry->loadStream(file);
entry->setVolume(volume);
+ entry->start();
// Search for any deleted videos so we can take a formerly used slot
for (uint32 i = 0; i < _videoStreams.size(); i++)
@@ -492,7 +495,7 @@ uint32 VideoManager::getTime(VideoHandle handle) {
uint32 VideoManager::getDuration(VideoHandle handle) {
assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getDuration();
+ return _videoStreams[handle]->getDuration().msecs();
}
bool VideoManager::endOfVideo(VideoHandle handle) {
@@ -511,14 +514,13 @@ bool VideoManager::isVideoPlaying() {
void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end) {
assert(handle != NULL_VID_HANDLE);
_videoStreams[handle].start = start;
- _videoStreams[handle].end = end;
- _videoStreams[handle]->seekToTime(start);
+ _videoStreams[handle]->setEndTime(end);
+ _videoStreams[handle]->seek(start);
}
void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) {
assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle].end = Audio::Timestamp(0xffffffff, 1);
- _videoStreams[handle]->seekToTime(time);
+ _videoStreams[handle]->seek(time);
updateMovies();
delete _videoStreams[handle].video;
_videoStreams[handle].clear();
@@ -526,7 +528,7 @@ void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) {
void VideoManager::seekToTime(VideoHandle handle, Audio::Timestamp time) {
assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle]->seekToTime(time);
+ _videoStreams[handle]->seek(time);
}
void VideoManager::setVideoLooping(VideoHandle handle, bool loop) {
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index 98bcadfb53..9dddcde09b 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -45,19 +45,19 @@ struct MLSTRecord {
struct VideoEntry {
// Playback variables
- Video::SeekableVideoDecoder *video;
+ Video::VideoDecoder *video;
uint16 x;
uint16 y;
bool loop;
bool enabled;
- Audio::Timestamp start, end;
+ Audio::Timestamp start;
// Identification
Common::String filename; // External video files
int id; // Internal Mohawk files
// Helper functions
- Video::SeekableVideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually
+ Video::VideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually
void clear();
bool endOfVideo();
};
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 5e39c893db..ee981a2c7d 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -617,7 +617,7 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) {
}
}
- delete []shadow;
+ delete[] shadow;
delete stream;
}
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index 839b2c6834..8d4afd6847 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -832,7 +832,7 @@ void AmigaDisk_ns::decodeCnv(byte *data, uint16 numFrames, uint16 width, uint16
assert(buf);
stream->read(buf, rawsize);
unpackBitmap(data, buf, numFrames, bytesPerPlane, height);
- delete []buf;
+ delete[] buf;
}
#undef NUM_PLANES
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 6868505c52..9855830478 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -766,7 +766,7 @@ Gfx::~Gfx() {
freeLabels();
- delete []_unpackedBitmap;
+ delete[] _unpackedBitmap;
return;
}
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index b43dd193b5..f8cb4b3647 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -144,7 +144,7 @@ public:
~Cnv() {
if (_freeData)
- delete []_data;
+ delete[] _data;
}
byte* getFramePtr(uint16 index) {
diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp
index 3cc25b36b0..dcc71e4f2f 100644
--- a/engines/parallaction/sound_ns.cpp
+++ b/engines/parallaction/sound_ns.cpp
@@ -237,7 +237,7 @@ AmigaSoundMan_ns::~AmigaSoundMan_ns() {
stopSfx(2);
stopSfx(3);
- delete []beepSoundBuffer;
+ delete[] beepSoundBuffer;
}
Audio::AudioStream *AmigaSoundMan_ns::loadChannelData(const char *filename, Channel *ch, bool looping) {
diff --git a/engines/pegasus/movie.cpp b/engines/pegasus/movie.cpp
index 5d393de492..fc722e5043 100644
--- a/engines/pegasus/movie.cpp
+++ b/engines/pegasus/movie.cpp
@@ -73,8 +73,6 @@ void Movie::initFromMovieFile(const Common::String &fileName, bool transparent)
error("Could not load video '%s'", fileName.c_str());
}
- _video->pauseVideo(true);
-
Common::Rect bounds(0, 0, _video->getWidth(), _video->getHeight());
sizeElement(_video->getWidth(), _video->getHeight());
_movieBox = bounds;
@@ -83,7 +81,7 @@ void Movie::initFromMovieFile(const Common::String &fileName, bool transparent)
allocateSurface(bounds);
setStart(0, getScale());
- setStop(_video->getDuration() * getScale() / 1000, getScale());
+ setStop(_video->getDuration().convertToFramerate(getScale()).totalNumberOfFrames(), getScale());
}
void Movie::redrawMovieWorld() {
@@ -149,7 +147,7 @@ void Movie::setTime(const TimeValue time, const TimeScale scale) {
else if (timeFrac >= Common::Rational(_stopTime, _stopScale))
return;
- _video->seekToTime(Audio::Timestamp(0, timeFrac.getNumerator(), timeFrac.getDenominator()));
+ _video->seek(Audio::Timestamp(0, timeFrac.getNumerator(), timeFrac.getDenominator()));
_time = timeFrac;
_lastMillis = 0;
}
@@ -166,15 +164,15 @@ void Movie::setRate(const Common::Rational rate) {
}
void Movie::start() {
- if (_video && _video->isPaused())
- _video->pauseVideo(false);
+ if (_video)
+ _video->start();
TimeBase::start();
}
void Movie::stop() {
- if (_video && !_video->isPaused())
- _video->pauseVideo(true);
+ if (_video)
+ _video->stop();
TimeBase::stop();
}
@@ -199,7 +197,7 @@ TimeValue Movie::getDuration(const TimeScale scale) const {
// but the problem is that too much code requires this function to behave this way...
if (_video)
- return _video->getDuration() * ((scale == 0) ? getScale() : scale) / 1000;
+ return _video->getDuration().convertToFramerate(((scale == 0) ? getScale() : scale)).totalNumberOfFrames();
return 0;
}
diff --git a/engines/pegasus/movie.h b/engines/pegasus/movie.h
index 593442fa44..efe4a7c244 100644
--- a/engines/pegasus/movie.h
+++ b/engines/pegasus/movie.h
@@ -32,7 +32,7 @@
#include "pegasus/surface.h"
namespace Video {
- class SeekableVideoDecoder;
+class VideoDecoder;
}
namespace Pegasus {
@@ -65,13 +65,13 @@ public:
virtual TimeValue getDuration(const TimeScale = 0) const;
// *** HACK ALERT
- Video::SeekableVideoDecoder *getMovie() { return _video; }
+ Video::VideoDecoder *getMovie() { return _video; }
void setVolume(uint16);
protected:
void updateTime();
- Video::SeekableVideoDecoder *_video;
+ Video::VideoDecoder *_video;
Common::Rect _movieBox;
};
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
index ce62b17265..a6806d5c46 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
@@ -205,13 +205,11 @@ void Caldoria::start() {
error("Could not load pullback movie");
// Draw the first frame so we can fade to it
- pullbackMovie->pauseVideo(true);
const Graphics::Surface *frame = pullbackMovie->decodeNextFrame();
assert(frame);
assert(frame->format == g_system->getScreenFormat());
g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 64, 112, frame->w, frame->h);
_vm->_gfx->doFadeInSync(kTwoSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond);
- pullbackMovie->pauseVideo(false);
bool saveAllowed = _vm->swapSaveAllowed(false);
bool openAllowed = _vm->swapLoadAllowed(false);
@@ -219,6 +217,8 @@ void Caldoria::start() {
bool skipped = false;
Input input;
+ pullbackMovie->start();
+
while (!_vm->shouldQuit() && !pullbackMovie->endOfVideo()) {
if (pullbackMovie->needsUpdate()) {
frame = pullbackMovie->decodeNextFrame();
diff --git a/engines/pegasus/neighborhood/mars/mars.cpp b/engines/pegasus/neighborhood/mars/mars.cpp
index c950a85897..816a13f01d 100644
--- a/engines/pegasus/neighborhood/mars/mars.cpp
+++ b/engines/pegasus/neighborhood/mars/mars.cpp
@@ -2405,6 +2405,8 @@ void Mars::doCanyonChase() {
if (!video->loadFile("Images/Mars/M44ESA.movie"))
error("Could not load interface->shuttle transition video");
+ video->start();
+
while (!_vm->shouldQuit() && !video->endOfVideo()) {
if (video->needsUpdate()) {
const Graphics::Surface *frame = video->decodeNextFrame();
@@ -3024,6 +3026,8 @@ void Mars::transportToRobotShip() {
if (!video->loadFile("Images/Mars/M98EAE.movie"))
error("Could not load shuttle->interface transition video");
+ video->start();
+
while (!_vm->shouldQuit() && !video->endOfVideo()) {
if (video->needsUpdate()) {
const Graphics::Surface *frame = video->decodeNextFrame();
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 0e426a2943..bbe2e0e212 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -289,8 +289,10 @@ void PegasusEngine::runIntro() {
bool skipped = false;
- Video::SeekableVideoDecoder *video = new Video::QuickTimeDecoder();
+ Video::VideoDecoder *video = new Video::QuickTimeDecoder();
if (video->loadFile(_introDirectory + "/BandaiLogo.movie")) {
+ video->start();
+
while (!shouldQuit() && !video->endOfVideo() && !skipped) {
if (video->needsUpdate()) {
const Graphics::Surface *frame = video->decodeNextFrame();
@@ -320,7 +322,8 @@ void PegasusEngine::runIntro() {
if (!video->loadFile(_introDirectory + "/Big Movie.movie"))
error("Could not load intro movie");
- video->seekToTime(Audio::Timestamp(0, 10 * 600, 600));
+ video->seek(Audio::Timestamp(0, 10 * 600, 600));
+ video->start();
playMovieScaled(video, 0, 0);
@@ -671,13 +674,14 @@ void PegasusEngine::introTimerExpired() {
bool skipped = false;
- Video::SeekableVideoDecoder *video = new Video::QuickTimeDecoder();
+ Video::VideoDecoder *video = new Video::QuickTimeDecoder();
if (!video->loadFile(_introDirectory + "/LilMovie.movie"))
error("Failed to load little movie");
bool saveAllowed = swapSaveAllowed(false);
bool openAllowed = swapLoadAllowed(false);
+ video->start();
skipped = playMovieScaled(video, 0, 0);
delete video;
@@ -815,13 +819,14 @@ void PegasusEngine::doGameMenuCommand(const GameMenuCommand command) {
_gfx->clearScreen();
_gfx->updateDisplay();
- Video::SeekableVideoDecoder *video = new Video::QuickTimeDecoder();
+ Video::VideoDecoder *video = new Video::QuickTimeDecoder();
if (!video->loadFile(_introDirectory + "/Closing.movie"))
error("Could not load closing movie");
uint16 x = (640 - video->getWidth() * 2) / 2;
uint16 y = (480 - video->getHeight() * 2) / 2;
+ video->start();
playMovieScaled(video, x, y);
delete video;
@@ -1261,7 +1266,7 @@ void PegasusEngine::checkFlashlight() {
_neighborhood->checkFlashlight();
}
-bool PegasusEngine::playMovieScaled(Video::SeekableVideoDecoder *video, uint16 x, uint16 y) {
+bool PegasusEngine::playMovieScaled(Video::VideoDecoder *video, uint16 x, uint16 y) {
bool skipped = false;
while (!shouldQuit() && !video->endOfVideo() && !skipped) {
@@ -2084,10 +2089,12 @@ void PegasusEngine::playEndMessage() {
void PegasusEngine::doSubChase() {
static const uint32 endTime = 133200 * 1000 / 600;
- Video::SeekableVideoDecoder *video = new Video::QuickTimeDecoder();
+ Video::VideoDecoder *video = new Video::QuickTimeDecoder();
if (!video->loadFile("Images/Norad Alpha/Sub Chase Movie"))
error("Failed to load sub chase");
+ video->start();
+
while (!shouldQuit() && !video->endOfVideo() && video->getTime() < endTime) {
if (video->needsUpdate()) {
const Graphics::Surface *frame = video->decodeNextFrame();
diff --git a/engines/pegasus/pegasus.h b/engines/pegasus/pegasus.h
index a1b4cff9ab..1ee0136c30 100644
--- a/engines/pegasus/pegasus.h
+++ b/engines/pegasus/pegasus.h
@@ -50,7 +50,7 @@ namespace Common {
}
namespace Video {
- class SeekableVideoDecoder;
+ class VideoDecoder;
}
namespace Pegasus {
@@ -253,7 +253,7 @@ private:
Hotspot _returnHotspot;
InputHandler *_savedHandler;
void showTempScreen(const Common::String &fileName);
- bool playMovieScaled(Video::SeekableVideoDecoder *video, uint16 x, uint16 y);
+ bool playMovieScaled(Video::VideoDecoder *video, uint16 x, uint16 y);
void throwAwayEverything();
void shellGameInput(const Input &input, const Hotspot *cursorSpot);
Common::RandomSource *_rnd;
diff --git a/engines/pegasus/surface.cpp b/engines/pegasus/surface.cpp
index 897305f2a3..343bc415f3 100644
--- a/engines/pegasus/surface.cpp
+++ b/engines/pegasus/surface.cpp
@@ -108,8 +108,8 @@ void Surface::getImageFromPICTStream(Common::SeekableReadStream *stream) {
_bounds = Common::Rect(0, 0, _surface->w, _surface->h);
}
-void Surface::getImageFromMovieFrame(Video::SeekableVideoDecoder *video, TimeValue time) {
- video->seekToTime(Audio::Timestamp(0, time, 600));
+void Surface::getImageFromMovieFrame(Video::VideoDecoder *video, TimeValue time) {
+ video->seek(Audio::Timestamp(0, time, 600));
const Graphics::Surface *frame = video->decodeNextFrame();
if (frame) {
@@ -344,7 +344,7 @@ void Frame::initFromPICTResource(Common::MacResManager *resFork, uint16 id, bool
_transparent = transparent;
}
-void Frame::initFromMovieFrame(Video::SeekableVideoDecoder *video, TimeValue time, bool transparent) {
+void Frame::initFromMovieFrame(Video::VideoDecoder *video, TimeValue time, bool transparent) {
getImageFromMovieFrame(video, time);
_transparent = transparent;
}
@@ -381,7 +381,7 @@ void Picture::initFromPICTResource(Common::MacResManager *resFork, uint16 id, bo
sizeElement(surfaceBounds.width(), surfaceBounds.height());
}
-void Picture::initFromMovieFrame(Video::SeekableVideoDecoder *video, TimeValue time, bool transparent) {
+void Picture::initFromMovieFrame(Video::VideoDecoder *video, TimeValue time, bool transparent) {
Frame::initFromMovieFrame(video, time, transparent);
Common::Rect surfaceBounds;
diff --git a/engines/pegasus/surface.h b/engines/pegasus/surface.h
index 34a88dbd53..311fb50419 100644
--- a/engines/pegasus/surface.h
+++ b/engines/pegasus/surface.h
@@ -41,7 +41,7 @@ namespace Graphics {
}
namespace Video {
- class SeekableVideoDecoder;
+ class VideoDecoder;
}
namespace Pegasus {
@@ -76,7 +76,7 @@ public:
virtual void getImageFromPICTFile(const Common::String &fileName);
virtual void getImageFromPICTResource(Common::MacResManager *resFork, uint16 id);
- virtual void getImageFromMovieFrame(Video::SeekableVideoDecoder *, TimeValue);
+ virtual void getImageFromMovieFrame(Video::VideoDecoder *, TimeValue);
protected:
bool _ownsSurface;
@@ -110,7 +110,7 @@ public:
virtual void initFromPICTFile(const Common::String &fileName, bool transparent = false);
virtual void initFromPICTResource(Common::MacResManager *resFork, uint16 id, bool transparent = false);
- virtual void initFromMovieFrame(Video::SeekableVideoDecoder *, TimeValue, bool transparent = false);
+ virtual void initFromMovieFrame(Video::VideoDecoder *, TimeValue, bool transparent = false);
};
class SpriteFrame : public Frame {
@@ -130,7 +130,7 @@ public:
virtual void initFromPICTFile(const Common::String &fileName, bool transparent = false);
virtual void initFromPICTResource(Common::MacResManager *resFork, uint16 id, bool transparent = false);
- virtual void initFromMovieFrame(Video::SeekableVideoDecoder *, TimeValue, bool transparent = false);
+ virtual void initFromMovieFrame(Video::VideoDecoder *, TimeValue, bool transparent = false);
virtual void draw(const Common::Rect &);
};
diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp
index 3acc87b856..f3b183c84f 100644
--- a/engines/queen/queen.cpp
+++ b/engines/queen/queen.cpp
@@ -56,8 +56,8 @@ static const PlainGameDescriptor queenGameDescriptor = {
};
static const ExtraGuiOption queenExtraGuiOption = {
- _s("Floppy intro"),
- _s("Use the floppy version's intro (CD version only)"),
+ _s("Alternative intro"),
+ _s("Use an alternative game intro (CD version only)"),
"alt_intro",
false
};
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index d39ec34cc8..9c178559f2 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -252,9 +252,6 @@ SaveStateDescriptor SagaMetaEngine::querySaveMetaInfos(const char *target, int s
debug(0, "Save is for: %s", title);
}
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
-
if (version >= 6) {
Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
desc.setThumbnail(thumbnail);
diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp
index b6470370af..260eca98e6 100644
--- a/engines/saga/introproc_saga2.cpp
+++ b/engines/saga/introproc_saga2.cpp
@@ -32,6 +32,7 @@
#include "common/keyboard.h"
#include "common/system.h"
#include "common/textconsole.h"
+#include "graphics/palette.h"
#include "graphics/surface.h"
#include "video/smk_decoder.h"
@@ -92,7 +93,7 @@ int Scene::FTA2EndProc(FTA2Endings whichEnding) {
}
void Scene::playMovie(const char *filename) {
- Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(_vm->_mixer);
+ Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder();
if (!smkDecoder->loadFile(filename))
return;
@@ -101,6 +102,8 @@ void Scene::playMovie(const char *filename) {
uint16 y = (g_system->getHeight() - smkDecoder->getHeight()) / 2;
bool skipVideo = false;
+ smkDecoder->start();
+
while (!_vm->shouldQuit() && !smkDecoder->endOfVideo() && !skipVideo) {
if (smkDecoder->needsUpdate()) {
const Graphics::Surface *frame = smkDecoder->decodeNextFrame();
@@ -108,7 +111,7 @@ void Scene::playMovie(const char *filename) {
_vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h);
if (smkDecoder->hasDirtyPalette())
- smkDecoder->setSystemPalette();
+ _vm->_system->getPaletteManager()->setPalette(smkDecoder->getPalette(), 0, 256);
_vm->_system->updateScreen();
}
diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp
index 5efc8d1f67..69c27b6a6b 100644
--- a/engines/saga/shorten.cpp
+++ b/engines/saga/shorten.cpp
@@ -519,9 +519,6 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
if (maxLPC > 0)
free(lpc);
- if (size > 0)
- free(unpackedBuffer);
-
delete gReader;
return unpackedBuffer;
}
diff --git a/engines/savestate.h b/engines/savestate.h
index 6cbdb22edf..c233554657 100644
--- a/engines/savestate.h
+++ b/engines/savestate.h
@@ -40,6 +40,8 @@ struct Surface;
*
* Further possibilites are a thumbnail, play time, creation date,
* creation time, delete protected, write protection.
+ *
+ * Saves are writable and deletable by default.
*/
class SaveStateDescriptor {
public:
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 40a6fd1415..1889d53480 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -250,20 +250,18 @@ void Console::postEnter() {
#endif
if (_videoFile.hasSuffix(".seq")) {
- SeqDecoder *seqDecoder = new SeqDecoder();
- seqDecoder->setFrameDelay(_videoFrameDelay);
- videoDecoder = seqDecoder;
+ videoDecoder = new SEQDecoder(_videoFrameDelay);
#ifdef ENABLE_SCI32
} else if (_videoFile.hasSuffix(".vmd")) {
- videoDecoder = new Video::VMDDecoder(g_system->getMixer());
+ videoDecoder = new Video::AdvancedVMDDecoder();
} else if (_videoFile.hasSuffix(".rbt")) {
- videoDecoder = new RobotDecoder(g_system->getMixer(), _engine->getPlatform() == Common::kPlatformMacintosh);
+ videoDecoder = new RobotDecoder(_engine->getPlatform() == Common::kPlatformMacintosh);
} else if (_videoFile.hasSuffix(".duk")) {
duckMode = true;
- videoDecoder = new Video::AviDecoder(g_system->getMixer());
+ videoDecoder = new Video::AVIDecoder();
#endif
} else if (_videoFile.hasSuffix(".avi")) {
- videoDecoder = new Video::AviDecoder(g_system->getMixer());
+ videoDecoder = new Video::AVIDecoder();
} else {
warning("Unrecognized video type");
}
@@ -2987,8 +2985,9 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) {
// Ignore specific leftover scripts, which require other non-existing scripts
if ((_engine->getGameId() == GID_HOYLE3 && itr->getNumber() == 995) ||
(_engine->getGameId() == GID_KQ5 && itr->getNumber() == 980) ||
- (_engine->getGameId() == GID_SLATER && itr->getNumber() == 947) ||
- (_engine->getGameId() == GID_MOTHERGOOSE256 && itr->getNumber() == 980)) {
+ (_engine->getGameId() == GID_KQ7 && itr->getNumber() == 111) ||
+ (_engine->getGameId() == GID_MOTHERGOOSE256 && itr->getNumber() == 980) ||
+ (_engine->getGameId() == GID_SLATER && itr->getNumber() == 947)) {
continue;
}
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 78df3065b2..58ac5f1fa6 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -397,8 +397,8 @@ static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_FB01_MIDI,
{
- _s("Use IMF/Yahama FB-01 for MIDI output"),
- _s("Use an IBM Music Feature card or a Yahama FB-01 FM synth module for MIDI output"),
+ _s("Use IMF/Yamaha FB-01 for MIDI output"),
+ _s("Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI output"),
"native_fb01",
false
}
@@ -762,9 +762,6 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl
Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
desc.setThumbnail(thumbnail);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
-
int day = (meta.saveDate >> 24) & 0xFF;
int month = (meta.saveDate >> 16) & 0xFF;
int year = meta.saveDate & 0xFFFF;
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 9872973e09..b978f40aba 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -1238,6 +1238,24 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // King's Quest 5 - English DOS Floppy
+ // VERSION file reports "0.000.051"
+ // Supplied by misterhands in bug report #3536863.
+ // This is the original English version, which has been externally patched to
+ // Polish in the Polish release below.
+ {"kq5", "", {
+ {"resource.map", 0, "70010c20138541f89013bb5e1b30f16a", 7998},
+ {"resource.000", 0, "a591bd4b879fc832b8095c0b3befe9e2", 276398},
+ {"resource.001", 0, "c0f48d4a7ebeaa6aa074fc98d77423e9", 1018560},
+ {"resource.002", 0, "7f188a95acdb60bbe32a8379ba299393", 1307048},
+ {"resource.003", 0, "0860785af59518b94d54718dddcd6907", 1348500},
+ {"resource.004", 0, "c4745dd1e261c22daa6477961d08bf6c", 1239887},
+ {"resource.005", 0, "6556ff8e7c4d1acf6a78aea154daa76c", 1287869},
+ {"resource.006", 0, "da82e4beb744731d0a151f1d4922fafa", 1170456},
+ {"resource.007", 0, "431def14ca29cdb5e6a5e84d3f38f679", 1240176},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// King's Quest 5 - English DOS Floppy (supplied by omer_mor in bug report #3036996)
// VERSION file reports "0.000.051"
{"kq5", "", {
@@ -1308,6 +1326,21 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // King's Quest 5 DOS Spanish Floppy 0.000.062 VGA (5 x 3.5" disks)
+ // Supplied by dianiu in bug report #3555646
+ {"kq5", "", {
+ {"resource.map", 0, "c09896a2a30c9b002c5cbbc62f5a5c3a", 8169},
+ {"resource.000", 0, "1f1d03aead44da46362ff40c0074a3ec", 335871},
+ {"resource.001", 0, "d1803ad904127ae091edb274ee8c047f", 1180637},
+ {"resource.002", 0, "d9cd5972016f650cc31fb7c2a2b0953a", 1102207},
+ {"resource.003", 0, "829c8caeff793f3cfcea2cb01aaa4150", 965586},
+ {"resource.004", 0, "0bd9e570ee04b025e43d3075998fae5b", 1117965},
+ {"resource.005", 0, "4aaa2e9a69089b9afbaaccbbf2c4e647", 1202936},
+ {"resource.006", 0, "65b520e60c4217e6a6572d9edf77193b", 1141985},
+ {"resource.007", 0, "f42b0100f0a1c30806814f8648b6bc28", 1145583},
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// King's Quest 5 - German DOS Floppy (supplied by markcoolio in bug report #2727101, also includes english language)
// SCI interpreter version 1.000.060
{"kq5", "", {
@@ -1354,8 +1387,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::IT_ITA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- // King's Quest 5 - Polish DOS Floppy (supplied by jacek909 in bug report #2725722, includes english language?!)
+ // King's Quest 5 - Polish DOS Floppy (supplied by jacek909 in bug report #2725722)
// SCI interpreter version 1.000.060
+ // VERSION file reports "0.000.051".
+ // This is actually an English version with external text resource patches (bug #3536863).
{"kq5", "", {
{"resource.map", 0, "70010c20138541f89013bb5e1b30f16a", 7998},
{"resource.000", 0, "a591bd4b879fc832b8095c0b3befe9e2", 276398},
@@ -1366,6 +1401,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "6556ff8e7c4d1acf6a78aea154daa76c", 1287869},
{"resource.006", 0, "da82e4beb744731d0a151f1d4922fafa", 1170456},
{"resource.007", 0, "431def14ca29cdb5e6a5e84d3f38f679", 1240176},
+ {"text.000", 0, "601aa35a3ddeb558e1280e0963e955a2", 1517},
AD_LISTEND},
Common::PL_POL, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
@@ -1447,6 +1483,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // King's Quest 6 - Spanish DOS Floppy (from jvprat)
+ // Executable scanning reports "1.cfs.158", VERSION file reports "1.000.000, July 5, 1994"
+ // SCI interpreter version 1.001.055
+ {"kq6", "", {
+ {"resource.map", 0, "a73a5ab04b8f60c4b75b946a4dccea5a", 8953},
+ {"resource.000", 0, "4da3ad5868a775549a7cc4f72770a58e", 8537260},
+ {"resource.msg", 0, "41eed2d3893e1ca6c3695deba4e9d2e8", 267102},
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// King's Quest 6 - English DOS CD (from the King's Quest Collection)
// Executable scanning reports "1.cfs.158", VERSION file reports "1.034 9/11/94 - KQ6 version 1.000.00G"
// SCI interpreter version 1.001.054
@@ -1465,16 +1511,6 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO5(GUIO_NOASPECT, GAMEOPTION_KQ6_WINDOWS_CURSORS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- // King's Quest 6 - Spanish DOS CD (from jvprat)
- // Executable scanning reports "1.cfs.158", VERSION file reports "1.000.000, July 5, 1994"
- // SCI interpreter version 1.001.055
- {"kq6", "CD", {
- {"resource.map", 0, "a73a5ab04b8f60c4b75b946a4dccea5a", 8953},
- {"resource.000", 0, "4da3ad5868a775549a7cc4f72770a58e", 8537260},
- {"resource.msg", 0, "41eed2d3893e1ca6c3695deba4e9d2e8", 267102},
- AD_LISTEND},
- Common::ES_ESP, Common::kPlatformPC, ADGF_CD, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
-
// King's Quest 6 - English Macintosh Floppy
// VERSION file reports "1.0"
{"kq6", "", {
@@ -2660,6 +2696,13 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Police Quest 3 - Spanish DOS v1.000 - Supplied by dianiu in bug report #3555647
+ {"pq3", "", {
+ {"resource.map", 0, "ffa0b4631c4e36d69631256d19ba29e7", 5421},
+ {"resource.000", 0, "5ee460af3d70c06a745cc482b6c783ba", 5410263},
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Police Quest 3 EGA
// Reported by musiclyinspired in bug report #3046573
{"pq3", "", {
@@ -2777,6 +2820,31 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy v1.102 Int#0.000.629 (suppled by digitoxin1 in bug report #3554611)
+ {"qfg1", "", {
+ {"resource.map", 0, "b162dbd4632250d4d83bed46d0783c10", 6396},
+ {"resource.000", 0, "40332d3ebfc70a4b6a6a0443c2763287", 78800},
+ {"resource.001", 0, "a270012fa74445d74c044d1b65a9ff8c", 459835},
+ {"resource.002", 0, "e64004e020fdf1813be52b639b08be89", 635561},
+ {"resource.003", 0, "f0af87c60ec869946da442833aa5afa8", 640502},
+ {"resource.004", 0, "f0af87c60ec869946da442833aa5afa8", 644575},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
+ // Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy v1.102 Int#0.000.629 (suppled by digitoxin1 in bug report #3554611)
+ {"qfg1", "", {
+ {"resource.map", 0, "5772a2c1bfae46f26582582c9901121e", 6858},
+ {"resource.000", 0, "40332d3ebfc70a4b6a6a0443c2763287", 78800},
+ {"resource.001", 0, "a270012fa74445d74c044d1b65a9ff8c", 75090},
+ {"resource.002", 0, "d22695c53835dfdece056d86f26c251e", 271354},
+ {"resource.003", 0, "3cd085e27078f269b3ece5838812ff41", 258084},
+ {"resource.004", 0, "8927c7a04a78f1e76f342db3ccc9d879", 267835},
+ {"resource.005", 0, "13d16cc9b90b51e2c8643cdf52a62957", 268807},
+ {"resource.006", 0, "48b2b3c964dcbeccb68e984e6d4e97db", 278473},
+ {"resource.007", 0, "f0af87c60ec869946da442833aa5afa8", 269237},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy (supplied by markcoolio in bug report #2723843)
// Executable scanning reports "0.000.566"
{"qfg1", "", {
@@ -2864,17 +2932,6 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- // Quest for Glory 1 (from abevi, bug report #2612718)
- {"qfg1", "", {
- {"resource.map", 0, "b162dbd4632250d4d83bed46d0783c10", 6396},
- {"resource.000", 0, "40332d3ebfc70a4b6a6a0443c2763287", 78800},
- {"resource.001", 0, "a270012fa74445d74c044d1b65a9ff8c", 459835},
- {"resource.002", 0, "e64004e020fdf1813be52b639b08be89", 635561},
- {"resource.003", 0, "f0af87c60ec869946da442833aa5afa8", 640502},
- {"resource.004", 0, "f0af87c60ec869946da442833aa5afa8", 644575},
- AD_LISTEND},
- Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
-
// Quest for Glory 1 - English DOS
// SCI interpreter version 0.000.629
{"qfg1", "", {
@@ -2981,6 +3038,21 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Quest for Glory 2 - English DOS (supplied by digitoxin1 in bug report #3554614)
+ // v1.102 9x3.5" (label: Int#11.20.90)
+ {"qfg2", "", {
+ {"resource.map", 0, "367023314ea33e3156297402f6c1da49", 8166},
+ {"resource.000", 0, "a17e374c4d33b81208c862bc0ffc1a38", 212119},
+ {"resource.001", 0, "e08d7887e30b12008c40f9570447711a", 331995},
+ {"resource.002", 0, "df137dc7869cab07e1149ba2333c815c", 467461},
+ {"resource.003", 0, "df137dc7869cab07e1149ba2333c815c", 502560},
+ {"resource.004", 0, "df137dc7869cab07e1149ba2333c815c", 488532},
+ {"resource.005", 0, "df137dc7869cab07e1149ba2333c815c", 478574},
+ {"resource.006", 0, "b1944bd664ddbd2859cdaa0c4a0d6281", 507489},
+ {"resource.007", 0, "cd2de58e27665d5853530de93fae7cd6", 490794},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Quest for Glory 2 - English DOS Non-Interactive Demo
// Executable scanning reports "1.000.046"
{"qfg2", "Demo", {
@@ -3536,7 +3608,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "ed90a8e3ccc53af6633ff6ab58392bae", 7054},
{"resource.000", 0, "63247e3901ab8963d4eece73747832e0", 5157378},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GAMEOPTION_SQ4_SILVER_CURSORS) },
+ Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO5(GUIO_MIDIGM, GAMEOPTION_SQ4_SILVER_CURSORS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// Space Quest 4 - English Windows CD (from the Space Quest Collection)
// Executable scanning reports "1.001.064", VERSION file reports "1.0"
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp
index 0d575f97dd..a0f7ebf4a2 100644
--- a/engines/sci/engine/file.cpp
+++ b/engines/sci/engine/file.cpp
@@ -57,11 +57,24 @@ namespace Sci {
reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool unwrapFilename) {
Common::String englishName = g_sci->getSciLanguageString(filename, K_LANG_ENGLISH);
+ englishName.toLowercase();
+
Common::String wrappedName = unwrapFilename ? g_sci->wrapFilename(englishName) : englishName;
Common::SeekableReadStream *inFile = 0;
Common::WriteStream *outFile = 0;
Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+ bool isCompressed = true;
+ const SciGameId gameId = g_sci->getGameId();
+ if ((gameId == GID_QFG1 || gameId == GID_QFG1VGA || gameId == GID_QFG2 || gameId == GID_QFG3)
+ && englishName.hasSuffix(".sav")) {
+ // QFG Characters are saved via the CharSave object.
+ // We leave them uncompressed so that they can be imported in later QFG
+ // games.
+ // Rooms/Scripts: QFG1: 601, QFG2: 840, QFG3/4: 52
+ isCompressed = false;
+ }
+
if (mode == _K_FILE_MODE_OPEN_OR_FAIL) {
// Try to open file, abort if not possible
inFile = saveFileMan->openForLoading(wrappedName);
@@ -74,12 +87,12 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_OPEN_OR_FAIL): failed to open file '%s'", englishName.c_str());
} else if (mode == _K_FILE_MODE_CREATE) {
// Create the file, destroying any content it might have had
- outFile = saveFileMan->openForSaving(wrappedName);
+ outFile = saveFileMan->openForSaving(wrappedName, isCompressed);
if (!outFile)
debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str());
} else if (mode == _K_FILE_MODE_OPEN_OR_CREATE) {
// Try to open file, create it if it doesn't exist
- outFile = saveFileMan->openForSaving(wrappedName);
+ outFile = saveFileMan->openForSaving(wrappedName, isCompressed);
if (!outFile)
debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str());
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index c8fe47d9fc..46051ef145 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -757,13 +757,26 @@ bool Kernel::debugSetFunction(const char *kernelName, int logging, int breakpoin
return true;
}
-void Kernel::setDefaultKernelNames(GameFeatures *features) {
- _kernelNames = Common::StringArray(s_defaultKernelNames, ARRAYSIZE(s_defaultKernelNames));
+#ifdef ENABLE_SCI32
+enum {
+ kKernelEntriesSci2 = 0x8b,
+ kKernelEntriesGk2Demo = 0xa0,
+ kKernelEntriesSci21 = 0x9d,
+ kKernelEntriesSci3 = 0xa1
+};
+#endif
+
+void Kernel::loadKernelNames(GameFeatures *features) {
+ _kernelNames.clear();
- // Some (later) SCI versions replaced CanBeHere by CantBeHere
- // If vocab.999 exists, the kernel function is still named CanBeHere
- if (_selectorCache.cantBeHere != -1)
- _kernelNames[0x4d] = "CantBeHere";
+ if (getSciVersion() <= SCI_VERSION_1_1) {
+ _kernelNames = Common::StringArray(s_defaultKernelNames, ARRAYSIZE(s_defaultKernelNames));
+
+ // Some (later) SCI versions replaced CanBeHere by CantBeHere
+ // If vocab.999 exists, the kernel function is still named CanBeHere
+ if (_selectorCache.cantBeHere != -1)
+ _kernelNames[0x4d] = "CantBeHere";
+ }
switch (getSciVersion()) {
case SCI_VERSION_0_EARLY:
@@ -817,66 +830,60 @@ void Kernel::setDefaultKernelNames(GameFeatures *features) {
_kernelNames[0x7c] = "Message";
break;
- default:
- // Use default table for the other versions
- break;
- }
-}
-
#ifdef ENABLE_SCI32
+ case SCI_VERSION_2:
+ _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesSci2);
+ break;
-enum {
- kKernelEntriesSci2 = 0x8b,
- kKernelEntriesGk2Demo = 0xa0,
- kKernelEntriesSci21 = 0x9d,
- kKernelEntriesSci3 = 0xa1
-};
-
-void Kernel::setKernelNamesSci2() {
- _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesSci2);
-}
+ case SCI_VERSION_2_1:
+ if (features->detectSci21KernelType() == SCI_VERSION_2) {
+ // Some early SCI2.1 games use a modified SCI2 kernel table instead of
+ // the SCI2.1 kernel table. We detect which version to use based on
+ // how kDoSound is called from Sound::play().
+ // Known games that use this:
+ // GK2 demo
+ // KQ7 1.4
+ // PQ4 SWAT demo
+ // LSL6
+ // PQ4CD
+ // QFG4CD
+
+ // This is interesting because they all have the same interpreter
+ // version (2.100.002), yet they would not be compatible with other
+ // games of the same interpreter.
+
+ _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesGk2Demo);
+ // OnMe is IsOnMe here, but they should be compatible
+ _kernelNames[0x23] = "Robot"; // Graph in SCI2
+ _kernelNames[0x2e] = "Priority"; // DisposeTextBitmap in SCI2
+ } else {
+ // Normal SCI2.1 kernel table
+ _kernelNames = Common::StringArray(sci21_default_knames, kKernelEntriesSci21);
+ }
+ break;
-void Kernel::setKernelNamesSci21(GameFeatures *features) {
- // Some SCI games use a modified SCI2 kernel table instead of the
- // SCI2.1 kernel table. We detect which version to use based on
- // how kDoSound is called from Sound::play().
- // Known games that use this:
- // GK2 demo
- // KQ7 1.4
- // PQ4 SWAT demo
- // LSL6
- // PQ4CD
- // QFG4CD
-
- // This is interesting because they all have the same interpreter
- // version (2.100.002), yet they would not be compatible with other
- // games of the same interpreter.
-
- if (getSciVersion() != SCI_VERSION_3 && features->detectSci21KernelType() == SCI_VERSION_2) {
- _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesGk2Demo);
- // OnMe is IsOnMe here, but they should be compatible
- _kernelNames[0x23] = "Robot"; // Graph in SCI2
- _kernelNames[0x2e] = "Priority"; // DisposeTextBitmap in SCI2
- } else if (getSciVersion() != SCI_VERSION_3) {
- _kernelNames = Common::StringArray(sci21_default_knames, kKernelEntriesSci21);
- } else if (getSciVersion() == SCI_VERSION_3) {
+ case SCI_VERSION_3:
_kernelNames = Common::StringArray(sci21_default_knames, kKernelEntriesSci3);
- }
-}
-#endif
-
-void Kernel::loadKernelNames(GameFeatures *features) {
- _kernelNames.clear();
+ // In SCI3, some kernel functions have been removed, and others have been added
+ _kernelNames[0x18] = "Dummy"; // AddMagnify in SCI2.1
+ _kernelNames[0x19] = "Dummy"; // DeleteMagnify in SCI2.1
+ _kernelNames[0x30] = "Dummy"; // SetScroll in SCI2.1
+ _kernelNames[0x39] = "Dummy"; // ShowMovie in SCI2.1
+ _kernelNames[0x4c] = "Dummy"; // ScrollWindow in SCI2.1
+ _kernelNames[0x56] = "Dummy"; // VibrateMouse in SCI2.1 (only used in QFG4 floppy)
+ _kernelNames[0x64] = "Dummy"; // AvoidPath in SCI2.1
+ _kernelNames[0x66] = "Dummy"; // MergePoly in SCI2.1
+ _kernelNames[0x8d] = "MessageBox"; // Dummy in SCI2.1
+ _kernelNames[0x9b] = "Minimize"; // Dummy in SCI2.1
-#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1)
- setKernelNamesSci21(features);
- else if (getSciVersion() == SCI_VERSION_2)
- setKernelNamesSci2();
- else
+ break;
#endif
- setDefaultKernelNames(features);
+
+ default:
+ // Use default table for the other versions
+ break;
+ }
mapFunctions();
}
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 677b790f93..f985a69ebc 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -224,23 +224,6 @@ public:
private:
/**
- * Sets the default kernel function names, based on the SCI version used.
- */
- void setDefaultKernelNames(GameFeatures *features);
-
-#ifdef ENABLE_SCI32
- /**
- * Sets the default kernel function names to the SCI2 kernel functions.
- */
- void setKernelNamesSci2();
-
- /**
- * Sets the default kernel function names to the SCI2.1 kernel functions.
- */
- void setKernelNamesSci21(GameFeatures *features);
-#endif
-
- /**
* Loads the kernel selector names.
*/
void loadSelectorNames();
@@ -429,6 +412,7 @@ reg_t kListAt(EngineState *s, int argc, reg_t *argv);
reg_t kString(EngineState *s, int argc, reg_t *argv);
reg_t kMulDiv(EngineState *s, int argc, reg_t *argv);
reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv);
// "Screen items" in SCI32 are views
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv);
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv);
@@ -453,6 +437,8 @@ reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv);
reg_t kEditText(EngineState *s, int argc, reg_t *argv);
reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv);
reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv);
+reg_t kSetScroll(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycle(EngineState *s, int argc, reg_t *argv);
// SCI2.1 Kernel Functions
reg_t kText(EngineState *s, int argc, reg_t *argv);
@@ -556,6 +542,7 @@ reg_t kFileIOWriteByte(EngineState *s, int argc, reg_t *argv);
reg_t kFileIOReadWord(EngineState *s, int argc, reg_t *argv);
reg_t kFileIOWriteWord(EngineState *s, int argc, reg_t *argv);
reg_t kFileIOCreateSaveSlot(EngineState *s, int argc, reg_t *argv);
+reg_t kFileIOIsValidDirectory(EngineState *s, int argc, reg_t *argv);
#endif
//@}
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 6965a5da45..f5f46285be 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -240,7 +240,7 @@ static const SciKernelMapSubEntry kFileIO_subops[] = {
{ SIG_SCI32, 16, MAP_CALL(FileIOWriteWord), "ii", NULL },
{ SIG_SCI32, 17, MAP_CALL(FileIOCreateSaveSlot), "ir", NULL },
{ SIG_SCI32, 18, MAP_EMPTY(FileIOChangeDirectory), "r", NULL }, // for SQ6, when changing the savegame directory in the save/load dialog
- { SIG_SCI32, 19, MAP_CALL(Stub), "r", NULL }, // for Torin / Torin demo
+ { SIG_SCI32, 19, MAP_CALL(FileIOIsValidDirectory), "r", NULL }, // for Torin / Torin demo
#endif
SCI_SUBOPENTRY_TERMINATOR
};
@@ -248,7 +248,7 @@ static const SciKernelMapSubEntry kFileIO_subops[] = {
#ifdef ENABLE_SCI32
static const SciKernelMapSubEntry kSave_subops[] = {
- { SIG_SCI32, 0, MAP_CALL(SaveGame), "[r0]i[r0](r)", NULL },
+ { SIG_SCI32, 0, MAP_CALL(SaveGame), "[r0]i[r0](r0)", NULL },
{ SIG_SCI32, 1, MAP_CALL(RestoreGame), "[r0]i[r0]", NULL },
{ SIG_SCI32, 2, MAP_CALL(GetSaveDir), "(r*)", NULL },
{ SIG_SCI32, 3, MAP_CALL(CheckSaveGame), ".*", NULL },
@@ -419,7 +419,10 @@ static SciKernelMapEntry s_kernelMap[] = {
{ 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(RemapColors), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL },
+#ifdef ENABLE_SCI32
+ { "RemapColors", kRemapColors32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", NULL, NULL },
+#endif
{ MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL },
{ MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL },
{ MAP_CALL(RestartGame), SIG_EVERYWHERE, "", NULL, NULL },
@@ -517,11 +520,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(EditText), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL },
{ MAP_CALL(MakeSaveFileName), SIG_EVERYWHERE, "rri", NULL, NULL },
-
- // SCI2 unmapped functions - TODO!
-
- // SetScroll - called by script 64909, Styler::doit()
- // PalCycle - called by Game::newRoom. Related to RemapColors.
+ { MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiiii(i)", NULL, NULL },
+ { MAP_CALL(PalCycle), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
// SCI2 Empty functions
@@ -561,6 +561,11 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_DUMMY(InputText), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_DUMMY(TextWidth), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_DUMMY(PointSize), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ // SetScroll is called by script 64909, Styler::doit(), but it doesn't seem to
+ // be used at all (plus, it was then changed to a dummy function in SCI3).
+ // Since this is most likely unused, and we got no test case, error out when
+ // it is called in order to find an actual call to it.
+ { MAP_DUMMY(SetScroll), SIG_EVERYWHERE, "(.*)", NULL, NULL },
// SCI2.1 Kernel Functions
{ MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
@@ -583,8 +588,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(Font), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
{ MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(AddLine), SIG_EVERYWHERE, "oiiiiiiiii", NULL, NULL },
- { MAP_CALL(UpdateLine), SIG_EVERYWHERE, "roiiiiiiiii", NULL, NULL },
- { MAP_CALL(DeleteLine), SIG_EVERYWHERE, "ro", NULL, NULL },
+ { MAP_CALL(UpdateLine), SIG_EVERYWHERE, "[r0]oiiiiiiiii", NULL, NULL },
+ { MAP_CALL(DeleteLine), SIG_EVERYWHERE, "[r0]o", NULL, NULL },
// SCI2.1 Empty Functions
@@ -629,11 +634,14 @@ static SciKernelMapEntry s_kernelMap[] = {
// SCI2.1 unmapped functions - TODO!
+ // SetHotRectangles - used by Phantasmagoria 1, script 64981 (used in the chase scene)
+ // <lskovlun> The idea, if I understand correctly, is that the engine generates events
+ // of a special HotRect type continuously when the mouse is on that rectangle
+
// MovePlaneItems - used by SQ6 to scroll through the inventory via the up/down buttons
// SetPalStyleRange - 2 integer parameters, start and end. All styles from start-end
// (inclusive) are set to 0
// MorphOn - used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270)
- // SetHotRectangles - used by Phantasmagoria 1
// SCI3 Kernel Functions
{ MAP_CALL(PlayDuck), SIG_EVERYWHERE, "(.*)", NULL, NULL },
@@ -828,7 +836,7 @@ static const char *const sci2_default_knames[] = {
/*0x20*/ "AddMagnify",
/*0x21*/ "DeleteMagnify",
/*0x22*/ "IsHiRes",
- /*0x23*/ "Graph",
+ /*0x23*/ "Graph", // Robot in early SCI2.1 games with a SCI2 kernel table
/*0x24*/ "InvertRect", // only in SCI2, not used in any SCI2 game
/*0x25*/ "TextSize",
/*0x26*/ "Message",
@@ -839,7 +847,7 @@ static const char *const sci2_default_knames[] = {
/*0x2b*/ "EditText",
/*0x2c*/ "InputText", // unused function
/*0x2d*/ "CreateTextBitmap",
- /*0x2e*/ "DisposeTextBitmap",
+ /*0x2e*/ "DisposeTextBitmap", // Priority in early SCI2.1 games with a SCI2 kernel table
/*0x2f*/ "GetEvent",
/*0x30*/ "GlobalToLocal",
/*0x31*/ "LocalToGlobal",
@@ -1099,7 +1107,7 @@ static const char *const sci21_default_knames[] = {
/*0x8a*/ "LoadChunk",
/*0x8b*/ "SetPalStyleRange",
/*0x8c*/ "AddPicAt",
- /*0x8d*/ "MessageBox", // SCI3, was Dummy in SCI2.1
+ /*0x8d*/ "Dummy", // MessageBox in SCI3
/*0x8e*/ "NewRoom", // debug function
/*0x8f*/ "Dummy",
/*0x90*/ "Priority",
@@ -1113,7 +1121,7 @@ static const char *const sci21_default_knames[] = {
/*0x98*/ "GetWindowsOption", // Windows only
/*0x99*/ "WinDLL", // Windows only
/*0x9a*/ "Dummy",
- /*0x9b*/ "Minimize", // SCI3, was Dummy in SCI2.1
+ /*0x9b*/ "Dummy", // Minimize in SCI3
/*0x9c*/ "DeletePic",
// == SCI3 only ===============
/*0x9d*/ "Dummy",
@@ -1127,57 +1135,73 @@ static const char *const sci21_default_knames[] = {
// Base set of opcode formats. They're copied and adjusted slightly in
// script_adjust_opcode_format depending on SCI version.
static const opcode_format g_base_opcode_formats[128][4] = {
- /*00*/
+ // 00 - 03 / bnot, add, sub, mul
{Script_None}, {Script_None}, {Script_None}, {Script_None},
- /*04*/
+ // 04 - 07 / div, mod, shr, shl
{Script_None}, {Script_None}, {Script_None}, {Script_None},
- /*08*/
+ // 08 - 0B / xor, and, or, neg
{Script_None}, {Script_None}, {Script_None}, {Script_None},
- /*0C*/
+ // 0C - 0F / not, eq, ne, gt
{Script_None}, {Script_None}, {Script_None}, {Script_None},
- /*10*/
+ // 10 - 13 / ge, lt, le, ugt
{Script_None}, {Script_None}, {Script_None}, {Script_None},
- /*14*/
+ // 14 - 17 / uge, ult, ule, bt
{Script_None}, {Script_None}, {Script_None}, {Script_SRelative},
- /*18*/
+ // 18 - 1B / bnt, jmp, ldi, push
{Script_SRelative}, {Script_SRelative}, {Script_SVariable}, {Script_None},
- /*1C*/
+ // 1C - 1F / pushi, toss, dup, link
{Script_SVariable}, {Script_None}, {Script_None}, {Script_Variable},
- /*20*/
+ // 20 - 23 / call, callk, callb, calle
{Script_SRelative, Script_Byte}, {Script_Variable, Script_Byte}, {Script_Variable, Script_Byte}, {Script_Variable, Script_SVariable, Script_Byte},
- /*24 (24=ret)*/
+ // 24 - 27 / ret, send, dummy, dummy
{Script_End}, {Script_Byte}, {Script_Invalid}, {Script_Invalid},
- /*28*/
+ // 28 - 2B / class, dummy, self, super
{Script_Variable}, {Script_Invalid}, {Script_Byte}, {Script_Variable, Script_Byte},
- /*2C*/
+ // 2C - 2F / rest, lea, selfID, dummy
{Script_SVariable}, {Script_SVariable, Script_Variable}, {Script_None}, {Script_Invalid},
- /*30*/
+ // 30 - 33 / pprev, pToa, aTop, pTos
{Script_None}, {Script_Property}, {Script_Property}, {Script_Property},
- /*34*/
+ // 34 - 37 / sTop, ipToa, dpToa, ipTos
{Script_Property}, {Script_Property}, {Script_Property}, {Script_Property},
- /*38*/
+ // 38 - 3B / dpTos, lofsa, lofss, push0
{Script_Property}, {Script_SRelative}, {Script_SRelative}, {Script_None},
- /*3C*/
+ // 3C - 3F / push1, push2, pushSelf, line
{Script_None}, {Script_None}, {Script_None}, {Script_Word},
- /*40-4F*/
+ // ------------------------------------------------------------------------
+ // 40 - 43 / lag, lal, lat, lap
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 44 - 47 / lsg, lsl, lst, lsp
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 48 - 4B / lagi, lali, lati, lapi
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 4C - 4F / lsgi, lsli, lsti, lspi
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
- /*50-5F*/
+ // ------------------------------------------------------------------------
+ // 50 - 53 / sag, sal, sat, sap
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 54 - 57 / ssg, ssl, sst, ssp
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 58 - 5B / sagi, sali, sati, sapi
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 5C - 5F / ssgi, ssli, ssti, sspi
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
- /*60-6F*/
+ // ------------------------------------------------------------------------
+ // 60 - 63 / plusag, plusal, plusat, plusap
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 64 - 67 / plussg, plussl, plusst, plussp
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 68 - 6B / plusagi, plusali, plusati, plusapi
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 6C - 6F / plussgi, plussli, plussti, plusspi
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
- /*70-7F*/
+ // ------------------------------------------------------------------------
+ // 70 - 73 / minusag, minusal, minusat, minusap
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 74 - 77 / minussg, minussl, minusst, minussp
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 78 - 7B / minusagi, minusali, minusati, minusapi
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param},
+ // 7C - 7F / minussgi, minussli, minussti, minusspi
{Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}
};
#undef END
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index a21e19802d..f7cc4f44b5 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -197,8 +197,15 @@ reg_t kCD(EngineState *s, int argc, reg_t *argv) {
// TODO: Stub
switch (argv[0].toUint16()) {
case 0:
- // Return whether the contents of disc argv[1] is available.
- return TRUE_REG;
+ if (argc == 1) {
+ // Check if a disc is in the drive
+ return TRUE_REG;
+ } else {
+ // Check if the specified disc is in the drive
+ // and return the current disc number. We just
+ // return the requested disc number.
+ return argv[1];
+ }
case 1:
// Return the current CD number
return make_reg(0, 1);
@@ -688,6 +695,13 @@ reg_t kFileIOCreateSaveSlot(EngineState *s, int argc, reg_t *argv) {
return TRUE_REG; // slot creation was successful
}
+reg_t kFileIOIsValidDirectory(EngineState *s, int argc, reg_t *argv) {
+ // Used in Torin's Passage and LSL7 to determine if the directory passed as
+ // a parameter (usually the save directory) is valid. We always return true
+ // here.
+ return TRUE_REG;
+}
+
#endif
// ---- Save operations -------------------------------------------------------
@@ -1002,7 +1016,7 @@ reg_t kAutoSave(EngineState *s, int argc, reg_t *argv) {
// the elapsed time from the timer object)
// This function has to return something other than 0 to proceed
- return s->r_acc;
+ return TRUE_REG;
}
#endif
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 0ef268f108..da377319c0 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -645,6 +645,20 @@ reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) {
if (paletteChanged)
g_sci->_gfxPalette->kernelAnimateSet();
+ // WORKAROUND: The game scripts in SQ4 floppy count the number of elapsed
+ // cycles in the intro from the number of successive kAnimate calls during
+ // the palette cycling effect, while showing the SQ4 logo. This worked in
+ // older computers because each animate call took awhile to complete.
+ // Normally, such scripts are handled automatically by our speed throttler,
+ // however in this case there are no calls to kGameIsRestarting (where the
+ // speed throttler gets called) between the different palette animation calls.
+ // Thus, we add a small delay between each animate call to make the whole
+ // palette animation effect slower and visible, and not have the logo screen
+ // get skipped because the scripts don't wait between animation steps. Fixes
+ // bug #3537232.
+ if (g_sci->getGameId() == GID_SQ4 && !g_sci->isCD() && s->currentRoomNumber() == 1)
+ g_sci->sleep(10);
+
return s->r_acc;
}
@@ -936,8 +950,9 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) {
}
}
if (objName == "savedHeros") {
- // Import of QfG character files dialog is shown
- // display additional popup information before letting user use it
+ // Import of QfG character files dialog is shown.
+ // Display additional popup information before letting user use it.
+ // For the SCI32 version of this, check kernelAddPlane().
reg_t changeDirButton = s->_segMan->findObjectByName("changeDirItem");
if (!changeDirButton.isNull()) {
// check if checkDirButton is still enabled, in that case we are called the first time during that room
@@ -950,6 +965,8 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) {
"for Quest for Glory 2. Example: 'qfg2-thief.sav'.");
}
}
+
+ // For the SCI32 version of this, check kListAt().
s->_chosenQfGImportItem = readSelectorValue(s->_segMan, controlObject, SELECTOR(mark));
}
@@ -1204,73 +1221,27 @@ reg_t kShow(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+// Early variant of the SCI32 kRemapColors kernel function, used in the demo of QFG4
reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
uint16 operation = argv[0].toUint16();
switch (operation) {
- case 0: { // Set remapping to base. 0 turns remapping off.
- int16 base = (argc >= 2) ? argv[1].toSint16() : 0;
- if (base != 0) // 0 is the default behavior when changing rooms in GK1, thus silencing the warning
- warning("kRemapColors: Set remapping to base %d", base);
+ case 0: { // remap by percent
+ uint16 percent = argv[1].toUint16();
+ g_sci->_gfxPalette->resetRemapping();
+ g_sci->_gfxPalette->setRemappingPercent(254, percent);
}
break;
- case 1: { // unknown
- // The demo of QFG4 calls this with 1+3 parameters, thus there are differences here
- //int16 unk1 = argv[1].toSint16();
- //int16 unk2 = argv[2].toSint16();
- //int16 unk3 = argv[3].toSint16();
- //uint16 unk4 = argv[4].toUint16();
- //uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0;
- kStub(s, argc, argv);
+ case 1: { // remap by range
+ uint16 from = argv[1].toUint16();
+ uint16 to = argv[2].toUint16();
+ uint16 base = argv[3].toUint16();
+ g_sci->_gfxPalette->resetRemapping();
+ g_sci->_gfxPalette->setRemappingRange(254, from, to, base);
}
break;
- case 2: { // remap by percent
- // This adjusts the alpha value of a specific color, and it operates on
- // an RGBA palette. Since we're operating on an RGB palette, we just
- // modify the color intensity instead
- // TODO: From what I understand, palette remapping should be placed
- // separately, so that it can be reset by case 0 above. Thus, we
- // should adjust the functionality of the Palette class accordingly.
- int16 color = argv[1].toSint16();
- if (color >= 10)
- color -= 10;
- uint16 percent = argv[2].toUint16(); // 0 - 100
- if (argc >= 4)
- warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16());
- warning("kRemapColors: RemapByPercent color %d by %d percent", color, percent);
- // TODO: It's not correct to set intensity here
- //g_sci->_gfxPalette->kernelSetIntensity(color, 255, percent, false);
- }
- break;
- case 3: { // remap to gray
- // NOTE: This adjusts the alpha value of a specific color, and it operates on
- // an RGBA palette
- int16 color = argv[1].toSint16(); // this is subtracted from a maximum color value, and can be offset by 10
- int16 percent = argv[2].toSint16(); // 0 - 100
- uint16 unk3 = (argc >= 4) ? argv[3].toUint16() : 0;
- warning("kRemapColors: RemapToGray color %d by %d percent (unk3 = %d)", color, percent, unk3);
- }
- break;
- case 4: { // unknown
- //int16 unk1 = argv[1].toSint16();
- //uint16 unk2 = argv[2].toUint16();
- //uint16 unk3 = argv[3].toUint16();
- //uint16 unk4 = (argc >= 5) ? argv[4].toUint16() : 0;
- kStub(s, argc, argv);
- }
- break;
- case 5: { // set color intensity
- // TODO: This isn't right, it should be setting a mapping table instead.
- // For PQ4, we can emulate this with kernelSetIntensity(). In QFG4, this
- // won't do.
- //int16 mapping = argv[1].toSint16();
- uint16 intensity = argv[2].toUint16();
- // HACK for PQ4
- if (g_sci->getGameId() == GID_PQ4)
- g_sci->_gfxPalette->kernelSetIntensity(0, 255, intensity, true);
-
- kStub(s, argc, argv);
- }
+ case 2: // turn remapping off (unused)
+ error("Unused subop kRemapColors(2) has been called");
break;
default:
break;
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 413ad1ecb1..8b3afeef99 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -39,6 +39,7 @@
#include "sci/graphics/cache.h"
#include "sci/graphics/compare.h"
#include "sci/graphics/controls16.h"
+#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/cursor.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/paint16.h"
@@ -171,8 +172,13 @@ reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)",
PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3]));
debugC(kDebugLevelStrings, "%s", text.c_str());
- uint16 maxWidth = argv[1].toUint16(); // nsRight - nsLeft + 1
- uint16 maxHeight = argv[2].toUint16(); // nsBottom - nsTop + 1
+ int16 maxWidth = argv[1].toUint16();
+ int16 maxHeight = argv[2].toUint16();
+ g_sci->_gfxCoordAdjuster->fromScriptToDisplay(maxHeight, maxWidth);
+ // These values can be larger than the screen in the SQ6 demo, room 100
+ // TODO: Find out why. For now, don't show any text in that room.
+ if (g_sci->getGameId() == GID_SQ6 && g_sci->isDemo() && s->currentRoomNumber() == 100)
+ return NULL_REG;
return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight);
}
case 1: {
@@ -197,18 +203,6 @@ reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv) {
- uint16 windowsOption = argv[0].toUint16();
- switch (windowsOption) {
- case 0:
- // Title bar on/off in Phantasmagoria, we return 0 (off)
- return NULL_REG;
- default:
- warning("GetWindowsOption: Unknown option %d", windowsOption);
- return NULL_REG;
- }
-}
-
reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case 1:
@@ -236,12 +230,12 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
// tables inside graphics/transitions.cpp
uint16 showStyle = argv[0].toUint16(); // 0 - 15
reg_t planeObj = argv[1]; // the affected plane
- //uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts
- //uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff
- //int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out
- //uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts
- //uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out
-#if 0
+ Common::String planeObjName = s->_segMan->getObjectName(planeObj);
+ uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts
+ uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff
+ int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out
+ uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts
+ uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out
int16 divisions;
// If the game has the pFadeArray selector, another parameter is used here,
@@ -253,7 +247,7 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
} else {
divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?)
}
-#endif
+
if (showStyle > 15) {
warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj));
return s->r_acc;
@@ -269,18 +263,29 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
// TODO: Check if the plane is in the list of planes to draw
+ Common::String effectName = "unknown";
+
switch (showStyle) {
- //case 0: // no transition, perhaps? (like in the previous SCI versions)
+ case 0: // no transition / show
+ effectName = "show";
+ break;
case 13: // fade out
+ effectName = "fade out";
// TODO
+ break;
case 14: // fade in
+ effectName = "fade in";
// TODO
+ break;
default:
- // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now
- kStub(s, argc, argv);
+ // TODO
break;
}
+ warning("kSetShowStyle: effect %d (%s) - plane: %04x:%04x (%s), sec: %d, "
+ "back: %d, prio: %d, animate: %d, ref frame: %d, divisions: %d",
+ showStyle, effectName.c_str(), PRINT_REG(planeObj), planeObjName.c_str(),
+ seconds, backColor, priority, animate, refFrame, divisions);
return s->r_acc;
}
@@ -364,7 +369,8 @@ reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
case 10: // Where, called by ScrollableWindow::where
// TODO
// argv[2] is an unknown integer
- kStub(s, argc, argv);
+ // Silenced the warnings because of the high amount of console spam
+ //kStub(s, argc, argv);
break;
case 11: // Go, called by ScrollableWindow::scrollTo
// 2 extra parameters here
@@ -638,6 +644,169 @@ reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
+ // Called in the intro of LSL6 hires (room 110)
+ // The end effect of this is the same as the old screen scroll transition
+
+ // 7 parameters
+ reg_t planeObject = argv[0];
+ //int16 x = argv[1].toSint16();
+ //int16 y = argv[2].toSint16();
+ uint16 pictureId = argv[3].toUint16();
+ // param 4: int (0 in LSL6, probably scroll direction? The picture in LSL6 scrolls down)
+ // param 5: int (first call is 1, then the subsequent one is 0 in LSL6)
+ // param 6: optional int (0 in LSL6)
+
+ // Set the new picture directly for now
+ //writeSelectorValue(s->_segMan, planeObject, SELECTOR(left), x);
+ //writeSelectorValue(s->_segMan, planeObject, SELECTOR(top), y);
+ writeSelectorValue(s->_segMan, planeObject, SELECTOR(picture), pictureId);
+ // and update our draw list
+ g_sci->_gfxFrameout->kernelUpdatePlane(planeObject);
+
+ // TODO
+ return kStub(s, argc, argv);
+}
+
+reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) {
+ // Examples: GK1 room 480 (Bayou ritual), LSL6 room 100 (title screen)
+
+ switch (argv[0].toUint16()) {
+ case 0: { // Palette animation initialization
+ // 3 or 4 extra params
+ // Case 1 sends fromColor and speed again, so we don't need them here.
+ // Only toColor is stored
+ //uint16 fromColor = argv[1].toUint16();
+ s->_palCycleToColor = argv[2].toUint16();
+ //uint16 speed = argv[3].toUint16();
+
+ // Invalidate the picture, so that the palette steps calls (case 1
+ // below) can update its palette without it being overwritten by the
+ // view/picture palettes.
+ g_sci->_gfxScreen->_picNotValid = 1;
+
+ // TODO: The fourth optional parameter is an unknown integer, and is 0 by default
+ if (argc == 5) {
+ // When this variant is used, picNotValid doesn't seem to be set
+ // (e.g. GK1 room 480). In this case, the animation step calls are
+ // not made, so perhaps this signifies the palette cycling steps
+ // to make.
+ // GK1 sets this to 6 (6 palette steps?)
+ g_sci->_gfxScreen->_picNotValid = 0;
+ }
+ kStub(s, argc, argv);
+ }
+ break;
+ case 1: { // Palette animation step
+ // This is the same as the old kPaletteAnimate call, with 1 set of colors.
+ // The end color is set up during initialization in case 0 above.
+
+ // 1 or 2 extra params
+ uint16 fromColor = argv[1].toUint16();
+ uint16 speed = (argc == 2) ? 1 : argv[2].toUint16();
+ // TODO: For some reason, this doesn't set the color correctly
+ // (e.g. LSL6 intro, room 100, Sierra logo)
+ if (g_sci->_gfxPalette->kernelAnimate(fromColor, s->_palCycleToColor, speed))
+ g_sci->_gfxPalette->kernelAnimateSet();
+ }
+ // No kStub() call here, as this gets called loads of times, like kPaletteAnimate
+ break;
+ // case 2 hasn't been encountered
+ // case 3 hasn't been encountered
+ case 4: // reset any palette cycling and make the picture valid again
+ // Gets called when changing rooms and after palette cycling animations finish
+ // 0 or 1 extra params
+ if (argc == 1) {
+ g_sci->_gfxScreen->_picNotValid = 0;
+ // TODO: This also seems to perform more steps
+ } else {
+ // The variant with the 1 extra param resets remapping to base
+ // TODO
+ }
+ kStub(s, argc, argv);
+ break;
+ default:
+ // TODO
+ kStub(s, argc, argv);
+ break;
+ }
+
+ return s->r_acc;
+}
+
+reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {
+ uint16 operation = argv[0].toUint16();
+
+ switch (operation) {
+ case 0: { // turn remapping off
+ // WORKAROUND: Game scripts in QFG4 erroneously turn remapping off in room
+ // 140 (the character point allocation screen) and never turn it back on,
+ // even if it's clearly used in that screen.
+ if (g_sci->getGameId() == GID_QFG4 && s->currentRoomNumber() == 140)
+ return s->r_acc;
+
+ int16 base = (argc >= 2) ? argv[1].toSint16() : 0;
+ if (base > 0)
+ warning("kRemapColors(0) called with base %d", base);
+ g_sci->_gfxPalette->resetRemapping();
+ }
+ break;
+ case 1: { // remap by range
+ uint16 color = argv[1].toUint16();
+ uint16 from = argv[2].toUint16();
+ uint16 to = argv[3].toUint16();
+ uint16 base = argv[4].toUint16();
+ uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0;
+ if (unk5 > 0)
+ warning("kRemapColors(1) called with 6 parameters, unknown parameter is %d", unk5);
+ g_sci->_gfxPalette->setRemappingRange(color, from, to, base);
+ }
+ break;
+ case 2: { // remap by percent
+ uint16 color = argv[1].toUint16();
+ uint16 percent = argv[2].toUint16(); // 0 - 100
+ if (argc >= 4)
+ warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16());
+ g_sci->_gfxPalette->setRemappingPercent(color, percent);
+ }
+ break;
+ case 3: { // remap to gray
+ // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0.
+ // In this room, it's used for the cloud before Baba Yaga appears.
+ int16 color = argv[1].toSint16();
+ int16 percent = argv[2].toSint16(); // 0 - 100
+ if (argc >= 4)
+ warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16());
+ g_sci->_gfxPalette->setRemappingPercentGray(color, percent);
+ }
+ break;
+ case 4: { // remap to percent gray
+ // Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200
+ int16 color = argv[1].toSint16();
+ int16 percent = argv[2].toSint16(); // 0 - 100
+ // argv[3] is unknown (a number, e.g. 200) - start color, perhaps?
+ if (argc >= 5)
+ warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16());
+ g_sci->_gfxPalette->setRemappingPercentGray(color, percent);
+ }
+ break;
+ case 5: { // don't map to range
+ //int16 mapping = argv[1].toSint16();
+ uint16 intensity = argv[2].toUint16();
+ // HACK for PQ4
+ if (g_sci->getGameId() == GID_PQ4)
+ g_sci->_gfxPalette->kernelSetIntensity(0, 255, intensity, true);
+
+ kStub(s, argc, argv);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return s->r_acc;
+}
+
#endif
} // End of namespace Sci
diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp
index 15d18eb4bb..342fa95eda 100644
--- a/engines/sci/engine/klists.cpp
+++ b/engines/sci/engine/klists.cpp
@@ -506,6 +506,11 @@ reg_t kListAt(EngineState *s, int argc, reg_t *argv) {
curIndex++;
}
+ // Update the virtual file selected in the character import screen of QFG4.
+ // For the SCI0-SCI1.1 version of this, check kDrawControl().
+ if (g_sci->inQfGImportRoom() && !strcmp(s->_segMan->getObjectName(curObject), "SelectorDText"))
+ s->_chosenQfGImportItem = listIndex;
+
return curObject;
}
diff --git a/engines/sci/engine/kmath.cpp b/engines/sci/engine/kmath.cpp
index 7570856dff..4b8fadbb84 100644
--- a/engines/sci/engine/kmath.cpp
+++ b/engines/sci/engine/kmath.cpp
@@ -77,7 +77,18 @@ reg_t kSqrt(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, (int16) sqrt((float) ABS(argv[0].toSint16())));
}
+/**
+ * Returns the angle (in degrees) between the two points determined by (x1, y1)
+ * and (x2, y2). The angle ranges from 0 to 359 degrees.
+ * What this function does is pretty simple but apparently the original is not
+ * accurate.
+ */
uint16 kGetAngleWorker(int16 x1, int16 y1, int16 x2, int16 y2) {
+ // SCI1 games (QFG2 and newer) use a simple atan implementation. SCI0 games
+ // use a somewhat less accurate calculation (below).
+ if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY)
+ return (int16)(360 - atan2((double)(x1 - x2), (double)(y1 - y2)) * 57.2958) % 360;
+
int16 xRel = x2 - x1;
int16 yRel = y1 - y2; // y-axis is mirrored.
int16 angle;
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 12c830f622..8b7fc4ffec 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -419,6 +419,18 @@ reg_t kGetSierraProfileInt(EngineState *s, int argc, reg_t *argv) {
return argv[2];
}
+reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv) {
+ uint16 windowsOption = argv[0].toUint16();
+ switch (windowsOption) {
+ case 0:
+ // Title bar on/off in Phantasmagoria, we return 0 (off)
+ return NULL_REG;
+ default:
+ warning("GetWindowsOption: Unknown option %d", windowsOption);
+ return NULL_REG;
+ }
+}
+
#endif
// kIconBar is really a subop of kMacPlatform for SCI1.1 Mac
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp
index b378b4d58b..0633267db4 100644
--- a/engines/sci/engine/ksound.cpp
+++ b/engines/sci/engine/ksound.cpp
@@ -140,12 +140,14 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
((argv[3].toUint16() & 0xff) << 16) |
((argv[4].toUint16() & 0xff) << 8) |
(argv[5].toUint16() & 0xff);
- if (argc == 8) {
+ // Removed warning because of the high amount of console spam
+ /*if (argc == 8) {
+ // TODO: Handle the extra 2 SCI21 params
// argv[6] is always 1
// argv[7] is the contents of global 229 (0xE5)
warning("kDoAudio: Play called with SCI2.1 extra parameters: %04x:%04x and %04x:%04x",
PRINT_REG(argv[6]), PRINT_REG(argv[7]));
- }
+ }*/
} else {
warning("kDoAudio: Play called with an unknown number of parameters (%d)", argc);
return NULL_REG;
@@ -244,6 +246,11 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
// Used in Pharkas whenever a speech sample starts (takes no params)
//warning("kDoAudio: Unhandled case 13, %d extra arguments passed", argc - 1);
break;
+ case 17:
+ // Seems to be some sort of audio sync, used in SQ6. Silenced the
+ // warning due to the high level of spam it produces. (takes no params)
+ //warning("kDoAudio: Unhandled case 17, %d extra arguments passed", argc - 1);
+ break;
default:
warning("kDoAudio: Unhandled case %d, %d extra arguments passed", argv[0].toUint16(), argc - 1);
}
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 2456ba1100..6bf9aff2fe 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -50,6 +50,8 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
if (!videoDecoder)
return;
+ videoDecoder->start();
+
byte *scaleBuffer = 0;
byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel;
uint16 width = videoDecoder->getWidth();
@@ -90,7 +92,7 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
EngineState *s = g_sci->getEngineState();
if (videoDecoder->hasDirtyPalette()) {
- byte *palette = (byte *)videoDecoder->getPalette() + s->_vmdPalStart * 3;
+ const byte *palette = videoDecoder->getPalette() + s->_vmdPalStart * 3;
g_system->getPaletteManager()->setPalette(palette, s->_vmdPalStart, s->_vmdPalEnd - s->_vmdPalStart);
}
@@ -108,7 +110,7 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
}
if (videoDecoder->hasDirtyPalette()) {
- byte *palette = (byte *)videoDecoder->getPalette() + s->_vmdPalStart * 3;
+ const byte *palette = videoDecoder->getPalette() + s->_vmdPalStart * 3;
g_system->getPaletteManager()->setPalette(palette, s->_vmdPalStart, s->_vmdPalEnd - s->_vmdPalStart);
}
@@ -162,9 +164,8 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
} else {
// DOS SEQ
// SEQ's are called with no subops, just the string and delay
- SeqDecoder *seqDecoder = new SeqDecoder();
- seqDecoder->setFrameDelay(argv[1].toUint16()); // Time between frames in ticks
- videoDecoder = seqDecoder;
+ // Time is specified as ticks
+ videoDecoder = new SEQDecoder(argv[1].toUint16());
if (!videoDecoder->loadFile(filename)) {
warning("Failed to open movie file %s", filename.c_str());
@@ -190,7 +191,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case 0: {
Common::String filename = s->_segMan->getString(argv[1]);
- videoDecoder = new Video::AviDecoder(g_system->getMixer());
+ videoDecoder = new Video::AVIDecoder();
if (filename.equalsIgnoreCase("gk2a.avi")) {
// HACK: Switch to 16bpp graphics for Indeo3.
@@ -209,6 +210,8 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
warning("Failed to open movie file %s", filename.c_str());
delete videoDecoder;
videoDecoder = 0;
+ } else {
+ s->_videoState.fileName = filename;
}
break;
}
@@ -250,6 +253,7 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
int16 y = argv[5].toUint16();
warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y);
g_sci->_robotDecoder->load(id);
+ g_sci->_robotDecoder->start();
g_sci->_robotDecoder->setPos(x, y);
}
break;
@@ -265,13 +269,13 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
warning("kRobot(%d)", subop);
break;
case 8: // sync
- //if (false) { // debug: automatically skip all robot videos
- if ((uint32)g_sci->_robotDecoder->getCurFrame() != g_sci->_robotDecoder->getFrameCount() - 1) {
- writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG);
- } else {
+ //if (true) { // debug: automatically skip all robot videos
+ if (g_sci->_robotDecoder->endOfVideo()) {
g_sci->_robotDecoder->close();
// Signal the engine scripts that the video is done
writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG);
+ } else {
+ writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG);
}
break;
default:
@@ -346,7 +350,7 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
break;
}
case 6: // Play
- videoDecoder = new Video::VMDDecoder(g_system->getMixer());
+ videoDecoder = new Video::AdvancedVMDDecoder();
if (s->_videoState.fileName.empty()) {
// Happens in Lighthouse
@@ -404,7 +408,7 @@ reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv) {
s->_videoState.reset();
s->_videoState.fileName = Common::String::format("%d.duk", argv[1].toUint16());
- videoDecoder = new Video::AviDecoder(g_system->getMixer());
+ videoDecoder = new Video::AVIDecoder();
if (!videoDecoder->loadFile(s->_videoState.fileName)) {
warning("Could not open Duck %s", s->_videoState.fileName.c_str());
diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp
index cddd01e10c..a92d572d35 100644
--- a/engines/sci/engine/message.cpp
+++ b/engines/sci/engine/message.cpp
@@ -400,11 +400,21 @@ Common::String MessageState::processString(const char *s) {
void MessageState::outputString(reg_t buf, const Common::String &str) {
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2) {
- SciString *sciString = _segMan->lookupString(buf);
- sciString->setSize(str.size() + 1);
- for (uint32 i = 0; i < str.size(); i++)
- sciString->setValue(i, str.c_str()[i]);
- sciString->setValue(str.size(), 0);
+ if (_segMan->getSegmentType(buf.getSegment()) == SEG_TYPE_STRING) {
+ SciString *sciString = _segMan->lookupString(buf);
+ sciString->setSize(str.size() + 1);
+ for (uint32 i = 0; i < str.size(); i++)
+ sciString->setValue(i, str.c_str()[i]);
+ sciString->setValue(str.size(), 0);
+ } else if (_segMan->getSegmentType(buf.getSegment()) == SEG_TYPE_ARRAY) {
+ // Happens in the intro of LSL6, we are asked to write the string
+ // into an array
+ SciArray<reg_t> *sciString = _segMan->lookupArray(buf);
+ sciString->setSize(str.size() + 1);
+ for (uint32 i = 0; i < str.size(); i++)
+ sciString->setValue(i, make_reg(0, str.c_str()[i]));
+ sciString->setValue(str.size(), NULL_REG);
+ }
} else {
#endif
SegmentRef buffer_r = _segMan->dereference(buf);
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 57334b89aa..037f4ab700 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -385,7 +385,7 @@ void Script::setLockers(int lockers) {
_lockers = lockers;
}
-uint32 Script::validateExportFunc(int pubfunct, bool relocateSci3) {
+uint32 Script::validateExportFunc(int pubfunct, bool relocSci3) {
bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
if (_numExports <= pubfunct) {
@@ -401,7 +401,7 @@ uint32 Script::validateExportFunc(int pubfunct, bool relocateSci3) {
if (getSciVersion() != SCI_VERSION_3) {
offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
} else {
- if (!relocateSci3)
+ if (!relocSci3)
offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct) + getCodeBlockOffsetSci3();
else
offset = relocateOffsetSci3(pubfunct * 2 + 22);
@@ -422,16 +422,9 @@ uint32 Script::validateExportFunc(int pubfunct, bool relocateSci3) {
}
}
- if (!offset) {
-#ifdef ENABLE_SCI32
- // WORKAROUNDS for invalid (empty) exports
- if (g_sci->getGameId() == GID_TORIN && _nr == 64036) {
- } else if (g_sci->getGameId() == GID_RAMA && _nr == 64908) {
- } else
-#endif
- error("Request for invalid exported function 0x%x of script %d", pubfunct, _nr);
- return NULL;
- }
+ // Note that it's perfectly normal to return a zero offset, especially in
+ // SCI1.1 and newer games. Examples include script 64036 in Torin's Passage,
+ // script 64908 in the demo of RAMA and script 1013 in KQ6 floppy.
if (offset >= _bufSize)
error("Invalid export function pointer");
diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h
index 1fc8caf313..0b499203c2 100644
--- a/engines/sci/engine/script.h
+++ b/engines/sci/engine/script.h
@@ -197,11 +197,11 @@ public:
* Validate whether the specified public function is exported by
* the script in the specified segment.
* @param pubfunct Index of the function to validate
- * @param relocateSci3 Decide whether to relocate this SCI3 public function or not
+ * @param relocSci3 Decide whether to relocate this SCI3 public function or not
* @return NULL if the public function is invalid, its
* offset into the script's segment otherwise
*/
- uint32 validateExportFunc(int pubfunct, bool relocateSci3);
+ uint32 validateExportFunc(int pubfunct, bool relocSci3);
/**
* Marks the script as deleted.
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 69eb377684..659c13b13e 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -978,7 +978,27 @@ const uint16 sq4CdPatchTextOptionsButton[] = {
PATCH_END
};
-// Patch 2: Add the ability to toggle among the three available options,
+// Patch 2: Adjust a check in babbleIcon::init, which handles the babble icon
+// (e.g. the two guys from Andromeda) shown when dying/quitting.
+// Fixes bug #3538418.
+const byte sq4CdSignatureBabbleIcon[] = {
+ 7,
+ 0x89, 0x5a, // lsg 5a
+ 0x35, 0x02, // ldi 02
+ 0x1a, // eq?
+ 0x31, 0x26, // bnt 26 [02a7]
+ 0
+};
+
+const uint16 sq4CdPatchBabbleIcon[] = {
+ 0x89, 0x5a, // lsg 5a
+ 0x35, 0x01, // ldi 01
+ 0x1a, // eq?
+ 0x2f, 0x26, // bt 26 [02a7]
+ PATCH_END
+};
+
+// Patch 3: Add the ability to toggle among the three available options,
// when the text options button is clicked: "Speech", "Text" and "Both".
// Refer to the patch above for additional details.
// iconTextSwitch::doit (called when the text options button is clicked)
@@ -1030,6 +1050,7 @@ const SciScriptSignature sq4Signatures[] = {
{ 298, "Floppy: endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x44), -3, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight },
{ 298, "Floppy (German): endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x4c), -3, sq4FloppySignatureEndlessFlightGerman, sq4FloppyPatchEndlessFlight },
{ 818, "CD: Speech and subtitles option", 1, PATCH_MAGICDWORD(0x89, 0x5a, 0x3c, 0x35), 0, sq4CdSignatureTextOptions, sq4CdPatchTextOptions },
+ { 0, "CD: Babble icon speech and subtitles fix", 1, PATCH_MAGICDWORD(0x89, 0x5a, 0x35, 0x02), 0, sq4CdSignatureBabbleIcon, sq4CdPatchBabbleIcon },
{ 818, "CD: Speech and subtitles option button", 1, PATCH_MAGICDWORD(0x35, 0x01, 0xa1, 0x53), 0, sq4CdSignatureTextOptionsButton, sq4CdPatchTextOptionsButton },
SCI_SIGNATUREENTRY_TERMINATOR
};
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index a6c145979f..951fc7c363 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -143,16 +143,27 @@ Script *SegManager::allocateScript(int script_nr, SegmentId *segid) {
}
void SegManager::deallocate(SegmentId seg) {
- if (!check(seg))
- error("SegManager::deallocate(): invalid segment ID");
+ if (seg < 1 || (uint)seg >= _heap.size())
+ error("Attempt to deallocate an invalid segment ID");
SegmentObj *mobj = _heap[seg];
+ if (!mobj)
+ error("Attempt to deallocate an already freed segment");
if (mobj->getType() == SEG_TYPE_SCRIPT) {
Script *scr = (Script *)mobj;
_scriptSegMap.erase(scr->getScriptNumber());
- if (scr->getLocalsSegment())
- deallocate(scr->getLocalsSegment());
+ if (scr->getLocalsSegment()) {
+ // Check if the locals segment has already been deallocated.
+ // If the locals block has been stored in a segment with an ID
+ // smaller than the segment ID of the script itself, it will be
+ // already freed at this point. This can happen when scripts are
+ // uninstantiated and instantiated again: they retain their own
+ // segment ID, but are allocated a new locals segment, which can
+ // have an ID smaller than the segment of the script itself.
+ if (_heap[scr->getLocalsSegment()])
+ deallocate(scr->getLocalsSegment());
+ }
}
delete mobj;
@@ -307,21 +318,6 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) {
return result[index];
}
-// validate the seg
-// return:
-// false - invalid seg
-// true - valid seg
-bool SegManager::check(SegmentId seg) {
- if (seg < 1 || (uint)seg >= _heap.size()) {
- return false;
- }
- if (!_heap[seg]) {
- warning("SegManager: seg %x is removed from memory, but not removed from hash_map", seg);
- return false;
- }
- return true;
-}
-
// return the seg if script_id is valid and in the map, else 0
SegmentId SegManager::getScriptSegment(int script_id) const {
return _scriptSegMap.getVal(script_id, 0);
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 356a1b04a7..074d3f6b0a 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -471,14 +471,6 @@ private:
void createClassTable();
SegmentId findFreeSegment() const;
-
- /**
- * Check segment validity
- * @param[in] seg The segment to validate
- * @return false if 'seg' is an invalid segment, true if
- * 'seg' is a valid segment
- */
- bool check(SegmentId seg);
};
} // End of namespace Sci
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index 94a3fe3ae5..0f0c8dcd66 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -122,8 +122,11 @@ void EngineState::reset(bool isRestoring) {
_videoState.reset();
_syncedAudioOptions = false;
+
_vmdPalStart = 0;
_vmdPalEnd = 256;
+
+ _palCycleToColor = 255;
}
void EngineState::speedThrottler(uint32 neededSleep) {
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 9ae6299d83..81090876c7 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -199,6 +199,8 @@ public:
uint16 _vmdPalStart, _vmdPalEnd;
bool _syncedAudioOptions;
+ uint16 _palCycleToColor;
+
/**
* Resets the engine state.
*/
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 5a2a39def2..3f43966976 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -1173,6 +1173,7 @@ void run_vm(EngineState *s) {
case op_line: // 0x3f (63)
// Debug opcode (line number)
+ //debug("Script %d, line %d", scr->getScriptNumber(), opparams[0]);
break;
case op_lag: // 0x40 (64)
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index a0fd6689df..8b38faa013 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -202,6 +202,7 @@ enum SciOpcodes {
op_push2 = 0x3d, // 061
op_pushSelf = 0x3e, // 062
op_line = 0x3f, // 063
+ //
op_lag = 0x40, // 064
op_lal = 0x41, // 065
op_lat = 0x42, // 066
@@ -218,6 +219,7 @@ enum SciOpcodes {
op_lsli = 0x4d, // 077
op_lsti = 0x4e, // 078
op_lspi = 0x4f, // 079
+ //
op_sag = 0x50, // 080
op_sal = 0x51, // 081
op_sat = 0x52, // 082
@@ -234,6 +236,7 @@ enum SciOpcodes {
op_ssli = 0x5d, // 093
op_ssti = 0x5e, // 094
op_sspi = 0x5f, // 095
+ //
op_plusag = 0x60, // 096
op_plusal = 0x61, // 097
op_plusat = 0x62, // 098
@@ -250,6 +253,7 @@ enum SciOpcodes {
op_plussli = 0x6d, // 109
op_plussti = 0x6e, // 110
op_plusspi = 0x6f, // 111
+ //
op_minusag = 0x70, // 112
op_minusal = 0x71, // 113
op_minusat = 0x72, // 114
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index ecb1e4c2d5..9fa0368784 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -36,13 +36,15 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = {
{ GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xcc6, 0, { WORKAROUND_FAKE, 0 } }, // op_or: when giving the papers to the customs officer, gets called against a pointer instead of a number - bug #3034464
{ GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xce0, 0, { WORKAROUND_FAKE, 0 } }, // Same as above, for the Spanish version - bug #3313962
{ GID_FANMADE, 516, 983, 0, "Wander", "setTarget", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_mul: The Legend of the Lost Jewel Demo (fan made): called with object as second parameter when attacked by insects - bug #3038913
+ { GID_GK1, 800,64992, 0, "Fwd", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when Mosely finds Gabriel and Grace near the end of the game, compares the Grooper object with 7
{ GID_ICEMAN, 199, 977, 0, "Grooper", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_add: While dancing with the girl
{ GID_MOTHERGOOSE256, -1, 999, 0, "Event", "new", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_and: constantly during the game (SCI1 version)
{ GID_MOTHERGOOSE256, -1, 4, 0, "rm004", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_or: when going north and reaching the castle (rooms 4 and 37) - bug #3038228
{ GID_MOTHERGOOSEHIRES,90, 90, 0, "newGameButton", "select", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_ge: MUMG Deluxe, when selecting "New Game" in the main menu. It tries to compare an integer with a list. Needs to return false for the game to continue.
+ { GID_PHANTASMAGORIA, 902, 0, 0, "", "export 7", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_shr: when starting a chapter in Phantasmagoria
{ GID_QFG1VGA, 301, 928, 0, "Blink", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_div: when entering the inn, gets called with 1 parameter, but 2nd parameter is used for div which happens to be an object
{ GID_QFG2, 200, 200, 0, "astro", "messages", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_lsi: when getting asked for your name by the astrologer bug #3039879
- { GID_GK1, 800,64992, 0, "Fwd", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when Mosely finds Gabriel and Grace near the end of the game, compares the Grooper object with 7
+ { GID_QFG4, 710,64941, 0, "RandCycle", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when the tentacle appears in the third room of the caves
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -162,10 +164,10 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_SQ1, -1, 703, 0, "", "export 1", -1, 0, { WORKAROUND_FAKE, 0 } }, // sub that's called from several objects while on sarien battle cruiser
{ GID_SQ1, -1, 703, 0, "firePulsar", "changeState", 0x18a, 0, { WORKAROUND_FAKE, 0 } }, // export 1, but called locally (when shooting at aliens)
{ GID_SQ4, -1, 398, 0, "showBox", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // CD: called when rummaging in Software Excess bargain bin
- { GID_SQ4, -1, 928, 0, "Narrator", "startText", -1, 1000, { WORKAROUND_FAKE, 1 } }, // CD: method returns this to the caller
+ { GID_SQ4, -1, 928, -1, "Narrator", "startText", -1, 1000, { WORKAROUND_FAKE, 1 } }, // CD: happens in the options dialog and in-game when speech and subtitles are used simultaneously
{ GID_SQ5, 201, 201, 0, "buttonPanel", "doVerb", -1, 0, { WORKAROUND_FAKE, 1 } }, // when looking at the orange or red button - bug #3038563
{ GID_SQ6, -1, 0, 0, "SQ6", "init", -1, 2, { WORKAROUND_FAKE, 0 } }, // Demo and full version: called when the game starts (demo: room 0, full: room 100)
- { GID_SQ6, 100, 64950, 0, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // called when pressing "Start game" in the main menu
+ { GID_SQ6, -1, 64950, -1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // called when pressing "Start game" in the main menu, when entering the Orion's Belt bar (room 300), and perhaps other places
{ GID_SQ6, -1, 64964, 0, "DPath", "init", -1, 1, { WORKAROUND_FAKE, 0 } }, // during the game
{ GID_TORIN, -1, 64017, 0, "oFlags", "clear", -1, 0, { WORKAROUND_FAKE, 0 } }, // entering Torin's home in the French version
SCI_WORKAROUNDENTRY_TERMINATOR
@@ -397,6 +399,7 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = {
{ GID_LSL6, 740, 740, 0, "showCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during ending, 4 additional parameters are passed by accident
{ GID_LSL6HIRES, 130, 130, 0, "recruitLarryScr", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during intro, a 3rd parameter is passed by accident
{ GID_SQ1, 43, 303, 0, "slotGuy", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when leaving ulence flats bar, parameter 1 is not passed - script error
+ { GID_QFG4, -1, 110, 0, "dreamer", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during the dream sequence, a 3rd parameter is passed by accident
SCI_WORKAROUNDENTRY_TERMINATOR
};
diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp
index fcdd057509..30184cc091 100644
--- a/engines/sci/graphics/font.cpp
+++ b/engines/sci/graphics/font.cpp
@@ -54,7 +54,7 @@ GfxFontFromResource::GfxFontFromResource(ResourceManager *resMan, GfxScreen *scr
}
GfxFontFromResource::~GfxFontFromResource() {
- delete []_chars;
+ delete[] _chars;
_resMan->unlockResource(_resource);
}
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 265a175e66..968014c032 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -28,6 +28,7 @@
#include "common/system.h"
#include "common/textconsole.h"
#include "engines/engine.h"
+#include "graphics/palette.h"
#include "graphics/surface.h"
#include "sci/sci.h"
@@ -117,27 +118,43 @@ void GfxFrameout::showCurrentScrollText() {
}
}
+extern void showScummVMDialog(const Common::String &message);
+
void GfxFrameout::kernelAddPlane(reg_t object) {
PlaneEntry newPlane;
if (_planes.empty()) {
// There has to be another way for sierra sci to do this or maybe script resolution is compiled into
// interpreter (TODO)
- uint16 tmpRunningWidth = readSelectorValue(_segMan, object, SELECTOR(resX));
- uint16 tmpRunningHeight = readSelectorValue(_segMan, object, SELECTOR(resY));
+ uint16 scriptWidth = readSelectorValue(_segMan, object, SELECTOR(resX));
+ uint16 scriptHeight = readSelectorValue(_segMan, object, SELECTOR(resY));
- // The above can be 0 in SCI3 (e.g. Phantasmagoria 2)
- if (tmpRunningWidth == 0 && tmpRunningHeight == 0) {
- tmpRunningWidth = 320;
- tmpRunningHeight = 200;
+ // Phantasmagoria 2 doesn't specify a script width/height
+ if (g_sci->getGameId() == GID_PHANTASMAGORIA2) {
+ scriptWidth = 640;
+ scriptHeight = 480;
}
- _coordAdjuster->setScriptsResolution(tmpRunningWidth, tmpRunningHeight);
+ assert(scriptWidth > 0 && scriptHeight > 0);
+ _coordAdjuster->setScriptsResolution(scriptWidth, scriptHeight);
+ }
+
+ // Import of QfG character files dialog is shown in QFG4.
+ // Display additional popup information before letting user use it.
+ // For the SCI0-SCI1.1 version of this, check kDrawControl().
+ if (g_sci->inQfGImportRoom() && !strcmp(_segMan->getObjectName(object), "DSPlane")) {
+ showScummVMDialog("Characters saved inside ScummVM are shown "
+ "automatically. Character files saved in the original "
+ "interpreter need to be put inside ScummVM's saved games "
+ "directory and a prefix needs to be added depending on which "
+ "game it was saved in: 'qfg1-' for Quest for Glory 1, 'qfg2-' "
+ "for Quest for Glory 2, 'qfg3-' for Quest for Glory 3. "
+ "Example: 'qfg2-thief.sav'.");
}
newPlane.object = object;
newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority));
- newPlane.lastPriority = 0xFFFF; // hidden
+ newPlane.lastPriority = -1; // hidden
newPlane.planeOffsetX = 0;
newPlane.planeOffsetY = 0;
newPlane.pictureId = kPlanePlainColored;
@@ -294,6 +311,10 @@ reg_t GfxFrameout::addPlaneLine(reg_t object, Common::Point startPoint, Common::
}
void GfxFrameout::updatePlaneLine(reg_t object, reg_t hunkId, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) {
+ // Check if we're asked to update a line that was never added
+ if (hunkId.isNull())
+ return;
+
for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) {
if (it->object == object) {
for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) {
@@ -311,6 +332,10 @@ void GfxFrameout::updatePlaneLine(reg_t object, reg_t hunkId, Common::Point star
}
void GfxFrameout::deletePlaneLine(reg_t object, reg_t hunkId) {
+ // Check if we're asked to delete a line that was never added (happens during the intro of LSL6)
+ if (hunkId.isNull())
+ return;
+
for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) {
if (it->object == object) {
for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) {
@@ -326,8 +351,10 @@ void GfxFrameout::deletePlaneLine(reg_t object, reg_t hunkId) {
void GfxFrameout::kernelAddScreenItem(reg_t object) {
// Ignore invalid items
- if (!_segMan->isObject(object))
+ if (!_segMan->isObject(object)) {
+ warning("kernelAddScreenItem: Attempt to add an invalid object (%04x:%04x)", PRINT_REG(object));
return;
+ }
FrameoutEntry *itemEntry = new FrameoutEntry();
memset(itemEntry, 0, sizeof(FrameoutEntry));
@@ -341,8 +368,10 @@ void GfxFrameout::kernelAddScreenItem(reg_t object) {
void GfxFrameout::kernelUpdateScreenItem(reg_t object) {
// Ignore invalid items
- if (!_segMan->isObject(object))
+ if (!_segMan->isObject(object)) {
+ warning("kernelUpdateScreenItem: Attempt to update an invalid object (%04x:%04x)", PRINT_REG(object));
return;
+ }
FrameoutEntry *itemEntry = findScreenItem(object);
if (!itemEntry) {
@@ -372,10 +401,9 @@ void GfxFrameout::kernelUpdateScreenItem(reg_t object) {
void GfxFrameout::kernelDeleteScreenItem(reg_t object) {
FrameoutEntry *itemEntry = findScreenItem(object);
- if (!itemEntry) {
- warning("kernelDeleteScreenItem: invalid object %04x:%04x", PRINT_REG(object));
+ // If the item could not be found, it may already have been deleted
+ if (!itemEntry)
return;
- }
_screenItems.remove(itemEntry);
delete itemEntry;
@@ -432,15 +460,10 @@ bool sortHelper(const FrameoutEntry* entry1, const FrameoutEntry* entry2) {
}
bool planeSortHelper(const PlaneEntry &entry1, const PlaneEntry &entry2) {
-// SegManager *segMan = g_sci->getEngineState()->_segMan;
-
-// uint16 plane1Priority = readSelectorValue(segMan, entry1, SELECTOR(priority));
-// uint16 plane2Priority = readSelectorValue(segMan, entry2, SELECTOR(priority));
-
- if (entry1.priority == 0xffff)
+ if (entry1.priority < 0)
return true;
- if (entry2.priority == 0xffff)
+ if (entry2.priority < 0)
return false;
return entry1.priority < entry2.priority;
@@ -466,7 +489,7 @@ void GfxFrameout::showVideo() {
uint16 y = videoDecoder->getPos().y;
if (videoDecoder->hasDirtyPalette())
- videoDecoder->setSystemPalette();
+ g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256);
while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
if (videoDecoder->needsUpdate()) {
@@ -475,7 +498,7 @@ void GfxFrameout::showVideo() {
g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h);
if (videoDecoder->hasDirtyPalette())
- videoDecoder->setSystemPalette();
+ g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256);
g_system->updateScreen();
}
@@ -606,13 +629,13 @@ void GfxFrameout::kernelFrameout() {
_screen->drawLine(startPoint, endPoint, it2->color, it2->priority, it2->control);
}
- uint16 planeLastPriority = it->lastPriority;
+ int16 planeLastPriority = it->lastPriority;
// Update priority here, sq6 sets it w/o UpdatePlane
- uint16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));
+ int16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));
it->lastPriority = planePriority;
- if (planePriority == 0xffff) { // Plane currently not meant to be shown
+ if (planePriority < 0) { // Plane currently not meant to be shown
// If plane was shown before, delete plane rect
if (planePriority != planeLastPriority)
_paint32->fillRect(it->planeRect, 0);
@@ -653,7 +676,7 @@ void GfxFrameout::kernelFrameout() {
if (view && view->isSci2Hires()) {
view->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x);
view->adjustToUpscaledCoordinates(itemEntry->z, dummyX);
- } else if (getSciVersion() == SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_2_1) {
_coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x);
_coordAdjuster->fromScriptToDisplay(itemEntry->z, dummyX);
}
@@ -676,13 +699,13 @@ void GfxFrameout::kernelFrameout() {
// TODO: maybe we should clip the cels rect with this, i'm not sure
// the only currently known usage is game menu of gk1
} else if (view) {
- if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128))
- view->getCelRect(itemEntry->loopNo, itemEntry->celNo,
- itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect);
- else
- view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo,
- itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX,
- itemEntry->scaleY, itemEntry->celRect);
+ if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128))
+ view->getCelRect(itemEntry->loopNo, itemEntry->celNo,
+ itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect);
+ else
+ view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo,
+ itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX,
+ itemEntry->scaleY, itemEntry->celRect);
Common::Rect nsRect = itemEntry->celRect;
// Translate back to actual coordinate within scrollable plane
@@ -691,7 +714,7 @@ void GfxFrameout::kernelFrameout() {
if (view && view->isSci2Hires()) {
view->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left);
view->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right);
- } else if (getSciVersion() == SCI_VERSION_2_1) {
+ } else if (getSciVersion() >= SCI_VERSION_2_1) {
_coordAdjuster->fromDisplayToScript(nsRect.top, nsRect.left);
_coordAdjuster->fromDisplayToScript(nsRect.bottom, nsRect.right);
}
@@ -706,7 +729,9 @@ void GfxFrameout::kernelFrameout() {
g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect);
}
- // FIXME: When does this happen, and why?
+ // Don't attempt to draw sprites that are outside the visible
+ // screen area. An example is the random people walking in
+ // Jackson Square in GK1.
if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= _screen->getDisplayHeight() ||
itemEntry->celRect.right < 0 || itemEntry->celRect.left >= _screen->getDisplayWidth())
continue;
@@ -719,6 +744,9 @@ void GfxFrameout::kernelFrameout() {
translatedClipRect = clipRect;
translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top);
} else {
+ // QFG4 passes invalid rectangles when a battle is starting
+ if (!clipRect.isValidRect())
+ continue;
clipRect.clip(it->planeClipRect);
translatedClipRect = clipRect;
translatedClipRect.translate(it->planeRect.left, it->planeRect.top);
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index ecaf450d89..5fd2824224 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -40,8 +40,8 @@ typedef Common::List<PlaneLineEntry> PlaneLineList;
struct PlaneEntry {
reg_t object;
- uint16 priority;
- uint16 lastPriority;
+ int16 priority;
+ int16 lastPriority;
int16 planeOffsetX;
int16 planeOffsetY;
GuiResourceId pictureId;
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index ea154c5037..53d69cdcca 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -100,6 +100,9 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen)
default:
error("GfxPalette: Unknown view type");
}
+
+ _remapOn = false;
+ resetRemapping();
}
GfxPalette::~GfxPalette() {
@@ -140,8 +143,9 @@ void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut)
memset(paletteOut, 0, sizeof(Palette));
// Setup 1:1 mapping
- for (colorNo = 0; colorNo < 256; colorNo++)
+ for (colorNo = 0; colorNo < 256; colorNo++) {
paletteOut->mapping[colorNo] = colorNo;
+ }
if (bytesLeft < 37) {
// This happens when loading palette of picture 0 in sq5 - the resource is broken and doesn't contain a full
@@ -329,6 +333,79 @@ void GfxPalette::set(Palette *newPalette, bool force, bool forceRealMerge) {
}
}
+byte GfxPalette::remapColor(byte remappedColor, byte screenColor) {
+ assert(_remapOn);
+ if (_remappingType[remappedColor] == kRemappingByRange)
+ return _remappingByRange[screenColor];
+ else if (_remappingType[remappedColor] == kRemappingByPercent)
+ return _remappingByPercent[screenColor];
+ else
+ error("remapColor(): Color %d isn't remapped", remappedColor);
+
+ return 0; // should never reach here
+}
+
+void GfxPalette::resetRemapping() {
+ _remapOn = false;
+ _remappingPercentToSet = 0;
+
+ for (int i = 0; i < 256; i++) {
+ _remappingType[i] = kRemappingNone;
+ _remappingByPercent[i] = i;
+ _remappingByRange[i] = i;
+ }
+}
+
+void GfxPalette::setRemappingPercent(byte color, byte percent) {
+ _remapOn = true;
+
+ // We need to defer the setup of the remapping table every time the screen
+ // palette is changed, so that kernelFindColor() can find the correct
+ // colors. Set it once here, in case the palette stays the same and update
+ // it on each palette change by copySysPaletteToScreen().
+ _remappingPercentToSet = percent;
+
+ for (int i = 0; i < 256; i++) {
+ byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100;
+ byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100;
+ byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100;
+ _remappingByPercent[i] = kernelFindColor(r, g, b);
+ }
+
+ _remappingType[color] = kRemappingByPercent;
+}
+
+void GfxPalette::setRemappingPercentGray(byte color, byte percent) {
+ _remapOn = true;
+
+ // We need to defer the setup of the remapping table every time the screen
+ // palette is changed, so that kernelFindColor() can find the correct
+ // colors. Set it once here, in case the palette stays the same and update
+ // it on each palette change by copySysPaletteToScreen().
+ _remappingPercentToSet = percent;
+
+ // Note: This is not what the original does, but the results are the same visually
+ for (int i = 0; i < 256; i++) {
+ byte rComponent = _sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100;
+ byte gComponent = _sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100;
+ byte bComponent = _sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100;
+ byte luminosity = rComponent + gComponent + bComponent;
+ _remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity);
+ }
+
+ _remappingType[color] = kRemappingByPercent;
+}
+
+void GfxPalette::setRemappingRange(byte color, byte from, byte to, byte base) {
+ _remapOn = true;
+
+ for (int i = from; i <= to; i++) {
+ _remappingByRange[i] = i + base;
+ }
+
+ _remappingType[color] = kRemappingByRange;
+}
+
bool GfxPalette::insert(Palette *newPalette, Palette *destPalette) {
bool paletteChanged = false;
@@ -491,6 +568,16 @@ void GfxPalette::copySysPaletteToScreen() {
}
}
+ // Check if we need to reset remapping by percent with the new colors.
+ if (_remappingPercentToSet) {
+ for (int i = 0; i < 256; i++) {
+ byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100;
+ byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100;
+ byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100;
+ _remappingByPercent[i] = kernelFindColor(r, g, b);
+ }
+ }
+
g_system->getPaletteManager()->setPalette(bpal, 0, 256);
}
@@ -999,8 +1086,9 @@ bool GfxPalette::loadClut(uint16 clutId) {
memset(&pal, 0, sizeof(Palette));
// Setup 1:1 mapping
- for (int i = 0; i < 256; i++)
+ for (int i = 0; i < 256; i++) {
pal.mapping[i] = i;
+ }
// Now load in the palette
for (int i = 1; i <= 236; i++) {
diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h
index a9ea1c32de..e974781d49 100644
--- a/engines/sci/graphics/palette.h
+++ b/engines/sci/graphics/palette.h
@@ -31,6 +31,12 @@ namespace Sci {
class ResourceManager;
class GfxScreen;
+enum ColorRemappingType {
+ kRemappingNone = 0,
+ kRemappingByRange = 1,
+ kRemappingByPercent = 2
+};
+
/**
* Palette class, handles palette operations like changing intensity, setting up the palette, merging different palettes
*/
@@ -53,6 +59,15 @@ public:
void getSys(Palette *pal);
uint16 getTotalColorCount() const { return _totalScreenColors; }
+ void resetRemapping();
+ void setRemappingPercent(byte color, byte percent);
+ void setRemappingPercentGray(byte color, byte percent);
+ void setRemappingRange(byte color, byte from, byte to, byte base);
+ bool isRemapped(byte color) const {
+ return _remapOn && (_remappingType[color] != kRemappingNone);
+ }
+ byte remapColor(byte remappedColor, byte screenColor);
+
void setOnScreen();
void copySysPaletteToScreen();
@@ -123,6 +138,12 @@ private:
int _palVarySignal;
uint16 _totalScreenColors;
+ bool _remapOn;
+ ColorRemappingType _remappingType[256];
+ byte _remappingByPercent[256];
+ byte _remappingByRange[256];
+ uint16 _remappingPercentToSet;
+
void loadMacIconBarPalette();
byte *_macClut;
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 4020518b72..246b6bfff9 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -53,23 +53,35 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
#ifdef ENABLE_SCI32
// GK1 Mac uses a 640x480 resolution too
- if (g_sci->getGameId() == GID_GK1 && g_sci->getPlatform() == Common::kPlatformMacintosh)
- _upscaledHires = GFX_SCREEN_UPSCALED_640x480;
+ if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
+ if (g_sci->getGameId() == GID_GK1)
+ _upscaledHires = GFX_SCREEN_UPSCALED_640x480;
+ }
#endif
if (_resMan->detectHires()) {
_width = 640;
+ _pitch = 640;
_height = 480;
} else {
_width = 320;
+ _pitch = 320;
_height = getLowResScreenHeight();
}
+#ifdef ENABLE_SCI32
+ // Phantasmagoria 1 sets a window area of 630x450
+ if (g_sci->getGameId() == GID_PHANTASMAGORIA) {
+ _width = 630;
+ _height = 450;
+ }
+#endif
+
// Japanese versions of games use hi-res font on upscaled version of the game.
if ((g_sci->getLanguage() == Common::JA_JPN) && (getSciVersion() <= SCI_VERSION_1_1))
_upscaledHires = GFX_SCREEN_UPSCALED_640x400;
- _pixels = _width * _height;
+ _pixels = _pitch * _height;
switch (_upscaledHires) {
case GFX_SCREEN_UPSCALED_640x400:
@@ -91,7 +103,7 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
_upscaledMapping[i] = (i * 12) / 5;
break;
default:
- _displayWidth = _width;
+ _displayWidth = _pitch;
_displayHeight = _height;
memset(&_upscaledMapping, 0, sizeof(_upscaledMapping) );
break;
@@ -207,7 +219,7 @@ byte GfxScreen::getDrawingMask(byte color, byte prio, byte control) {
}
void GfxScreen::putPixel(int x, int y, byte drawMask, byte color, byte priority, byte control) {
- int offset = y * _width + x;
+ int offset = y * _pitch + x;
if (drawMask & GFX_SCREEN_MASK_VISUAL) {
_visualScreen[offset] = color;
@@ -240,7 +252,7 @@ void GfxScreen::putFontPixel(int startingY, int x, int y, byte color) {
// Do not scale ourselves, but put it on the display directly
putPixelOnDisplay(x, y + startingY, color);
} else {
- int offset = (startingY + y) * _width + x;
+ int offset = (startingY + y) * _pitch + x;
_visualScreen[offset] = color;
if (!_upscaledHires) {
@@ -342,19 +354,19 @@ void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, u
}
byte GfxScreen::getVisual(int x, int y) {
- return _visualScreen[y * _width + x];
+ return _visualScreen[y * _pitch + x];
}
byte GfxScreen::getPriority(int x, int y) {
- return _priorityScreen[y * _width + x];
+ return _priorityScreen[y * _pitch + x];
}
byte GfxScreen::getControl(int x, int y) {
- return _controlScreen[y * _width + x];
+ return _controlScreen[y * _pitch + x];
}
byte GfxScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) {
- int offset = y * _width + x;
+ int offset = y * _pitch + x;
byte match = 0;
if (screenMask & GFX_SCREEN_MASK_VISUAL) {
@@ -415,14 +427,14 @@ void GfxScreen::bitsSave(Common::Rect rect, byte mask, byte *memoryPtr) {
memcpy(memoryPtr, (void *)&mask, sizeof(mask)); memoryPtr += sizeof(mask);
if (mask & GFX_SCREEN_MASK_VISUAL) {
- bitsSaveScreen(rect, _visualScreen, _width, memoryPtr);
+ bitsSaveScreen(rect, _visualScreen, _pitch, memoryPtr);
bitsSaveDisplayScreen(rect, memoryPtr);
}
if (mask & GFX_SCREEN_MASK_PRIORITY) {
- bitsSaveScreen(rect, _priorityScreen, _width, memoryPtr);
+ bitsSaveScreen(rect, _priorityScreen, _pitch, memoryPtr);
}
if (mask & GFX_SCREEN_MASK_CONTROL) {
- bitsSaveScreen(rect, _controlScreen, _width, memoryPtr);
+ bitsSaveScreen(rect, _controlScreen, _pitch, memoryPtr);
}
if (mask & GFX_SCREEN_MASK_DISPLAY) {
if (!_upscaledHires)
@@ -475,14 +487,14 @@ void GfxScreen::bitsRestore(byte *memoryPtr) {
memcpy((void *)&mask, memoryPtr, sizeof(mask)); memoryPtr += sizeof(mask);
if (mask & GFX_SCREEN_MASK_VISUAL) {
- bitsRestoreScreen(rect, memoryPtr, _visualScreen, _width);
+ bitsRestoreScreen(rect, memoryPtr, _visualScreen, _pitch);
bitsRestoreDisplayScreen(rect, memoryPtr);
}
if (mask & GFX_SCREEN_MASK_PRIORITY) {
- bitsRestoreScreen(rect, memoryPtr, _priorityScreen, _width);
+ bitsRestoreScreen(rect, memoryPtr, _priorityScreen, _pitch);
}
if (mask & GFX_SCREEN_MASK_CONTROL) {
- bitsRestoreScreen(rect, memoryPtr, _controlScreen, _width);
+ bitsRestoreScreen(rect, memoryPtr, _controlScreen, _pitch);
}
if (mask & GFX_SCREEN_MASK_DISPLAY) {
if (!_upscaledHires)
@@ -560,7 +572,7 @@ void GfxScreen::dither(bool addToFlag) {
if (!_unditheringEnabled) {
// Do dithering on visual and display-screen
for (y = 0; y < _height; y++) {
- for (x = 0; x < _width; x++) {
+ for (x = 0; x < _pitch; x++) {
color = *visualPtr;
if (color & 0xF0) {
color ^= color << 4;
@@ -585,7 +597,7 @@ void GfxScreen::dither(bool addToFlag) {
memset(&_ditheredPicColors, 0, sizeof(_ditheredPicColors));
// Do dithering on visual screen and put decoded but undithered byte onto display-screen
for (y = 0; y < _height; y++) {
- for (x = 0; x < _width; x++) {
+ for (x = 0; x < _pitch; x++) {
color = *visualPtr;
if (color & 0xF0) {
color ^= color << 4;
diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h
index 73ea596ba1..01fb899edb 100644
--- a/engines/sci/graphics/screen.h
+++ b/engines/sci/graphics/screen.h
@@ -132,6 +132,7 @@ public:
private:
uint16 _width;
+ uint16 _pitch;
uint16 _height;
uint _pixels;
uint16 _displayWidth;
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 4e5c4da8b2..36aaae9232 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -741,8 +741,14 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const
const int x2 = clipRectTranslated.left + x;
const int y2 = clipRectTranslated.top + y;
if (!upscaledHires) {
- if (priority >= _screen->getPriority(x2, y2))
- _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0);
+ if (priority >= _screen->getPriority(x2, y2)) {
+ if (!_palette->isRemapped(palette->mapping[color])) {
+ _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0);
+ } else {
+ byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2));
+ _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0);
+ }
+ }
} else {
// UpscaledHires means view is hires and is supposed to
// get drawn onto lowres screen.
@@ -851,7 +857,12 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect,
const int x2 = clipRectTranslated.left + x;
const int y2 = clipRectTranslated.top + y;
if (color != clearKey && priority >= _screen->getPriority(x2, y2)) {
- _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0);
+ if (!_palette->isRemapped(palette->mapping[color])) {
+ _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0);
+ } else {
+ byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2));
+ _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0);
+ }
}
}
}
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index d43a9d06fc..42ae00b525 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -632,7 +632,7 @@ void SciEngine::initGraphics() {
_gfxPaint = _gfxPaint32;
_gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen);
_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxText32);
- _robotDecoder = new RobotDecoder(g_system->getMixer(), getPlatform() == Common::kPlatformMacintosh);
+ _robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
_gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32);
} else {
#endif
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 123dd21894..528bb51393 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -67,7 +67,8 @@ int AudioPlayer::startAudio(uint16 module, uint32 number) {
if (audioStream) {
_wPlayFlag = false;
- _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream);
+ Audio::Mixer::SoundType soundType = (module == 65535) ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType;
+ _mixer->playStream(soundType, &_audioHandle, audioStream);
return sampleLen;
} else {
// Don't throw a warning in this case. getAudioStream() already has. Some games
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index 989df7c8a1..5d32f40f18 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -96,7 +96,7 @@ void SoundCommandParser::initSoundResource(MusicEntry *newSound) {
if (_useDigitalSFX || !newSound->soundRes) {
int sampleLen;
newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen);
- newSound->soundType = Audio::Mixer::kSpeechSoundType;
+ newSound->soundType = Audio::Mixer::kSFXSoundType;
}
}
@@ -367,24 +367,36 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {
case 4: // SCI01+
case 5: // SCI1+ (SCI1 late sound scheme), with fade and continue
- musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX);
- // sometimes we get objects in that position, fix it up (ffs. workarounds)
- if (!argv[1].getSegment())
- musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16();
- else
- musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5;
- musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo();
- musicSlot->fadeTicker = 0;
-
if (argc == 5) {
// TODO: We currently treat this argument as a boolean, but may
// have to handle different non-zero values differently. (e.g.,
- // some KQ6 scripts pass 3 here)
- musicSlot->stopAfterFading = (argv[4].toUint16() != 0);
+ // some KQ6 scripts pass 3 here).
+ // There is a script bug in KQ6, room 460 (the room with the flying
+ // books). An object is passed here, which should not be treated as
+ // a true flag. Fixes bugs #3555404 and #3291115.
+ musicSlot->stopAfterFading = (argv[4].isNumber() && argv[4].toUint16() != 0);
} else {
musicSlot->stopAfterFading = false;
}
+ musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX);
+ // Check if the song is already at the requested volume. If it is, don't
+ // perform any fading. Happens for example during the intro of Longbow.
+ if (musicSlot->fadeTo != musicSlot->volume) {
+ // sometimes we get objects in that position, fix it up (ffs. workarounds)
+ if (!argv[1].getSegment())
+ musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16();
+ else
+ musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5;
+ musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo();
+ } else {
+ // Stop the music, if requested. Fixes bug #3555404.
+ if (musicSlot->stopAfterFading)
+ processStopSound(obj, false);
+ }
+
+ musicSlot->fadeTicker = 0;
+
// WORKAROUND/HACK: In the labyrinth in KQ6, when falling in the pit and
// lighting the lantern, the game scripts perform a fade in of the game
// music, but set it to stop after fading. Remove that flag here. This is
@@ -497,12 +509,7 @@ void SoundCommandParser::processUpdateCues(reg_t obj) {
// fireworks).
// It is also needed in other games, e.g. LSL6 when talking to the
// receptionist (bug #3192166).
- if (g_sci->getGameId() == GID_LONGBOW && g_sci->getEngineState()->currentRoomNumber() == 95) {
- // HACK: Don't set a signal here in the intro of Longbow, as that makes some dialog
- // boxes disappear too soon (bug #3044844).
- } else {
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- }
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
if (_soundVersion <= SCI_VERSION_0_LATE) {
processStopSound(obj, false);
} else {
diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp
index ebcfac6054..608c77136f 100644
--- a/engines/sci/video/robot_decoder.cpp
+++ b/engines/sci/video/robot_decoder.cpp
@@ -22,11 +22,13 @@
#include "common/archive.h"
#include "common/stream.h"
+#include "common/substream.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "common/util.h"
#include "graphics/surface.h"
+#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "sci/resource.h"
@@ -63,57 +65,26 @@ namespace Sci {
// our graphics engine, it looks just like a part of the room. A RBT can move
// around the screen and go behind other objects. (...)
-#ifdef ENABLE_SCI32
-
-enum robotPalTypes {
+enum RobotPalTypes {
kRobotPalVariable = 0,
kRobotPalConstant = 1
};
-RobotDecoder::RobotDecoder(Audio::Mixer *mixer, bool isBigEndian) {
- _surface = 0;
- _width = 0;
- _height = 0;
+RobotDecoder::RobotDecoder(bool isBigEndian) {
_fileStream = 0;
- _audioStream = 0;
- _dirtyPalette = false;
_pos = Common::Point(0, 0);
- _mixer = mixer;
_isBigEndian = isBigEndian;
+ _frameTotalSize = 0;
}
RobotDecoder::~RobotDecoder() {
close();
}
-bool RobotDecoder::load(GuiResourceId id) {
- // TODO: RAMA's robot 1003 cannot be played (shown at the menu screen) -
- // its drawn at odd coordinates. SV can't play it either (along with some
- // others), so it must be some new functionality added in RAMA's robot
- // videos. Skip it for now.
- if (g_sci->getGameId() == GID_RAMA && id == 1003)
- return false;
-
- // TODO: The robot video in the Lighthouse demo gets stuck
- if (g_sci->getGameId() == GID_LIGHTHOUSE && id == 16)
- return false;
-
- Common::String fileName = Common::String::format("%d.rbt", id);
- Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName);
-
- if (!stream) {
- warning("Unable to open robot file %s", fileName.c_str());
- return false;
- }
-
- return loadStream(stream);
-}
-
bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) {
close();
_fileStream = new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), _isBigEndian, DisposeAfterUse::YES);
- _surface = new Graphics::Surface();
readHeaderChunk();
@@ -125,131 +96,60 @@ bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) {
if (_header.version < 4 || _header.version > 6)
error("Unknown robot version: %d", _header.version);
- if (_header.hasSound) {
- _audioStream = Audio::makeQueuingAudioStream(11025, false);
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_audioHandle, _audioStream, -1, getVolume(), getBalance());
- }
+ RobotVideoTrack *videoTrack = new RobotVideoTrack(_header.frameCount);
+ addTrack(videoTrack);
- readPaletteChunk(_header.paletteDataSize);
- readFrameSizesChunk();
- calculateVideoDimensions();
- _surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
+ if (_header.hasSound)
+ addTrack(new RobotAudioTrack());
+ videoTrack->readPaletteChunk(_fileStream, _header.paletteDataSize);
+ readFrameSizesChunk();
+ videoTrack->calculateVideoDimensions(_fileStream, _frameTotalSize);
return true;
}
-void RobotDecoder::readHeaderChunk() {
- // Header (60 bytes)
- _fileStream->skip(6);
- _header.version = _fileStream->readUint16();
- _header.audioChunkSize = _fileStream->readUint16();
- _header.audioSilenceSize = _fileStream->readUint16();
- _fileStream->skip(2);
- _header.frameCount = _fileStream->readUint16();
- _header.paletteDataSize = _fileStream->readUint16();
- _header.unkChunkDataSize = _fileStream->readUint16();
- _fileStream->skip(5);
- _header.hasSound = _fileStream->readByte();
- _fileStream->skip(34);
-
- // Some videos (e.g. robot 1305 in Phantasmagoria and
- // robot 184 in Lighthouse) have an unknown chunk before
- // the palette chunk (probably used for sound preloading).
- // Skip it here.
- if (_header.unkChunkDataSize)
- _fileStream->skip(_header.unkChunkDataSize);
-}
-
-void RobotDecoder::readPaletteChunk(uint16 chunkSize) {
- byte *paletteData = new byte[chunkSize];
- _fileStream->read(paletteData, chunkSize);
-
- // SCI1.1 palette
- byte palFormat = paletteData[32];
- uint16 palColorStart = paletteData[25];
- uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29);
+bool RobotDecoder::load(GuiResourceId id) {
+ // TODO: RAMA's robot 1003 cannot be played (shown at the menu screen) -
+ // its drawn at odd coordinates. SV can't play it either (along with some
+ // others), so it must be some new functionality added in RAMA's robot
+ // videos. Skip it for now.
+ if (g_sci->getGameId() == GID_RAMA && id == 1003)
+ return false;
+
+ // TODO: The robot video in the Lighthouse demo gets stuck
+ if (g_sci->getGameId() == GID_LIGHTHOUSE && id == 16)
+ return false;
- int palOffset = 37;
- memset(_palette, 0, 256 * 3);
+ Common::String fileName = Common::String::format("%d.rbt", id);
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName);
- for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
- if (palFormat == kRobotPalVariable)
- palOffset++;
- _palette[colorNo * 3 + 0] = paletteData[palOffset++];
- _palette[colorNo * 3 + 1] = paletteData[palOffset++];
- _palette[colorNo * 3 + 2] = paletteData[palOffset++];
+ if (!stream) {
+ warning("Unable to open robot file %s", fileName.c_str());
+ return false;
}
- _dirtyPalette = true;
- delete[] paletteData;
+ return loadStream(stream);
}
+void RobotDecoder::close() {
+ VideoDecoder::close();
-void RobotDecoder::readFrameSizesChunk() {
- // The robot video file contains 2 tables, with one entry for each frame:
- // - A table containing the size of the image in each video frame
- // - A table containing the total size of each video frame.
- // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots,
- // they contain 32-bit integers.
-
- _frameTotalSize = new uint32[_header.frameCount];
-
- // TODO: The table reading code can probably be removed once the
- // audio chunk size is figured out (check the TODO inside processNextFrame())
-#if 0
- // We don't need any of the two tables to play the video, so we ignore
- // both of them.
- uint16 wordSize = _header.version == 6 ? 4 : 2;
- _fileStream->skip(_header.frameCount * wordSize * 2);
-#else
- switch (_header.version) {
- case 4:
- case 5: // sizes are 16-bit integers
- // Skip table with frame image sizes, as we don't need it
- _fileStream->skip(_header.frameCount * 2);
- for (int i = 0; i < _header.frameCount; ++i)
- _frameTotalSize[i] = _fileStream->readUint16();
- break;
- case 6: // sizes are 32-bit integers
- // Skip table with frame image sizes, as we don't need it
- _fileStream->skip(_header.frameCount * 4);
- for (int i = 0; i < _header.frameCount; ++i)
- _frameTotalSize[i] = _fileStream->readUint32();
- break;
- default:
- error("Can't yet handle index table for robot version %d", _header.version);
- }
-#endif
-
- // 2 more unknown tables
- _fileStream->skip(1024 + 512);
+ delete _fileStream;
+ _fileStream = 0;
- // Pad to nearest 2 kilobytes
- uint32 curPos = _fileStream->pos();
- if (curPos & 0x7ff)
- _fileStream->seek((curPos & ~0x7ff) + 2048);
+ delete[] _frameTotalSize;
+ _frameTotalSize = 0;
}
-void RobotDecoder::calculateVideoDimensions() {
- // This is an O(n) operation, as each frame has a different size.
- // We need to know the actual frame size to have a constant video size.
- uint32 pos = _fileStream->pos();
-
- for (uint32 curFrame = 0; curFrame < _header.frameCount; curFrame++) {
- _fileStream->skip(4);
- uint16 frameWidth = _fileStream->readUint16();
- uint16 frameHeight = _fileStream->readUint16();
- if (frameWidth > _width)
- _width = frameWidth;
- if (frameHeight > _height)
- _height = frameHeight;
- _fileStream->skip(_frameTotalSize[curFrame] - 8);
- }
+void RobotDecoder::readNextPacket() {
+ // Get our track
+ RobotVideoTrack *videoTrack = (RobotVideoTrack *)getTrack(0);
+ videoTrack->increaseCurFrame();
+ Graphics::Surface *surface = videoTrack->getSurface();
- _fileStream->seek(pos);
-}
+ if (videoTrack->endOfTrack())
+ return;
-const Graphics::Surface *RobotDecoder::decodeNextFrame() {
// Read frame image header (24 bytes)
_fileStream->skip(3);
byte frameScale = _fileStream->readByte();
@@ -258,23 +158,28 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() {
_fileStream->skip(4); // unknown, almost always 0
uint16 frameX = _fileStream->readUint16();
uint16 frameY = _fileStream->readUint16();
+
// TODO: In v4 robot files, frameX and frameY have a different meaning.
// Set them both to 0 for v4 for now, so that robots in PQ:SWAT show up
// correctly.
if (_header.version == 4)
frameX = frameY = 0;
+
uint16 compressedSize = _fileStream->readUint16();
uint16 frameFragments = _fileStream->readUint16();
_fileStream->skip(4); // unknown
uint32 decompressedSize = frameWidth * frameHeight * frameScale / 100;
+
// FIXME: A frame's height + position can go off limits... why? With the
// following, we cut the contents to fit the frame
- uint16 scaledHeight = CLIP<uint16>(decompressedSize / frameWidth, 0, _height - frameY);
+ uint16 scaledHeight = CLIP<uint16>(decompressedSize / frameWidth, 0, surface->h - frameY);
+
// FIXME: Same goes for the frame's width + position. In this case, we
// modify the position to fit the contents on screen.
- if (frameWidth + frameX > _width)
- frameX = _width - frameWidth;
- assert (frameWidth + frameX <= _width && scaledHeight + frameY <= _height);
+ if (frameWidth + frameX > surface->w)
+ frameX = surface->w - frameWidth;
+
+ assert(frameWidth + frameX <= surface->w && scaledHeight + frameY <= surface->h);
DecompressorLZS lzs;
byte *decompressedFrame = new byte[decompressedSize];
@@ -305,24 +210,23 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() {
// Copy over the decompressed frame
byte *inFrame = decompressedFrame;
- byte *outFrame = (byte *)_surface->pixels;
+ byte *outFrame = (byte *)surface->pixels;
// Black out the surface
- memset(outFrame, 0, _width * _height);
+ memset(outFrame, 0, surface->w * surface->h);
// Move to the correct y coordinate
- outFrame += _width * frameY;
+ outFrame += surface->w * frameY;
for (uint16 y = 0; y < scaledHeight; y++) {
memcpy(outFrame + frameX, inFrame, frameWidth);
inFrame += frameWidth;
- outFrame += _width;
+ outFrame += surface->w;
}
delete[] decompressedFrame;
- // +1 because we start with frame number -1
- uint32 audioChunkSize = _frameTotalSize[_curFrame + 1] - (24 + compressedSize);
+ uint32 audioChunkSize = _frameTotalSize[videoTrack->getCurFrame()] - (24 + compressedSize);
// TODO: The audio chunk size below is usually correct, but there are some
// exceptions (e.g. robot 4902 in Phantasmagoria, towards its end)
@@ -337,51 +241,166 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() {
// Queue the next audio frame
// FIXME: For some reason, there are audio hiccups/gaps
if (_header.hasSound) {
- _fileStream->skip(8); // header
- _audioStream->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize - 8),
- (audioChunkSize - 8) * 2, DisposeAfterUse::NO,
- Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN);
+ RobotAudioTrack *audioTrack = (RobotAudioTrack *)getTrack(1);
+ _fileStream->skip(8); // header
+ audioChunkSize -= 8;
+ audioTrack->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize), audioChunkSize * 2);
} else {
_fileStream->skip(audioChunkSize);
- }
-
- if (_curFrame == -1)
- _startTime = g_system->getMillis();
+ }
+}
- _curFrame++;
+void RobotDecoder::readHeaderChunk() {
+ // Header (60 bytes)
+ _fileStream->skip(6);
+ _header.version = _fileStream->readUint16();
+ _header.audioChunkSize = _fileStream->readUint16();
+ _header.audioSilenceSize = _fileStream->readUint16();
+ _fileStream->skip(2);
+ _header.frameCount = _fileStream->readUint16();
+ _header.paletteDataSize = _fileStream->readUint16();
+ _header.unkChunkDataSize = _fileStream->readUint16();
+ _fileStream->skip(5);
+ _header.hasSound = _fileStream->readByte();
+ _fileStream->skip(34);
- return _surface;
+ // Some videos (e.g. robot 1305 in Phantasmagoria and
+ // robot 184 in Lighthouse) have an unknown chunk before
+ // the palette chunk (probably used for sound preloading).
+ // Skip it here.
+ if (_header.unkChunkDataSize)
+ _fileStream->skip(_header.unkChunkDataSize);
}
-void RobotDecoder::close() {
- if (!_fileStream)
- return;
+void RobotDecoder::readFrameSizesChunk() {
+ // The robot video file contains 2 tables, with one entry for each frame:
+ // - A table containing the size of the image in each video frame
+ // - A table containing the total size of each video frame.
+ // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots,
+ // they contain 32-bit integers.
- delete _fileStream;
- _fileStream = 0;
+ _frameTotalSize = new uint32[_header.frameCount];
+ // TODO: The table reading code can probably be removed once the
+ // audio chunk size is figured out (check the TODO inside processNextFrame())
+#if 0
+ // We don't need any of the two tables to play the video, so we ignore
+ // both of them.
+ uint16 wordSize = _header.version == 6 ? 4 : 2;
+ _fileStream->skip(_header.frameCount * wordSize * 2);
+#else
+ switch (_header.version) {
+ case 4:
+ case 5: // sizes are 16-bit integers
+ // Skip table with frame image sizes, as we don't need it
+ _fileStream->skip(_header.frameCount * 2);
+ for (int i = 0; i < _header.frameCount; ++i)
+ _frameTotalSize[i] = _fileStream->readUint16();
+ break;
+ case 6: // sizes are 32-bit integers
+ // Skip table with frame image sizes, as we don't need it
+ _fileStream->skip(_header.frameCount * 4);
+ for (int i = 0; i < _header.frameCount; ++i)
+ _frameTotalSize[i] = _fileStream->readUint32();
+ break;
+ default:
+ error("Can't yet handle index table for robot version %d", _header.version);
+ }
+#endif
+
+ // 2 more unknown tables
+ _fileStream->skip(1024 + 512);
+
+ // Pad to nearest 2 kilobytes
+ uint32 curPos = _fileStream->pos();
+ if (curPos & 0x7ff)
+ _fileStream->seek((curPos & ~0x7ff) + 2048);
+}
+
+RobotDecoder::RobotVideoTrack::RobotVideoTrack(int frameCount) : _frameCount(frameCount) {
+ _surface = new Graphics::Surface();
+ _curFrame = -1;
+ _dirtyPalette = false;
+}
+
+RobotDecoder::RobotVideoTrack::~RobotVideoTrack() {
_surface->free();
delete _surface;
- _surface = 0;
+}
- if (_header.hasSound) {
- _mixer->stopHandle(_audioHandle);
- //delete _audioStream; _audioStream = 0;
+uint16 RobotDecoder::RobotVideoTrack::getWidth() const {
+ return _surface->w;
+}
+
+uint16 RobotDecoder::RobotVideoTrack::getHeight() const {
+ return _surface->h;
+}
+
+Graphics::PixelFormat RobotDecoder::RobotVideoTrack::getPixelFormat() const {
+ return _surface->format;
+}
+
+void RobotDecoder::RobotVideoTrack::readPaletteChunk(Common::SeekableSubReadStreamEndian *stream, uint16 chunkSize) {
+ byte *paletteData = new byte[chunkSize];
+ stream->read(paletteData, chunkSize);
+
+ // SCI1.1 palette
+ byte palFormat = paletteData[32];
+ uint16 palColorStart = paletteData[25];
+ uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29);
+
+ int palOffset = 37;
+ memset(_palette, 0, 256 * 3);
+
+ for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
+ if (palFormat == kRobotPalVariable)
+ palOffset++;
+ _palette[colorNo * 3 + 0] = paletteData[palOffset++];
+ _palette[colorNo * 3 + 1] = paletteData[palOffset++];
+ _palette[colorNo * 3 + 2] = paletteData[palOffset++];
}
- reset();
+ _dirtyPalette = true;
+ delete[] paletteData;
}
-void RobotDecoder::updateVolume() {
- if (g_system->getMixer()->isSoundHandleActive(_audioHandle))
- g_system->getMixer()->setChannelVolume(_audioHandle, getVolume());
+void RobotDecoder::RobotVideoTrack::calculateVideoDimensions(Common::SeekableSubReadStreamEndian *stream, uint32 *frameSizes) {
+ // This is an O(n) operation, as each frame has a different size.
+ // We need to know the actual frame size to have a constant video size.
+ uint32 pos = stream->pos();
+
+ uint16 width = 0, height = 0;
+
+ for (int curFrame = 0; curFrame < _frameCount; curFrame++) {
+ stream->skip(4);
+ uint16 frameWidth = stream->readUint16();
+ uint16 frameHeight = stream->readUint16();
+ if (frameWidth > width)
+ width = frameWidth;
+ if (frameHeight > height)
+ height = frameHeight;
+ stream->skip(frameSizes[curFrame] - 8);
+ }
+
+ stream->seek(pos);
+
+ _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
}
-void RobotDecoder::updateBalance() {
- if (g_system->getMixer()->isSoundHandleActive(_audioHandle))
- g_system->getMixer()->setChannelBalance(_audioHandle, getBalance());
+RobotDecoder::RobotAudioTrack::RobotAudioTrack() {
+ _audioStream = Audio::makeQueuingAudioStream(11025, false);
}
-#endif
+RobotDecoder::RobotAudioTrack::~RobotAudioTrack() {
+ delete _audioStream;
+}
+
+void RobotDecoder::RobotAudioTrack::queueBuffer(byte *buffer, int size) {
+ _audioStream->queueBuffer(buffer, size, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN);
+}
+
+Audio::AudioStream *RobotDecoder::RobotAudioTrack::getAudioStream() const {
+ return _audioStream;
+}
} // End of namespace Sci
diff --git a/engines/sci/video/robot_decoder.h b/engines/sci/video/robot_decoder.h
index e9cefe7d91..ebc3262939 100644
--- a/engines/sci/video/robot_decoder.h
+++ b/engines/sci/video/robot_decoder.h
@@ -25,84 +25,103 @@
#include "common/rational.h"
#include "common/rect.h"
-#include "common/stream.h"
-#include "common/substream.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "graphics/pixelformat.h"
#include "video/video_decoder.h"
-namespace Sci {
+namespace Audio {
+class QueuingAudioStream;
+}
-#ifdef ENABLE_SCI32
-
-struct RobotHeader {
- // 6 bytes, identifier bytes
- uint16 version;
- uint16 audioChunkSize;
- uint16 audioSilenceSize;
- // 2 bytes, unknown
- uint16 frameCount;
- uint16 paletteDataSize;
- uint16 unkChunkDataSize;
- // 5 bytes, unknown
- byte hasSound;
- // 34 bytes, unknown
-};
+namespace Common {
+class SeekableSubReadStreamEndian;
+}
+
+namespace Sci {
-class RobotDecoder : public Video::FixedRateVideoDecoder {
+class RobotDecoder : public Video::VideoDecoder {
public:
- RobotDecoder(Audio::Mixer *mixer, bool isBigEndian);
+ RobotDecoder(bool isBigEndian);
virtual ~RobotDecoder();
bool loadStream(Common::SeekableReadStream *stream);
bool load(GuiResourceId id);
void close();
-
- bool isVideoLoaded() const { return _fileStream != 0; }
- uint16 getWidth() const { return _width; }
- uint16 getHeight() const { return _height; }
- uint32 getFrameCount() const { return _header.frameCount; }
- const Graphics::Surface *decodeNextFrame();
- Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
- const byte *getPalette() { _dirtyPalette = false; return _palette; }
- bool hasDirtyPalette() const { return _dirtyPalette; }
+
void setPos(uint16 x, uint16 y) { _pos = Common::Point(x, y); }
Common::Point getPos() const { return _pos; }
protected:
- // VideoDecoder API
- void updateVolume();
- void updateBalance();
-
- // FixedRateVideoDecoder API
- Common::Rational getFrameRate() const { return Common::Rational(60, 10); }
-
+ void readNextPacket();
+
private:
+ class RobotVideoTrack : public FixedRateVideoTrack {
+ public:
+ RobotVideoTrack(int frameCount);
+ ~RobotVideoTrack();
+
+ uint16 getWidth() const;
+ uint16 getHeight() const;
+ Graphics::PixelFormat getPixelFormat() const;
+ int getCurFrame() const { return _curFrame; }
+ int getFrameCount() const { return _frameCount; }
+ const Graphics::Surface *decodeNextFrame() { return _surface; }
+ const byte *getPalette() const { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+
+ void readPaletteChunk(Common::SeekableSubReadStreamEndian *stream, uint16 chunkSize);
+ void calculateVideoDimensions(Common::SeekableSubReadStreamEndian *stream, uint32 *frameSizes);
+ Graphics::Surface *getSurface() { return _surface; }
+ void increaseCurFrame() { _curFrame++; }
+
+ protected:
+ Common::Rational getFrameRate() const { return Common::Rational(60, 10); }
+
+ private:
+ int _frameCount;
+ int _curFrame;
+ byte _palette[256 * 3];
+ mutable bool _dirtyPalette;
+ Graphics::Surface *_surface;
+ };
+
+ class RobotAudioTrack : public AudioTrack {
+ public:
+ RobotAudioTrack();
+ ~RobotAudioTrack();
+
+ Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kMusicSoundType; }
+
+ void queueBuffer(byte *buffer, int size);
+
+ protected:
+ Audio::AudioStream *getAudioStream() const;
+
+ private:
+ Audio::QueuingAudioStream *_audioStream;
+ };
+
+ struct RobotHeader {
+ // 6 bytes, identifier bytes
+ uint16 version;
+ uint16 audioChunkSize;
+ uint16 audioSilenceSize;
+ // 2 bytes, unknown
+ uint16 frameCount;
+ uint16 paletteDataSize;
+ uint16 unkChunkDataSize;
+ // 5 bytes, unknown
+ byte hasSound;
+ // 34 bytes, unknown
+ } _header;
+
void readHeaderChunk();
- void readPaletteChunk(uint16 chunkSize);
void readFrameSizesChunk();
- void calculateVideoDimensions();
-
- void freeData();
- RobotHeader _header;
Common::Point _pos;
bool _isBigEndian;
+ uint32 *_frameTotalSize;
Common::SeekableSubReadStreamEndian *_fileStream;
-
- uint16 _width;
- uint16 _height;
- uint32 *_frameTotalSize;
- byte _palette[256 * 3];
- bool _dirtyPalette;
- Graphics::Surface *_surface;
- Audio::QueuingAudioStream *_audioStream;
- Audio::SoundHandle _audioHandle;
- Audio::Mixer *_mixer;
};
-#endif
} // End of namespace Sci
diff --git a/engines/sci/video/seq_decoder.cpp b/engines/sci/video/seq_decoder.cpp
index abd64911a7..a7b6346eca 100644
--- a/engines/sci/video/seq_decoder.cpp
+++ b/engines/sci/video/seq_decoder.cpp
@@ -41,33 +41,44 @@ enum seqFrameTypes {
kSeqFrameDiff = 1
};
-SeqDecoder::SeqDecoder() {
- _fileStream = 0;
- _surface = 0;
- _dirtyPalette = false;
+SEQDecoder::SEQDecoder(uint frameDelay) : _frameDelay(frameDelay) {
}
-SeqDecoder::~SeqDecoder() {
+SEQDecoder::~SEQDecoder() {
close();
}
-bool SeqDecoder::loadStream(Common::SeekableReadStream *stream) {
+bool SEQDecoder::loadStream(Common::SeekableReadStream *stream) {
close();
+ addTrack(new SEQVideoTrack(stream, _frameDelay));
+
+ return true;
+}
+
+SEQDecoder::SEQVideoTrack::SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay) {
+ assert(stream);
+ assert(frameDelay != 0);
_fileStream = stream;
+ _frameDelay = frameDelay;
+ _curFrame = -1;
+
_surface = new Graphics::Surface();
_surface->create(SEQ_SCREEN_WIDTH, SEQ_SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_frameCount = _fileStream->readUint16LE();
- // Set palette
- int paletteChunkSize = _fileStream->readUint32LE();
- readPaletteChunk(paletteChunkSize);
+ // Set initial palette
+ readPaletteChunk(_fileStream->readUint32LE());
+}
- return true;
+SEQDecoder::SEQVideoTrack::~SEQVideoTrack() {
+ delete _fileStream;
+ _surface->free();
+ delete _surface;
}
-void SeqDecoder::readPaletteChunk(uint16 chunkSize) {
+void SEQDecoder::SEQVideoTrack::readPaletteChunk(uint16 chunkSize) {
byte *paletteData = new byte[chunkSize];
_fileStream->read(paletteData, chunkSize);
@@ -91,23 +102,7 @@ void SeqDecoder::readPaletteChunk(uint16 chunkSize) {
delete[] paletteData;
}
-void SeqDecoder::close() {
- if (!_fileStream)
- return;
-
- _frameDelay = 0;
-
- delete _fileStream;
- _fileStream = 0;
-
- _surface->free();
- delete _surface;
- _surface = 0;
-
- reset();
-}
-
-const Graphics::Surface *SeqDecoder::decodeNextFrame() {
+const Graphics::Surface *SEQDecoder::SEQVideoTrack::decodeNextFrame() {
int16 frameWidth = _fileStream->readUint16LE();
int16 frameHeight = _fileStream->readUint16LE();
int16 frameLeft = _fileStream->readUint16LE();
@@ -142,9 +137,6 @@ const Graphics::Surface *SeqDecoder::decodeNextFrame() {
delete[] buf;
}
- if (_curFrame == -1)
- _startTime = g_system->getMillis();
-
_curFrame++;
return _surface;
}
@@ -159,7 +151,7 @@ const Graphics::Surface *SeqDecoder::decodeNextFrame() {
} \
memcpy(dest + writeRow * SEQ_SCREEN_WIDTH + writeCol, litData + litPos, n);
-bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) {
+bool SEQDecoder::SEQVideoTrack::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) {
int writeRow = 0;
int writeCol = left;
int litPos = 0;
@@ -237,4 +229,9 @@ bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litS
return true;
}
+const byte *SEQDecoder::SEQVideoTrack::getPalette() const {
+ _dirtyPalette = false;
+ return _palette;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h
index 800a3c9024..890f349feb 100644
--- a/engines/sci/video/seq_decoder.h
+++ b/engines/sci/video/seq_decoder.h
@@ -40,44 +40,49 @@ namespace Sci {
/**
* Implementation of the Sierra SEQ decoder, used in KQ6 DOS floppy/CD and GK1 DOS
*/
-class SeqDecoder : public Video::FixedRateVideoDecoder {
+class SEQDecoder : public Video::VideoDecoder {
public:
- SeqDecoder();
- virtual ~SeqDecoder();
+ SEQDecoder(uint frameDelay);
+ virtual ~SEQDecoder();
bool loadStream(Common::SeekableReadStream *stream);
- void close();
-
- void setFrameDelay(int frameDelay) { _frameDelay = frameDelay; }
-
- bool isVideoLoaded() const { return _fileStream != 0; }
- uint16 getWidth() const { return SEQ_SCREEN_WIDTH; }
- uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; }
- uint32 getFrameCount() const { return _frameCount; }
- const Graphics::Surface *decodeNextFrame();
- Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
- const byte *getPalette() { _dirtyPalette = false; return _palette; }
- bool hasDirtyPalette() const { return _dirtyPalette; }
-
-protected:
- Common::Rational getFrameRate() const { assert(_frameDelay); return Common::Rational(60, _frameDelay); }
private:
- enum {
- SEQ_SCREEN_WIDTH = 320,
- SEQ_SCREEN_HEIGHT = 200
+ class SEQVideoTrack : public FixedRateVideoTrack {
+ public:
+ SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay);
+ ~SEQVideoTrack();
+
+ uint16 getWidth() const { return SEQ_SCREEN_WIDTH; }
+ uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; }
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
+ int getCurFrame() const { return _curFrame; }
+ int getFrameCount() const { return _frameCount; }
+ const Graphics::Surface *decodeNextFrame();
+ const byte *getPalette() const;
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+
+ protected:
+ Common::Rational getFrameRate() const { return Common::Rational(60, _frameDelay); }
+
+ private:
+ enum {
+ SEQ_SCREEN_WIDTH = 320,
+ SEQ_SCREEN_HEIGHT = 200
+ };
+
+ void readPaletteChunk(uint16 chunkSize);
+ bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey);
+
+ Common::SeekableReadStream *_fileStream;
+ int _curFrame, _frameCount;
+ byte _palette[256 * 3];
+ mutable bool _dirtyPalette;
+ Graphics::Surface *_surface;
+ uint _frameDelay;
};
- void readPaletteChunk(uint16 chunkSize);
- bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey);
-
- uint16 _width, _height;
- uint16 _frameDelay;
- Common::SeekableReadStream *_fileStream;
- byte _palette[256 * 3];
- bool _dirtyPalette;
- uint32 _frameCount;
- Graphics::Surface *_surface;
+ uint _frameDelay;
};
} // End of namespace Sci
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index ebf1a2675c..5404c7f8b1 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -20,9 +20,6 @@
*
*/
-// FIXME: Avoid using printf
-#define FORBIDDEN_SYMBOL_EXCEPTION_printf
-
#include "base/plugins.h"
#include "common/archive.h"
@@ -1066,15 +1063,19 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co
// unknown MD5, or with a medium debug level in case of a known MD5 (for
// debugging purposes).
if (!findInMD5Table(res.md5.c_str())) {
- printf("Your game version appears to be unknown. If this is *NOT* a fan-modified\n");
- printf("version (in particular, not a fan-made translation), please, report the\n");
- printf("following data to the ScummVM team along with name of the game you tried\n");
- printf("to add and its version/language/etc.:\n");
+ Common::String md5Warning;
+
+ md5Warning = "Your game version appears to be unknown. If this is *NOT* a fan-modified\n";
+ md5Warning += "version (in particular, not a fan-made translation), please, report the\n";
+ md5Warning += "following data to the ScummVM team along with name of the game you tried\n";
+ md5Warning += "to add and its version/language/etc.:\n";
- printf(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n",
+ md5Warning += Common::String::format(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n",
res.game.gameid,
generateFilenameForDetection(res.fp.pattern, res.fp.genMethod).c_str(),
res.md5.c_str());
+
+ g_system->logMessage(LogMessageType::kWarning, md5Warning.c_str());
} else {
debug(1, "Using MD5 '%s'", res.md5.c_str());
}
@@ -1266,7 +1267,6 @@ SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int
Graphics::Surface *thumbnail = ScummEngine::loadThumbnailFromSlot(target, slot);
SaveStateDescriptor desc(slot, saveDesc);
- desc.setDeletableFlag(true);
desc.setThumbnail(thumbnail);
SaveStateMetaInfos infos;
diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp
index 40e99c26a8..be17a3b305 100644
--- a/engines/scumm/he/animation_he.cpp
+++ b/engines/scumm/he/animation_he.cpp
@@ -40,7 +40,7 @@ MoviePlayer::MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer) : _vm(vm) {
_video = new Video::BinkDecoder();
else
#endif
- _video = new Video::SmackerDecoder(mixer);
+ _video = new Video::SmackerDecoder();
_flags = 0;
_wizResNum = 0;
@@ -61,11 +61,16 @@ int MoviePlayer::load(const char *filename, int flags, int image) {
if (_video->isVideoLoaded())
_video->close();
+ // Ensure that Bink will use our PixelFormat
+ _video->setDefaultHighColorFormat(g_system->getScreenFormat());
+
if (!_video->loadFile(filename)) {
warning("Failed to load video file %s", filename);
return -1;
}
+ _video->start();
+
debug(1, "Playing video %s", filename);
if (flags & 2)
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 0814e3bfe1..d4eefe8c28 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 Fri Jun 15 09:16:45 2012
+ This file was generated by the md5table tool on Sat Jul 07 23:39:27 2012
DO NOT EDIT MANUALLY!
*/
@@ -191,6 +191,7 @@ static const MD5Table md5table[] = {
{ "45082a5c9f42ba14dacfe1fdeeba819d", "freddicove", "HE 100", "Demo", 18422, Common::EN_ANY, Common::kPlatformUnknown },
{ "45152f7cf2ba8f43cf8a8ea2e740ae09", "monkey", "VGA", "VGA", 8357, Common::ES_ESP, Common::kPlatformPC },
{ "4521138d15d1fd7649c31fb981746231", "pajama2", "HE 98.5", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown },
+ { "4522564b3c31aaf218b6a96826a549fd", "maze", "HE 99", "", -1, Common::EN_USA, Common::kPlatformWindows },
{ "46b53fd430adcfbed791b48a0d4b079f", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformPC },
{ "470c45b636139bb40716daa1c7edaad0", "loom", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformPC },
{ "477dbafbd66a53c98416dc01aef019ad", "monkey", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformPC },
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index ddafd964eb..f7add4eed2 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -37,6 +37,7 @@
#include "gui/message.h"
+#include "video/dxa_decoder.h"
#include "video/psx_decoder.h"
#include "video/smk_decoder.h"
@@ -96,9 +97,8 @@ static const char *const sequenceListPSX[20] = {
// Basic movie player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType)
- : _vm(vm), _textMan(textMan), _resMan(resMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) {
- _bgSoundStream = NULL;
+MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType)
+ : _vm(vm), _textMan(textMan), _resMan(resMan), _system(system) {
_decoderType = decoderType;
_decoder = decoder;
@@ -107,7 +107,6 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::
}
MoviePlayer::~MoviePlayer() {
- delete _bgSoundHandle;
delete _decoder;
}
@@ -116,16 +115,12 @@ MoviePlayer::~MoviePlayer() {
* @param id the id of the file
*/
bool MoviePlayer::load(uint32 id) {
- Common::File f;
Common::String filename;
- if (_decoderType == kVideoDecoderDXA)
- _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(sequenceList[id]);
- else
- _bgSoundStream = NULL;
-
if (SwordEngine::_systemVars.showText) {
+ Common::File f;
filename = Common::String::format("%s.txt", sequenceList[id]);
+
if (f.open(filename)) {
Common::String line;
int lineNo = 0;
@@ -169,7 +164,6 @@ bool MoviePlayer::load(uint32 id) {
_movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color));
lastEnd = endFrame;
}
- f.close();
}
}
@@ -189,6 +183,7 @@ bool MoviePlayer::load(uint32 id) {
// Need to load here in case it fails in which case we'd need
// to go back to paletted mode
if (_decoder->loadFile(filename)) {
+ _decoder->start();
return true;
} else {
initGraphics(g_system->getWidth(), g_system->getHeight(), true);
@@ -197,30 +192,27 @@ bool MoviePlayer::load(uint32 id) {
break;
}
- return _decoder->loadFile(filename.c_str());
-}
+ if (!_decoder->loadFile(filename))
+ return false;
-void MoviePlayer::play() {
- if (_bgSoundStream)
- _snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream);
+ // For DXA, also add the external sound file
+ if (_decoderType == kVideoDecoderDXA)
+ _decoder->addStreamFileTrack(sequenceList[id]);
- bool terminated = false;
+ _decoder->start();
+ return true;
+}
+void MoviePlayer::play() {
_textX = 0;
_textY = 0;
- terminated = !playVideo();
-
- if (terminated)
- _snd->stopHandle(*_bgSoundHandle);
+ playVideo();
_textMan->releaseText(2, false);
_movieTexts.clear();
- while (_snd->isSoundHandleActive(*_bgSoundHandle))
- _system->delayMillis(100);
-
// It's tempting to call _screen->fullRefresh() here to restore the old
// palette. However, that causes glitches with DXA movies, where the
// previous location would be momentarily drawn, before switching to
@@ -320,7 +312,7 @@ bool MoviePlayer::playVideo() {
}
if (_decoder->hasDirtyPalette()) {
- _decoder->setSystemPalette();
+ _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256);
if (!_movieTexts.empty()) {
// Look for the best color indexes to use to display the subtitles
@@ -506,24 +498,12 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) {
scaledFrame.free();
}
-DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
- : _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
-}
-
-uint32 DXADecoderWithSound::getTime() const {
- if (_mixer->isSoundHandleActive(*_bgSoundHandle))
- return _mixer->getSoundElapsedTime(*_bgSoundHandle);
-
- return DXADecoder::getTime();
-}
-
///////////////////////////////////////////////////////////////////////////////
// Factory function for creating the appropriate cutscene player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system) {
+MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system) {
Common::String filename;
- Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle;
// For the PSX version, we'll try the PlayStation stream files
if (vm->isPsx()) {
@@ -534,7 +514,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
#ifdef USE_RGB_COLOR
// All BS1 PSX videos run the videos at 2x speed
Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x);
- return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX);
+ return new MoviePlayer(vm, textMan, resMan, system, psxDecoder, kVideoDecoderPSX);
#else
GUI::MessageDialog dialog(Common::String::format(_("PSX stream cutscene '%s' cannot be played in paletted mode"), filename.c_str()), _("OK"));
dialog.runModal();
@@ -546,20 +526,20 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
filename = Common::String::format("%s.smk", sequenceList[id]);
if (Common::File::exists(filename)) {
- Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(snd);
- return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK);
+ Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder();
+ return new MoviePlayer(vm, textMan, resMan, system, smkDecoder, kVideoDecoderSMK);
}
filename = Common::String::format("%s.dxa", sequenceList[id]);
if (Common::File::exists(filename)) {
#ifdef USE_ZLIB
- DXADecoderWithSound *dxaDecoder = new DXADecoderWithSound(snd, bgSoundHandle);
- return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA);
+ Video::VideoDecoder *dxaDecoder = new Video::DXADecoder();
+ return new MoviePlayer(vm, textMan, resMan, system, dxaDecoder, kVideoDecoderDXA);
#else
GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK"));
dialog.runModal();
- return NULL;
+ return 0;
#endif
}
@@ -569,7 +549,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
if (Common::File::exists(filename)) {
GUI::MessageDialog dialog(_("MPEG2 cutscenes are no longer supported"), _("OK"));
dialog.runModal();
- return NULL;
+ return 0;
}
if (!vm->isPsx() || scumm_stricmp(sequenceList[id], "enddemo") != 0) {
@@ -578,7 +558,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
dialog.runModal();
}
- return NULL;
+ return 0;
}
} // End of namespace Sword1
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
index c2ed86a1a3..d0c61f5eb3 100644
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@ -23,16 +23,19 @@
#ifndef SWORD1_ANIMATION_H
#define SWORD1_ANIMATION_H
-#include "video/dxa_decoder.h"
-#include "video/video_decoder.h"
-
#include "common/list.h"
-#include "audio/audiostream.h"
-
#include "sword1/screen.h"
#include "sword1/sound.h"
+namespace Graphics {
+struct Surface;
+}
+
+namespace Video {
+class VideoDecoder;
+}
+
namespace Sword1 {
enum DecoderType {
@@ -55,21 +58,9 @@ public:
}
};
-class DXADecoderWithSound : public Video::DXADecoder {
-public:
- DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle);
- ~DXADecoderWithSound() {}
-
- uint32 getTime() const;
-
-private:
- Audio::Mixer *_mixer;
- Audio::SoundHandle *_bgSoundHandle;
-};
-
class MoviePlayer {
public:
- MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType);
+ MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType);
virtual ~MoviePlayer();
bool load(uint32 id);
void play();
@@ -78,7 +69,6 @@ protected:
SwordEngine *_vm;
Text *_textMan;
ResMan *_resMan;
- Audio::Mixer *_snd;
OSystem *_system;
Common::List<MovieText> _movieTexts;
int _textX, _textY, _textWidth, _textHeight;
@@ -88,8 +78,6 @@ protected:
DecoderType _decoderType;
Video::VideoDecoder *_decoder;
- Audio::SoundHandle *_bgSoundHandle;
- Audio::AudioStream *_bgSoundStream;
bool playVideo();
void performPostProcessing(byte *screen);
@@ -100,7 +88,7 @@ protected:
void convertColor(byte r, byte g, byte b, float &h, float &s, float &v);
};
-MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system);
+MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system);
} // End of namespace Sword1
diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp
index 087dcd09d8..5662e4672b 100644
--- a/engines/sword1/detection.cpp
+++ b/engines/sword1/detection.cpp
@@ -268,9 +268,6 @@ SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int
SaveStateDescriptor desc(slot, name);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
-
if (versionSave < 2) // These older version of the savegames used a flag to signal presence of thumbnail
in->skip(1);
diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp
index 8e04861edf..757d768780 100644
--- a/engines/sword1/logic.cpp
+++ b/engines/sword1/logic.cpp
@@ -959,7 +959,7 @@ int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int3
// meantime, we don't want any looping sound effects still playing.
_sound->quitScreen();
- MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _mixer, _system);
+ MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _system);
if (player) {
_screen->clearScreen();
if (player->load(sequenceId))
diff --git a/engines/sword1/objectman.cpp b/engines/sword1/objectman.cpp
index d0803590a7..5d1864d58d 100644
--- a/engines/sword1/objectman.cpp
+++ b/engines/sword1/objectman.cpp
@@ -99,13 +99,64 @@ uint8 ObjectMan::fnCheckForTextLine(uint32 textId) {
char *ObjectMan::lockText(uint32 textId) {
uint8 lang = SwordEngine::_systemVars.language;
+ char *text = lockText(textId, lang);
+ if (text == 0) {
+ if (lang != BS1_ENGLISH) {
+ text = lockText(textId, BS1_ENGLISH);
+ if (text != 0)
+ warning("Missing translation for textId %u (\"%s\")", textId, text);
+ unlockText(textId, BS1_ENGLISH);
+ }
+
+ return _missingSubTitleStr;
+ }
+ return text;
+}
+
+char *ObjectMan::lockText(uint32 textId, uint8 lang) {
char *addr = (char *)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]);
if (addr == 0)
- return _missingSubTitleStr;
+ return NULL;
addr += sizeof(Header);
if ((textId & ITM_ID) >= _resMan->readUint32(addr)) {
+ // Workaround for missing sentences in some langages in the demo.
+ switch(textId) {
+ case 8455194:
+ return const_cast<char *>(_translationId8455194[lang]);
+ case 8455195:
+ return const_cast<char *>(_translationId8455195[lang]);
+ case 8455196:
+ return const_cast<char *>(_translationId8455196[lang]);
+ case 8455197:
+ return const_cast<char *>(_translationId8455197[lang]);
+ case 8455198:
+ return const_cast<char *>(_translationId8455198[lang]);
+ case 8455199:
+ return const_cast<char *>(_translationId8455199[lang]);
+ case 8455200:
+ return const_cast<char *>(_translationId8455200[lang]);
+ case 8455201:
+ return const_cast<char *>(_translationId8455201[lang]);
+ case 8455202:
+ return const_cast<char *>(_translationId8455202[lang]);
+ case 8455203:
+ return const_cast<char *>(_translationId8455203[lang]);
+ case 8455204:
+ return const_cast<char *>(_translationId8455204[lang]);
+ case 8455205:
+ return const_cast<char *>(_translationId8455205[lang]);
+ case 6488080:
+ return const_cast<char *>(_translationId6488080[lang]);
+ case 6488081:
+ return const_cast<char *>(_translationId6488081[lang]);
+ case 6488082:
+ return const_cast<char *>(_translationId6488082[lang]);
+ case 6488083:
+ return const_cast<char *>(_translationId6488083[lang]);
+ }
+
warning("ObjectMan::lockText(%d): only %d texts in file", textId & ITM_ID, _resMan->readUint32(addr));
- return _missingSubTitleStr;
+ return NULL;
}
uint32 offset = _resMan->readUint32(addr + ((textId & ITM_ID) + 1) * 4);
if (offset == 0) {
@@ -113,15 +164,19 @@ char *ObjectMan::lockText(uint32 textId) {
// We use the hardcoded text in this case.
if (textId == 2950145)
return const_cast<char *>(_translationId2950145[lang]);
-
+
warning("ObjectMan::lockText(%d): text number has no text lines", textId);
- return _missingSubTitleStr;
+ return NULL;
}
return addr + offset;
}
void ObjectMan::unlockText(uint32 textId) {
- _resMan->resClose(_textList[textId / ITM_PER_SEC][SwordEngine::_systemVars.language]);
+ unlockText(textId, SwordEngine::_systemVars.language);
+}
+
+void ObjectMan::unlockText(uint32 textId, uint8 lang) {
+ _resMan->resClose(_textList[textId / ITM_PER_SEC][lang]);
}
uint32 ObjectMan::lastTextNumber(int section) {
@@ -186,7 +241,193 @@ const char *const ObjectMan::_translationId2950145[7] = {
"Eh?", // Italian
"\277Eh?", // Spanish
"Ano?", // Czech
- " " // Portuguese
+ NULL // Portuguese
+};
+
+// The translations for the next texts are missing in the demo but are present
+// in the full game. The translations were therefore extracted from the full game.
+
+// Missing translation for textId 8455194 (in the demo).
+const char *const ObjectMan::_translationId8455194[7] = {
+ NULL, // "Who was the guy you were supposed to meet?", // English (not needed)
+ "Qui \351tait l'homme que vous deviez rencontrer?", // French
+ "Wer war der Typ, den Du treffen wolltest?", // German
+ "Chi dovevi incontrare?", // Italian
+ "\277Qui\351n era el hombre con el que ten\355as que encontrarte?", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455195 (in the demo).
+const char *const ObjectMan::_translationId8455195[7] = {
+ NULL, // "His name was Plantard. I didn't know him, but he called me last night.", // English (not needed)
+ "Son nom \351tait Plantard. Je ne le connaissais pas, mais il m'avait t\351l\351phon\351 la veille.", // French
+ "Sein Name war Plantard. Ich kannte ihn nicht, aber er hat mich letzte Nacht angerufen.", // German
+ "Si chiamava Plantard. Mi ha chiamato ieri sera, ma non lo conoscevo.", // Italian
+ "Su nombre era Plantard. Yo no lo conoc\355a pero \351l me llam\363 ayer por la noche.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455196 (in the demo).
+const char *const ObjectMan::_translationId8455196[7] = {
+ NULL, // "He said he had a story which would interest me.", // English (not needed)
+ "Il a dit qu'il avait une histoire qui devrait m'int\351resser.", // French
+ "Er sagte, er h\344tte eine Story, die mich interessieren w\374rde.", // German
+ "Mi disse che aveva una storia che mi poteva interessare.", // Italian
+ "Dijo que ten\355a una historia que me interesar\355a.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455197 (in the demo).
+const char *const ObjectMan::_translationId8455197[7] = {
+ NULL, // "He asked me to meet him at the caf\351.", // English (not needed)
+ "Il m'a demand\351 de le rencontrer au caf\351.", // French
+ "Er fragte mich, ob wir uns im Caf\351 treffen k\366nnten.", // German
+ "Mi chiese di incontrarci al bar.", // Italian
+ "Me pidi\363 que nos encontr\341ramos en el caf\351.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455198 (in the demo).
+const char *const ObjectMan::_translationId8455198[7] = {
+ NULL, // "I guess I'll never know what he wanted to tell me...", // English (not needed)
+ "Je suppose que je ne saurai jamais ce qu'il voulait me dire...", // French
+ "Ich werde wohl nie erfahren, was er mir sagen wollte...", // German
+ "Penso che non sapr\362 mai che cosa voleva dirmi...", // Italian
+ "Supongo que nunca sabr\351 qu\351 me quer\355a contar...", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455199 (in the demo).
+const char *const ObjectMan::_translationId8455199[7] = {
+ NULL, // "Not unless you have Rosso's gift for psychic interrogation.", // English (not needed)
+ "Non, \340 moins d'avoir les dons de Rosso pour les interrogatoires psychiques.", // French
+ "Es sei denn, Du h\344ttest Rosso's Gabe der parapsychologischen Befragung.", // German
+ "A meno che tu non riesca a fare interrogatori telepatici come Rosso.", // Italian
+ "A no ser que tengas el don de Rosso para la interrogaci\363n ps\355quica.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455200 (in the demo).
+const char *const ObjectMan::_translationId8455200[7] = {
+ NULL, // "How did Plantard get your name?", // English (not needed)
+ "Comment Plantard a-t-il obtenu votre nom?", // French
+ "Woher hat Plantard Deinen Namen?", // German
+ "Come ha fatto Plantard a sapere il tuo nome?", // Italian
+ "\277C\363mo consigui\363 Plantard tu nombre?", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455201 (in the demo).
+const char *const ObjectMan::_translationId8455201[7] = {
+ NULL, // "Through the newspaper - La Libert\351.", // English (not needed)
+ "Par mon journal... La Libert\351.", // French
+ "\334ber die Zeitung - La Libert\351.", // German
+ "Tramite il giornale La Libert\351.", // Italian
+ "Por el peri\363dico - La Libert\351.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455202 (in the demo).
+const char *const ObjectMan::_translationId8455202[7] = {
+ NULL, // "I'd written an article linking two unsolved murders, one in Italy, the other in Japan.", // English (not needed)
+ "J'ai \351crit un article o\371 je faisais le lien entre deux meurtres inexpliqu\351s, en Italie et au japon.", // French
+ "Ich habe einen Artikel geschrieben, in dem ich zwei ungel\366ste Morde miteinander in Verbindung bringe, einen in Italien, einen anderen in Japan.", // German
+ "Ho scritto un articolo che metteva in collegamento due omicidi insoluti in Italia e Giappone.", // Italian
+ "Yo hab\355a escrito un art\355culo conectando dos asesinatos sin resolver, uno en Italia, el otro en Jap\363n.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455203 (in the demo).
+const char *const ObjectMan::_translationId8455203[7] = {
+ NULL, // "The cases were remarkably similar...", // English (not needed)
+ "Les affaires \351taient quasiment identiques...", // French
+ "Die F\344lle sind sich bemerkenswert \344hnlich...", // German
+ "I casi erano sorprendentemente uguali...", // Italian
+ "Los casos eran incre\355blemente parecidos...", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455204 (in the demo).
+const char *const ObjectMan::_translationId8455204[7] = {
+ NULL, // "...a wealthy victim, no apparent motive, and a costumed killer.", // English (not needed)
+ "...une victime riche, pas de motif apparent, et un tueur d\351guis\351.", // French
+ "...ein wohlhabendes Opfer, kein offensichtliches Motiv, und ein verkleideter Killer.", // German
+ "...una vittima ricca, nessun motivo apparente e un assassino in costume.", // Italian
+ "...una v\355ctima rica, sin motivo aparente, y un asesino disfrazado.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 8455205 (in the demo).
+const char *const ObjectMan::_translationId8455205[7] = {
+ NULL, // "Plantard said he could supply me with more information.", // English (not needed)
+ "Plantard m'a dit qu'il pourrait me fournir des renseignements.", // French
+ "Plantard sagte, er k\366nne mir weitere Informationen beschaffen.", // German
+ "Plantard mi disse che mi avrebbe fornito ulteriori informazioni.", // Italian
+ "Plantard dijo que \351l me pod\355a proporcionar m\341s informaci\363n.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 6488080 (in the demo).
+const char *const ObjectMan::_translationId6488080[7] = {
+ NULL, // "I wasn't going to head off all over Paris until I'd investigated some more.", // English (not needed)
+ "Je ferais mieux d'enqu\351ter un peu par ici avant d'aller me promener ailleurs.", // French
+ "Ich durchquere nicht ganz Paris, bevor ich etwas mehr herausgefunden habe.", // German
+ "Non mi sarei incamminato per tutta Parigi prima di ulteriori indagini.", // Italian
+ "No iba a ponerme a recorrer Par\355s sin haber investigado un poco m\341s.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// The next three sentences are specific to the demo and only the english text is present.
+// The translations were provided by:
+// French: Thierry Crozat
+// German: Simon Sawatzki
+// Italian: Matteo Angelino
+// Spanish: Tomás Maidagan
+
+// Missing translation for textId 6488081 (in the demo).
+const char *const ObjectMan::_translationId6488081[7] = {
+ NULL, // "I wasn't sure what I was going to do when I caught up with that clown...", // English (not needed)
+ "Je ne savais pas ce que je ferais quand je rattraperais le clown...", // French
+ "Ich wu\337te nicht, worauf ich mich einlie\337, als ich dem Clown nachjagte...", // German
+ "Non sapevo cosa avrei fatto una volta raggiunto quel clown...", // Italian
+ "No sab\355a muy bien qu\351 es lo que har\355a cuando alcanzara al payaso...", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 6488082 (in the demo).
+const char *const ObjectMan::_translationId6488082[7] = {
+ NULL, // "...but before I knew it, I was drawn into a desperate race between two ruthless enemies.", // English (not needed)
+ "...mais avant de m'en rendre compte je me retrouvais happ\351 dans une course effr\351n\351e entre deux ennemis impitoyables.", // French
+ "... doch bevor ich mich versah, war ich inmitten eines Wettlaufs von zwei r\374cksichtslosen Feinden.", // German
+ "... ma prima che me ne rendessi conto, fui trascinato in una corsa disperata con due spietati nemici.", // Italian
+ "...pero sin darme cuenta, acab\351 en medio de una desesperada carrera entre dos despiadados enemigos.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
+};
+
+// Missing translation for textId 6488083 (in the demo).
+const char *const ObjectMan::_translationId6488083[7] = {
+ NULL, // "The goal: the mysterious power of the Broken Sword.", // English (not needed)
+ "Le but: les pouvoirs myst\351rieux de l'\351p\351e bris\351e.", // French
+ "Das Ziel: die geheimnisvolle Macht des zerbrochenen Schwertes.", // German
+ "Obiettivo: il misterioso potere della Spada spezzata.", // Italian
+ "El objetivo: el misterioso poder de la Espada Rota.", // Spanish
+ NULL, // Czech
+ NULL // Portuguese
};
} // End of namespace Sword1
diff --git a/engines/sword1/objectman.h b/engines/sword1/objectman.h
index ca3c7c1526..197b437c15 100644
--- a/engines/sword1/objectman.h
+++ b/engines/sword1/objectman.h
@@ -53,6 +53,9 @@ public:
void saveLiveList(uint16 *dest); // for loading/saving
void loadLiveList(uint16 *src);
private:
+ char *lockText(uint32 textId, uint8 language);
+ void unlockText(uint32 textId, uint8 language);
+
ResMan *_resMan;
static const uint32 _objectList[TOTAL_SECTIONS]; //a table of pointers to object files
static const uint32 _textList[TOTAL_SECTIONS][7]; //a table of pointers to text files
@@ -60,6 +63,22 @@ private:
uint8 *_cptData[TOTAL_SECTIONS];
static char _missingSubTitleStr[];
static const char *const _translationId2950145[7]; //translation for textId 2950145 (missing from cluster file for some langages)
+ static const char *const _translationId8455194[7]; //translation for textId 8455194 (missing in the demo)
+ static const char *const _translationId8455195[7]; //translation for textId 8455195 (missing in the demo)
+ static const char *const _translationId8455196[7]; //translation for textId 8455196 (missing in the demo)
+ static const char *const _translationId8455197[7]; //translation for textId 8455197 (missing in the demo)
+ static const char *const _translationId8455198[7]; //translation for textId 8455198 (missing in the demo)
+ static const char *const _translationId8455199[7]; //translation for textId 8455199 (missing in the demo)
+ static const char *const _translationId8455200[7]; //translation for textId 8455200 (missing in the demo)
+ static const char *const _translationId8455201[7]; //translation for textId 8455201 (missing in the demo)
+ static const char *const _translationId8455202[7]; //translation for textId 8455202 (missing in the demo)
+ static const char *const _translationId8455203[7]; //translation for textId 8455203 (missing in the demo)
+ static const char *const _translationId8455204[7]; //translation for textId 8455204 (missing in the demo)
+ static const char *const _translationId8455205[7]; //translation for textId 8455205 (missing in the demo)
+ static const char *const _translationId6488080[7]; //translation for textId 6488081 (missing in the demo)
+ static const char *const _translationId6488081[7]; //translation for textId 6488081 (missing in the demo)
+ static const char *const _translationId6488082[7]; //translation for textId 6488082 (missing in the demo)
+ static const char *const _translationId6488083[7]; //translation for textId 6488083 (missing in the demo)
};
} // End of namespace Sword1
diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp
index 3574074b00..61bf5257ab 100644
--- a/engines/sword1/sound.cpp
+++ b/engines/sword1/sound.cpp
@@ -142,7 +142,7 @@ void Sound::checkSpeechFileEndianness() {
be_diff_sum += fabs((double)(be_value - prev_be_value));
prev_be_value = be_value;
}
- delete [] data;
+ delete[] data;
}
// Set the big endian flag
_bigEndianSpeech = (be_diff_sum < le_diff_sum);
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 5e3f8929e9..00260f789a 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -38,8 +38,11 @@
#include "sword2/screen.h"
#include "sword2/animation.h"
+#include "graphics/palette.h"
+
#include "gui/message.h"
+#include "video/dxa_decoder.h"
#include "video/smk_decoder.h"
#include "video/psx_decoder.h"
@@ -51,9 +54,8 @@ namespace Sword2 {
// Basic movie player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType)
- : _vm(vm), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) {
- _bgSoundStream = NULL;
+MoviePlayer::MoviePlayer(Sword2Engine *vm, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType)
+ : _vm(vm), _system(system) {
_decoderType = decoderType;
_decoder = decoder;
@@ -62,7 +64,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, A
}
MoviePlayer::~MoviePlayer() {
- delete _bgSoundHandle;
delete _decoder;
}
@@ -75,11 +76,6 @@ bool MoviePlayer::load(const char *name) {
if (_vm->shouldQuit())
return false;
- if (_decoderType == kVideoDecoderDXA)
- _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(name);
- else
- _bgSoundStream = NULL;
-
_textSurface = NULL;
Common::String filename;
@@ -99,6 +95,7 @@ bool MoviePlayer::load(const char *name) {
// Need to load here in case it fails in which case we'd need
// to go back to paletted mode
if (_decoder->loadFile(filename)) {
+ _decoder->start();
return true;
} else {
initGraphics(640, 480, true);
@@ -106,7 +103,15 @@ bool MoviePlayer::load(const char *name) {
}
}
- return _decoder->loadFile(filename.c_str());
+ if (!_decoder->loadFile(filename))
+ return false;
+
+ // For DXA, also add the external sound file
+ if (_decoderType == kVideoDecoderDXA)
+ _decoder->addStreamFileTrack(name);
+
+ _decoder->start();
+ return true;
}
void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut) {
@@ -122,24 +127,15 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI
if (leadIn)
_vm->_sound->playMovieSound(leadIn, kLeadInSound);
- if (_bgSoundStream)
- _snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream);
-
- bool terminated = false;
-
- terminated = !playVideo();
+ bool terminated = !playVideo();
closeTextObject(_currentMovieText, NULL, 0);
if (terminated) {
- _snd->stopHandle(*_bgSoundHandle);
_vm->_sound->stopMovieSounds();
_vm->_sound->stopSpeech();
}
- while (_snd->isSoundHandleActive(*_bgSoundHandle))
- _system->delayMillis(100);
-
if (_decoderType == kVideoDecoderPSX) {
// Need to jump back to paletted color
initGraphics(640, 480, true);
@@ -336,7 +332,7 @@ bool MoviePlayer::playVideo() {
}
if (_decoder->hasDirtyPalette()) {
- _decoder->setSystemPalette();
+ _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256);
uint32 maxWeight = 0;
uint32 minWeight = 0xFFFFFFFF;
@@ -406,31 +402,19 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) {
scaledFrame.free();
}
-DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
- : _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
-}
-
-uint32 DXADecoderWithSound::getTime() const {
- if (_mixer->isSoundHandleActive(*_bgSoundHandle))
- return _mixer->getSoundElapsedTime(*_bgSoundHandle);
-
- return DXADecoder::getTime();
-}
-
///////////////////////////////////////////////////////////////////////////////
// Factory function for creating the appropriate cutscene player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount) {
+MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system, uint32 frameCount) {
Common::String filename;
- Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle;
filename = Common::String::format("%s.str", name);
if (Common::File::exists(filename)) {
#ifdef USE_RGB_COLOR
Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x, frameCount);
- return new MoviePlayer(vm, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX);
+ return new MoviePlayer(vm, system, psxDecoder, kVideoDecoderPSX);
#else
GUI::MessageDialog dialog(_("PSX cutscenes found but ScummVM has been built without RGB color support"), _("OK"));
dialog.runModal();
@@ -441,16 +425,16 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *s
filename = Common::String::format("%s.smk", name);
if (Common::File::exists(filename)) {
- Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(snd);
- return new MoviePlayer(vm, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK);
+ Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder();
+ return new MoviePlayer(vm, system, smkDecoder, kVideoDecoderSMK);
}
filename = Common::String::format("%s.dxa", name);
if (Common::File::exists(filename)) {
#ifdef USE_ZLIB
- DXADecoderWithSound *dxaDecoder = new DXADecoderWithSound(snd, bgSoundHandle);
- return new MoviePlayer(vm, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA);
+ Video::DXADecoder *dxaDecoder = new Video::DXADecoder();
+ return new MoviePlayer(vm, system, dxaDecoder, kVideoDecoderDXA);
#else
GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK"));
dialog.runModal();
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index 3d5c42b7f7..b2a243b2ca 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -25,12 +25,16 @@
#ifndef SWORD2_ANIMATION_H
#define SWORD2_ANIMATION_H
-#include "video/dxa_decoder.h"
-#include "video/video_decoder.h"
-#include "audio/mixer.h"
-
#include "sword2/screen.h"
+namespace Graphics {
+struct Surface;
+}
+
+namespace Video {
+class VideoDecoder;
+}
+
namespace Sword2 {
enum DecoderType {
@@ -55,20 +59,9 @@ struct MovieText {
}
};
-class DXADecoderWithSound : public Video::DXADecoder {
-public:
- DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle);
- ~DXADecoderWithSound() {}
-
- uint32 getTime() const;
-private:
- Audio::Mixer *_mixer;
- Audio::SoundHandle *_bgSoundHandle;
-};
-
class MoviePlayer {
public:
- MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType);
+ MoviePlayer(Sword2Engine *vm, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType);
virtual ~MoviePlayer();
bool load(const char *name);
@@ -76,7 +69,6 @@ public:
protected:
Sword2Engine *_vm;
- Audio::Mixer *_snd;
OSystem *_system;
MovieText *_movieTexts;
uint32 _numMovieTexts;
@@ -87,8 +79,6 @@ protected:
DecoderType _decoderType;
Video::VideoDecoder *_decoder;
- Audio::SoundHandle *_bgSoundHandle;
- Audio::AudioStream *_bgSoundStream;
uint32 _leadOut;
int _leadOutFrame;
@@ -105,7 +95,7 @@ protected:
uint32 getWhiteColor();
};
-MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount);
+MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system, uint32 frameCount);
} // End of namespace Sword2
diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp
index 836b252d6c..07fcaa094b 100644
--- a/engines/sword2/function.cpp
+++ b/engines/sword2/function.cpp
@@ -2139,7 +2139,7 @@ int32 Logic::fnPlaySequence(int32 *params) {
uint32 frameCount = Sword2Engine::isPsx() ? params[1] : 0;
- _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system, frameCount);
+ _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_system, frameCount);
if (_moviePlayer && _moviePlayer->load(filename)) {
_moviePlayer->play(_sequenceTextList, _sequenceTextLines, _smackerLeadIn, _smackerLeadOut);
diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp
index 9ee13b4b6d..a95532ec65 100644
--- a/engines/sword25/fmv/movieplayer.cpp
+++ b/engines/sword25/fmv/movieplayer.cpp
@@ -61,6 +61,7 @@ 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);
_decoder.loadStream(in);
+ _decoder.start();
GraphicEngine *pGfx = Kernel::getInstance()->getGfx();
diff --git a/engines/sword25/fmv/movieplayer.h b/engines/sword25/fmv/movieplayer.h
index 1d256e56ba..2f5614b505 100644
--- a/engines/sword25/fmv/movieplayer.h
+++ b/engines/sword25/fmv/movieplayer.h
@@ -39,7 +39,7 @@
#include "sword25/gfx/bitmap.h"
#ifdef USE_THEORADEC
-#include "sword25/fmv/theora_decoder.h"
+#include "video/theora_decoder.h"
#endif
#define THEORA_INDIRECT_RENDERING
@@ -141,7 +141,7 @@ private:
#ifdef USE_THEORADEC
- TheoraDecoder _decoder;
+ Video::TheoraDecoder _decoder;
Graphics::Surface *_backSurface;
int _outX, _outY;
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp
deleted file mode 100644
index d38f5a26cf..0000000000
--- a/engines/sword25/fmv/theora_decoder.cpp
+++ /dev/null
@@ -1,565 +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.
- *
- */
-
-/*
- * Source is based on the player example from libvorbis package,
- * available at: http://svn.xiph.org/trunk/theora/examples/player_example.c
- *
- * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS
- * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE
- * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.
- *
- * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009
- * by the Xiph.Org Foundation and contributors http://www.xiph.org/
- *
- */
-
-#include "sword25/fmv/theora_decoder.h"
-
-#ifdef USE_THEORADEC
-#include "common/system.h"
-#include "common/textconsole.h"
-#include "common/util.h"
-#include "graphics/yuv_to_rgb.h"
-#include "audio/decoders/raw.h"
-#include "sword25/kernel/common.h"
-
-namespace Sword25 {
-
-#define AUDIOFD_FRAGSIZE 10240
-
-static double rint(double v) {
- return floor(v + 0.5);
-}
-
-TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) {
- _fileStream = 0;
-
- _theoraPacket = 0;
- _vorbisPacket = 0;
- _theoraDecode = 0;
- _theoraSetup = 0;
- _nextFrameStartTime = 0.0;
-
- _soundType = soundType;
- _audStream = 0;
- _audHandle = new Audio::SoundHandle();
-
- ogg_sync_init(&_oggSync);
-
- _curFrame = -1;
- _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t));
-
- reset();
-}
-
-TheoraDecoder::~TheoraDecoder() {
- close();
- delete _fileStream;
- delete _audHandle;
- free(_audiobuf);
-}
-
-void TheoraDecoder::queuePage(ogg_page *page) {
- if (_theoraPacket)
- ogg_stream_pagein(&_theoraOut, page);
-
- if (_vorbisPacket)
- ogg_stream_pagein(&_vorbisOut, page);
-}
-
-int TheoraDecoder::bufferData() {
- char *buffer = ogg_sync_buffer(&_oggSync, 4096);
- int bytes = _fileStream->read(buffer, 4096);
-
- ogg_sync_wrote(&_oggSync, bytes);
-
- return bytes;
-}
-
-bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
- close();
-
- _endOfAudio = false;
- _endOfVideo = false;
- _fileStream = stream;
-
- // start up Ogg stream synchronization layer
- ogg_sync_init(&_oggSync);
-
- // init supporting Vorbis structures needed in header parsing
- vorbis_info_init(&_vorbisInfo);
- vorbis_comment_init(&_vorbisComment);
-
- // init supporting Theora structures needed in header parsing
- th_comment_init(&_theoraComment);
- th_info_init(&_theoraInfo);
-
- // Ogg file open; parse the headers
- // Only interested in Vorbis/Theora streams
- bool foundHeader = false;
- while (!foundHeader) {
- int ret = bufferData();
-
- if (ret == 0)
- break;
-
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
- ogg_stream_state test;
-
- // is this a mandated initial header? If not, stop parsing
- if (!ogg_page_bos(&_oggPage)) {
- // don't leak the page; get it into the appropriate stream
- queuePage(&_oggPage);
- foundHeader = true;
- break;
- }
-
- ogg_stream_init(&test, ogg_page_serialno(&_oggPage));
- ogg_stream_pagein(&test, &_oggPage);
- ogg_stream_packetout(&test, &_oggPacket);
-
- // identify the codec: try theora
- if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) {
- // it is theora
- memcpy(&_theoraOut, &test, sizeof(test));
- _theoraPacket = 1;
- } else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) {
- // it is vorbis
- memcpy(&_vorbisOut, &test, sizeof(test));
- _vorbisPacket = 1;
- } else {
- // whatever it is, we don't care about it
- ogg_stream_clear(&test);
- }
- }
- // fall through to non-bos page parsing
- }
-
- // we're expecting more header packets.
- while ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) {
- int ret;
-
- // look for further theora headers
- while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) {
- if (ret < 0)
- error("Error parsing Theora stream headers; corrupt stream?");
-
- if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket))
- error("Error parsing Theora stream headers; corrupt stream?");
-
- _theoraPacket++;
- }
-
- // look for more vorbis header packets
- while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) {
- if (ret < 0)
- error("Error parsing Vorbis stream headers; corrupt stream?");
-
- if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket))
- error("Error parsing Vorbis stream headers; corrupt stream?");
-
- _vorbisPacket++;
-
- if (_vorbisPacket == 3)
- break;
- }
-
- // The header pages/packets will arrive before anything else we
- // care about, or the stream is not obeying spec
-
- if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
- queuePage(&_oggPage); // demux into the appropriate stream
- } else {
- ret = bufferData(); // someone needs more data
-
- if (ret == 0)
- error("End of file while searching for codec headers.");
- }
- }
-
- // and now we have it all. initialize decoders
- if (_theoraPacket) {
- _theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup);
- debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps",
- _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height,
- (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator);
-
- switch (_theoraInfo.pixel_fmt) {
- case TH_PF_420:
- debug(1, " 4:2:0 video");
- break;
- case TH_PF_422:
- debug(1, " 4:2:2 video");
- break;
- case TH_PF_444:
- debug(1, " 4:4:4 video");
- break;
- case TH_PF_RSVD:
- default:
- debug(1, " video\n (UNKNOWN Chroma sampling!)");
- break;
- }
-
- if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height)
- debug(1, " Frame content is %dx%d with offset (%d,%d).",
- _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y);
-
- switch (_theoraInfo.colorspace){
- case TH_CS_UNSPECIFIED:
- /* nothing to report */
- break;
- case TH_CS_ITU_REC_470M:
- debug(1, " encoder specified ITU Rec 470M (NTSC) color.");
- break;
- case TH_CS_ITU_REC_470BG:
- debug(1, " encoder specified ITU Rec 470BG (PAL) color.");
- break;
- default:
- debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace);
- break;
- }
-
- debug(1, "Encoded by %s", _theoraComment.vendor);
- if (_theoraComment.comments) {
- debug(1, "theora comment header:");
- for (int i = 0; i < _theoraComment.comments; i++) {
- if (_theoraComment.user_comments[i]) {
- int len = _theoraComment.comment_lengths[i];
- char *value = (char *)malloc(len + 1);
- if (value) {
- memcpy(value, _theoraComment.user_comments[i], len);
- value[len] = '\0';
- debug(1, "\t%s", value);
- free(value);
- }
- }
- }
- }
-
- th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax));
- _ppLevel = _ppLevelMax;
- th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel));
- _ppInc = 0;
- } else {
- // tear down the partial theora setup
- th_info_clear(&_theoraInfo);
- th_comment_clear(&_theoraComment);
- }
-
- th_setup_free(_theoraSetup);
- _theoraSetup = 0;
-
- if (_vorbisPacket) {
- vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo);
- vorbis_block_init(&_vorbisDSP, &_vorbisBlock);
- debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.",
- _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate);
-
- _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels);
-
- // Get enough audio data to start us off
- while (_audStream->numQueuedStreams() == 0) {
- // Queue more data
- bufferData();
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
- queuePage(&_oggPage);
-
- queueAudio();
- }
-
- if (_audStream)
- g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream, -1, getVolume(), getBalance());
- } else {
- // tear down the partial vorbis setup
- vorbis_info_clear(&_vorbisInfo);
- vorbis_comment_clear(&_vorbisComment);
- _endOfAudio = true;
- }
-
- _surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat());
-
- // Set up a display surface
- _displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y);
- _displaySurface.w = _theoraInfo.pic_width;
- _displaySurface.h = _theoraInfo.pic_height;
- _displaySurface.format = _surface.format;
- _displaySurface.pitch = _surface.pitch;
-
- // Set the frame rate
- _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator);
-
- return true;
-}
-
-void TheoraDecoder::close() {
- if (_vorbisPacket) {
- ogg_stream_clear(&_vorbisOut);
- vorbis_block_clear(&_vorbisBlock);
- vorbis_dsp_clear(&_vorbisDSP);
- vorbis_comment_clear(&_vorbisComment);
- vorbis_info_clear(&_vorbisInfo);
-
- g_system->getMixer()->stopHandle(*_audHandle);
-
- _audStream = 0;
- _vorbisPacket = false;
- }
- if (_theoraPacket) {
- ogg_stream_clear(&_theoraOut);
- th_decode_free(_theoraDecode);
- th_comment_clear(&_theoraComment);
- th_info_clear(&_theoraInfo);
- _theoraDecode = 0;
- _theoraPacket = false;
- }
-
- if (!_fileStream)
- return;
-
- ogg_sync_clear(&_oggSync);
-
- delete _fileStream;
- _fileStream = 0;
-
- _surface.free();
- _displaySurface.pixels = 0;
- _displaySurface.free();
-
- reset();
-}
-
-const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
- // First, let's get our frame
- while (_theoraPacket) {
- // theora is one in, one out...
- if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) {
-
- if (_ppInc) {
- _ppLevel += _ppInc;
- th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel));
- _ppInc = 0;
- }
-
- if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) {
- _curFrame++;
-
- // Convert YUV data to RGB data
- th_ycbcr_buffer yuv;
- th_decode_ycbcr_out(_theoraDecode, yuv);
- translateYUVtoRGBA(yuv);
-
- if (_curFrame == 0)
- _startTime = g_system->getMillis();
-
- double time = th_granule_time(_theoraDecode, _oggPacket.granulepos);
-
- // We need to calculate when the next frame should be shown
- // This is all in floating point because that's what the Ogg code gives us
- // Ogg is a lossy container format, so it doesn't always list the time to the
- // next frame. In such cases, we need to calculate it ourselves.
- if (time == -1.0)
- _nextFrameStartTime += _frameRate.getInverse().toDouble();
- else
- _nextFrameStartTime = time;
-
- // break out
- break;
- }
- } else {
- // If we can't get any more frames, we're done.
- if (_theoraOut.e_o_s || _fileStream->eos()) {
- _endOfVideo = true;
- break;
- }
-
- // Queue more data
- bufferData();
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
- queuePage(&_oggPage);
- }
-
- // Update audio if we can
- queueAudio();
- }
-
- // Force at least some audio to be buffered
- // TODO: 5 is very arbitrary. We probably should do something like QuickTime does.
- while (!_endOfAudio && _audStream->numQueuedStreams() < 5) {
- bufferData();
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
- queuePage(&_oggPage);
-
- bool queuedAudio = queueAudio();
- if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) {
- _endOfAudio = true;
- break;
- }
- }
-
- return &_displaySurface;
-}
-
-bool TheoraDecoder::queueAudio() {
- if (!_audStream)
- return false;
-
- // An audio buffer should have been allocated (either in the constructor or after queuing the current buffer)
- if (!_audiobuf) {
- warning("[TheoraDecoder::queueAudio] Invalid audio buffer");
- return false;
- }
-
- bool queuedAudio = false;
-
- for (;;) {
- float **pcm;
-
- // if there's pending, decoded audio, grab it
- int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm);
- if (ret > 0) {
- int count = _audiobufFill / 2;
- int maxsamples = ((AUDIOFD_FRAGSIZE - _audiobufFill) / _vorbisInfo.channels) >> 1;
- int i;
- for (i = 0; i < ret && i < maxsamples; i++)
- for (int j = 0; j < _vorbisInfo.channels; j++) {
- int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767);
- _audiobuf[count++] = val;
- }
-
- vorbis_synthesis_read(&_vorbisDSP, i);
- _audiobufFill += (i * _vorbisInfo.channels) << 1;
-
- if (_audiobufFill == AUDIOFD_FRAGSIZE) {
- byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO;
-#ifdef SCUMM_LITTLE_ENDIAN
- flags |= Audio::FLAG_LITTLE_ENDIAN;
-#endif
- _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, flags);
-
- // The audio mixer is now responsible for the old audio buffer.
- // We need to create a new one.
- _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t));
- if (!_audiobuf) {
- warning("[TheoraDecoder::queueAudio] Cannot allocate memory for audio buffer");
- return false;
- }
-
- _audiobufFill = 0;
- queuedAudio = true;
- }
- } else {
- // no pending audio; is there a pending packet to decode?
- if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) {
- if (vorbis_synthesis(&_vorbisBlock, &_oggPacket) == 0) // test for success!
- vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock);
- } else // we've buffered all we have, break out for now
- return queuedAudio;
- }
- }
-
- // Unreachable
- return false;
-}
-
-void TheoraDecoder::reset() {
- VideoDecoder::reset();
-
- // FIXME: This does a rewind() instead of a reset()!
-
- if (_fileStream)
- _fileStream->seek(0);
-
- _audiobufFill = 0;
- _audiobufReady = false;
-
- _curFrame = -1;
-
- _theoraPacket = 0;
- _vorbisPacket = 0;
-}
-
-bool TheoraDecoder::endOfVideo() const {
- return !isVideoLoaded() || (_endOfVideo && (!_audStream || (_audStream->endOfData() && _endOfAudio)));
-}
-
-uint32 TheoraDecoder::getTimeToNextFrame() const {
- if (endOfVideo() || _curFrame < 0)
- return 0;
-
- uint32 elapsedTime = getTime();
- uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000);
-
- if (nextFrameStartTime <= elapsedTime)
- return 0;
-
- return nextFrameStartTime - elapsedTime;
-}
-
-uint32 TheoraDecoder::getTime() const {
- if (_audStream)
- return g_system->getMixer()->getSoundElapsedTime(*_audHandle);
-
- return VideoDecoder::getTime();
-}
-
-void TheoraDecoder::pauseVideoIntern(bool pause) {
- if (_audStream)
- g_system->getMixer()->pauseHandle(*_audHandle, pause);
-}
-
-enum TheoraYUVBuffers {
- kBufferY = 0,
- kBufferU = 1,
- kBufferV = 2
-};
-
-void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) {
- // Width and height of all buffers have to be divisible by 2.
- assert((YUVBuffer[kBufferY].width & 1) == 0);
- assert((YUVBuffer[kBufferY].height & 1) == 0);
- assert((YUVBuffer[kBufferU].width & 1) == 0);
- assert((YUVBuffer[kBufferV].width & 1) == 0);
-
- // UV images have to have a quarter of the Y image resolution
- assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1);
- assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1);
- assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1);
- assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1);
-
- Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride);
-}
-
-void TheoraDecoder::updateVolume() {
- if (g_system->getMixer()->isSoundHandleActive(*_audHandle))
- g_system->getMixer()->setChannelVolume(*_audHandle, getVolume());
-}
-
-void TheoraDecoder::updateBalance() {
- if (g_system->getMixer()->isSoundHandleActive(*_audHandle))
- g_system->getMixer()->setChannelBalance(*_audHandle, getBalance());
-}
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h
deleted file mode 100644
index 739040024f..0000000000
--- a/engines/sword25/fmv/theora_decoder.h
+++ /dev/null
@@ -1,144 +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.
- *
- */
-
-#ifndef SWORD25_THEORADECODER_H
-#define SWORD25_THEORADECODER_H
-
-#include "common/scummsys.h" // for USE_THEORADEC
-
-#ifdef USE_THEORADEC
-
-#include "common/rational.h"
-#include "video/video_decoder.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "graphics/pixelformat.h"
-#include "graphics/surface.h"
-
-#include <theora/theoradec.h>
-#include <vorbis/codec.h>
-
-namespace Common {
-class SeekableReadStream;
-}
-
-namespace Sword25 {
-
-/**
- *
- * Decoder for Theora videos.
- * Video decoder used in engines:
- * - sword25
- */
-class TheoraDecoder : public Video::VideoDecoder {
-public:
- TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType);
- virtual ~TheoraDecoder();
-
- /**
- * Load a video file
- * @param stream the stream to load
- */
- bool loadStream(Common::SeekableReadStream *stream);
- void close();
- void reset();
-
- /**
- * Decode the next frame and return the frame's surface
- * @note the return surface should *not* be freed
- * @note this may return 0, in which case the last frame should be kept on screen
- */
- const Graphics::Surface *decodeNextFrame();
-
- bool isVideoLoaded() const { return _fileStream != 0; }
- uint16 getWidth() const { return _displaySurface.w; }
- uint16 getHeight() const { return _displaySurface.h; }
-
- uint32 getFrameCount() const {
- // It is not possible to get frame count easily
- // I.e. seeking is required
- assert(0);
- return 0;
- }
-
- Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; }
- uint32 getTime() const;
- uint32 getTimeToNextFrame() const;
-
- bool endOfVideo() const;
-
-protected:
- // VideoDecoder API
- void updateVolume();
- void updateBalance();
- void pauseVideoIntern(bool pause);
-
-private:
- void queuePage(ogg_page *page);
- bool queueAudio();
- int bufferData();
- void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer);
-
- Common::SeekableReadStream *_fileStream;
- Graphics::Surface _surface;
- Graphics::Surface _displaySurface;
- Common::Rational _frameRate;
- double _nextFrameStartTime;
- bool _endOfVideo;
- bool _endOfAudio;
-
- Audio::Mixer::SoundType _soundType;
- Audio::SoundHandle *_audHandle;
- Audio::QueuingAudioStream *_audStream;
-
- ogg_sync_state _oggSync;
- ogg_page _oggPage;
- ogg_packet _oggPacket;
- ogg_stream_state _vorbisOut;
- ogg_stream_state _theoraOut;
- th_info _theoraInfo;
- th_comment _theoraComment;
- th_dec_ctx *_theoraDecode;
- th_setup_info *_theoraSetup;
- vorbis_info _vorbisInfo;
- vorbis_dsp_state _vorbisDSP;
- vorbis_block _vorbisBlock;
- vorbis_comment _vorbisComment;
-
- int _theoraPacket;
- int _vorbisPacket;
-
- int _ppLevelMax;
- int _ppLevel;
- int _ppInc;
-
- // single audio fragment audio buffering
- int _audiobufFill;
- bool _audiobufReady;
- ogg_int16_t *_audiobuf;
-};
-
-} // End of namespace Sword25
-
-#endif
-
-#endif
diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk
index 302120c500..e24a221244 100644
--- a/engines/sword25/module.mk
+++ b/engines/sword25/module.mk
@@ -85,11 +85,6 @@ MODULE_OBJS := \
util/pluto/pluto.o \
util/pluto/plzio.o
-ifdef USE_THEORADEC
-MODULE_OBJS += \
- fmv/theora_decoder.o
-endif
-
# This module can be built as a plugin
ifeq ($(ENABLE_SWORD25), DYNAMIC_PLUGIN)
PLUGIN := 1
diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp
index 78b2db19eb..69fae3dc4e 100644
--- a/engines/sword25/sfx/soundengine.cpp
+++ b/engines/sword25/sfx/soundengine.cpp
@@ -239,16 +239,20 @@ void SoundEngine::setSoundVolume(uint handle, float volume) {
debugC(1, kDebugSound, "SoundEngine::setSoundVolume(%d, %f)", handle, volume);
SndHandle* sndHandle = findHandle(handle);
- if (sndHandle != NULL)
+ if (sndHandle != NULL) {
+ sndHandle->volume = volume;
_mixer->setChannelVolume(sndHandle->handle, (byte)(volume * 255));
+ }
}
void SoundEngine::setSoundPanning(uint handle, float pan) {
debugC(1, kDebugSound, "SoundEngine::setSoundPanning(%d, %f)", handle, pan);
SndHandle* sndHandle = findHandle(handle);
- if (sndHandle != NULL)
+ if (sndHandle != NULL) {
+ sndHandle->pan = pan;
_mixer->setChannelBalance(sndHandle->handle, (int8)(pan * 127));
+ }
}
void SoundEngine::pauseSound(uint handle) {
@@ -324,13 +328,16 @@ bool SoundEngine::canLoadResource(const Common::String &fileName) {
return fname.hasSuffix(".ogg");
}
-
- bool SoundEngine::persist(OutputPersistenceBlock &writer) {
+bool SoundEngine::persist(OutputPersistenceBlock &writer) {
writer.write(_maxHandleId);
for (uint i = 0; i < SOUND_HANDLES; i++) {
writer.write(_handles[i].id);
+ // Don't restart sounds which already finished playing.
+ if (_handles[i].type != kFreeHandle && !_mixer->isSoundHandleActive(_handles[i].handle))
+ _handles[i].type = kFreeHandle;
+
writer.writeString(_handles[i].fileName);
writer.write((int)_handles[i].sndType);
writer.write(_handles[i].volume);
@@ -374,7 +381,8 @@ bool SoundEngine::unpersist(InputPersistenceBlock &reader) {
reader.read(layer);
if (reader.isGood()) {
- playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i);
+ if (sndType != kFreeHandle)
+ playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i);
} else
return false;
}
diff --git a/engines/sword25/util/pluto/pluto.cpp b/engines/sword25/util/pluto/pluto.cpp
index d645e5ed2a..b7f5e30340 100644
--- a/engines/sword25/util/pluto/pluto.cpp
+++ b/engines/sword25/util/pluto/pluto.cpp
@@ -895,10 +895,10 @@ static void unpersistnumber(UnpersistInfo *upi)
static void unpersiststring(UnpersistInfo *upi)
{
/* perms reftbl sptbl ref */
- int length;
+ size_t length;
char* string;
lua_checkstack(upi->L, 1);
- verify(LIF(Z,read)(&upi->zio, &length, sizeof(int)) == 0);
+ verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0);
string = pdep_newvector(upi->L, length, char);
verify(LIF(Z,read)(&upi->zio, string, length) == 0);
lua_pushlstring(upi->L, string, length);
diff --git a/engines/teenagent/callbacks.cpp b/engines/teenagent/callbacks.cpp
index 8882531d27..934727a478 100644
--- a/engines/teenagent/callbacks.cpp
+++ b/engines/teenagent/callbacks.cpp
@@ -2252,7 +2252,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
return true;
case 0x78e0:
- processCallback(0x50c5);
+ processCallback(0x505c);
return false;
case 0x78e7:
@@ -2265,7 +2265,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
case 0x78f5:
if (CHECK_FLAG(0xDB95, 1)) {
- displayMessage(0x3575);
+ displayMessage(0x3E75);
return true;
} else
return false;
@@ -3925,7 +3925,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
displayMessage(0x39ae);
break;
default:
- displayMessage(0x39b7);
+ displayMessage(0x3ab7);
}
return true;
diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp
index dad876dd97..2de6f49c44 100644
--- a/engines/teenagent/detection.cpp
+++ b/engines/teenagent/detection.cpp
@@ -80,7 +80,7 @@ static const ADGameDescription teenAgentGameDescriptions[] = {
};
enum {
- MAX_SAVES = 20
+ MAX_SAVES = 20
};
class TeenAgentMetaEngine : public AdvancedMetaEngine {
@@ -123,16 +123,15 @@ public:
virtual SaveStateList listSaves(const char *target) const {
Common::String pattern = target;
- pattern += ".*";
+ pattern += ".??";
Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
Common::sort(filenames.begin(), filenames.end());
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
- int slot;
- const char *ext = strrchr(file->c_str(), '.');
- if (ext && (slot = atoi(ext + 1)) >= 0 && slot < MAX_SAVES) {
+ int slot = atoi(file->c_str() + file->size() - 2);
+ if (slot >= 0 && slot < MAX_SAVES) {
Common::ScopedPtr<Common::InSaveFile> in(g_system->getSavefileManager()->openForLoading(*file));
if (!in)
continue;
@@ -174,7 +173,6 @@ public:
return SaveStateDescriptor(slot, desc);
SaveStateDescriptor ssd(slot, desc);
- ssd.setDeletableFlag(true);
//checking for the thumbnail
if (Graphics::Surface *const thumb = Graphics::loadThumbnail(*in))
diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp
index 597ca670c0..dff58f98e2 100644
--- a/engines/teenagent/resources.cpp
+++ b/engines/teenagent/resources.cpp
@@ -22,6 +22,7 @@
#include "teenagent/resources.h"
#include "teenagent/teenagent.h"
#include "common/textconsole.h"
+#include "common/translation.h"
#include "common/zlib.h"
namespace TeenAgent {
@@ -64,28 +65,47 @@ bool Resources::loadArchives(const ADGameDescription *gd) {
Common::File *dat_file = new Common::File();
if (!dat_file->open("teenagent.dat")) {
delete dat_file;
- Common::String errorMessage = "You're missing the 'teenagent.dat' file. Get it from the ScummVM website";
- GUIErrorMessage(errorMessage);
+ Common::String errorMessage = _("You're missing the 'teenagent.dat' file. Get it from the ScummVM website");
warning("%s", errorMessage.c_str());
+ GUIErrorMessage(errorMessage);
return false;
}
+
+ // teenagent.dat used to be compressed with zlib compression. The usage of
+ // zlib here is no longer needed, and it's maintained only for backwards
+ // compatibility.
Common::SeekableReadStream *dat = Common::wrapCompressedReadStream(dat_file);
+
+#if !defined(USE_ZLIB)
+ uint16 header = dat->readUint16BE();
+ bool isCompressed = (header == 0x1F8B ||
+ ((header & 0x0F00) == 0x0800 &&
+ header % 31 == 0));
+ dat->seek(-2, SEEK_CUR);
+
+ if (isCompressed) {
+ // teenagent.dat is compressed, but zlib hasn't been compiled in
+ delete dat;
+ Common::String errorMessage = _("The teenagent.dat file is compressed and zlib hasn't been included in this executable. Please decompress it");
+ warning("%s", errorMessage.c_str());
+ GUIErrorMessage(errorMessage);
+ return false;
+ }
+#endif
+
cseg.read(dat, 0xb3b0);
dseg.read(dat, 0xe790);
eseg.read(dat, 0x8be2);
-
delete dat;
- {
- FilePack varia;
- varia.open("varia.res");
- font7.load(varia, 7);
- font7.width_pack = 1;
- font7.height = 11;
- font8.load(varia, 8);
- font8.height = 31;
- varia.close();
- }
+ FilePack varia;
+ varia.open("varia.res");
+ font7.load(varia, 7);
+ font7.width_pack = 1;
+ font7.height = 11;
+ font8.load(varia, 8);
+ font8.height = 31;
+ varia.close();
off.open("off.res");
on.open("on.res");
diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp
index f06de6f803..57c069fe59 100644
--- a/engines/teenagent/teenagent.cpp
+++ b/engines/teenagent/teenagent.cpp
@@ -535,9 +535,8 @@ Common::Error TeenAgentEngine::run() {
syncSoundSettings();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, music, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, false);
setMusic(1);
- music->start();
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, music, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, false);
int load_slot = Common::ConfigManager::instance().getInt("save_slot");
if (load_slot >= 0) {
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
index 082694b728..590e6c6d81 100644
--- a/engines/testbed/graphics.cpp
+++ b/engines/testbed/graphics.cpp
@@ -1028,7 +1028,7 @@ TestExitStatus GFXtests::paletteRotation() {
GFXTestSuite::setCustomColor(255, 0, 0);
Testsuite::clearScreen();
- if(Testsuite::handleInteractiveInput("Did you see a rotation in colors of rectangles displayed on screen?", "Yes", "No", kOptionRight)) {
+ if (Testsuite::handleInteractiveInput("Did you see a rotation in colors of rectangles displayed on screen?", "Yes", "No", kOptionRight)) {
return kTestFailed;
}
@@ -1121,7 +1121,7 @@ TestExitStatus GFXtests::pixelFormats() {
g_system->updateScreen();
g_system->delayMillis(500);
- if(Testsuite::handleInteractiveInput("Were you able to notice the colored rectangles on the screen for this format?", "Yes", "No", kOptionLeft)) {
+ if (Testsuite::handleInteractiveInput("Were you able to notice the colored rectangles on the screen for this format?", "Yes", "No", kOptionLeft)) {
numPassed++;
} else {
numFailed++;
diff --git a/engines/testbed/testsuite.cpp b/engines/testbed/testsuite.cpp
index 655179aa74..39eeca31bd 100644
--- a/engines/testbed/testsuite.cpp
+++ b/engines/testbed/testsuite.cpp
@@ -289,7 +289,7 @@ void Testsuite::execute() {
continue;
}
- if((*i)->isInteractive && !ConfParams.isSessionInteractive()) {
+ if ((*i)->isInteractive && !ConfParams.isSessionInteractive()) {
logPrintf("Info! Skipping Test: %s, non-interactive environment is selected\n", ((*i)->featureName).c_str());
_numTestsSkipped++;
continue;
diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp
index 0f662e22bd..2e4be33e53 100644
--- a/engines/tinsel/detection.cpp
+++ b/engines/tinsel/detection.cpp
@@ -63,6 +63,14 @@ uint16 TinselEngine::getVersion() const {
return _gameDescription->version;
}
+bool TinselEngine::getIsADGFDemo() const {
+ return (bool)(_gameDescription->desc.flags & ADGF_DEMO);
+}
+
+bool TinselEngine::isCD() const {
+ return (bool)(_gameDescription->desc.flags & ADGF_CD);
+}
+
} // End of namespace Tinsel
static const PlainGameDescriptor tinselGames[] = {
diff --git a/engines/tinsel/detection_tables.h b/engines/tinsel/detection_tables.h
index b6b19f6ee7..631c2dce14 100644
--- a/engines/tinsel/detection_tables.h
+++ b/engines/tinsel/detection_tables.h
@@ -47,7 +47,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_DEMO,
+ 0,
TINSEL_V0,
},
@@ -61,12 +61,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_DEMO,
+ ADGF_DEMO | ADGF_CD,
GUIO0()
},
GID_DW1,
0,
- GF_CD,
+ 0,
TINSEL_V1,
},
#if 0
@@ -81,12 +81,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformMacintosh,
- ADGF_DEMO,
+ ADGF_DEMO | ADGF_CD,
GUIO0()
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES | GF_BIG_ENDIAN,
+ GF_SCNFILES,
TINSEL_V1,
},
#endif
@@ -110,7 +110,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -133,7 +133,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -156,7 +156,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -179,7 +179,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -195,7 +195,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_FLOPPY | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -214,7 +214,42 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_ENHANCED_AUDIO_SUPPORT,
+ TINSEL_V1,
+ },
+
+ { // Polish fan translation CD V1 version, with *.gra files (same as the floppy one, with english.smp)
+ {
+ "dw",
+ "CD",
+ {
+ {"dw.gra", 0, "ef05bbd2a754bd11a2e87bcd84ab5ccf", 781864},
+ {"english.smp", 0, NULL, -1},
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ ADGF_CD,
+ GUIO_NONE
+ },
+ GID_DW1,
+ 0,
+ GF_ENHANCED_AUDIO_SUPPORT,
+ TINSEL_V1,
+ },
+
+ { // Polish fan translaction floppy V1 version, with *.gra files
+ {
+ "dw",
+ "Floppy",
+ AD_ENTRY1s("dw.gra", "ef05bbd2a754bd11a2e87bcd84ab5ccf", 781864),
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO_NOSPEECH
+ },
+ GID_DW1,
+ 0,
+ GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -236,7 +271,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -261,7 +296,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -280,12 +315,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::DE_DEU,
Common::kPlatformPC,
- ADGF_DROPLANGUAGE | ADGF_CD,
+ ADGF_DROPLANGUAGE,
GUIO0()
},
GID_DW1,
0,
- GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
{
@@ -308,7 +343,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
{
@@ -331,7 +366,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -351,7 +386,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -371,7 +406,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -390,7 +425,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -408,12 +443,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformPSX,
- ADGF_DEMO,
+ ADGF_CD | ADGF_DEMO,
GUIO0()
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES,
+ GF_SCNFILES,
TINSEL_V1,
},
@@ -434,7 +469,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
#endif
@@ -456,7 +491,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT | GF_BIG_ENDIAN,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
@@ -475,7 +510,7 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT | GF_ALT_MIDI,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT | GF_ALT_MIDI,
TINSEL_V1,
},
@@ -496,11 +531,32 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
+ TINSEL_V1,
+ },
+
+ { // Polish fan translaction Discworld 1
+ {
+ "dw",
+ "CD",
+ {
+ {"dw.scn", 0, "fa169d2c98660215ebd84b49c1899eef", 776396},
+ {"english.txt", 0, "c1a53eb7ec812689dab70e2bb22cf2ab", 224151},
+ {"english.smp", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::PL_POL,
+ Common::kPlatformPC,
+ ADGF_CD,
+ GUIO_NONE
+ },
+ GID_DW1,
+ 0,
+ GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT,
TINSEL_V1,
},
- { // English DW2 demo
+ { // English Discworld 2 demo
{
"dw2",
"Demo",
@@ -511,12 +567,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_DEMO,
+ ADGF_DEMO | ADGF_CD,
GUIO1(GUIO_NOASPECT)
},
GID_DW2,
0,
- GF_CD | GF_SCNFILES | GF_DEMO,
+ GF_SCNFILES,
TINSEL_V2,
},
@@ -531,12 +587,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::EN_GRB,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_CD,
GUIO1(GUIO_NOASPECT)
},
GID_DW2,
0,
- GF_CD | GF_SCNFILES,
+ GF_SCNFILES,
TINSEL_V2,
},
@@ -551,12 +607,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::EN_USA,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_CD,
GUIO1(GUIO_NOASPECT)
},
GID_DW2,
0,
- GF_CD | GF_SCNFILES,
+ GF_SCNFILES,
TINSEL_V2,
},
@@ -571,12 +627,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::FR_FRA,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_CD,
GUIO1(GUIO_NOASPECT)
},
GID_DW2,
0,
- GF_CD | GF_SCNFILES,
+ GF_SCNFILES,
TINSEL_V2,
},
@@ -591,12 +647,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::DE_DEU,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_CD,
GUIO1(GUIO_NOASPECT)
},
GID_DW2,
0,
- GF_CD | GF_SCNFILES,
+ GF_SCNFILES,
TINSEL_V2,
},
@@ -612,12 +668,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::IT_ITA,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_CD,
GUIO1(GUIO_NOASPECT)
},
GID_DW2,
0,
- GF_CD | GF_SCNFILES,
+ GF_SCNFILES,
TINSEL_V2,
},
{
@@ -632,12 +688,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_CD,
GUIO1(GUIO_NOASPECT)
},
GID_DW2,
0,
- GF_CD | GF_SCNFILES,
+ GF_SCNFILES,
TINSEL_V2,
},
@@ -653,12 +709,12 @@ static const TinselGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformPC,
- ADGF_NO_FLAGS,
+ ADGF_CD,
GUIO1(GUIO_NOASPECT)
},
GID_DW2,
0,
- GF_CD | GF_SCNFILES,
+ GF_SCNFILES,
TINSEL_V2,
},
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index fbe9e8d1f6..56ee2ea752 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -753,6 +753,11 @@ static CONFBOX t1RestartBox[] = {
#endif
};
+static CONFBOX t1RestartBoxPSX[] = {
+ { AAGBUT, INITGAME, TM_NONE, NULL, USE_POINTER, 122, 48, 23, 19, NULL, IX1_TICK1 },
+ { AAGBUT, CLOSEWIN, TM_NONE, NULL, USE_POINTER, 82, 48, 23, 19, NULL, IX1_CROSS1 }
+};
+
static CONFBOX t2RestartBox[] = {
{ AAGBUT, INITGAME, TM_NONE, NULL, 0, 140, 78, BW, BH, NULL, IX2_TICK1 },
{ AAGBUT, CLOSEWIN, TM_NONE, NULL, 0, 60, 78, BW, BH, NULL, IX2_CROSS1 }
@@ -763,10 +768,10 @@ static CONFINIT t1ciRestart = { 6, 2, 72, 53, false, t1RestartBox, ARRAYSIZE(t1R
#else
static CONFINIT t1ciRestart = { 4, 2, 98, 53, false, t1RestartBox, ARRAYSIZE(t1RestartBox), SIX_RESTART_HEADING };
#endif
+static CONFINIT t1ciRestartPSX = { 8, 2, 46, 53, false, t1RestartBoxPSX, ARRAYSIZE(t1RestartBoxPSX), SIX_RESTART_HEADING };
static CONFINIT t2ciRestart = { 4, 2, 196, 53, false, t2RestartBox, sizeof(t2RestartBox)/sizeof(CONFBOX), SS_RESTART_HEADING };
-#define ciRestart (TinselV2 ? t2ciRestart : t1ciRestart)
-#define restartBox (TinselV2 ? t2RestartBox : t1RestartBox)
+#define ciRestart (TinselV2 ? t2ciRestart : (TinselV1PSX ? t1ciRestartPSX : t1ciRestart))
/*-------------------------------------------------------------*\
| This is the sound control 'menu'. In Discworld 2, it also |
@@ -1038,18 +1043,20 @@ static bool RePosition();
static bool LanguageChange() {
LANGUAGE nLang = _vm->_config->_language;
- if (_vm->getFeatures() & GF_USE_3FLAGS) {
- // VERY quick dodgy bodge
- if (cd.selBox == 0)
- nLang = TXT_FRENCH; // = 1
- else if (cd.selBox == 1)
- nLang = TXT_GERMAN; // = 2
- else
- nLang = TXT_SPANISH; // = 4
- } else if (_vm->getFeatures() & GF_USE_4FLAGS) {
- nLang = (LANGUAGE)(cd.selBox + 1);
- } else if (_vm->getFeatures() & GF_USE_5FLAGS) {
- nLang = (LANGUAGE)cd.selBox;
+ if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) {
+ // Languages: TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN, TXT_ITALIAN, TXT_SPANISH
+ // 5 flag versions include English
+ int selected = (_vm->getFeatures() & GF_USE_5FLAGS) ? cd.selBox : cd.selBox + 1;
+ // Make sure that a language flag has been selected. If the user has
+ // changed the language speed slider and hasn't clicked on a flag, it
+ // won't be selected.
+ if (selected >= 0 && selected <= 4) {
+ nLang = (LANGUAGE)selected;
+
+ // 3 flag versions don't include Italian
+ if (selected >= 3 && (_vm->getFeatures() & GF_USE_3FLAGS))
+ nLang = TXT_SPANISH;
+ }
}
if (nLang != _vm->_config->_language) {
@@ -1256,6 +1263,20 @@ static INV_OBJECT *GetInvObject(int id) {
}
/**
+ * Returns true if the given id represents a valid inventory object
+ */
+bool GetIsInvObject(int id) {
+ INV_OBJECT *pObject = g_invObjects;
+
+ for (int i = 0; i < g_numObjects; i++, pObject++) {
+ if (pObject->id == id)
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Convert item ID number to index.
*/
static int GetObjectIndex(int id) {
diff --git a/engines/tinsel/dialogs.h b/engines/tinsel/dialogs.h
index 8c48eb8b76..ab53ba771c 100644
--- a/engines/tinsel/dialogs.h
+++ b/engines/tinsel/dialogs.h
@@ -152,6 +152,8 @@ void InvSetLimit(int invno, int n);
void InvSetSize(int invno, int MinWidth, int MinHeight,
int StartWidth, int StartHeight, int MaxWidth, int MaxHeight);
+bool GetIsInvObject(int id);
+
int WhichInventoryOpen();
bool IsTopWindow();
diff --git a/engines/tinsel/drives.cpp b/engines/tinsel/drives.cpp
index 5c4b939e4e..3ecef83753 100644
--- a/engines/tinsel/drives.cpp
+++ b/engines/tinsel/drives.cpp
@@ -149,7 +149,7 @@ bool GotoCD() {
bool TinselFile::_warningShown = false;
-TinselFile::TinselFile() : ReadStreamEndian((_vm->getFeatures() & GF_BIG_ENDIAN) != 0) {
+TinselFile::TinselFile() : ReadStreamEndian(TinselV1Mac) {
_stream = NULL;
}
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index c3089db990..14d588dcec 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -99,14 +99,16 @@ void SetupHandleTable() {
MEMHANDLE *pH;
TinselFile f;
- if (f.open(TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME)) {
+ const char *indexFileName = TinselV1PSX ? PSX_INDEX_FILENAME : INDEX_FILENAME;
+
+ if (f.open(indexFileName)) {
// get size of index file
len = f.size();
if (len > 0) {
if ((len % RECORD_SIZE) != 0) {
// index file is corrupt
- error(FILE_IS_CORRUPT, TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME);
+ error(FILE_IS_CORRUPT, indexFileName);
}
// calc number of handles
@@ -132,16 +134,16 @@ void SetupHandleTable() {
if (f.eos() || f.err()) {
// index file is corrupt
- error(FILE_IS_CORRUPT, (TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME));
+ error(FILE_IS_CORRUPT, indexFileName);
}
// close the file
f.close();
} else { // index file is corrupt
- error(FILE_IS_CORRUPT, (TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME));
+ error(FILE_IS_CORRUPT, indexFileName);
}
} else { // cannot find the index file
- error(CANNOT_FIND_FILE, (TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME));
+ error(CANNOT_FIND_FILE, indexFileName);
}
// allocate memory nodes and load all permanent graphics
diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp
index fa5334a033..b3bfbcc5dc 100644
--- a/engines/tinsel/music.cpp
+++ b/engines/tinsel/music.cpp
@@ -131,16 +131,13 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
g_currentMidi = dwFileOffset;
g_currentLoop = bLoop;
- if (_vm->_config->_musicVolume != 0) {
- bool mute = false;
- if (ConfMan.hasKey("mute"))
- mute = ConfMan.getBool("mute");
+ bool mute = false;
+ if (ConfMan.hasKey("mute"))
+ mute = ConfMan.getBool("mute");
- SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume);
- }
+ SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume);
// the index and length of the last tune loaded
- static uint32 dwLastMidiIndex = 0; // FIXME: Avoid non-const global vars
uint32 dwSeqLen = 0; // length of the sequence
// Support for external music from the music enhancement project
@@ -181,61 +178,53 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
if (dwFileOffset == 0)
return true;
- if (dwFileOffset != dwLastMidiIndex) {
- Common::File midiStream;
-
- // open MIDI sequence file in binary mode
- if (!midiStream.open(MIDI_FILE))
- error(CANNOT_FIND_FILE, MIDI_FILE);
-
- // update index of last tune loaded
- dwLastMidiIndex = dwFileOffset;
-
- // move to correct position in the file
- midiStream.seek(dwFileOffset, SEEK_SET);
-
- // read the length of the sequence
- dwSeqLen = midiStream.readUint32LE();
-
- // make sure buffer is large enough for this sequence
- assert(dwSeqLen > 0 && dwSeqLen <= g_midiBuffer.size);
-
- // stop any currently playing tune
- _vm->_midiMusic->stop();
-
- // read the sequence
- if (midiStream.read(g_midiBuffer.pDat, dwSeqLen) != dwSeqLen)
- error(FILE_IS_CORRUPT, MIDI_FILE);
-
- midiStream.close();
-
- // WORKAROUND for bug #2820054 "DW1: No intro music at first start on Wii",
- // which actually affects all ports, since it's specific to the GRA version.
- //
- // The GRA version does not seem to set the channel volume at all for the first
- // intro track, thus we need to do that here. We only initialize the channels
- // used in that sequence. And we are using 127 as default channel volume.
- //
- // Only in the GRA version dwFileOffset can be "38888", just to be sure, we
- // check for the SCN files feature flag not being set though.
- if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) {
- _vm->_midiMusic->send(0x7F07B0 | 3);
- _vm->_midiMusic->send(0x7F07B0 | 5);
- _vm->_midiMusic->send(0x7F07B0 | 8);
- _vm->_midiMusic->send(0x7F07B0 | 10);
- _vm->_midiMusic->send(0x7F07B0 | 13);
- }
+ Common::File midiStream;
- _vm->_midiMusic->playMIDI(dwSeqLen, bLoop);
+ // open MIDI sequence file in binary mode
+ if (!midiStream.open(MIDI_FILE))
+ error(CANNOT_FIND_FILE, MIDI_FILE);
- // Store the length
- //dwLastSeqLen = dwSeqLen;
- } else {
- // dwFileOffset == dwLastMidiIndex
- _vm->_midiMusic->stop();
- _vm->_midiMusic->playMIDI(dwSeqLen, bLoop);
+ // move to correct position in the file
+ midiStream.seek(dwFileOffset, SEEK_SET);
+
+ // read the length of the sequence
+ dwSeqLen = midiStream.readUint32LE();
+
+ // make sure buffer is large enough for this sequence
+ assert(dwSeqLen > 0 && dwSeqLen <= g_midiBuffer.size);
+
+ // stop any currently playing tune
+ _vm->_midiMusic->stop();
+
+ // read the sequence. This needs to be read again before playSEQ() is
+ // called even if the music is restarting, as playSEQ() reads the file
+ // name off the buffer itself. However, that function adds SMF headers
+ // to the buffer, thus if it's read again, the SMF headers will be read
+ // and the filename will always be 'MThd'.
+ if (midiStream.read(g_midiBuffer.pDat, dwSeqLen) != dwSeqLen)
+ error(FILE_IS_CORRUPT, MIDI_FILE);
+
+ midiStream.close();
+
+ // WORKAROUND for bug #2820054 "DW1: No intro music at first start on Wii",
+ // which actually affects all ports, since it's specific to the GRA version.
+ //
+ // The GRA version does not seem to set the channel volume at all for the first
+ // intro track, thus we need to do that here. We only initialize the channels
+ // used in that sequence. And we are using 127 as default channel volume.
+ //
+ // Only in the GRA version dwFileOffset can be "38888", just to be sure, we
+ // check for the SCN files feature flag not being set though.
+ if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) {
+ _vm->_midiMusic->send(0x7F07B0 | 3);
+ _vm->_midiMusic->send(0x7F07B0 | 5);
+ _vm->_midiMusic->send(0x7F07B0 | 8);
+ _vm->_midiMusic->send(0x7F07B0 | 10);
+ _vm->_midiMusic->send(0x7F07B0 | 13);
}
+ _vm->_midiMusic->playMIDI(dwSeqLen, bLoop);
+
return true;
}
@@ -279,27 +268,7 @@ int GetMidiVolume() {
*/
void SetMidiVolume(int vol) {
assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume);
-
- static int priorVolMusic = 0; // FIXME: Avoid non-const global vars
-
- if (vol == 0 && priorVolMusic == 0) {
- // Nothing to do
- } else if (vol == 0 && priorVolMusic != 0) {
- // Stop current midi sequence
- StopMidi();
- _vm->_midiMusic->setVolume(vol);
- } else if (vol != 0 && priorVolMusic == 0) {
- // Perhaps restart last midi sequence
- if (g_currentLoop)
- PlayMidiSequence(g_currentMidi, true);
-
- _vm->_midiMusic->setVolume(vol);
- } else if (vol != 0 && priorVolMusic != 0) {
- // Alter current volume
- _vm->_midiMusic->setVolume(vol);
- }
-
- priorVolMusic = vol;
+ _vm->_midiMusic->setVolume(vol);
}
/**
@@ -309,7 +278,7 @@ void OpenMidiFiles() {
Common::File midiStream;
// Demo version has no midi file
- if ((_vm->getFeatures() & GF_DEMO) || (TinselVersion == TINSEL_V2))
+ if (TinselV0 || TinselV2)
return;
if (g_midiBuffer.pDat)
@@ -942,14 +911,12 @@ void RestoreMidiFacts(SCNHANDLE Midi, bool Loop) {
g_currentMidi = Midi;
g_currentLoop = Loop;
- if (_vm->_config->_musicVolume != 0 && Loop) {
- bool mute = false;
- if (ConfMan.hasKey("mute"))
- mute = ConfMan.getBool("mute");
+ bool mute = false;
+ if (ConfMan.hasKey("mute"))
+ mute = ConfMan.getBool("mute");
- PlayMidiSequence(g_currentMidi, true);
- SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume);
- }
+ PlayMidiSequence(g_currentMidi, true);
+ SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume);
}
#if 0
diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp
index 60f04b47fd..6ea18c8268 100644
--- a/engines/tinsel/pcode.cpp
+++ b/engines/tinsel/pcode.cpp
@@ -122,6 +122,8 @@ static uint32 g_hMasterScript;
struct WorkaroundEntry {
TinselEngineVersion version; ///< Engine version this workaround applies to
bool scnFlag; ///< Only applicable for Tinsel 1 (DW 1)
+ bool isDemo; ///< Flags whether it's for a demo
+ Common::Platform platform; ///< Platform filter
SCNHANDLE hCode; ///< Script to apply fragment to
int ip; ///< Script offset to run this fragment before
int numBytes; ///< Number of bytes in the script
@@ -129,6 +131,7 @@ struct WorkaroundEntry {
};
#define FRAGMENT_WORD(x) (byte)(x & 0xFF), (byte)(x >> 8)
+#define FRAGMENT_DWORD(x) (byte)(x & 0xFF), (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24)
static const byte fragment1[] = {OP_ZERO, OP_GSTORE | OPSIZE16, 206, 0};
static const byte fragment2[] = {OP_LIBCALL | OPSIZE8, 110};
@@ -149,6 +152,10 @@ static const byte fragment12[] = {OP_JMPTRUE | OPSIZE16, FRAGMENT_WORD(1491),
OP_IMM | OPSIZE16, FRAGMENT_WORD(322), OP_LIBCALL | OPSIZE8, 46, // Give back the whistle
OP_JUMP | OPSIZE16, FRAGMENT_WORD(1568)};
static const byte fragment13[] = {OP_ZERO, OP_GSTORE | OPSIZE16, FRAGMENT_WORD(306)};
+static const byte fragment14[] = {OP_LIBCALL | OPSIZE8, 58,
+ OP_IMM, FRAGMENT_DWORD((42 << 23)), OP_ONE, OP_ZERO, OP_LIBCALL | OPSIZE8, 44,
+ OP_LIBCALL | OPSIZE8, 97, OP_JUMP | OPSIZE16, FRAGMENT_WORD(2220)
+};
#undef FRAGMENT_WORD
@@ -157,7 +164,7 @@ const WorkaroundEntry workaroundList[] = {
// book back to the present. In the GRA version, it was global 373,
// and was reset when he is returned to the past, but was forgotten
// in the SCN version, so this ensures the flag is properly reset.
- {TINSEL_V1, true, 427942095, 1, sizeof(fragment1), fragment1},
+ {TINSEL_V1, true, false, Common::kPlatformUnknown, 427942095, 1, sizeof(fragment1), fragment1},
// DW1-GRA: Rincewind exiting the Inn is blocked by the luggage.
// Whilst you can then move into walkable areas, saving and
@@ -165,26 +172,26 @@ const WorkaroundEntry workaroundList[] = {
// fragment turns off NPC blocking for the Outside Inn rooms so that
// the luggage won't block Past Outside Inn.
// See bug report #2525010.
- {TINSEL_V1, false, 444622076, 0, sizeof(fragment2), fragment2},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 444622076, 0, sizeof(fragment2), fragment2},
// Present Outside Inn
- {TINSEL_V1, false, 352600876, 0, sizeof(fragment2), fragment2},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 352600876, 0, sizeof(fragment2), fragment2},
// DW1-GRA: Talking to palace guards in Act 2 gives !!!HIGH
// STRING||| - this happens if you initiate dialog with one of the
// guards, but not the other. So these fragments provide the correct
// talk parameters where needed.
// See bug report #2831159.
- {TINSEL_V1, false, 310506872, 463, sizeof(fragment4), fragment4},
- {TINSEL_V1, false, 310506872, 485, sizeof(fragment5), fragment5},
- {TINSEL_V1, false, 310506872, 513, sizeof(fragment6), fragment6},
- {TINSEL_V1, false, 310506872, 613, sizeof(fragment7), fragment7},
- {TINSEL_V1, false, 310506872, 641, sizeof(fragment8), fragment8},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 463, sizeof(fragment4), fragment4},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 485, sizeof(fragment5), fragment5},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 513, sizeof(fragment6), fragment6},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 613, sizeof(fragment7), fragment7},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 641, sizeof(fragment8), fragment8},
// DW1-SCN: The script for the lovable street-Starfish does a
// 'StopSample' after flicking the coin to ensure it's sound is
// stopped, but which also accidentally can stop any active
// conversation with the Amazon.
- {TINSEL_V1, true, 394640351, 121, sizeof(fragment9), fragment9},
+ {TINSEL_V1, true, false, Common::kPlatformUnknown, 394640351, 121, sizeof(fragment9), fragment9},
// DW2: In the garden, global #490 is set when the bees begin their
// 'out of hive' animation, and reset when done. But if the game is
@@ -197,25 +204,29 @@ const WorkaroundEntry workaroundList[] = {
// * Stealing the mallets from the wizards (bug #2820788).
// This fix ensures that the global is reset when the Garden scene
// is loaded (both entering and restoring a game).
- {TINSEL_V2, true, 2888147476U, 0, sizeof(fragment3), fragment3},
+ {TINSEL_V2, true, false, Common::kPlatformUnknown, 2888147476U, 0, sizeof(fragment3), fragment3},
// DW1-GRA: Corrects text being drawn partially off-screen during
// the blackboard description of the Librarian.
- {TINSEL_V1, false, 293831402, 133, sizeof(fragment10), fragment10},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 293831402, 133, sizeof(fragment10), fragment10},
// DW1-GRA/SCN: Corrects the dead-end of being able to give the
// whistle back to the pirate before giving him the parrot.
// See bug report #2934211.
- {TINSEL_V1, true, 352601285, 1569, sizeof(fragment11), fragment11},
- {TINSEL_V1, false, 352602304, 1488, sizeof(fragment12), fragment12},
+ {TINSEL_V1, true, false, Common::kPlatformUnknown, 352601285, 1569, sizeof(fragment11), fragment11},
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 352602304, 1488, sizeof(fragment12), fragment12},
// DW2: Corrects a bug with global 306 not being cleared if you leave
// the marketplace scene whilst D'Blah is talking (even if it's not
// actually audible); returning to the scene and clicking on him multiple
// times would cause the game to crash
- {TINSEL_V2, true, 1109294728, 0, sizeof(fragment13), fragment13},
+ {TINSEL_V2, true, false, Common::kPlatformUnknown, 1109294728, 0, sizeof(fragment13), fragment13},
+
+ // DW1 PSX DEMO: Alters a script in the PSX DW1 demo to show the Idle animation scene rather than
+ // quitting the game when no user input happens for a while
+ {TINSEL_V1, true, true, Common::kPlatformPSX, 0, 2186, sizeof(fragment14), fragment14},
- {TINSEL_V0, false, 0, 0, 0, NULL}
+ {TINSEL_V0, false, false, Common::kPlatformUnknown, 0, 0, 0, NULL}
};
//----------------- LOCAL GLOBAL DATA --------------------
@@ -582,6 +593,8 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
if ((wkEntry->version == TinselVersion) &&
(wkEntry->hCode == ic->hCode) &&
(wkEntry->ip == ip) &&
+ (wkEntry->isDemo == _vm->getIsADGFDemo()) &&
+ ((wkEntry->platform == Common::kPlatformUnknown) || (wkEntry->platform == _vm->getPlatform())) &&
(!TinselV1 || (wkEntry->scnFlag == ((_vm->getFeatures() & GF_SCNFILES) != 0)))) {
// Point to start of workaround fragment
ip = 0;
diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp
index 0a552c8c2b..518e27f02b 100644
--- a/engines/tinsel/saveload.cpp
+++ b/engines/tinsel/saveload.cpp
@@ -55,8 +55,7 @@ namespace Tinsel {
* only saves/loads those which are valid for the version of the savegame
* which is being loaded/saved currently.
*/
-#define CURRENT_VER 1
-// TODO: Not yet used
+#define CURRENT_VER 2
/**
* An auxillary macro, used to specify savegame versions. We use this instead
@@ -97,12 +96,13 @@ struct SaveGameHeader {
TimeDate dateTime;
bool scnFlag;
byte language;
+ uint16 numInterpreters; // Savegame version 2 or later only
};
enum {
DW1_SAVEGAME_ID = 0x44575399, // = 'DWSc' = "DiscWorld 1 ScummVM"
DW2_SAVEGAME_ID = 0x44573253, // = 'DW2S' = "DiscWorld 2 ScummVM"
- SAVEGAME_HEADER_SIZE = 4 + 4 + 4 + SG_DESC_LEN + 7 + 1 + 1
+ SAVEGAME_HEADER_SIZE = 4 + 4 + 4 + SG_DESC_LEN + 7 + 1 + 1 + 2
};
#define SAVEGAME_ID (TinselV2 ? (uint32)DW2_SAVEGAME_ID : (uint32)DW1_SAVEGAME_ID)
@@ -186,6 +186,15 @@ static bool syncSaveGameHeader(Common::Serializer &s, SaveGameHeader &hdr) {
}
}
+ // Handle the number of interpreter contexts that will be saved in the savegame
+ if (tmp >= 2) {
+ tmp -= 2;
+ hdr.numInterpreters = NUM_INTERPRET;
+ s.syncAsUint16LE(hdr.numInterpreters);
+ } else {
+ hdr.numInterpreters = (TinselV2 ? 70 : 64) - 20;
+ }
+
// Skip over any extra bytes
s.skip(tmp);
return true;
@@ -262,7 +271,7 @@ static void syncSoundReel(Common::Serializer &s, SOUNDREELS &sr) {
s.syncAsSint32LE(sr.actorCol);
}
-static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd) {
+static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd, int numInterp) {
s.syncAsUint32LE(sd.SavedSceneHandle);
s.syncAsUint32LE(sd.SavedBgroundHandle);
for (int i = 0; i < MAX_MOVERS; ++i)
@@ -273,7 +282,7 @@ static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd) {
s.syncAsSint32LE(sd.NumSavedActors);
s.syncAsSint32LE(sd.SavedLoffset);
s.syncAsSint32LE(sd.SavedToffset);
- for (int i = 0; i < NUM_INTERPRET; ++i)
+ for (int i = 0; i < numInterp; ++i)
sd.SavedICInfo[i].syncWithSerializer(s);
for (int i = 0; i < MAX_POLY; ++i)
s.syncAsUint32LE(sd.SavedDeadPolys[i]);
@@ -422,7 +431,7 @@ char *ListEntry(int i, letype which) {
return NULL;
}
-static void DoSync(Common::Serializer &s) {
+static bool DoSync(Common::Serializer &s, int numInterp) {
int sg = 0;
if (TinselV2) {
@@ -434,7 +443,7 @@ static void DoSync(Common::Serializer &s) {
if (TinselV2 && s.isLoading())
HoldItem(INV_NOICON);
- syncSavedData(s, *g_srsd);
+ syncSavedData(s, *g_srsd, numInterp);
syncGlobInfo(s); // Glitter globals
syncInvInfo(s); // Inventory data
@@ -443,6 +452,10 @@ static void DoSync(Common::Serializer &s) {
sg = WhichItemHeld();
s.syncAsSint32LE(sg);
if (s.isLoading()) {
+ if (sg != -1 && !GetIsInvObject(sg))
+ // Not a valid inventory object, so return false
+ return false;
+
if (TinselV2)
g_thingHeld = sg;
else
@@ -459,7 +472,7 @@ static void DoSync(Common::Serializer &s) {
if (*g_SaveSceneSsCount != 0) {
SAVED_DATA *sdPtr = g_SaveSceneSsData;
for (int i = 0; i < *g_SaveSceneSsCount; ++i, ++sdPtr)
- syncSavedData(s, *sdPtr);
+ syncSavedData(s, *sdPtr, numInterp);
// Flag that there is a saved scene to return to. Note that in this context 'saved scene'
// is a stored scene to return to from another scene, such as from the Summoning Book close-up
@@ -469,6 +482,8 @@ static void DoSync(Common::Serializer &s) {
if (!TinselV2)
syncAllActorsAlive(s);
+
+ return true;
}
/**
@@ -487,8 +502,23 @@ static bool DoRestore() {
delete f; // Invalid header, or savegame too new -> skip it
return false;
}
+
+ // Load in the data. For older savegame versions, we potentially need to load the data twice, once
+ // for pre 1.5 savegames, and if that fails, a second time for 1.5 savegames
+ int numInterpreters = hdr.numInterpreters;
+ int32 currentPos = f->pos();
+ for (int tryNumber = 0; tryNumber < ((hdr.ver >= 2) ? 1 : 2); ++tryNumber) {
+ // If it's the second loop iteration, try with the 1.5 savegame number of interpreter contexts
+ if (tryNumber == 1) {
+ f->seek(currentPos);
+ numInterpreters = 80;
+ }
- DoSync(s);
+ // Load the savegame data
+ if (DoSync(s, numInterpreters))
+ // Data load was successful (or likely), so break out of loop
+ break;
+ }
uint32 id = f->readSint32LE();
if (id != (uint32)0xFEEDFACE)
@@ -575,7 +605,7 @@ static void DoSave() {
return;
}
- DoSync(s);
+ DoSync(s, hdr.numInterpreters);
// Write out the special Id for Discworld savegames
f->writeUint32LE(0xFEEDFACE);
diff --git a/engines/tinsel/scene.h b/engines/tinsel/scene.h
index baaff27a3e..06e5c096d9 100644
--- a/engines/tinsel/scene.h
+++ b/engines/tinsel/scene.h
@@ -75,9 +75,9 @@ enum REEL {
typedef enum { TRANS_DEF, TRANS_CUT, TRANS_FADE } TRANSITS;
// amount to shift scene handles by
-#define SCNHANDLE_SHIFT ((TinselV2 && !IsDemo) ? 25 : 23)
-#define OFFSETMASK ((TinselV2 && !IsDemo) ? 0x01ffffffL : 0x007fffffL)
-#define HANDLEMASK ((TinselV2 && !IsDemo) ? 0xFE000000L : 0xFF800000L)
+#define SCNHANDLE_SHIFT ((TinselV2 && !TinselV2Demo) ? 25 : 23)
+#define OFFSETMASK ((TinselV2 && !TinselV2Demo) ? 0x01ffffffL : 0x007fffffL)
+#define HANDLEMASK ((TinselV2 && !TinselV2Demo) ? 0xFE000000L : 0xFF800000L)
void DoHailScene(SCNHANDLE scene);
diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp
index f575b03270..e052302cfd 100644
--- a/engines/tinsel/sound.cpp
+++ b/engines/tinsel/sound.cpp
@@ -75,7 +75,7 @@ SoundManager::~SoundManager() {
// playSample for DiscWorld 1
bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::SoundHandle *handle) {
// Floppy version has no sample file
- if (_vm->getFeatures() & GF_FLOPPY)
+ if (!_vm->isCD())
return false;
// no sample driver?
@@ -182,7 +182,7 @@ bool SoundManager::playSample(int id, int sub, bool bLooped, int x, int y, int p
Audio::Mixer::SoundType type, Audio::SoundHandle *handle) {
// Floppy version has no sample file
- if (_vm->getFeatures() & GF_FLOPPY)
+ if (!_vm->isCD())
return false;
// no sample driver?
@@ -471,7 +471,7 @@ void SoundManager::setSFXVolumes(uint8 volume) {
*/
void SoundManager::openSampleFiles() {
// Floppy and demo versions have no sample files, except for the Discworld 2 demo
- if (_vm->getFeatures() & GF_FLOPPY || (IsDemo && !TinselV2))
+ if (!_vm->isCD() || TinselV0)
return;
TinselFile f;
diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp
index 5dda836144..058f8eb6fd 100644
--- a/engines/tinsel/tinlib.cpp
+++ b/engines/tinsel/tinlib.cpp
@@ -1625,10 +1625,6 @@ static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, bool bComplete, int
* Play a midi file.
*/
static void PlayMidi(CORO_PARAM, SCNHANDLE hMidi, int loop, bool complete) {
- // FIXME: This is a workaround for the FIXME below
- if (GetMidiVolume() == 0)
- return;
-
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1637,18 +1633,13 @@ static void PlayMidi(CORO_PARAM, SCNHANDLE hMidi, int loop, bool complete) {
PlayMidiSequence(hMidi, loop == MIDI_LOOP);
- // FIXME: The following check messes up the script arguments when
- // entering the secret door in the bookshelf in the library,
- // leading to a crash, when the music volume is set to 0 (MidiPlaying()
- // always false then).
- //
- // Why exactly this happens is unclear. An analysis of the involved
- // script(s) might reveal more.
- //
- // Note: This check&sleep was added in DW v2. It was most likely added
- // to ensure that the MIDI song started playing before the next opcode
+ // This check&sleep was added in DW v2. It was most likely added to
+ // ensure that the MIDI song started playing before the next opcode
// is executed.
- if (!MidiPlaying())
+ // In DW1, it messes up the script arguments when entering the secret
+ // door in the bookshelf in the library, leading to a crash, when the
+ // music volume is set to 0.
+ if (!MidiPlaying() && TinselV2)
CORO_SLEEP(1);
if (complete) {
@@ -3412,7 +3403,7 @@ static void TalkOrSay(CORO_PARAM, SPEECH_TYPE speechType, SCNHANDLE hText, int x
// Kick off the sample now (perhaps with a delay)
if (g_bNoPause)
g_bNoPause = false;
- else if (!IsDemo)
+ else if (!TinselV2Demo)
CORO_SLEEP(SysVar(SV_SPEECHDELAY));
//SamplePlay(VOICE, hText, _ctx->sub, false, -1, -1, PRIORITY_TALK);
@@ -4244,7 +4235,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 if (TinselV2Demo) libCode = DW2DEMO_CODES[operand];
else libCode = DW2_CODES[operand];
debug(7, "CallLibraryRoutine op %d (escOn %d, myEscape %d)", operand, pic->escOn, pic->myEscape);
diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h
index bac7ef6efb..123249125e 100644
--- a/engines/tinsel/tinsel.h
+++ b/engines/tinsel/tinsel.h
@@ -63,21 +63,16 @@ enum TinselGameID {
};
enum TinselGameFeatures {
- GF_DEMO = 1 << 0,
- GF_CD = 1 << 1,
- GF_FLOPPY = 1 << 2,
- GF_SCNFILES = 1 << 3,
- GF_ENHANCED_AUDIO_SUPPORT = 1 << 4,
- GF_ALT_MIDI = 1 << 5, // Alternate sequence in midi.dat file
+ GF_SCNFILES = 1 << 0,
+ GF_ENHANCED_AUDIO_SUPPORT = 1 << 1,
+ GF_ALT_MIDI = 1 << 2, // Alternate sequence in midi.dat file
// The GF_USE_?FLAGS values specify how many country flags are displayed
// in the subtitles options dialog.
// None of these defined -> 1 language, in ENGLISH.TXT
- GF_USE_3FLAGS = 1 << 6, // French, German, Spanish
- GF_USE_4FLAGS = 1 << 7, // French, German, Spanish, Italian
- GF_USE_5FLAGS = 1 << 8, // All 5 flags
-
- GF_BIG_ENDIAN = 1 << 9
+ GF_USE_3FLAGS = 1 << 3, // French, German, Spanish
+ GF_USE_4FLAGS = 1 << 4, // French, German, Spanish, Italian
+ GF_USE_5FLAGS = 1 << 5 // All 5 flags
};
/**
@@ -134,13 +129,12 @@ typedef bool (*KEYFPTR)(const Common::KeyState &);
#define TinselV0 (TinselVersion == TINSEL_V0)
#define TinselV1 (TinselVersion == TINSEL_V1)
#define TinselV2 (TinselVersion == TINSEL_V2)
+#define TinselV2Demo (TinselVersion == TINSEL_V2 && _vm->getIsADGFDemo())
#define TinselV1PSX (TinselVersion == TINSEL_V1 && _vm->getPlatform() == Common::kPlatformPSX)
#define TinselV1Mac (TinselVersion == TINSEL_V1 && _vm->getPlatform() == Common::kPlatformMacintosh)
-#define IsDemo (_vm->getFeatures() & GF_DEMO)
-
-#define READ_16(v) ((_vm->getFeatures() & GF_BIG_ENDIAN) ? READ_BE_UINT16(v) : READ_LE_UINT16(v))
-#define READ_32(v) ((_vm->getFeatures() & GF_BIG_ENDIAN) ? READ_BE_UINT32(v) : READ_LE_UINT32(v))
+#define READ_16(v) (TinselV1Mac ? READ_BE_UINT16(v) : READ_LE_UINT16(v))
+#define READ_32(v) (TinselV1Mac ? READ_BE_UINT32(v) : READ_LE_UINT32(v))
// Global reference to the TinselEngine object
extern TinselEngine *_vm;
@@ -186,6 +180,8 @@ public:
uint16 getVersion() const;
uint32 getFlags() const;
Common::Platform getPlatform() const;
+ bool getIsADGFDemo() const;
+ bool isCD() const;
const char *getSampleIndex(LANGUAGE lang);
const char *getSampleFile(LANGUAGE lang);
diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp
index c532bbbf09..c1a57638c2 100644
--- a/engines/toltecs/detection.cpp
+++ b/engines/toltecs/detection.cpp
@@ -273,8 +273,6 @@ SaveStateDescriptor ToltecsMetaEngine::querySaveMetaInfos(const char *target, in
if (error == Toltecs::ToltecsEngine::kRSHENoError) {
SaveStateDescriptor desc(slot, header.description);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
desc.setThumbnail(header.thumbnail);
if (header.version > 0) {
diff --git a/engines/toon/anim.cpp b/engines/toon/anim.cpp
index 84f6fa375c..1c85a8d798 100644
--- a/engines/toon/anim.cpp
+++ b/engines/toon/anim.cpp
@@ -132,7 +132,7 @@ Common::Rect Animation::getRect() {
return Common::Rect(_x1, _y1, _x2, _y2);
}
-void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy) {
+void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy) {
debugC(3, kDebugAnim, "drawFrame(surface, %d, %d, %d)", frame, xx, yy);
if (frame < 0)
frame = 0;
@@ -146,10 +146,13 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int
if (_frames[frame]._ref != -1)
frame = _frames[frame]._ref;
- int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
- int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
- int32 offsX = 0;
- int32 offsY = 0;
+ if (!_frames[frame]._data)
+ return;
+
+ int16 rectX = _frames[frame]._x2 - _frames[frame]._x1;
+ int16 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+ int16 offsX = 0;
+ int16 offsY = 0;
_vm->addDirtyRect(xx + _x1 + _frames[frame]._x1, yy + _y1 + _frames[frame]._y1, xx + rectX + _x1 + _frames[frame]._x1 , yy + rectY + _y1 + _frames[frame]._y1);
@@ -186,10 +189,10 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int
int32 destPitch = surface.pitch;
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++) {
+ for (int16 y = 0; y < rectY; y++) {
uint8 *cur = curRow;
uint8 *c = srcRow + y * (_frames[frame]._x2 - _frames[frame]._x1);
- for (int32 x = 0; x < rectX; x++) {
+ for (int16 x = 0; x < rectX; x++) {
if (*c)
*cur = *c;
c++;
@@ -199,27 +202,27 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int
}
}
-void Animation::drawFrameWithMask(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask) {
+void Animation::drawFrameWithMask(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask) {
debugC(1, kDebugAnim, "drawFrameWithMask(surface, %d, %d, %d, %d, mask)", frame, xx, yy, zz);
warning("STUB: drawFrameWithMask()");
}
-void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask, int32 scale) {
+void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask, int32 scale) {
debugC(5, kDebugAnim, "drawFrameWithMaskAndScale(surface, %d, %d, %d, %d, mask, %d)", frame, xx, yy, zz, scale);
if (_frames[frame]._ref != -1)
frame = _frames[frame]._ref;
- int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
- int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+ int16 rectX = _frames[frame]._x2 - _frames[frame]._x1;
+ int16 rectY = _frames[frame]._y2 - _frames[frame]._y1;
- int32 finalWidth = rectX * scale / 1024;
- int32 finalHeight = rectY * scale / 1024;
+ int16 finalWidth = rectX * scale / 1024;
+ int16 finalHeight = rectY * scale / 1024;
// compute final x1, y1, x2, y2
- int32 xx1 = xx + _x1 + _frames[frame]._x1 * scale / 1024;
- int32 yy1 = yy + _y1 + _frames[frame]._y1 * scale / 1024;
- int32 xx2 = xx1 + finalWidth;
- int32 yy2 = yy1 + finalHeight;
- int32 w = _frames[frame]._x2 - _frames[frame]._x1;
+ int16 xx1 = xx + _x1 + _frames[frame]._x1 * scale / 1024;
+ int16 yy1 = yy + _y1 + _frames[frame]._y1 * scale / 1024;
+ int16 xx2 = xx1 + finalWidth;
+ int16 yy2 = yy1 + finalHeight;
+ int16 w = _frames[frame]._x2 - _frames[frame]._x1;
_vm->addDirtyRect(xx1, yy1, xx2, yy2);
@@ -233,8 +236,8 @@ void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 fram
if (strstr(_name, "SHADOW"))
shadowFlag = true;
- for (int32 y = yy1; y < yy2; y++) {
- for (int32 x = xx1; x < xx2; x++) {
+ for (int16 y = yy1; y < yy2; y++) {
+ for (int16 x = xx1; x < xx2; x++) {
if (x < 0 || x >= 1280 || y < 0 || y >= 400)
continue;
@@ -242,8 +245,8 @@ void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 fram
uint8 *curMask = curRowMask + x + y * destPitchMask;
// find the good c
- int32 xs = (x - xx1) * 1024 / scale;
- int32 ys = (y - yy1) * 1024 / scale;
+ int16 xs = (x - xx1) * 1024 / scale;
+ int16 ys = (y - yy1) * 1024 / scale;
uint8 *cc = &c[ys * w + xs];
if (*cc && ((*curMask) >= zz)) {
if (shadowFlag)
@@ -272,7 +275,7 @@ Common::Rect Animation::getFrameRect(int32 frame) {
return Common::Rect(_frames[frame]._x1, _frames[frame]._y1, _frames[frame]._x2, _frames[frame]._y2);
}
-int32 Animation::getFrameWidth(int32 frame) {
+int16 Animation::getFrameWidth(int32 frame) {
debugC(4, kDebugAnim, "getFrameWidth(%d)", frame);
if ((frame < 0) || (frame >= _numFrames))
return 0;
@@ -283,7 +286,7 @@ int32 Animation::getFrameWidth(int32 frame) {
return _frames[frame]._x2 - _frames[frame]._x1;
}
-int32 Animation::getFrameHeight(int32 frame) {
+int16 Animation::getFrameHeight(int32 frame) {
debugC(4, kDebugAnim, "getFrameHeight(%d)", frame);
if (frame < 0 || frame >= _numFrames)
return 0;
@@ -294,15 +297,15 @@ int32 Animation::getFrameHeight(int32 frame) {
return _frames[frame]._y2 - _frames[frame]._y1;
}
-int32 Animation::getWidth() const {
+int16 Animation::getWidth() const {
return _x2 - _x1;
}
-int32 Animation::getHeight() const {
+int16 Animation::getHeight() const {
return _y2 - _y1;
}
-void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, byte *colorMap) {
+void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, byte *colorMap) {
debugC(4, kDebugAnim, "drawFontFrame(surface, %d, %d, %d, colorMap)", frame, xx, yy);
if (frame < 0)
frame = 0;
@@ -316,8 +319,8 @@ void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx,
if (_frames[frame]._ref != -1)
frame = _frames[frame]._ref;
- int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
- int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+ int16 rectX = _frames[frame]._x2 - _frames[frame]._x1;
+ int16 rectY = _frames[frame]._y2 - _frames[frame]._y1;
if ((xx + _x1 + _frames[frame]._x1 < 0) || (yy + _y1 + _frames[frame]._y1 < 0))
return;
@@ -337,9 +340,9 @@ void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx,
int32 destPitch = surface.pitch;
uint8 *c = _frames[frame]._data;
uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1);
- for (int32 y = 0; y < rectY; y++) {
+ for (int16 y = 0; y < rectY; y++) {
unsigned char *cur = curRow;
- for (int32 x = 0; x < rectX; x++) {
+ for (int16 x = 0; x < rectX; x++) {
if (*c && *c < 4)
*cur = colorMap[*c];
c++;
@@ -349,7 +352,7 @@ void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx,
}
}
-void Animation::drawFrameOnPicture(int32 frame, int32 xx, int32 yy) {
+void Animation::drawFrameOnPicture(int32 frame, int16 xx, int16 yy) {
debugC(1, kDebugAnim, "drawFrameOnPicture(%d, %d, %d)", frame, xx, yy);
if (frame < 0)
frame = 0;
@@ -363,8 +366,8 @@ void Animation::drawFrameOnPicture(int32 frame, int32 xx, int32 yy) {
if (_frames[frame]._ref != -1)
frame = _frames[frame]._ref;
- int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
- int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+ int16 rectX = _frames[frame]._x2 - _frames[frame]._x1;
+ int16 rectY = _frames[frame]._y2 - _frames[frame]._y1;
Picture *pic = _vm->getPicture();
@@ -386,9 +389,9 @@ void Animation::drawFrameOnPicture(int32 frame, int32 xx, int32 yy) {
int32 destPitch = pic->getWidth();
uint8 *c = _frames[frame]._data;
uint8 *curRow = (uint8 *)pic->getDataPtr() + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1);
- for (int32 y = 0; y < rectY; y++) {
+ for (int16 y = 0; y < rectY; y++) {
unsigned char *cur = curRow;
- for (int32 x = 0; x < rectX; x++) {
+ for (int16 x = 0; x < rectX; x++) {
if (*c)
*cur = *c;
c++;
@@ -455,8 +458,8 @@ void AnimationInstance::render() {
if (frame >= _animation->_numFrames)
frame = _animation->_numFrames - 1;
- int32 x = _x;
- int32 y = _y;
+ int16 x = _x;
+ int16 y = _y;
if (_alignBottom) {
int32 offsetX = (_animation->_x2 - _animation->_x1) / 2 * (_scale - 1024);
@@ -498,7 +501,7 @@ void AnimationInstance::setAnimation(Animation *animation, bool setRange) {
}
}
-void AnimationInstance::setAnimationRange(int32 rangeStart, int rangeEnd) {
+void AnimationInstance::setAnimationRange(int32 rangeStart, int32 rangeEnd) {
debugC(5, kDebugAnim, "setAnimationRange(%d, %d)", rangeStart, rangeEnd);
_rangeStart = rangeStart;
_rangeEnd = rangeEnd;
@@ -510,7 +513,7 @@ void AnimationInstance::setAnimationRange(int32 rangeStart, int rangeEnd) {
_currentFrame = _rangeEnd;
}
-void AnimationInstance::setPosition(int32 x, int32 y, int32 z, bool relative) {
+void AnimationInstance::setPosition(int16 x, int16 y, int32 z, bool relative) {
debugC(5, kDebugAnim, "setPosition(%d, %d, %d, %d)", x, y, z, (relative) ? 1 : 0);
if (relative || !_animation) {
_x = x;
@@ -523,7 +526,7 @@ void AnimationInstance::setPosition(int32 x, int32 y, int32 z, bool relative) {
}
}
-void AnimationInstance::moveRelative(int32 dx, int32 dy, int32 dz) {
+void AnimationInstance::moveRelative(int16 dx, int16 dy, int32 dz) {
debugC(1, kDebugAnim, "moveRelative(%d, %d, %d)", dx, dy, dz);
_x += dx;
_y += dy;
@@ -568,13 +571,13 @@ void AnimationInstance::setUseMask(bool useMask) {
_useMask = useMask;
}
-void AnimationInstance::getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) const {
+void AnimationInstance::getRect(int16 *x1, int16 *y1, int16 *x2, int16 *y2) const {
debugC(5, kDebugAnim, "getRect(%d, %d, %d, %d)", *x1, *y1, *x2, *y2);
- int32 rectX = _animation->_frames[_currentFrame]._x2 - _animation->_frames[_currentFrame]._x1;
- int32 rectY = _animation->_frames[_currentFrame]._y2 - _animation->_frames[_currentFrame]._y1;
+ int16 rectX = _animation->_frames[_currentFrame]._x2 - _animation->_frames[_currentFrame]._x1;
+ int16 rectY = _animation->_frames[_currentFrame]._y2 - _animation->_frames[_currentFrame]._y1;
- int32 finalWidth = rectX * _scale / 1024;
- int32 finalHeight = rectY * _scale / 1024;
+ int16 finalWidth = rectX * _scale / 1024;
+ int16 finalHeight = rectY * _scale / 1024;
// compute final x1, y1, x2, y2
*x1 = _x + _animation->_x1 + _animation->_frames[_currentFrame]._x1 * _scale / 1024;
@@ -583,7 +586,7 @@ void AnimationInstance::getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) cons
*y2 = *y1 + finalHeight;
}
-void AnimationInstance::setX(int32 x, bool relative) {
+void AnimationInstance::setX(int16 x, bool relative) {
debugC(1, kDebugAnim, "setX(%d, %d)", x, (relative) ? 1 : 0);
if (relative || !_animation)
_x = x;
@@ -591,7 +594,7 @@ void AnimationInstance::setX(int32 x, bool relative) {
_x = x - _animation->_x1;
}
-void AnimationInstance::setY(int32 y, bool relative) {
+void AnimationInstance::setY(int16 y, bool relative) {
debugC(1, kDebugAnim, "setY(%d, %d)", y, (relative) ? 1 : 0);
if (relative || !_animation)
_y = y;
@@ -614,11 +617,11 @@ int32 AnimationInstance::getLayerZ() const {
return _layerZ;
}
-int32 AnimationInstance::getX2() const {
+int16 AnimationInstance::getX2() const {
return _x + _animation->_x1;
}
-int32 AnimationInstance::getY2() const {
+int16 AnimationInstance::getY2() const {
return _y + _animation->_y1;
}
@@ -647,6 +650,7 @@ void AnimationInstance::save(Common::WriteStream *stream) {
stream->writeSint32LE(_visible);
stream->writeSint32LE(_useMask);
}
+
void AnimationInstance::load(Common::ReadStream *stream) {
_currentFrame = stream->readSint32LE();
_currentTime = stream->readSint32LE();
@@ -695,14 +699,13 @@ void AnimationManager::updateInstance(AnimationInstance* instance) {
}
void AnimationManager::addInstance(AnimationInstance *instance) {
-
// if the instance already exists, we skip the add
for (uint32 i = 0; i < _instances.size(); i++) {
if (_instances[i] == instance)
return;
}
- int found = -1;
+ int32 found = -1;
// here we now do an ordered insert (closer to the original game)
for (uint32 i = 0; i < _instances.size(); i++) {
@@ -712,11 +715,10 @@ void AnimationManager::addInstance(AnimationInstance *instance) {
}
}
- if ( found == -1 ) {
+ if (found == -1)
_instances.push_back(instance);
- } else {
+ else
_instances.insert_at(found, instance);
- }
}
void AnimationManager::removeInstance(AnimationInstance *instance) {
diff --git a/engines/toon/anim.h b/engines/toon/anim.h
index eb8dcbd600..cd550b2621 100644
--- a/engines/toon/anim.h
+++ b/engines/toon/anim.h
@@ -36,10 +36,10 @@ class Picture;
class ToonEngine;
struct AnimationFrame {
- int32 _x1;
- int32 _y1;
- int32 _x2;
- int32 _y2;
+ int16 _x1;
+ int16 _y1;
+ int16 _x2;
+ int16 _y2;
int32 _ref;
uint8 *_data;
};
@@ -49,10 +49,10 @@ public:
Animation(ToonEngine *vm);
~Animation();
- int32 _x1;
- int32 _y1;
- int32 _x2;
- int32 _y2;
+ int16 _x1;
+ int16 _y1;
+ int16 _x2;
+ int16 _y2;
int32 _numFrames;
int32 _fps;
AnimationFrame *_frames;
@@ -61,18 +61,18 @@ public:
char _name[32];
bool loadAnimation(const Common::String &file);
- void drawFrame(Graphics::Surface &surface, int32 frame, int32 x, int32 y);
- void drawFontFrame(Graphics::Surface &surface, int32 frame, int32 x, int32 y, byte *colorMap);
- void drawFrameOnPicture(int32 frame, int32 x, int32 y);
- void drawFrameWithMask(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask);
- void drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask, int32 scale);
+ void drawFrame(Graphics::Surface &surface, int32 frame, int16 x, int16 y);
+ void drawFontFrame(Graphics::Surface &surface, int32 frame, int16 x, int16 y, byte *colorMap);
+ void drawFrameOnPicture(int32 frame, int16 x, int16 y);
+ void drawFrameWithMask(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask);
+ void drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask, int32 scale);
void drawStrip(int32 offset = 0);
void applyPalette(int32 offset, int32 srcOffset, int32 numEntries);
Common::Rect getFrameRect(int32 frame);
- int32 getFrameWidth(int32 frame);
- int32 getFrameHeight(int32 frame);
- int32 getWidth() const;
- int32 getHeight() const;
+ int16 getFrameWidth(int32 frame);
+ int16 getFrameHeight(int32 frame);
+ int16 getWidth() const;
+ int16 getHeight() const;
Common::Rect getRect();
protected:
ToonEngine *_vm;
@@ -92,25 +92,25 @@ public:
void renderOnPicture();
void setAnimation(Animation *animation, bool setRange = true);
void playAnimation();
- void setAnimationRange(int32 rangeStart, int rangeEnd);
+ void setAnimationRange(int32 rangeStart, int32 rangeEnd);
void setFps(int32 fps);
void setLooping(bool enable);
void stopAnimation();
void setFrame(int32 position);
void forceFrame(int32 position);
- void setPosition(int32 x, int32 y, int32 z, bool relative = false);
+ void setPosition(int16 x, int16 y, int32 z, bool relative = false);
Animation *getAnimation() const { return _animation; }
void setScale(int32 scale, bool align = false);
void setVisible(bool visible);
bool getVisible() const { return _visible; }
void setUseMask(bool useMask);
- void moveRelative(int32 dx, int32 dy, int32 dz);
- void getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) const;
- int32 getX() const { return _x; }
- int32 getY() const { return _y; }
+ void moveRelative(int16 dx, int16 dy, int32 dz);
+ void getRect(int16 *x1, int16 *y1, int16 *x2, int16 *y2) const;
+ int16 getX() const { return _x; }
+ int16 getY() const { return _y; }
int32 getZ() const { return _z; }
- int32 getX2() const;
- int32 getY2() const;
+ int16 getX2() const;
+ int16 getY2() const;
int32 getZ2() const;
int32 getFrame() const { return _currentFrame; }
void reset();
@@ -120,8 +120,8 @@ public:
void setId(int32 id) { _id = id; }
int32 getId() const { return _id; }
- void setX(int32 x, bool relative = false);
- void setY(int32 y, bool relative = false);
+ void setX(int16 x, bool relative = false);
+ void setY(int16 y, bool relative = false);
void setZ(int32 z, bool relative = false);
void setLayerZ(int32 layer);
int32 getLayerZ() const;
@@ -133,8 +133,8 @@ protected:
int32 _currentTime;
int32 _fps;
Animation *_animation;
- int32 _x;
- int32 _y;
+ int16 _x;
+ int16 _y;
int32 _z;
int32 _layerZ;
int32 _rangeStart;
diff --git a/engines/toon/audio.cpp b/engines/toon/audio.cpp
index 77822ab078..bc0e051057 100644
--- a/engines/toon/audio.cpp
+++ b/engines/toon/audio.cpp
@@ -326,7 +326,7 @@ bool AudioStreamInstance::readPacket() {
}
if (numDecompressedBytes > _bufferMaxSize) {
- delete [] _buffer;
+ delete[] _buffer;
_bufferMaxSize = numDecompressedBytes;
_buffer = new int16[numDecompressedBytes];
}
diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp
index 09730626f2..479f4965f3 100644
--- a/engines/toon/character.cpp
+++ b/engines/toon/character.cpp
@@ -62,7 +62,7 @@ Character::Character(ToonEngine *vm) : _vm(vm) {
_speed = 150; // 150 = nominal drew speed
_lastWalkTime = 0;
_numPixelToWalk = 0;
- _nextIdleTime = _vm->getSystem()->getMillis() + (_vm->randRange(0, 600) + 300) * _vm->getTickLength();
+ _nextIdleTime = _vm->_system->getMillis() + (_vm->randRange(0, 600) + 300) * _vm->getTickLength();
_lineToSayId = 0;
}
@@ -101,7 +101,7 @@ void Character::setFacing(int32 facing) {
int32 dir = 0;
- _lastWalkTime = _vm->getSystem()->getMillis();
+ _lastWalkTime = _vm->_system->getMillis();
if ((_facing - facing + 8) % 8 > (facing - _facing + 8) % 8)
dir = 1;
else
@@ -188,7 +188,7 @@ bool Character::walkTo(int16 newPosX, int16 newPosY) {
_currentPathNode = 0;
stopSpecialAnim();
- _lastWalkTime = _vm->getSystem()->getMillis();
+ _lastWalkTime = _vm->_system->getMillis();
_numPixelToWalk = 0;
@@ -220,8 +220,8 @@ bool Character::walkTo(int16 newPosX, int16 newPosY) {
}
// in 1/1000 pixels
- _numPixelToWalk += _speed * (_vm->getSystem()->getMillis() - _lastWalkTime) * _scale / 1024;
- _lastWalkTime = _vm->getSystem()->getMillis();
+ _numPixelToWalk += _speed * (_vm->_system->getMillis() - _lastWalkTime) * _scale / 1024;
+ _lastWalkTime = _vm->_system->getMillis();
while (_numPixelToWalk >= 1000 && _currentPathNode < _currentPath.size()) {
_x = _currentPath[_currentPathNode].x;
@@ -356,8 +356,8 @@ void Character::update(int32 timeIncrement) {
}
// in 1/1000 pixels
- _numPixelToWalk += _speed * (_vm->getSystem()->getMillis() - _lastWalkTime) * _scale / 1024;
- _lastWalkTime = _vm->getSystem()->getMillis();
+ _numPixelToWalk += _speed * (_vm->_system->getMillis() - _lastWalkTime) * _scale / 1024;
+ _lastWalkTime = _vm->_system->getMillis();
while (_numPixelToWalk > 1000 && _currentPathNode < _currentPath.size()) {
_x = _currentPath[_currentPathNode].x;
@@ -534,35 +534,33 @@ int32 Character::getFacingFromDirection(int16 dx, int16 dy) {
dx = -dx;
int32 facingEntry = 0;
- int32 ydiff = dy;
+ int16 ydiff = dy;
if (ydiff < 0) {
++facingEntry;
ydiff = -ydiff;
}
- facingEntry <<= 1;
+ facingEntry *= 2;
- int32 xdiff = dx;
+ int16 xdiff = dx;
if (xdiff < 0) {
++facingEntry;
xdiff = -xdiff;
}
- facingEntry <<= 1;
+ facingEntry *= 2;
if (xdiff >= ydiff) {
- int32 temp = ydiff;
+ // Swap xdiff and ydiff
+ int16 temp = ydiff;
ydiff = xdiff;
xdiff = temp;
- } else {
- facingEntry += 1;
- }
-
- facingEntry <<= 1;
+ } else
+ facingEntry++;
- int32 temp = (ydiff + 1) >> 1;
+ facingEntry *= 2;
- if (xdiff < temp)
- facingEntry += 1;
+ if (xdiff < ((ydiff + 1) / 2))
+ facingEntry++;
return facingTable[facingEntry];
}
diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp
index 8234934972..3877fa2a6c 100644
--- a/engines/toon/detection.cpp
+++ b/engines/toon/detection.cpp
@@ -133,7 +133,7 @@ public:
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- return detectGameFilebased(allFiles, Toon::fileBasedFallback);
+ return detectGameFilebased(allFiles, fslist, Toon::fileBasedFallback);
}
virtual const char *getName() const {
@@ -234,9 +234,6 @@ SaveStateDescriptor ToonMetaEngine::querySaveMetaInfos(const char *target, int s
Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
desc.setThumbnail(thumbnail);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
-
uint32 saveDate = file->readUint32BE();
uint16 saveTime = file->readUint16BE();
diff --git a/engines/toon/font.cpp b/engines/toon/font.cpp
index d58663a00c..1e851ff4ae 100644
--- a/engines/toon/font.cpp
+++ b/engines/toon/font.cpp
@@ -65,10 +65,10 @@ byte FontRenderer::textToFont(byte c) {
return map_textToFont[c - 0x80];
}
-void FontRenderer::renderText(int32 x, int32 y, const Common::String &origText, int32 mode) {
+void FontRenderer::renderText(int16 x, int16 y, const Common::String &origText, int32 mode) {
debugC(5, kDebugFont, "renderText(%d, %d, %s, %d)", x, y, origText.c_str(), mode);
- int32 xx, yy;
+ int16 xx, yy;
computeSize(origText, &xx, &yy);
if (mode & 2) {
@@ -83,8 +83,8 @@ void FontRenderer::renderText(int32 x, int32 y, const Common::String &origText,
_vm->addDirtyRect(x, y, x + xx, y + yy);
- int32 curX = x;
- int32 curY = y;
+ int16 curX = x;
+ int16 curY = y;
int32 height = 0;
const byte *text = (const byte *)origText.c_str();
@@ -98,20 +98,20 @@ void FontRenderer::renderText(int32 x, int32 y, const Common::String &origText,
curChar = textToFont(curChar);
_currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX, curY, _currentFontColor);
curX = curX + _currentFont->getFrameWidth(curChar) - 1;
- height = MAX(height, _currentFont->getFrameHeight(curChar));
+ height = MAX<int32>(height, _currentFont->getFrameHeight(curChar));
}
text++;
}
}
-void FontRenderer::computeSize(const Common::String &origText, int32 *retX, int32 *retY) {
+void FontRenderer::computeSize(const Common::String &origText, int16 *retX, int16 *retY) {
debugC(4, kDebugFont, "computeSize(%s, retX, retY)", origText.c_str());
- int32 lineWidth = 0;
- int32 lineHeight = 0;
- int32 totalHeight = 0;
- int32 totalWidth = 0;
- int32 lastLineHeight = 0;
+ int16 lineWidth = 0;
+ int16 lineHeight = 0;
+ int16 totalHeight = 0;
+ int16 totalWidth = 0;
+ int16 lastLineHeight = 0;
const byte *text = (const byte *)origText.c_str();
while (*text) {
@@ -127,8 +127,8 @@ void FontRenderer::computeSize(const Common::String &origText, int32 *retX, int3
lastLineHeight = 0;
} else {
curChar = textToFont(curChar);
- int32 charWidth = _currentFont->getFrameWidth(curChar) - 1;
- int32 charHeight = _currentFont->getFrameHeight(curChar);
+ int16 charWidth = _currentFont->getFrameWidth(curChar) - 1;
+ int16 charHeight = _currentFont->getFrameHeight(curChar);
lineWidth += charWidth;
lineHeight = MAX(lineHeight, charHeight);
@@ -137,7 +137,7 @@ void FontRenderer::computeSize(const Common::String &origText, int32 *retX, int3
// assume we only need to take the lower bound into
// consideration.
Common::Rect charRect = _currentFont->getFrameRect(curChar);
- lastLineHeight = MAX<int32>(lastLineHeight, charRect.bottom);
+ lastLineHeight = MAX(lastLineHeight, charRect.bottom);
}
text++;
}
@@ -189,7 +189,7 @@ void FontRenderer::setFontColor(int32 fontColor1, int32 fontColor2, int32 fontCo
_currentFontColor[3] = fontColor3;
}
-void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &origText, int32 mode) {
+void FontRenderer::renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode) {
debugC(5, kDebugFont, "renderMultiLineText(%d, %d, %s, %d)", x, y, origText.c_str(), mode);
// divide the text in several lines
@@ -204,10 +204,10 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &o
byte *it = text;
- int32 maxWidth = 0;
- int32 curWidth = 0;
+ int16 maxWidth = 0;
+ int16 curWidth = 0;
- while (1) {
+ while (true) {
byte *lastLine = it;
byte *lastSpace = it;
int32 lastSpaceX = 0;
@@ -223,7 +223,7 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &o
curChar = textToFont(curChar);
int width = _currentFont->getFrameWidth(curChar);
- curWidth += MAX<int32>(width - 2, 0);
+ curWidth += MAX(width - 2, 0);
it++;
curLetterNr++;
}
@@ -260,8 +260,8 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &o
//numLines++;
// get font height (assumed to be constant)
- int32 height = _currentFont->getHeight();
- int textSize = (height - 2) * numLines;
+ int16 height = _currentFont->getHeight();
+ int32 textSize = (height - 2) * numLines;
y = y - textSize;
if (y < 30)
y = 30;
@@ -278,8 +278,8 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &o
x = TOON_SCREEN_WIDTH - (maxWidth / 2) - 30;
// we have good coordinates now, we can render the multi line
- int32 curX = x;
- int32 curY = y;
+ int16 curX = x;
+ int16 curY = y;
for (int32 i = 0; i < numLines; i++) {
const byte *line = lines[i];
diff --git a/engines/toon/font.h b/engines/toon/font.h
index 349d9d1ee7..2a46ad3559 100644
--- a/engines/toon/font.h
+++ b/engines/toon/font.h
@@ -33,9 +33,9 @@ public:
~FontRenderer();
void setFont(Animation *font);
- void computeSize(const Common::String &origText, int32 *retX, int32 *retY);
- void renderText(int32 x, int32 y, const Common::String &origText, int32 mode);
- void renderMultiLineText(int32 x, int32 y, const Common::String &origText, int32 mode);
+ void computeSize(const Common::String &origText, int16 *retX, int16 *retY);
+ void renderText(int16 x, int16 y, const Common::String &origText, int32 mode);
+ void renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode);
void setFontColorByCharacter(int32 characterId);
void setFontColor(int32 fontColor1, int32 fontColor2, int32 fontColor3);
protected:
diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp
index ce2cdf1bb9..8b8f0ab577 100644
--- a/engines/toon/hotspot.cpp
+++ b/engines/toon/hotspot.cpp
@@ -57,7 +57,7 @@ void Hotspots::save(Common::WriteStream *Stream) {
}
}
-int32 Hotspots::FindBasedOnCorner(int32 x, int32 y) {
+int32 Hotspots::FindBasedOnCorner(int16 x, int16 y) {
debugC(1, kDebugHotspot, "FindBasedOnCorner(%d, %d)", x, y);
for (int32 i = 0; i < _numItems; i++) {
@@ -73,7 +73,7 @@ int32 Hotspots::FindBasedOnCorner(int32 x, int32 y) {
return -1;
}
-int32 Hotspots::Find(int32 x, int32 y) {
+int32 Hotspots::Find(int16 x, int16 y) {
debugC(6, kDebugHotspot, "Find(%d, %d)", x, y);
int32 priority = -1;
diff --git a/engines/toon/hotspot.h b/engines/toon/hotspot.h
index 70e80046e1..3852e2e42e 100644
--- a/engines/toon/hotspot.h
+++ b/engines/toon/hotspot.h
@@ -51,8 +51,8 @@ public:
~Hotspots();
bool LoadRif(const Common::String &rifName, const Common::String &additionalRifName);
- int32 Find(int32 x, int32 y);
- int32 FindBasedOnCorner(int32 x, int32 y);
+ int32 Find(int16 x, int16 y);
+ int32 FindBasedOnCorner(int16 x, int16 y);
HotspotData *Get(int32 id);
int32 getCount() const { return _numItems; }
diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp
index 8cdf92363f..8c85e20f7c 100644
--- a/engines/toon/movie.cpp
+++ b/engines/toon/movie.cpp
@@ -25,6 +25,7 @@
#include "common/keyboard.h"
#include "common/stream.h"
#include "common/system.h"
+#include "graphics/palette.h"
#include "graphics/surface.h"
#include "toon/audio.h"
@@ -33,6 +34,10 @@
namespace Toon {
+ToonstruckSmackerDecoder::ToonstruckSmackerDecoder() : Video::SmackerDecoder() {
+ _lowRes = false;
+}
+
void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) {
debugC(6, kDebugMovie, "handleAudioTrack(%d, %d, %d)", track, chunkSize, unpackedSize);
@@ -40,33 +45,21 @@ void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, ui
/* uint16 width = */ _fileStream->readUint16LE();
uint16 height = _fileStream->readUint16LE();
_lowRes = (height == getHeight() / 2);
- } else
+ } else {
Video::SmackerDecoder::handleAudioTrack(track, chunkSize, unpackedSize);
+ }
}
-bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename) {
- debugC(1, kDebugMovie, "loadFile(%s)", filename.c_str());
+bool ToonstruckSmackerDecoder::loadStream(Common::SeekableReadStream *stream) {
+ if (!Video::SmackerDecoder::loadStream(stream))
+ return false;
_lowRes = false;
-
- if (Video::SmackerDecoder::loadFile(filename)) {
- if (_surface->h == 200) {
- if (_surface) {
- _surface->free();
- delete _surface;
- }
- _surface = new Graphics::Surface();
- _surface->create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
- _header.flags = 4;
- }
-
- return true;
- }
- return false;
+ return true;
}
-ToonstruckSmackerDecoder::ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : Video::SmackerDecoder(mixer, soundType) {
- _lowRes = false;
+Video::SmackerDecoder::SmackerVideoTrack *ToonstruckSmackerDecoder::createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const {
+ return Video::SmackerDecoder::createVideoTrack(width, height, frameCount, frameRate, (height == 200) ? 4 : flags, signature);
}
// decoder is deallocated with Movie destruction i.e. new ToonstruckSmackerDecoder is needed
@@ -103,46 +96,49 @@ void Movie::play(const Common::String &video, int32 flags) {
bool Movie::playVideo(bool isFirstIntroVideo) {
debugC(1, kDebugMovie, "playVideo(isFirstIntroVideo: %d)", isFirstIntroVideo);
+
+ _decoder->start();
+
while (!_vm->shouldQuit() && !_decoder->endOfVideo()) {
if (_decoder->needsUpdate()) {
const Graphics::Surface *frame = _decoder->decodeNextFrame();
if (frame) {
if (_decoder->isLowRes()) {
// handle manually 2x scaling here
- Graphics::Surface* surf = _vm->getSystem()->lockScreen();
+ Graphics::Surface* surf = _vm->_system->lockScreen();
for (int y = 0; y < frame->h / 2; y++) {
memcpy(surf->getBasePtr(0, y * 2 + 0), frame->getBasePtr(0, y), frame->pitch);
memcpy(surf->getBasePtr(0, y * 2 + 1), frame->getBasePtr(0, y), frame->pitch);
}
- _vm->getSystem()->unlockScreen();
+ _vm->_system->unlockScreen();
} else {
- _vm->getSystem()->copyRectToScreen(frame->pixels, frame->pitch, 0, 0, frame->w, frame->h);
+ _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, 0, 0, frame->w, frame->h);
// WORKAROUND: There is an encoding glitch in the first intro video. This hides this using the adjacent pixels.
if (isFirstIntroVideo) {
int32 currentFrame = _decoder->getCurFrame();
if (currentFrame >= 956 && currentFrame <= 1038) {
debugC(1, kDebugMovie, "Triggered workaround for glitch in first intro video...");
- _vm->getSystem()->copyRectToScreen(frame->getBasePtr(frame->w-188, 123), frame->pitch, frame->w-188, 124, 188, 1);
- _vm->getSystem()->copyRectToScreen(frame->getBasePtr(frame->w-188, 126), frame->pitch, frame->w-188, 125, 188, 1);
- _vm->getSystem()->copyRectToScreen(frame->getBasePtr(0, 125), frame->pitch, 0, 126, 64, 1);
- _vm->getSystem()->copyRectToScreen(frame->getBasePtr(0, 128), frame->pitch, 0, 127, 64, 1);
+ _vm->_system->copyRectToScreen(frame->getBasePtr(frame->w-188, 123), frame->pitch, frame->w-188, 124, 188, 1);
+ _vm->_system->copyRectToScreen(frame->getBasePtr(frame->w-188, 126), frame->pitch, frame->w-188, 125, 188, 1);
+ _vm->_system->copyRectToScreen(frame->getBasePtr(0, 125), frame->pitch, 0, 126, 64, 1);
+ _vm->_system->copyRectToScreen(frame->getBasePtr(0, 128), frame->pitch, 0, 127, 64, 1);
}
}
}
}
- _decoder->setSystemPalette();
- _vm->getSystem()->updateScreen();
+ _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256);
+ _vm->_system->updateScreen();
}
Common::Event event;
- while (_vm->getSystem()->getEventManager()->pollEvent(event))
+ while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE)) {
_vm->dirtyAllScreen();
return false;
}
- _vm->getSystem()->delayMillis(10);
+ _vm->_system->delayMillis(10);
}
_vm->dirtyAllScreen();
return !_vm->shouldQuit();
diff --git a/engines/toon/movie.h b/engines/toon/movie.h
index 2cd33302f2..e795182cba 100644
--- a/engines/toon/movie.h
+++ b/engines/toon/movie.h
@@ -30,13 +30,17 @@ namespace Toon {
class ToonstruckSmackerDecoder : public Video::SmackerDecoder {
public:
- ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType);
- virtual ~ToonstruckSmackerDecoder() {}
- void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize);
- bool loadFile(const Common::String &filename);
+ ToonstruckSmackerDecoder();
+
+ bool loadStream(Common::SeekableReadStream *stream);
bool isLowRes() { return _lowRes; }
+
protected:
- bool _lowRes;
+ void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize);
+ SmackerVideoTrack *createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const;
+
+private:
+ bool _lowRes;
};
class Movie {
diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp
index ff136e5acb..204b0fe576 100644
--- a/engines/toon/picture.cpp
+++ b/engines/toon/picture.cpp
@@ -150,7 +150,7 @@ void Picture::setupPalette() {
_vm->setPaletteEntries(_palette, 1, 128);
}
-void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy) {
+void Picture::drawMask(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 dy) {
debugC(1, kDebugPicture, "drawMask(surface, %d, %d, %d, %d)", x, y, dx, dy);
for (int32 i = 0; i < 128; i++) {
@@ -161,8 +161,8 @@ void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, i
_vm->setPaletteEntries(color, i, 1);
}
- int32 rx = MIN(_width, surface.w - x);
- int32 ry = MIN(_height, surface.h - y);
+ int16 rx = MIN<int16>(_width, surface.w - x);
+ int16 ry = MIN<int16>(_height, surface.h - y);
if (rx < 0 || ry < 0)
return;
@@ -172,10 +172,10 @@ void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, i
uint8 *c = _data + _width * dy + dx;
uint8 *curRow = (uint8 *)surface.pixels + y * destPitch + x;
- for (int32 yy = 0; yy < ry; yy++) {
+ for (int16 yy = 0; yy < ry; yy++) {
uint8 *curSrc = c;
uint8 *cur = curRow;
- for (int32 xx = 0; xx < rx; xx++) {
+ for (int16 xx = 0; xx < rx; xx++) {
//*cur = (*curSrc >> 5) * 8; // & 0x1f;
*cur = (*curSrc & 0x1f) ? 127 : 0;
@@ -187,10 +187,9 @@ void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, i
}
}
-void Picture::drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray) {
-
- int32 rx = MIN(_width, surface.w - x);
- int32 ry = MIN(_height, surface.h - y);
+void Picture::drawWithRectList(Graphics::Surface& surface, int16 x, int16 y, int16 dx, int16 dy, Common::Array<Common::Rect>& rectArray) {
+ int16 rx = MIN<int16>(_width, surface.w - x);
+ int16 ry = MIN<int16>(_height, surface.h - y);
if (rx < 0 || ry < 0)
return;
@@ -202,16 +201,16 @@ void Picture::drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int
Common::Rect rect = rectArray[i];
- int32 fillRx = MIN<int32>(rx, rect.right - rect.left);
- int32 fillRy = MIN<int32>(ry, rect.bottom - rect.top);
+ int16 fillRx = MIN<int32>(rx, rect.right - rect.left);
+ int16 fillRy = MIN<int32>(ry, rect.bottom - rect.top);
uint8 *c = _data + _width * (dy + rect.top) + (dx + rect.left);
uint8 *curRow = (uint8 *)surface.pixels + (y + rect.top) * destPitch + (x + rect.left);
- for (int32 yy = 0; yy < fillRy; yy++) {
+ for (int16 yy = 0; yy < fillRy; yy++) {
uint8 *curSrc = c;
uint8 *cur = curRow;
- for (int32 xx = 0; xx < fillRx; xx++) {
+ for (int16 xx = 0; xx < fillRx; xx++) {
*cur = *curSrc;
curSrc++;
cur++;
@@ -222,11 +221,11 @@ void Picture::drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int
}
}
-void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy) {
+void Picture::draw(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 dy) {
debugC(6, kDebugPicture, "draw(surface, %d, %d, %d, %d)", x, y, dx, dy);
- int32 rx = MIN(_width, surface.w - x);
- int32 ry = MIN(_height, surface.h - y);
+ int16 rx = MIN<int16>(_width, surface.w - x);
+ int16 ry = MIN<int16>(_height, surface.h - y);
if (rx < 0 || ry < 0)
return;
@@ -236,10 +235,10 @@ void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32
uint8 *c = _data + _width * dy + dx;
uint8 *curRow = (uint8 *)surface.pixels + y * destPitch + x;
- for (int32 yy = 0; yy < ry; yy++) {
+ for (int16 yy = 0; yy < ry; yy++) {
uint8 *curSrc = c;
uint8 *cur = curRow;
- for (int32 xx = 0; xx < rx; xx++) {
+ for (int16 xx = 0; xx < rx; xx++) {
*cur = *curSrc;
curSrc++;
cur++;
@@ -249,7 +248,7 @@ void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32
}
}
-uint8 Picture::getData(int32 x, int32 y) {
+uint8 Picture::getData(int16 x, int16 y) {
debugC(6, kDebugPicture, "getData(%d, %d)", x, y);
if (!_data)
@@ -259,7 +258,7 @@ uint8 Picture::getData(int32 x, int32 y) {
}
// use original work from johndoe
-void Picture::floodFillNotWalkableOnMask(int32 x, int32 y) {
+void Picture::floodFillNotWalkableOnMask(int16 x, int16 y) {
debugC(1, kDebugPicture, "floodFillNotWalkableOnMask(%d, %d)", x, y);
// Stack-based floodFill algorithm based on
// http://student.kuleuven.be/~m0216922/CG/files/floodfill.cpp
@@ -292,10 +291,10 @@ void Picture::floodFillNotWalkableOnMask(int32 x, int32 y) {
}
}
-void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable) {
+void Picture::drawLineOnMask(int16 x, int16 y, int16 x2, int16 y2, bool walkable) {
debugC(1, kDebugPicture, "drawLineOnMask(%d, %d, %d, %d, %d)", x, y, x2, y2, (walkable) ? 1 : 0);
- static int32 lastX = 0;
- static int32 lastY = 0;
+ static int16 lastX = 0;
+ static int16 lastY = 0;
if (x == -1) {
x = lastX;
@@ -303,12 +302,12 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable
}
uint32 bx = x << 16;
- int32 dx = x2 - x;
+ int16 dx = x2 - x;
uint32 by = y << 16;
- int32 dy = y2 - y;
- uint32 adx = abs(dx);
- uint32 ady = abs(dy);
- int32 t = 0;
+ int16 dy = y2 - y;
+ uint16 adx = abs(dx);
+ uint16 ady = abs(dy);
+ int16 t = 0;
if (adx <= ady)
t = ady;
else
@@ -317,9 +316,7 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable
int32 cdx = (dx << 16) / t;
int32 cdy = (dy << 16) / t;
- int32 i = t;
- while (i) {
-
+ for (int16 i = t; i > 0; i--) {
int32 rx = bx >> 16;
int32 ry = by >> 16;
@@ -337,7 +334,6 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable
bx += cdx;
by += cdy;
- i--;
}
}
} // End of namespace Toon
diff --git a/engines/toon/picture.h b/engines/toon/picture.h
index 460c5b58a2..5e79612a39 100644
--- a/engines/toon/picture.h
+++ b/engines/toon/picture.h
@@ -33,25 +33,27 @@
namespace Toon {
class ToonEngine;
-class Picture {
+class Picture {
public:
Picture(ToonEngine *vm);
~Picture();
+
bool loadPicture(const Common::String &file);
void setupPalette();
- void draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy);
- void drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray);
- void drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy);
- void drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable);
- void floodFillNotWalkableOnMask(int32 x, int32 y);
- uint8 getData(int32 x, int32 y);
+ void draw(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 dy);
+ void drawWithRectList(Graphics::Surface& surface, int16 x, int16 y, int16 dx, int16 dy, Common::Array<Common::Rect>& rectArray);
+ void drawMask(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 dy);
+ void drawLineOnMask(int16 x, int16 y, int16 x2, int16 y2, bool walkable);
+ void floodFillNotWalkableOnMask(int16 x, int16 y);
+ uint8 getData(int16 x, int16 y);
uint8 *getDataPtr() { return _data; }
- int32 getWidth() const { return _width; }
- int32 getHeight() const { return _height; }
+ int16 getWidth() const { return _width; }
+ int16 getHeight() const { return _height; }
+
protected:
- int32 _width;
- int32 _height;
+ int16 _width;
+ int16 _height;
uint8 *_data;
uint8 *_palette; // need to be copied at 3-387
int32 _paletteEntries;
diff --git a/engines/toon/script_func.cpp b/engines/toon/script_func.cpp
index e9b7534198..1fa4058114 100644
--- a/engines/toon/script_func.cpp
+++ b/engines/toon/script_func.cpp
@@ -564,9 +564,9 @@ int32 ScriptFunc::sys_Cmd_Exit_Conversation(EMCState *state) {
int32 ScriptFunc::sys_Cmd_Set_Mouse_Pos(EMCState *state) {
if (_vm->state()->_inCloseUp) {
- _vm->getSystem()->warpMouse(stackPos(0), stackPos(1));
+ _vm->_system->warpMouse(stackPos(0), stackPos(1));
} else {
- _vm->getSystem()->warpMouse(stackPos(0) - _vm->state()->_currentScrollValue, stackPos(1));
+ _vm->_system->warpMouse(stackPos(0) - _vm->state()->_currentScrollValue, stackPos(1));
}
return 0;
}
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
index 416daa1fe8..9fd8415676 100644
--- a/engines/toon/toon.cpp
+++ b/engines/toon/toon.cpp
@@ -51,7 +51,7 @@ void ToonEngine::init() {
_currentScriptRegion = 0;
_resources = new Resources(this);
_animationManager = new AnimationManager(this);
- _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder(_mixer));
+ _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder());
_hotspots = new Hotspots(this);
_mainSurface = new Graphics::Surface();
@@ -820,7 +820,6 @@ Common::Error ToonEngine::run() {
ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
: Engine(syst), _gameDescription(gameDescription),
_language(gameDescription->language), _rnd("toon") {
- _system = syst;
_tickLength = 16;
_currentPicture = NULL;
_inventoryPicture = NULL;
@@ -1224,7 +1223,7 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
_script->init(&_sceneAnimationScripts[i]._state, _sceneAnimationScripts[i]._data);
if (!forGameLoad) {
_script->start(&_sceneAnimationScripts[i]._state, 9 + i);
- _sceneAnimationScripts[i]._lastTimer = getSystem()->getMillis();
+ _sceneAnimationScripts[i]._lastTimer = _system->getMillis();
_sceneAnimationScripts[i]._frozen = false;
_sceneAnimationScripts[i]._frozenForConversation = false;
}
@@ -1588,12 +1587,12 @@ void ToonEngine::clickEvent() {
}
void ToonEngine::selectHotspot() {
- int32 x1 = 0;
- int32 x2 = 0;
- int32 y1 = 0;
- int32 y2 = 0;
+ int16 x1 = 0;
+ int16 x2 = 0;
+ int16 y1 = 0;
+ int16 y2 = 0;
- int32 mouseX = _mouseX;
+ int16 mouseX = _mouseX;
if (_gameState->_inCutaway)
mouseX += TOON_BACKBUFFER_WIDTH;
@@ -1693,7 +1692,6 @@ void ToonEngine::selectHotspot() {
}
void ToonEngine::exitScene() {
-
fadeOut(5);
// disable all scene animation
@@ -2831,7 +2829,6 @@ void ToonEngine::playSoundWrong() {
}
void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) {
-
if (characterId < 0)
characterId = 0;
@@ -2852,8 +2849,8 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) {
}
} else if (characterId == 1) {
// flux
- int32 x = _flux->getX();
- int32 y = _flux->getY();
+ int16 x = _flux->getX();
+ int16 y = _flux->getY();
if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) {
if (!_gameState->_inCutaway) {
*retX = x;
@@ -2885,7 +2882,7 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) {
if (character && !_gameState->_inCutaway) {
if (character->getAnimationInstance()) {
if (character->getX() >= _gameState->_currentScrollValue && character->getX() <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) {
- int32 x1, y1, x2, y2;
+ int16 x1, y1, x2, y2;
character->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2);
*retX = (x1 + x2) / 2;
*retY = y1;
@@ -2896,7 +2893,6 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) {
}
Character *ToonEngine::getCharacterById(int32 charId) {
-
for (int32 i = 0; i < 8; i++) {
if (_characters[i] && _characters[i]->getId() == charId)
return _characters[i];
diff --git a/engines/toon/toon.h b/engines/toon/toon.h
index 540f3e403b..d40c489011 100644
--- a/engines/toon/toon.h
+++ b/engines/toon/toon.h
@@ -289,10 +289,6 @@ public:
return _oldTimer2;
}
- OSystem *getSystem() {
- return _system;
- }
-
AudioManager *getAudioManager() {
return _audioManager;
}
@@ -340,7 +336,6 @@ public:
void clearDirtyRects();
protected:
- OSystem *_system;
int32 _tickLength;
Resources *_resources;
TextResource *_genericTexts;
diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp
index 35dd54776f..e4bbe0c4c1 100644
--- a/engines/touche/detection.cpp
+++ b/engines/touche/detection.cpp
@@ -135,19 +135,13 @@ public:
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- const ADGameDescription *matchedDesc = detectGameFilebased(allFiles, Touche::fileBasedFallback);
-
- if (matchedDesc) { // We got a match
- Common::String report = Common::String::format(_("Your game version has been detected using "
- "filename matching as a variant of %s."), matchedDesc->gameid);
- report += "\n";
- report += _("If this is an original and unmodified version, please report any");
- report += "\n";
- report += _("information previously printed by ScummVM to the team.");
- report += "\n";
- g_system->logMessage(LogMessageType::kInfo, report.c_str());
- }
+ ADFilePropertiesMap filesProps;
+
+ const ADGameDescription *matchedDesc = detectGameFilebased(allFiles, fslist, Touche::fileBasedFallback, &filesProps);
+ if (!matchedDesc)
+ return 0;
+ reportUnknown(fslist.begin()->getParent(), filesProps);
return matchedDesc;
}
diff --git a/engines/tsage/blue_force/blueforce_dialogs.cpp b/engines/tsage/blue_force/blueforce_dialogs.cpp
index a76d5839a9..23701c9e5b 100644
--- a/engines/tsage/blue_force/blueforce_dialogs.cpp
+++ b/engines/tsage/blue_force/blueforce_dialogs.cpp
@@ -88,7 +88,7 @@ RightClickDialog::~RightClickDialog() {
void RightClickDialog::draw() {
// Save the covered background area
- _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
+ _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
// Draw the dialog image
g_globals->gfxManager().copyFrom(_surface, _bounds.left, _bounds.top);
@@ -323,7 +323,7 @@ void AmmoBeltDialog::draw() {
if (!_savedArea) {
// Save the covered background area
- _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
+ _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
} else {
bounds.moveTo(0, 0);
}
diff --git a/engines/tsage/blue_force/blueforce_scenes9.cpp b/engines/tsage/blue_force/blueforce_scenes9.cpp
index 2178f31b30..1cb8191640 100644
--- a/engines/tsage/blue_force/blueforce_scenes9.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes9.cpp
@@ -794,12 +794,12 @@ bool Scene910::Lyle::startAction(CursorType action, Event &event) {
Scene910 *scene = (Scene910 *)BF_GLOBALS._sceneManager._scene;
if (action == CURSOR_USE) {
- if (BF_GLOBALS._v4CEE2 == 0)
+ if (BF_GLOBALS._nico910State == 0)
return NamedObject::startAction(action, event);
else
return false;
} else if (action == CURSOR_TALK) {
- if ((BF_GLOBALS._hiddenDoorStatus != 0) || (BF_GLOBALS._v4CEE2 != 0)) {
+ if ((BF_GLOBALS._hiddenDoorStatus != 0) || (BF_GLOBALS._nico910State != 0)) {
scene->_stripManager.start(9100 + _field90, &BF_GLOBALS._stripProxy);
if (_field90 < 1)
_field90++;
@@ -833,7 +833,7 @@ bool Scene910::Nico::startAction(CursorType action, Event &event) {
return true;
break;
case CURSOR_TALK:
- if (BF_GLOBALS._v4CEE2 >= 4)
+ if (BF_GLOBALS._nico910State >= 4)
return NamedObject::startAction(action, event);
if (BF_GLOBALS._v4CEE6 < 4)
@@ -847,8 +847,8 @@ bool Scene910::Nico::startAction(CursorType action, Event &event) {
return true;
break;
case INV_COLT45:
- if (BF_GLOBALS._v4CEE2 > 1) {
- if (BF_GLOBALS._v4CEE2 != 4) {
+ if (BF_GLOBALS._nico910State > 1) {
+ if (BF_GLOBALS._nico910State != 4) {
if ((BF_GLOBALS.getFlag(gunDrawn)) && (BF_GLOBALS.getFlag(fGunLoaded)) && (BF_GLOBALS.getHasBullets())) {
if (scene->_field2DE0 == 0) {
BF_GLOBALS._player.disableControl();
@@ -880,7 +880,7 @@ bool Scene910::Nico::startAction(CursorType action, Event &event) {
break;
case INV_BADGE:
case INV_ID:
- if (BF_GLOBALS._v4CEE2 >= 4)
+ if (BF_GLOBALS._nico910State >= 4)
return NamedObject::startAction(action, event);
if (BF_GLOBALS._v4CEE6 < 4)
@@ -895,11 +895,12 @@ bool Scene910::Nico::startAction(CursorType action, Event &event) {
return true;
break;
case INV_YELLOW_CORD:
- if (BF_GLOBALS._v4CEE2 < 4) {
+ if (BF_GLOBALS._nico910State < 4) {
BF_GLOBALS._player.disableControl();
scene->_yellowCord.fixPriority(121);
scene->_sceneSubMode = 10;
scene->_sceneMode = 9123;
+ BF_GLOBALS._nico910State = 3;
if (BF_GLOBALS._player._visage == 1911)
scene->setAction(&scene->_sequenceManager1, scene, 9123, &BF_GLOBALS._player, NULL);
else
@@ -995,7 +996,7 @@ bool Scene910::Stuart::startAction(CursorType action, Event &event) {
return true;
} else {
BF_GLOBALS._player.disableControl();
- if (BF_GLOBALS._v4CEE2 == 4) {
+ if (BF_GLOBALS._nico910State == 4) {
scene->_sceneSubMode = 11;
scene->_sceneMode = 9123;
if (BF_GLOBALS._player._visage == 1911)
@@ -1136,7 +1137,7 @@ bool Scene910::BreakerBox::startAction(CursorType action, Event &event) {
SceneItem::display2(910, 62);
return true;
} else if (scene->_sceneMode != 9120) {
- if (BF_GLOBALS._v4CEE2 == 1) {
+ if (BF_GLOBALS._nico910State == 1) {
BF_GLOBALS._player.disableControl();
scene->_sceneMode = 9118;
scene->setAction(&scene->_sequenceManager1, scene, 9118, &BF_GLOBALS._player, &scene->_nico, NULL);
@@ -1291,7 +1292,7 @@ bool Scene910::Object13::startAction(CursorType action, Event &event) {
switch (_state) {
case 1:
- if (BF_GLOBALS._v4CEE2 < 1) {
+ if (BF_GLOBALS._nico910State < 1) {
if (_frame == 2) {
if (!BF_GLOBALS.getFlag(fGotPointsForClosingDoor)) {
T2_GLOBALS._uiElements.addScore(30);
@@ -1299,7 +1300,7 @@ bool Scene910::Object13::startAction(CursorType action, Event &event) {
}
scene->_sceneMode = 0;
if (BF_GLOBALS._dayNumber == 5) {
- if (BF_GLOBALS._v4CEE2 == 0) {
+ if (BF_GLOBALS._nico910State == 0) {
scene->_breakerBoxInset.remove();
// _objectList.draw();
BF_GLOBALS._player.disableControl();
@@ -1309,7 +1310,7 @@ bool Scene910::Object13::startAction(CursorType action, Event &event) {
scene->_nico.postInit();
scene->_sceneMode = 9129;
scene->setAction(&scene->_sequenceManager1, scene, 9129, &BF_GLOBALS._player, &scene->_nico, NULL);
- } else if (BF_GLOBALS._v4CEE2 == 2) {
+ } else if (BF_GLOBALS._nico910State == 2) {
scene->_breakerBoxInset.remove();
// _objectList.draw();
BF_GLOBALS._player.disableControl();
@@ -1612,7 +1613,7 @@ bool Scene910::BlackPlug::startAction(CursorType action, Event &event) {
SET_EXT_FGCOLOR, 13, LIST_END);
return true;
}
- if (BF_GLOBALS._v4CEE2 == 3) {
+ if (BF_GLOBALS._nico910State == 3) {
SceneItem::display(910, 84, SET_WIDTH, 312,
SET_X, GLOBALS._sceneManager._scene->_sceneBounds.left + 4,
SET_Y, GLOBALS._sceneManager._scene->_sceneBounds.top + UI_INTERFACE_Y + 2,
@@ -1830,7 +1831,7 @@ bool Scene910::Generator::startAction(CursorType action, Event &event) {
SET_Y, GLOBALS._sceneManager._scene->_sceneBounds.top + UI_INTERFACE_Y + 2,
SET_FONT, 4, SET_BG_COLOR, 1, SET_FG_COLOR, 19, SET_EXT_BGCOLOR, 9,
SET_EXT_FGCOLOR, 13, LIST_END);
- else if (BF_GLOBALS._v4CEE2 == 1) {
+ else if (BF_GLOBALS._nico910State == 1) {
BF_GLOBALS._player.disableControl();
scene->_sceneMode = 9118;
scene->setAction(&scene->_sequenceManager1, scene, 9118, &BF_GLOBALS._player, &scene->_nico, NULL);
@@ -1869,7 +1870,7 @@ bool Scene910::Item2::startAction(CursorType action, Event &event) {
bool Scene910::Item3::startAction(CursorType action, Event &event) {
Scene910 *scene = (Scene910 *)BF_GLOBALS._sceneManager._scene;
- if ((action == CURSOR_TALK) && (BF_GLOBALS._v4CEE2 == 4) && (BF_GLOBALS._v4CEE4 == 0)) {
+ if ((action == CURSOR_TALK) && (BF_GLOBALS._nico910State == 4) && (BF_GLOBALS._v4CEE4 == 0)) {
BF_GLOBALS._player.disableControl();
scene->_sceneMode = 15;
scene->_stripManager.start(9102, scene);
@@ -1907,7 +1908,7 @@ bool Scene910::Item15::startAction(CursorType action, Event &event) {
bool Scene910::Item16::startAction(CursorType action, Event &event) {
Scene910 *scene = (Scene910 *)BF_GLOBALS._sceneManager._scene;
- if ((BF_GLOBALS._hiddenDoorStatus == 0) || (BF_GLOBALS._v4CEE2 != 0))
+ if ((BF_GLOBALS._hiddenDoorStatus == 0) || (BF_GLOBALS._nico910State != 0))
return false;
if (BF_GLOBALS._player._visage == 1911) {
@@ -2016,7 +2017,7 @@ void Scene910::postInit(SceneObjectList *OwnerList) {
if (BF_GLOBALS._dayNumber < 5)
_item17.setDetails(Rect(0, 149, 29, 167), 910, -1, -1, -1, 1, NULL);
- if (BF_GLOBALS._v4CEE2 == 0)
+ if (BF_GLOBALS._nico910State == 0)
_item16.setDetails(Rect(265, 18, 319, 102), 910, -1, -1, -1, 1, NULL);
_breakerBox.setDetails(910, 6, -1, -1, 1, (SceneItem *)NULL);
@@ -2048,7 +2049,7 @@ void Scene910::postInit(SceneObjectList *OwnerList) {
|| (BF_GLOBALS._sceneManager._previousScene == 190)
|| (BF_GLOBALS._sceneManager._previousScene == 300)) {
BF_GLOBALS._sceneManager._previousScene = 900;
- BF_GLOBALS._v4CEE2 = 0;
+ BF_GLOBALS._nico910State = 0;
BF_GLOBALS._v4CEE4 = 0;
}
@@ -2142,7 +2143,7 @@ void Scene910::postInit(SceneObjectList *OwnerList) {
_nico.setPosition(Common::Point(262, 124));
_nico.setStrip(6);
BF_GLOBALS._v4CEE6 = 0;
- BF_GLOBALS._v4CEE2 = 1;
+ BF_GLOBALS._nico910State = 1;
_nico.setDetails(910, 63, 64, 67, 5, &_item4);
BF_GLOBALS._v4CECA = 2;
if (BF_GLOBALS._v4CECC == 0)
@@ -2157,7 +2158,7 @@ void Scene910::postInit(SceneObjectList *OwnerList) {
BF_GLOBALS._player.disableControl();
}
- if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._v4CEE2 == 0)){
+ if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._nico910State == 0)){
_shadow.postInit();
_shadow.setAction(&_action2);
}
@@ -2297,7 +2298,7 @@ void Scene910::signal() {
case 13:
BF_GLOBALS._player.disableControl();
BF_GLOBALS._player.setAction(&_sequenceManager2, NULL, 9117, &_nico, NULL);
- BF_GLOBALS._v4CEE2 = 2;
+ BF_GLOBALS._nico910State = 2;
// No break on purpose
case 15:
_stuart.postInit();
@@ -2314,7 +2315,7 @@ void Scene910::signal() {
_lyle._field90 = 1;
_sceneMode = 10;
addFader((const byte *)&black, 2, this);
- BF_GLOBALS._v4CEE2 = 1;
+ BF_GLOBALS._nico910State = 1;
BF_GLOBALS._walkRegions.disableRegion(16);
BF_GLOBALS._walkRegions.disableRegion(14);
BF_GLOBALS._sceneItems.remove(&_item16);
@@ -2324,7 +2325,7 @@ void Scene910::signal() {
BF_GLOBALS._player._frame = 1;
if (_field2DE2 == 0) {
_field2DE2 = 1;
- if (BF_GLOBALS._v4CEE2 == 4) {
+ if (BF_GLOBALS._nico910State == 4) {
_sceneMode = 9149;
setAction(&_sequenceManager1, this, 9149, &BF_GLOBALS._player, NULL);
} else {
@@ -2452,7 +2453,7 @@ void Scene910::signal() {
break;
case 9114:
_fakeWall.hide();
- if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._v4CEE2 == 0)) {
+ if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._nico910State == 0)) {
BF_GLOBALS._player.disableControl();
_nico.postInit();
_nico.setDetails(910, 63, 64, 65, 5, &_item4);
@@ -2496,7 +2497,7 @@ void Scene910::signal() {
case 9121:
_item3.setDetails(7, 910, 96, 60, 61, 3);
BF_GLOBALS._v4CEE4 = 2;
- if (BF_GLOBALS._v4CEE2 == 4) {
+ if (BF_GLOBALS._nico910State == 4) {
_sceneMode = 20;
_stripManager.start(9115, this);
} else {
@@ -2527,7 +2528,7 @@ void Scene910::signal() {
setAction(&_sequenceManager1, this, 9111, &BF_GLOBALS._player, &_blackCord, NULL);
break;
case 5:
- switch (BF_GLOBALS._v4CEE2 - 1) {
+ switch (BF_GLOBALS._nico910State - 1) {
case 0:
_sceneMode = 9118;
setAction(&_sequenceManager1, this, 9118, &BF_GLOBALS._player, &_nico, NULL);
@@ -2598,7 +2599,7 @@ void Scene910::signal() {
break;
case 9125:
BF_GLOBALS.setFlag(fBackupAt340);
- BF_GLOBALS._v4CEE2 = 4;
+ BF_GLOBALS._nico910State = 4;
_stuart.postInit();
_nico.setDetails(910, 72, 73, 74, 3, (SceneItem *)NULL);
_stuart.setDetails(910, 66, 67, 68, 5, &_nico);
@@ -2645,7 +2646,7 @@ void Scene910::signal() {
}
_lyle.setAction(&_sequenceManager2, NULL, 9131, &_lyle, NULL);
BF_GLOBALS._walkRegions.enableRegion(16);
- if (BF_GLOBALS._v4CEE2 == 4)
+ if (BF_GLOBALS._nico910State == 4)
BF_INVENTORY.setObjectScene(INV_YELLOW_CORD, 0);
else
BF_INVENTORY.setObjectScene(INV_HALF_YELLOW_CORD, 910);
@@ -2679,7 +2680,7 @@ void Scene910::signal() {
}
break;
case 9143:
- if (BF_GLOBALS._v4CEE2 == 0) {
+ if (BF_GLOBALS._nico910State == 0) {
BF_GLOBALS._v51C44 = 1;
BF_GLOBALS._sceneManager.changeScene(920);
} else {
@@ -2730,7 +2731,7 @@ void Scene910::process(Event &event) {
if (_item17._bounds.contains(event.mousePos)) {
GfxSurface surface = _cursorVisage.getFrame(EXITFRAME_SW);
BF_GLOBALS._events.setCursor(surface);
- } else if ((BF_GLOBALS._hiddenDoorStatus == 0) || (BF_GLOBALS._v4CEE2 != 0)) {
+ } else if ((BF_GLOBALS._hiddenDoorStatus == 0) || (BF_GLOBALS._nico910State != 0)) {
CursorType cursorId = BF_GLOBALS._events.getCursor();
BF_GLOBALS._events.setCursor(cursorId);
} else if (!_item16._bounds.contains(event.mousePos)) {
@@ -2755,7 +2756,7 @@ void Scene910::process(Event &event) {
_sceneMode = 9123;
setAction(&_sequenceManager1, this, 9123, &BF_GLOBALS._player, NULL);
event.handled = true;
- } else if (BF_GLOBALS._v4CEE2 <= 1) {
+ } else if (BF_GLOBALS._nico910State <= 1) {
if (BF_GLOBALS.getFlag(fCanDrawGun)) {
BF_GLOBALS._player.addMover(NULL);
BF_GLOBALS._player.disableControl();
@@ -2776,7 +2777,7 @@ void Scene910::process(Event &event) {
event.handled = true;
break;
case CURSOR_WALK:
- if (BF_GLOBALS._v4CEE2 == 1) {
+ if (BF_GLOBALS._nico910State == 1) {
BF_GLOBALS._player.disableControl();
if (BF_GLOBALS._player._visage == 1911) {
BF_GLOBALS._player.disableControl();
@@ -2826,7 +2827,7 @@ void Scene910::dispatch() {
_sceneSubMode = 3;
_sceneMode = 9123;
setAction(&_sequenceManager1, this, 9123, &BF_GLOBALS._player, NULL);
- } else if (BF_GLOBALS._v4CEE2 == 0) {
+ } else if (BF_GLOBALS._nico910State == 0) {
_sceneMode = 9143;
setAction(&_sequenceManager1, this, 9143, &BF_GLOBALS._player, NULL);
} else {
@@ -2840,7 +2841,7 @@ void Scene910::dispatch() {
}
}
- if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._player._position.x > 250) && (_sceneMode != 9135) && (_sceneMode != 11) && (BF_GLOBALS._hiddenDoorStatus != 0) && (BF_GLOBALS._v4CEE2 == 0)) {
+ if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._player._position.x > 250) && (_sceneMode != 9135) && (_sceneMode != 11) && (BF_GLOBALS._hiddenDoorStatus != 0) && (BF_GLOBALS._nico910State == 0)) {
BF_GLOBALS._player.disableControl();
_shadow.remove();
_nico.remove();
@@ -2853,7 +2854,7 @@ void Scene910::dispatch() {
}
void Scene910::checkGun() {
- if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._v4CEE2 == 0) && (BF_GLOBALS._hiddenDoorStatus != 0))
+ if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._nico910State == 0) && (BF_GLOBALS._hiddenDoorStatus != 0))
SceneItem::display(910, 70, SET_WIDTH, 312,
SET_X, GLOBALS._sceneManager._scene->_sceneBounds.left + 4,
SET_Y, GLOBALS._sceneManager._scene->_sceneBounds.top + UI_INTERFACE_Y + 2,
@@ -2900,7 +2901,7 @@ void Scene910::closeHiddenDoor() {
setAction(&_sequenceManager1, this, 9115, &_fakeWall, &_object5, NULL);
}
- if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._v4CEE2 == 0)) {
+ if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._nico910State == 0)) {
// _objectList.draw();
if (BF_GLOBALS._sceneObjects->contains(&_breakerBoxInset))
_breakerBoxInset.remove();
diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp
index 06fbffb751..ba27db9104 100644
--- a/engines/tsage/converse.cpp
+++ b/engines/tsage/converse.cpp
@@ -505,7 +505,7 @@ void ConversationChoiceDialog::draw() {
// Make a backup copy of the area the dialog will occupy
Rect tempRect = _bounds;
tempRect.collapse(-10, -10);
- _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), tempRect);
+ _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), tempRect);
// Fill in the contents of the entire dialog
_gfxManager._bounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp
index 0c458f5c35..bcadfdc201 100644
--- a/engines/tsage/detection.cpp
+++ b/engines/tsage/detection.cpp
@@ -164,8 +164,6 @@ public:
// Create the return descriptor
SaveStateDescriptor desc(slot, header.saveName);
- desc.setDeletableFlag(true);
- desc.setWriteProtectedFlag(false);
desc.setThumbnail(header.thumbnail);
desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
desc.setSaveTime(header.saveHour, header.saveMinutes);
diff --git a/engines/tsage/detection_tables.h b/engines/tsage/detection_tables.h
index d538cbacbf..a84ee5662f 100644
--- a/engines/tsage/detection_tables.h
+++ b/engines/tsage/detection_tables.h
@@ -105,7 +105,7 @@ static const tSageGameDescription gameDescriptions[] = {
AD_ENTRY1s("blue.rlb", "17c3993415e8a2cf93040eef7e88ec93", 1156508),
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_TESTING,
+ ADGF_UNSTABLE,
GUIO2(GUIO_NOSPEECH, GUIO_NOSFX)
},
GType_BlueForce,
@@ -120,7 +120,7 @@ static const tSageGameDescription gameDescriptions[] = {
AD_ENTRY1s("blue.rlb", "17eabb456cb1546c66baf1aff387ba6a", 10032614),
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_TESTING,
+ ADGF_NO_FLAGS,
GUIO2(GUIO_NOSPEECH, GUIO_NOSFX)
},
GType_BlueForce,
@@ -134,7 +134,7 @@ static const tSageGameDescription gameDescriptions[] = {
AD_ENTRY1s("blue.rlb", "99983f48cb218f1f3760cf2f9a7ef11d", 63863322),
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD,
GUIO2(GUIO_NOSPEECH, GUIO_NOSFX)
},
GType_BlueForce,
@@ -150,7 +150,7 @@ static const tSageGameDescription gameDescriptions[] = {
AD_ENTRY1s("blue.rlb", "5b2b35c51b62e82d82b0791540bfae2d", 10082565),
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_CD | ADGF_TESTING,
+ ADGF_CD | ADGF_UNSTABLE,
GUIO2(GUIO_NOSPEECH, GUIO_NOSFX)
},
GType_BlueForce,
diff --git a/engines/tsage/dialogs.cpp b/engines/tsage/dialogs.cpp
index 972d591c34..77ac0a25d7 100644
--- a/engines/tsage/dialogs.cpp
+++ b/engines/tsage/dialogs.cpp
@@ -116,7 +116,7 @@ void ModalDialog::draw() {
// Make a backup copy of the area the dialog will occupy
Rect tempRect = _bounds;
tempRect.collapse(-10, -10);
- _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), tempRect);
+ _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), tempRect);
_gfxManager.activate();
diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp
index 59eb59b194..de9463268b 100644
--- a/engines/tsage/globals.cpp
+++ b/engines/tsage/globals.cpp
@@ -247,7 +247,7 @@ void BlueForceGlobals::synchronize(Serializer &s) {
for (int i = 0; i < 18; i++)
s.syncAsByte(_breakerBoxStatusArr[i]);
s.syncAsSint16LE(_hiddenDoorStatus);
- s.syncAsSint16LE(_v4CEE2);
+ s.syncAsSint16LE(_nico910State);
s.syncAsSint16LE(_v4CEE4);
s.syncAsSint16LE(_v4CEE6);
s.syncAsSint16LE(_v4CEE8);
@@ -320,7 +320,7 @@ void BlueForceGlobals::reset() {
_breakerBoxStatusArr[16] = 3;
_breakerBoxStatusArr[17] = 0;
_hiddenDoorStatus = 0;
- _v4CEE2 = 0;
+ _nico910State = 0;
_v4CEE4 = 0;
_v4CEE6 = 0;
_v4CEE8 = 0;
diff --git a/engines/tsage/globals.h b/engines/tsage/globals.h
index 45226c921b..d190b6a2a4 100644
--- a/engines/tsage/globals.h
+++ b/engines/tsage/globals.h
@@ -200,7 +200,7 @@ public:
int _v4CECC;
int8 _breakerBoxStatusArr[18];
int _hiddenDoorStatus;
- int _v4CEE2;
+ int _nico910State;
int _v4CEE4;
int _v4CEE6;
int _v4CEE8;
diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp
index 0781ae4544..fb0b0b0cbb 100644
--- a/engines/tsage/graphics.cpp
+++ b/engines/tsage/graphics.cpp
@@ -38,7 +38,7 @@ namespace TsAGE {
* @src Source surface
* @bounds Area to backup
*/
-GfxSurface *Surface_getArea(GfxSurface &src, const Rect &bounds) {
+GfxSurface *surfaceGetArea(GfxSurface &src, const Rect &bounds) {
assert(bounds.isValidRect());
GfxSurface *dest = new GfxSurface();
dest->create(bounds.width(), bounds.height());
@@ -437,7 +437,7 @@ bool GfxSurface::displayText(const Common::String &msg, const Common::Point &pt)
// Make a backup copy of the area the text will occupy
Rect saveRect = textRect;
saveRect.collapse(-20, -8);
- GfxSurface *savedArea = Surface_getArea(gfxManager.getSurface(), saveRect);
+ GfxSurface *savedArea = surfaceGetArea(gfxManager.getSurface(), saveRect);
// Display the text
gfxManager._font.writeLines(msg.c_str(), textRect, ALIGN_LEFT);
@@ -1073,7 +1073,7 @@ void GfxDialog::draw() {
Rect tempRect(_bounds);
// Make a backup copy of the area the dialog will occupy
- _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
+ _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
// Set the palette for use in the dialog
setPalette();
diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h
index 9c6f13e407..9175b1050a 100644
--- a/engines/tsage/graphics.h
+++ b/engines/tsage/graphics.h
@@ -339,7 +339,7 @@ public:
static void setPalette();
};
-GfxSurface *Surface_getArea(GfxSurface &src, const Rect &bounds);
+GfxSurface *surfaceGetArea(GfxSurface &src, const Rect &bounds);
GfxSurface surfaceFromRes(const byte *imgData);
GfxSurface surfaceFromRes(int resNum, int rlbNum, int subNum);
diff --git a/engines/tsage/ringworld/ringworld_dialogs.cpp b/engines/tsage/ringworld/ringworld_dialogs.cpp
index 0e451b8429..4728e66cd9 100644
--- a/engines/tsage/ringworld/ringworld_dialogs.cpp
+++ b/engines/tsage/ringworld/ringworld_dialogs.cpp
@@ -59,7 +59,7 @@ void RightClickButton::highlight() {
_savedButton = NULL;
} else {
// Highlight button by getting the needed highlighted image resource
- _savedButton = Surface_getArea(g_globals->gfxManager().getSurface(), _bounds);
+ _savedButton = surfaceGetArea(g_globals->gfxManager().getSurface(), _bounds);
uint size;
byte *imgData = g_resourceManager->getSubResource(7, 2, _buttonIndex, &size);
@@ -122,7 +122,7 @@ RightClickButton *RightClickDialog::findButton(const Common::Point &pt) {
void RightClickDialog::draw() {
// Save the covered background area
- _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
+ _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
// Draw the dialog image
g_globals->gfxManager().copyFrom(_surface, _bounds.left, _bounds.top);
diff --git a/engines/tsage/ringworld/ringworld_logic.cpp b/engines/tsage/ringworld/ringworld_logic.cpp
index 00c219f2ee..7d571b40d7 100644
--- a/engines/tsage/ringworld/ringworld_logic.cpp
+++ b/engines/tsage/ringworld/ringworld_logic.cpp
@@ -295,7 +295,7 @@ void SceneArea::display() {
_bounds.setWidth(_surface.getBounds().width());
_bounds.setHeight(_surface.getBounds().height());
- _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
+ _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
draw2();
}
diff --git a/engines/tsage/ringworld/ringworld_scenes5.cpp b/engines/tsage/ringworld/ringworld_scenes5.cpp
index 3b415bdb6a..004ccbbb6d 100644
--- a/engines/tsage/ringworld/ringworld_scenes5.cpp
+++ b/engines/tsage/ringworld/ringworld_scenes5.cpp
@@ -1893,7 +1893,7 @@ void Scene4045::postInit(SceneObjectList *OwnerList) {
_olloFace.setStrip(4);
_olloFace.fixPriority(152);
- if(g_globals->_sceneManager._previousScene == 4050) {
+ if (g_globals->_sceneManager._previousScene == 4050) {
g_globals->_soundHandler.play(155);
g_globals->_player.setPosition(Common::Point(72, 128));
g_globals->_player.enableControl();
diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp
index 30ae6be7b1..478fdcf5a5 100644
--- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp
+++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp
@@ -85,7 +85,7 @@ RightClickDialog::~RightClickDialog() {
void RightClickDialog::draw() {
// Save the covered background area
- _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
+ _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds);
// Draw the dialog image
g_globals->gfxManager().copyFrom(_surface, _bounds.left, _bounds.top);
diff --git a/engines/tsage/ringworld2/ringworld2_speakers.h b/engines/tsage/ringworld2/ringworld2_speakers.h
index e336564c5f..fa2946d56c 100644
--- a/engines/tsage/ringworld2/ringworld2_speakers.h
+++ b/engines/tsage/ringworld2/ringworld2_speakers.h
@@ -504,14 +504,14 @@ public:
class SpeakerSoldier300 : public SpeakerSoldier {
public:
- SpeakerSoldier300() : SpeakerSoldier(60) {};
+ SpeakerSoldier300() : SpeakerSoldier(60) {}
virtual Common::String getClassName() { return "SpeakerSoldier300"; }
virtual void proc15();
};
class SpeakerSoldier1625 : public SpeakerSoldier {
public:
- SpeakerSoldier1625() : SpeakerSoldier(5) {};
+ SpeakerSoldier1625() : SpeakerSoldier(5) {}
virtual Common::String getClassName() { return "SpeakerSoldier1625"; }
};
@@ -585,7 +585,7 @@ public:
class SpeakerWebbster3240 : public SpeakerWebbster {
public:
- SpeakerWebbster3240() : SpeakerWebbster(10) {};
+ SpeakerWebbster3240() : SpeakerWebbster(10) {}
virtual Common::String getClassName() { return "SpeakerWebbster3240"; }
virtual void proc15();
@@ -593,7 +593,7 @@ public:
class SpeakerWebbster3375 : public SpeakerWebbster {
public:
- SpeakerWebbster3375() : SpeakerWebbster(60) {};
+ SpeakerWebbster3375() : SpeakerWebbster(60) {}
virtual Common::String getClassName() { return "SpeakerWebbster3375"; }
virtual void proc15();
@@ -601,7 +601,7 @@ public:
class SpeakerWebbster3385 : public SpeakerWebbster {
public:
- SpeakerWebbster3385() : SpeakerWebbster(60) {};
+ SpeakerWebbster3385() : SpeakerWebbster(60) {}
virtual Common::String getClassName() { return "SpeakerWebbster3385"; }
virtual void proc15();
@@ -609,7 +609,7 @@ public:
class SpeakerWebbster3395 : public SpeakerWebbster {
public:
- SpeakerWebbster3395() : SpeakerWebbster(60) {};
+ SpeakerWebbster3395() : SpeakerWebbster(60) {}
virtual Common::String getClassName() { return "SpeakerWebbster3395"; }
virtual void proc15();
@@ -617,7 +617,7 @@ public:
class SpeakerWebbster3400 : public SpeakerWebbster {
public:
- SpeakerWebbster3400() : SpeakerWebbster(27) {};
+ SpeakerWebbster3400() : SpeakerWebbster(27) {}
virtual Common::String getClassName() { return "SpeakerWebbster3400"; }
virtual void proc15();
diff --git a/engines/tsage/user_interface.cpp b/engines/tsage/user_interface.cpp
index 10cb6961dc..4bd9e49875 100644
--- a/engines/tsage/user_interface.cpp
+++ b/engines/tsage/user_interface.cpp
@@ -112,7 +112,7 @@ void UIQuestion::showItem(int resNum, int rlbNum, int frameNum) {
imgRect.center(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
// Save the area behind where the image will be displayed
- GfxSurface *savedArea = Surface_getArea(GLOBALS.gfxManager().getSurface(), imgRect);
+ GfxSurface *savedArea = surfaceGetArea(GLOBALS.gfxManager().getSurface(), imgRect);
// Draw the image
GLOBALS.gfxManager().copyFrom(objImage, imgRect);
diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp
index 775fd6f1a0..16c4f4f6f0 100644
--- a/engines/tucker/sequences.cpp
+++ b/engines/tucker/sequences.cpp
@@ -28,6 +28,7 @@
#include "audio/decoders/wave.h"
#include "graphics/palette.h"
+#include "graphics/surface.h"
#include "tucker/tucker.h"
#include "tucker/graphics.h"
@@ -749,6 +750,7 @@ void AnimationSequencePlayer::openAnimation(int index, const char *fileName) {
_seqNum = 1;
return;
}
+ _flicPlayer[index].start();
_flicPlayer[index].decodeNextFrame();
if (index == 0) {
getRGBPalette(index);
@@ -801,7 +803,7 @@ void AnimationSequencePlayer::playIntroSeq19_20() {
if (_flicPlayer[0].getCurFrame() >= 115) {
surface = _flicPlayer[1].decodeNextFrame();
if (_flicPlayer[1].endOfVideo())
- _flicPlayer[1].reset();
+ _flicPlayer[1].rewind();
}
bool framesLeft = decodeNextAnimationFrame(0, false);